expose sound device topology information
RFC PATCH 1/11 expose sound device topology information
Hi,
these are some tentative patches to allow sound drivers to provide routing information to userspace. (So far, snd-usb-audio has a partial implementation; I haven't yet had time for snd-hda-intel. I haven't even looked at ASoC.)
The media controller API <linux/media.h> allows prividing routing information, but its implementation does not quite fit the sound drivers:
* it allows reconfiguration of links, but not in a way that would be useful for ALSA selector controls;
* it allows drivers to access the entity graph and pipelines, which is not needed;
* it is rather heavyweight.
Therefore, these patches create their own implementation of the media controller API. In this implementation, all entity and link information is completely static, and more space-efficient.
For simplicity, the ioctls hook into the ALSA control device instead of creating a new /dev/media* device.
The separate implementation does not allow sharing of one media controller device in the case of combined audio/video devices. However, separate drivers would already be a problem for HDMI outputs (GPU and sound); it appears we might need some mechanism to connect the topologies of multiple media devices.
TLVs (for jack entities, and for associating controls with entities) are not yet defined.
Example output for my simple UA-1A device (not all information is decoded correctly):
$ media-ctl -p -d /dev/snd/controlC5 Opening media device /dev/snd/controlC5 Enumerating entities Found 4 entities Enumerating pads and links Media controller API version 0.0.0
Media device information
------------------------
driver snd-usb-audio
model EDIROL UA-1A
serial
bus info usb-0000:00:12.2-4.3 hw revision 0x101 driver version 0.0.0
Device topology
- entity 1: USB Audio (1 pad, 1 link)
type Node subtype ALSA
device node name /dev/tty (should be hw:5,0,0)
pad0: Source
-> "OT3":0 [ENABLED,IMMUTABLE]
- entity 3: OT3 (1 pad, 1 link)
type Unknown subtype Unknown (should be Jack)
pad0: Sink
<- "USB Audio":0 [ENABLED,IMMUTABLE]
- entity 4: IT4 (1 pad, 1 link)
type Unknown subtype Unknown
pad0: Source
-> "USB Audio":0 [ENABLED,IMMUTABLE]
- entity 7: USB Audio (1 pad, 1 link)
type Node subtype ALSA
device node name /dev/tty
pad0: Sink
<- "IT4":0 [ENABLED,IMMUTABLE]
include/linux/media.h | 9 include/sound/core.h | 13 + include/sound/media.h | 116 ++++++++++ include/sound/pcm.h | 6 sound/core/Kconfig | 7 sound/core/Makefile | 1 sound/core/init.c | 4 sound/core/media.c | 425 ++++++++++++++++++++++++++++++++++++++ sound/core/pcm.c | 46 ++++ sound/core/sound.c | 3 sound/pci/hda/hda_intel.c | 2 sound/usb/card.c | 2 sound/usb/mixer.c | 278 ++++++++++++++++++++++++ sound/usb/quirks.c | 4 sound/usb/stream.c | 16 - sound/usb/stream.h | 1 16 files changed, 925 insertions(+), 8 deletions(-)
Regards,
Clemens
RFC PATCH 1/11 ALSA: implement MEDIA_IOC_DEVICE_INFO
Add a callback to snd_card to allow card drivers to return driver- specific information.
--- include/sound/core.h | 5 +++ include/sound/media.h | 50 ++++++++++++++++++++++++++++++++ sound/core/Kconfig | 7 +++++ sound/core/Makefile | 1 + sound/core/media.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ sound/core/sound.c | 3 ++ 6 files changed, 142 insertions(+), 0 deletions(-) create mode 100644 include/sound/media.h create mode 100644 sound/core/media.c
include/sound/core.h +5 -0
@@ -42,6 +42,7 @@ struct pci_dev;struct module ;struct device ;struct device_attribute ; +struct snd_media_card_ops ;/* device allocation stuff */
@@ -145,6 +146,10 @@ struct snd_card {struct snd_mixer_oss *mixer_oss;int mixer_oss_change_count;#endif + +#ifdef CONFIG_SND_MEDIA +const struct snd_media_card_ops *media_ops; +#endif };#ifdef CONFIG_PM
include/sound/media.h new file +50 -0
50 lines not on this page · raw message
sound/core/Kconfig +7 -0
@@ -147,6 +147,13 @@ config SND_SEQ_RTCTIMER_DEFAULT If in doubt, say Y. +config SND_MEDIA + bool "Media Controller API (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + Say Y here to enable the media controller API, which allows to + retrieve the internal topology of sound devices. + config SND_DYNAMIC_MINORS bool "Dynamic device file minor numbers" help
sound/core/Makefile +1 -0
@@ -9,6 +9,7 @@ snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o snd-$(CONFIG_SND_VMASTER) += vmaster.o snd-$(CONFIG_SND_KCTL_JACK) += ctljack.o snd-$(CONFIG_SND_JACK) += jack.o +snd-$(CONFIG_SND_MEDIA) += media.o snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ pcm_memory.o
sound/core/media.c new file +76 -0
76 lines not on this page · raw message
sound/core/sound.c +3 -0
@@ -30,6 +30,7 @@#include <sound/version.h> #include <sound/control.h> #include <sound/initval.h> +#include <sound/media.h> #include <linux/kmod.h> #include <linux/mutex.h>
@@ -467,6 +468,7 @@ static int __init alsa_sound_init(void)return -ENOMEM ; }snd_info_minor_register (); +snd_media_init ();#ifndef MODULE printk (KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n" );#endif
@@ -475,6 +477,7 @@ static int __init alsa_sound_init(void) static void __exit alsa_sound_exit(void) { +snd_media_exit ();snd_info_minor_unregister ();snd_info_done ();unregister_chrdev (major,"alsa" );
Re: [RFC PATCH 01/11] ALSA: implement MEDIA_IOC_DEVICE_INFO
sound/core/Kconfig config SND_SEQ_RTCTIMER_DEFAULT · line 155
Quoted 6 lines · Clemens Ladisch
sound/core/Kconfig +6
-0+config SND_MEDIA + bool "Media Controller API (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + Say Y here to enable the media controller API, which allows to + retrieve the internal topology of sound devices.
I think there's a general consensus these days that EXPERIMENTAL is pretty meaningless so we probably shouldn't bother with it. The text is also a bit confusing, it enables use of the media controller API for ALSA devices really.
I have to say I'm also a bit surprised that there's no core framework for media controller and we're open coding ioctl() implementations here, I'd have thought there would at least be a way of enumerating all media controller devices in the system...
Re: [RFC PATCH 01/11] ALSA: implement MEDIA_IOC_DEVICE_INFO
Quoted 10 lines · Mark Brown
sound/core/Kconfig config SND_SEQ_RTCTIMER_DEFAULT · line 155
Quoted 6 lines · Clemens Ladisch
sound/core/Kconfig +6
-0+config SND_MEDIA + bool "Media Controller API (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + Say Y here to enable the media controller API, which allows to + retrieve the internal topology of sound devices.I think there's a general consensus these days that EXPERIMENTAL is pretty meaningless so we probably shouldn't bother with it.
Well, I couldn't claim this to be any less experimental than the implementation in drivers/media/. :)
Quoted 2 lines
The text is also a bit confusing, it enables use of the media controller API for ALSA devices really.
It's in the ALSA menu. I could put "ALSA" in the title if it helps.
Quoted 2 lines
I have to say I'm also a bit surprised that there's no core framework for media controller and we're open coding
ioctl()implementations here,
drivers/media/media-*.c exists, but I did not use that implementation because someone expressed concern about it being too heavyweight ...
Quoted 2 lines
I'd have thought there would at least be a way of enumerating all media controller devices in the system...
It appears userspace is supposed to check all /dev/media* devices. (Using /dev/snd/controlC* is just a makeshift arrangement; I'll have to reuse some part of the media device registration framework, or tell udev to create symlinks.)
Regards,
Clemens
Re: [RFC PATCH 01/11] ALSA: implement MEDIA_IOC_DEVICE_INFO
At Fri, 07 Sep 2012 09:14:30 +0200,
Quoted 13 lines · Clemens Ladisch
Quoted 10 lines · Mark Brown
sound/core/Kconfig config SND_SEQ_RTCTIMER_DEFAULT · line 155
Quoted 6 lines · Clemens Ladisch
sound/core/Kconfig +6
-0+config SND_MEDIA + bool "Media Controller API (EXPERIMENTAL)" + depends on EXPERIMENTAL + help + Say Y here to enable the media controller API, which allows to + retrieve the internal topology of sound devices.I think there's a general consensus these days that EXPERIMENTAL is pretty meaningless so we probably shouldn't bother with it.
Quoted 2 lines
Well, I couldn't claim this to be any less experimental than the implementation in
drivers/media/. :)
In the previous kernel summit, we agreed to drop CONFIG_EXPERIMENTAL since it's just useless. So, no need to add yet another new entry with that flag.
Quoted 4 lines
Quoted 2 lines
The text is also a bit confusing, it enables use of the media controller API for ALSA devices really.
It's in the ALSA menu. I could put "ALSA" in the title if it helps.
Yeah, I also prefer with that.
Takashi
RFC PATCH 2/11 ALSA: implement MEDIA_IOC_ENUM_ENTITIES
In reply to Clemens LadischAllow drivers to create entities. To avoid bloat, the snd_media_entity structure stores only basic information and retrieves the full entitiy information on demand with a callback.
--- include/sound/core.h | 5 ++ include/sound/media.h | 23 ++++++++++ sound/core/init.c | 4 ++ sound/core/media.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 145 insertions(+), 1 deletions(-)
include/sound/core.h +4 -1
@@ -51,7 +51,8 @@ struct snd_media_card_ops;typedef int __bitwise snd_device_type_t ;#define SNDRV_DEV_TOPLEVEL ((__force snd_device_type_t) 0)#define SNDRV_DEV_CONTROL ((__force snd_device_type_t) 1) -#define SNDRV_DEV_LOWLEVEL_PRE ((__force snd_device_type_t) 2) +#define SNDRV_DEV_MEDIA ((__force snd_device_type_t) 2) +#define SNDRV_DEV_LOWLEVEL_PRE ((__force snd_device_type_t) 3)#define SNDRV_DEV_LOWLEVEL_NORMAL ((__force snd_device_type_t) 0x1000)#define SNDRV_DEV_PCM ((__force snd_device_type_t) 0x1001)#define SNDRV_DEV_RAWMIDI ((__force snd_device_type_t) 0x1002)
@@ -149,6 +150,8 @@ struct snd_card {#ifdef CONFIG_SND_MEDIA const struct snd_media_card_ops *media_ops; +struct mutex media_mutex; +struct list_head media_entities;#endif };
include/sound/media.h +23 -0
@@ -23,16 +23,29 @@#include <linux/init.h> struct snd_card ; +struct snd_media_entity ;struct media_device_info ; +struct media_entity_desc ;struct snd_media_card_ops {int (*get_info)(struct snd_card *card,struct media_device_info *info); }; +typedef int (*snd_media_entity_get_desc_t )(struct snd_card *card, +void *private_data, +struct media_entity_desc *desc); +#ifdef CONFIG_SND_MEDIA #define snd_card_set_media_ops (card, ops) ((card)->media_ops = (ops)) +int snd_media_entity_create (struct snd_card *card, +snd_media_entity_get_desc_t get_desc, +unsigned int id, +unsigned int sinks,unsigned int sources, +void *private_data); + +int snd_media_create (struct snd_card *card);void __init snd_media_init (void ); void __exit snd_media_exit(void);
@@ -40,6 +53,16 @@ void __exit snd_media_exit(void);#define snd_card_set_media_ops (card, ops) +static inline int snd_media_entity_create (struct snd_card *card, +snd_media_entity_get_desc_t get_desc, +unsigned int id, +unsigned int sinks,unsigned int sources, +void *private_data) +{return 0 ; } + + +static inline int snd_media_create (struct snd_card *card) +{return 0 ; }static inline void snd_media_init () { }static inline void snd_media_exit ()
sound/core/init.c +4 -0
@@ -32,6 +32,7 @@#include <sound/core.h> #include <sound/control.h> #include <sound/info.h> +#include <sound/media.h> /* monitor files for graceful shutdown (hotplug) */ struct snd_monitor_file {
@@ -224,6 +225,9 @@ int snd_card_create(int idx, const char *xid,snd_printk (KERN_ERR "unable to register control minors\n" ); goto __error; } + err =snd_media_create (card); +if (err <0 ) + goto __error_ctl; err =snd_info_card_create (card);if (err <0 ) {snd_printk (KERN_ERR "unable to create card info\n" );
sound/core/media.c +114 -0
138 lines not on this page · raw message
RFC PATCH 3/11 ALSA: pcm: add ALSA PCM device entities
In reply to Clemens LadischAdd a helper function for creating entities representing ALSA PCM devices.
--- include/sound/pcm.h | 6 ++++++ sound/core/pcm.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 0 deletions(-)
include/sound/pcm.h +6 -0
@@ -480,6 +480,12 @@ int snd_pcm_new_internal(struct snd_card *card, const char *id, int device, int playback_count, int capture_count, struct snd_pcm **rpcm);int snd_pcm_new_stream (struct snd_pcm *pcm,int stream,int substream_count); +#ifdef CONFIG_SND_MEDIA +int snd_pcm_media_entities_create (struct snd_pcm *pcm,int stream, +unsigned int id); +#else +#define snd_pcm_media_entities_create (pcm, stream, id) +#endif int snd_pcm_notify (struct snd_pcm_notify *notify,int nfree);
sound/core/pcm.c +46 -0
63 lines not on this page · raw message
RFC PATCH 4/11 ALSA: implement MEDIA_IOC_ENUM_LINKS (1)
In reply to Clemens LadischAllow to retrieve pad information.
--- sound/core/media.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 44 insertions(+), 0 deletions(-)
sound/core/media.c +44 -0
@@ -161,6 +161,48 @@ static int snd_media_enum_entities(struct snd_card *card,return copy_to_user (descp, &desc,sizeof (desc)); } +static int snd_media_enum_links (struct snd_card *card, +struct media_links_enum __user *linksp) +{ +struct media_links_enum links; +struct snd_media_entity *entity; + +if (copy_from_user (&links, linksp,sizeof (links))) +return -EFAULT ; + +mutex_lock (&card->media_mutex); + entity =search_entity (card, links.entity); +mutex_unlock (&card->media_mutex); +if (!entity) +return -EINVAL ; + +if (links.pads) { +struct media_pad_desc pad; +unsigned int i; + +memset (&pad,0 ,sizeof (pad)); + pad.entity = entity->id; + + pad.flags =MEDIA_PAD_FL_SINK ; +for (i =0 ; i < entity->sinks; i++) { +if (copy_to_user (links.pads, &pad,sizeof (pad))) +return -EFAULT ; + links.pads++; + pad.index++; + } + + pad.flags =MEDIA_PAD_FL_SOURCE ; +for (i =0 ; i < entity->sources; i++) { +if (copy_to_user (links.pads, &pad,sizeof (pad))) +return -EFAULT ; + links.pads++; + pad.index++; + } + } + +return 0 ; +} +static int snd_media_control_ioctl (struct snd_card *card,struct snd_ctl_file *ctl_file,unsigned int cmd,unsigned long arg)
@@ -172,6 +214,8 @@ static int snd_media_control_ioctl(struct snd_card *card,return snd_media_device_info (card, argp);case MEDIA_IOC_ENUM_ENTITIES :return snd_media_enum_entities (card, argp); +case MEDIA_IOC_ENUM_LINKS : +return snd_media_enum_links (card, argp);default :return -ENOIOCTLCMD ; }
RFC PATCH 5/11 ALSA: implement MEDIA_IOC_ENUM_LINKS (2)
In reply to Clemens LadischAllow drivers to create links between entities.
--- include/sound/core.h | 3 ++ include/sound/media.h | 11 ++++++ sound/core/media.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 0 deletions(-)
include/sound/core.h +3 -0
@@ -43,6 +43,7 @@ struct module;struct device ;struct device_attribute ;struct snd_media_card_ops ; +struct snd_media_link ;/* device allocation stuff */
@@ -152,6 +153,8 @@ struct snd_card {const struct snd_media_card_ops *media_ops;struct mutex media_mutex;struct list_head media_entities; +unsigned int media_links_count; +struct snd_media_link *media_links;#endif };
include/sound/media.h +11 -0
@@ -44,6 +44,11 @@ int snd_media_entity_create(struct snd_card *card,unsigned int id, unsigned int sinks, unsigned int sources, void *private_data); +int snd_media_link_create (struct snd_card *card, +unsigned int source_entity, +unsigned int source_pad, +unsigned int sink_entity, +unsigned int sink_pad);int snd_media_create (struct snd_card *card);void __init snd_media_init (void );
@@ -59,6 +64,12 @@ static inline int snd_media_entity_create(struct snd_card *card, unsigned int sinks, unsigned int sources, void *private_data) { return 0; } +static inline int snd_media_link_create (struct snd_card *card, +unsigned int source_entity, +unsigned int source_pad, +unsigned int sink_entity, +unsigned int sink_pad) +{return 0 ; }static inline int snd_media_create (struct snd_card *card)
sound/core/media.c +86 -0
122 lines not on this page · raw message
RFC PATCH 6/11 ALSA: implement MEDIA_IOC_SETUP_LINK
In reply to Clemens LadischJust for compatibility with the media controller API, implement the setup link ioctl, which does not actually do anything.
--- sound/core/media.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 41 insertions(+), 0 deletions(-)
sound/core/media.c +41 -0
@@ -289,6 +289,45 @@ static int snd_media_enum_links(struct snd_card *card,return 0 ; } +static int snd_media_setup_link (struct snd_card *card, +struct media_link_desc __user *descp) +{ +struct media_link_desc desc; +struct snd_media_entity *source, *sink; +struct snd_media_link *link; +unsigned int i; +int err; + +if (copy_from_user (&desc, descp,sizeof (desc))) +return -EFAULT ; + +if (desc.flags != (MEDIA_LNK_FL_ENABLED |MEDIA_LNK_FL_IMMUTABLE )) +return -EINVAL ; + +mutex_lock (&card->media_mutex); + source =search_entity (card, desc.source.entity); + sink =search_entity (card, desc.sink.entity); +mutex_unlock (&card->media_mutex); +if (!source || !sink) +return -EINVAL ; + + err = -EINVAL ; +mutex_lock (&card->media_mutex); +for (i =0 ; i < card->media_links_count; i++) { + link = &card->media_links[i]; +if (link->source_entity == desc.source.entity && + link->sink_entity == desc.sink.entity && + link->source_pad == desc.source.index && + link->sink_pad == desc.sink.index) { + err =0 ; +break ; + } + } +mutex_unlock (&card->media_mutex); + +return err; +} +static int snd_media_control_ioctl (struct snd_card *card,struct snd_ctl_file *ctl_file,unsigned int cmd,unsigned long arg)
@@ -302,6 +341,8 @@ static int snd_media_control_ioctl(struct snd_card *card,return snd_media_enum_entities (card, argp);case MEDIA_IOC_ENUM_LINKS :return snd_media_enum_links (card, argp); +case MEDIA_IOC_SETUP_LINK : +return snd_media_setup_link (card, argp);default :return -ENOIOCTLCMD ; }
RFC PATCH 7/11 media: add entity types for ALSA
In reply to Clemens LadischAdd entity types for describing the topology of sound devices.
JACK entities represent connections to the outside world. Properties of the jack will be described by a TLV on the jack entity.
MIXER entities add their inputs together, while SELECTOR entities route on of their inputs to the output. PROCESSING entities represent volume/ mute controls or other effects processing units. These entities may have ALSA controls associated with them, which is indicated by those controls having a TLV containing the entity ID and the control type.
SPLIT and MERGE entities are needed for HDA codecs, whose topology is constructed of stereo channel pairs.
--- include/linux/media.h | 9 +++++++++ 1 files changed, 9 insertions(+), 0 deletions(-)
include/linux/media.h +9 -0
@@ -57,6 +57,15 @@ struct media_device_info {#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH (MEDIA_ENT_T_V4L2_SUBDEV + 2)#define MEDIA_ENT_T_V4L2_SUBDEV_LENS (MEDIA_ENT_T_V4L2_SUBDEV + 3) +#define MEDIA_ENT_T_JACK (3 << MEDIA_ENT_TYPE_SHIFT) + +#define MEDIA_ENT_T_ALSA (4 << MEDIA_ENT_TYPE_SHIFT) +#define MEDIA_ENT_T_ALSA_MIXER (MEDIA_ENT_T_ALSA + 1) +#define MEDIA_ENT_T_ALSA_SELECTOR (MEDIA_ENT_T_ALSA + 2) +#define MEDIA_ENT_T_ALSA_PROCESSING (MEDIA_ENT_T_ALSA + 3) +#define MEDIA_ENT_T_ALSA_SPLIT (MEDIA_ENT_T_ALSA + 4) +#define MEDIA_ENT_T_ALSA_MERGE (MEDIA_ENT_T_ALSA + 5) +#define MEDIA_ENT_FL_DEFAULT (1 << 0)struct media_entity_desc {
RFC PATCH 8/11 ALSA: usb-audio: implement card get_info callback
In reply to Clemens LadischAdd a helper for retrieving information about USB devices.
--- include/sound/media.h | 16 ++++++++++++++++ sound/core/media.c | 28 ++++++++++++++++++++++++++++ sound/usb/card.c | 2 ++ 3 files changed, 46 insertions(+), 0 deletions(-)
include/sound/media.h +16 -0
@@ -39,6 +39,15 @@ typedef int (*snd_media_entity_get_desc_t)(struct snd_card *card,#define snd_card_set_media_ops (card, ops) ((card)->media_ops = (ops)) +#if defined(CONFIG_USB ) || defined(CONFIG_USB_MODULE ) +int snd_media_get_usb_card_info (struct snd_card *card, +struct media_device_info *info); + +extern const struct snd_media_card_ops snd_media_default_usb_ops; +#define snd_card_set_media_ops_default_usb (card) \ + snd_card_set_media_ops((card), &snd_media_default_usb_ops) +#endif + int snd_media_entity_create(struct snd_card *card, snd_media_entity_get_desc_t get_desc, unsigned int id,
@@ -58,6 +67,13 @@ void __exit snd_media_exit(void);#define snd_card_set_media_ops (card, ops) +#if defined(CONFIG_USB ) || defined(CONFIG_USB_MODULE ) +#define snd_card_set_media_ops_default_usb (card) +static inline int snd_media_get_usb_card_info (struct snd_card *card, +struct media_device_info *info) +{return 0 ; } +#endif + static inline int snd_media_entity_create(struct snd_card *card, snd_media_entity_get_desc_t get_desc, unsigned int id,
sound/core/media.c +28 -0
@@ -24,6 +24,7 @@#include <linux/media.h> #include <linux/string.h> #include <linux/uaccess.h> +#include <linux/usb.h> #include <sound/core.h> #include <sound/control.h> #include <sound/media.h>
@@ -328,6 +329,33 @@ static int snd_media_setup_link(struct snd_card *card,return err; } +#if defined(CONFIG_USB ) || defined(CONFIG_USB_MODULE ) +int snd_media_get_usb_card_info (struct snd_card *card, +struct media_device_info *info) +{ +struct usb_interface *intf; +struct usb_device *usb; + +if (snd_BUG_ON (!card->dev)) +return -ENXIO ; + intf =to_usb_interface (card->dev); + usb =interface_to_usbdev (intf); + +if (usb->serial) +strlcpy (info->serial, usb->serial,sizeof (info->serial)); +usb_make_path (usb, info->bus_info,sizeof (info->bus_info)); + info->hw_revision =le16_to_cpu (usb->descriptor.bcdDevice); + +return 0 ; +} +EXPORT_SYMBOL (snd_media_get_usb_card_info); + +const struct snd_media_card_ops snd_media_default_usb_ops = { + .get_info = snd_media_get_usb_card_info, +}; +EXPORT_SYMBOL (snd_media_default_usb_ops); +#endif +static int snd_media_control_ioctl (struct snd_card *card,struct snd_ctl_file *ctl_file,unsigned int cmd,unsigned long arg)
sound/usb/card.c +2 -0
@@ -52,6 +52,7 @@#include <sound/control.h> #include <sound/core.h> #include <sound/info.h> +#include <sound/media.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/initval.h>
@@ -490,6 +491,7 @@ snd_usb_audio_probe(struct usb_device *dev, goto __error; }snd_card_set_dev (chip->card, &intf->dev); +snd_card_set_media_ops_default_usb (chip->card); chip->pm_intf = intf;break ; }
RFC PATCH 9/11 ALSA: usb-audio: create PCM device entities
In reply to Clemens Ladisch--- sound/usb/quirks.c | 4 ++-- sound/usb/stream.c | 16 +++++++++++----- sound/usb/stream.h | 1 + 3 files changed, 14 insertions(+), 7 deletions(-)
sound/usb/quirks.c +2 -2
@@ -152,7 +152,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, stream = (fp->endpoint &USB_DIR_IN ) ?SNDRV_PCM_STREAM_CAPTURE :SNDRV_PCM_STREAM_PLAYBACK ; - err =snd_usb_add_audio_stream (chip, stream, fp); + err =snd_usb_add_audio_stream (chip, stream,0 , fp);if (err <0 ) {kfree (fp);kfree (rate_table);
@@ -258,7 +258,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, stream = (fp->endpoint &USB_DIR_IN ) ?SNDRV_PCM_STREAM_CAPTURE :SNDRV_PCM_STREAM_PLAYBACK ; - err =snd_usb_add_audio_stream (chip, stream, fp); + err =snd_usb_add_audio_stream (chip, stream,0 , fp);if (err <0 ) {kfree (fp);return err;
sound/usb/stream.c +11 -5
@@ -78,7 +78,7 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)*/ static void snd_usb_init_substream (struct snd_usb_stream *as, -int stream, +int stream,u8 terminal_id,struct audioformat *fp) {struct snd_usb_substream *subs = &as->substream[stream];
@@ -98,6 +98,9 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, subs->num_formats++; subs->fmt_type = fp->fmt_type; subs->ep_num = fp->endpoint; + +if (terminal_id >0 ) +snd_pcm_media_entities_create (as->pcm, stream, terminal_id); }/*
@@ -106,7 +109,7 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,* if not, create a new pcm stream. */ int snd_usb_add_audio_stream (struct snd_usb_audio *chip, -int stream, +int stream,u8 terminal_id,struct audioformat *fp) {struct list_head *p;
@@ -138,7 +141,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, err =snd_pcm_new_stream (as->pcm, stream,1 );if (err <0 )return err; -snd_usb_init_substream (as, stream, fp); +snd_usb_init_substream (as, stream, terminal_id, fp);return 0 ; }
@@ -166,7 +169,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,else strcpy (pcm->name,"USB Audio" ); -snd_usb_init_substream (as, stream, fp); +snd_usb_init_substream (as, stream, terminal_id, fp);list_add (&as->list, &chip->pcm_list); chip->pcm_devs++;
@@ -260,6 +263,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)struct audioformat *fp =NULL ;int num, protocol, clock =0 ;struct uac_format_type_i_continuous_descriptor *fmt; +u8 terminal_id =0 ; dev = chip->dev;
@@ -324,6 +328,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) } format =le16_to_cpu (as->wFormatTag);/* remember the format value */ + terminal_id = as->bTerminalLink;break ; }
@@ -347,6 +352,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) num_channels = as->bNrChannels; format =le32_to_cpu (as->bmFormats); + terminal_id = as->bTerminalLink;/* lookup the terminal associated to this interface * to extract the clock */
@@ -460,7 +466,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) }snd_printdd (KERN_INFO "%d:%u:%d: add audio endpoint %#x\n" , dev->devnum, iface_no, altno, fp->endpoint); - err =snd_usb_add_audio_stream (chip, stream, fp); + err =snd_usb_add_audio_stream (chip, stream, terminal_id, fp);if (err <0 ) {kfree (fp->rate_table);kfree (fp);
sound/usb/stream.h +1 -0
@@ -6,6 +6,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip,int snd_usb_add_audio_stream (struct snd_usb_audio *chip,int stream, +u8 terminal_id,struct audioformat *fp);#endif /* __USBAUDIO_STREAM_H */
RFC PATCH 10/11 ALSA: usb-audio: add terminal/unit entities and links
In reply to Clemens LadischUse the terminal/unit descriptors to create entities and links.
(This should be integrated with parse_audio_unit(), but that function does not yet support all unit types.)
--- sound/usb/mixer.c | 278 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 278 insertions(+), 0 deletions(-)
sound/usb/mixer.c +278 -0
@@ -45,6 +45,7 @@#include <linux/bitops.h> #include <linux/init.h> #include <linux/list.h> +#include <linux/media.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/usb.h>
@@ -55,6 +56,7 @@#include <sound/control.h> #include <sound/hwdep.h> #include <sound/info.h> +#include <sound/media.h> #include <sound/tlv.h> #include "usbaudio.h"
@@ -1969,6 +1971,278 @@ static int snd_usb_mixer_dev_free(struct snd_device *device)return 0 ; } +static void unit_name (struct media_entity_desc *entity, +const u8 *desc,const char *prefix) +{ +/* TODO: read the terminal name from the device */ +sprintf (entity->name,"%s%u" , prefix, desc[3 ]); +} + +static int input_terminal_get_desc (struct snd_card *card, +void *private_data, +struct media_entity_desc *desc) +{ +unit_name (desc, private_data,"IT" ); + desc->type =MEDIA_ENT_T_JACK ; +return 0 ; +} + +static int output_terminal_get_desc (struct snd_card *card, +void *private_data, +struct media_entity_desc *desc) +{ +unit_name (desc, private_data,"OT" ); + desc->type =MEDIA_ENT_T_JACK ; +return 0 ; +} + +static int mixer_unit_get_desc (struct snd_card *card, +void *private_data, +struct media_entity_desc *desc) +{ +unit_name (desc, private_data,"MU" ); + desc->type =MEDIA_ENT_T_ALSA_MIXER ; +return 0 ; +} + +static int selector_unit_get_desc (struct snd_card *card, +void *private_data, +struct media_entity_desc *desc) +{ +unit_name (desc, private_data,"SU" ); + desc->type =MEDIA_ENT_T_ALSA_SELECTOR ; +return 0 ; +} + +static int feature_unit_get_desc (struct snd_card *card, +void *private_data, +struct media_entity_desc *desc) +{ +unit_name (desc, private_data,"FU" ); + desc->type =MEDIA_ENT_T_ALSA_PROCESSING ; +return 0 ; +} + +static int processing_unit_get_desc (struct snd_card *card, +void *private_data, +struct media_entity_desc *desc) +{ +unit_name (desc, private_data,"PU" ); + desc->type =MEDIA_ENT_T_ALSA_PROCESSING ; +return 0 ; +} + +static int extension_unit_get_desc (struct snd_card *card, +void *private_data, +struct media_entity_desc *desc) +{ +unit_name (desc, private_data,"XU" ); + desc->type =MEDIA_ENT_T_ALSA_PROCESSING ; +return 0 ; +} + +static int effect_unit_v2_get_desc (struct snd_card *card, +void *private_data, +struct media_entity_desc *desc) +{ +unit_name (desc, private_data,"EU" ); + desc->type =MEDIA_ENT_T_ALSA_PROCESSING ; +return 0 ; +} + +static int src_v2_get_desc (struct snd_card *card, +void *private_data, +struct media_entity_desc *desc) +{ +unit_name (desc, private_data,"SRC" ); + desc->type =MEDIA_ENT_T_ALSA_PROCESSING ; +return 0 ; +} + +static int snd_usb_mixer_entity (struct mixer_build *state,const u8 *desc) +{ +snd_media_entity_get_desc_t get_desc =NULL ; +unsigned int sinks =0 , sources =0 , source_ids_count =0 , i; +const u8 *source_ids =NULL ; +u8 source_id =0 ; +int err; + +if (desc[0 ] <4 ) +return 0 ; + +if (state->mixer->protocol ==UAC_VERSION_1 ) { +switch (desc[2 ]) { +case UAC_INPUT_TERMINAL : +if (desc[0 ] >=6 && + desc[5 ] != (UAC_TERMINAL_STREAMING >>8 )) { + get_desc = &input_terminal_get_desc; + sources =1 ; + } +break ; +case UAC_OUTPUT_TERMINAL : +if (desc[0 ] >=8 ) { + source_id = desc[7 ]; +if (desc[5 ] != (UAC_TERMINAL_STREAMING >>8 )) + get_desc = &output_terminal_get_desc; + } +break ; +case UAC_MIXER_UNIT : +if (desc[0 ] >=6 ) { + source_ids = &desc[5 ]; + get_desc = &mixer_unit_get_desc; + sources =1 ; + } +break ; +case UAC_SELECTOR_UNIT : +if (desc[0 ] >=6 ) { + source_ids = &desc[5 ]; + get_desc = &selector_unit_get_desc; + sources =1 ; + } +break ; +case UAC_FEATURE_UNIT : +if (desc[0 ] >=5 ) { + source_id = desc[4 ]; + get_desc = &feature_unit_get_desc; + sources =1 ; + } +break ; +case UAC1_PROCESSING_UNIT : +if (desc[0 ] >=8 ) { + source_ids = &desc[7 ]; + get_desc = &processing_unit_get_desc; + sources =1 ; + } +break ; +case UAC1_EXTENSION_UNIT : +if (desc[0 ] >=7 && desc[0 ] >=7 + desc[6 ]) { + source_ids_count = desc[6 ]; + source_ids = &desc[7 ]; + get_desc = &extension_unit_get_desc; + sources =1 ; + } +break ; + } + }else { +switch (desc[2 ]) { +case UAC_INPUT_TERMINAL : +if (desc[0 ] >=6 && + desc[5 ] != (UAC_TERMINAL_STREAMING >>8 )) { + get_desc = &input_terminal_get_desc; + sources =1 ; + } +break ; +case UAC_OUTPUT_TERMINAL : +if (desc[0 ] >=8 ) { + source_id = desc[7 ]; +if (desc[5 ] != (UAC_TERMINAL_STREAMING >>8 )) + get_desc = &output_terminal_get_desc; + } +break ; +case UAC_MIXER_UNIT : +if (desc[0 ] >=5 && desc[0 ] >=5 + desc[4 ]) { + source_ids_count = desc[4 ]; + source_ids = &desc[5 ]; + get_desc = &mixer_unit_get_desc; + sources =1 ; + } +break ; +case UAC_SELECTOR_UNIT : +if (desc[0 ] >=5 && desc[0 ] >=5 + desc[4 ]) { + source_ids_count = desc[4 ]; + source_ids = &desc[5 ]; + get_desc = &selector_unit_get_desc; + sources =1 ; + } +break ; +case UAC_FEATURE_UNIT : +if (desc[0 ] >=5 ) { + source_id = desc[4 ]; + get_desc = &feature_unit_get_desc; + sources =1 ; + } +break ; +case UAC2_EFFECT_UNIT : +if (desc[0 ] >=7 ) { + source_id = desc[6 ]; + get_desc = &effect_unit_v2_get_desc; + sources =1 ; + } +break ; +case UAC2_PROCESSING_UNIT_V2 : +if (desc[0 ] >=7 && desc[0 ] >=7 + desc[6 ]) { + source_ids_count = desc[6 ]; + source_ids = &desc[7 ]; + get_desc = &processing_unit_get_desc; + sources =1 ; + } +break ; +case UAC2_EXTENSION_UNIT_V2 : +if (desc[0 ] >=7 && desc[0 ] >=7 + desc[6 ]) { + source_ids_count = desc[6 ]; + source_ids = &desc[7 ]; + get_desc = &extension_unit_get_desc; + sources =1 ; + } +break ; +case UAC2_SAMPLE_RATE_CONVERTER : +if (desc[0 ] >=5 ) { + source_id = desc[4 ]; + get_desc = &src_v2_get_desc; + sources =1 ; + } +break ; + } + } + +if (source_id !=0 ) { + err =snd_media_link_create (state->chip->card, + source_id,0 , desc[3 ],0 ); +if (err <0 ) +return err; + sinks =1 ; + } +else if (source_ids !=NULL ) { +if (source_ids_count ==0 && + source_ids + source_ids_count <= desc + desc[0 ]) + source_ids_count = desc + desc[0 ] - source_ids; +for (i =0 ; i < source_ids_count; i++) { + err =snd_media_link_create (state->chip->card, + source_ids[i],0 , + desc[3 ], i); +if (err <0 ) +return err; + } + sinks = source_ids_count; + } + +if (get_desc) { + err =snd_media_entity_create (state->chip->card, get_desc, + desc[3 ], sinks, sources, + (void *)desc); +if (err <0 ) +return err; + } + +return 0 ; +} + +static int snd_usb_mixer_entities (struct mixer_build *state) +{ +void *p; +int err; + + p =NULL ; +while ((p =snd_usb_find_desc (state->mixer->hostif->extra, + state->mixer->hostif->extralen, + p,USB_DT_CS_INTERFACE )) !=NULL ) { + err =snd_usb_mixer_entity (state, p); +if (err <0 ) +return err; + } +return 0 ; +} +/* * create mixer controls *
@@ -1997,6 +2271,10 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) } } + err =snd_usb_mixer_entities (&state); +if (err <0 ) +return err; + p =NULL ;while ((p =snd_usb_find_csint_desc (mixer->hostif->extra, mixer->hostif->extralen, p,UAC_OUTPUT_TERMINAL )) !=NULL ) {
RFC PATCH 11/11 ALSA: hda-intel: implement card get_info callback
In reply to Clemens LadischAdd a helper for retrieving information about PCI devices.
(Codec topology information is not yet implemented.)
--- include/sound/media.h | 16 ++++++++++++++++ sound/core/media.c | 36 ++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_intel.c | 2 ++ 3 files changed, 54 insertions(+), 0 deletions(-)
include/sound/media.h +16 -0
@@ -39,6 +39,15 @@ typedef int (*snd_media_entity_get_desc_t)(struct snd_card *card,#define snd_card_set_media_ops (card, ops) ((card)->media_ops = (ops)) +#ifdef CONFIG_PCI +int snd_media_get_pci_card_info (struct snd_card *card, +struct media_device_info *info); + +extern const struct snd_media_card_ops snd_media_default_pci_ops; +#define snd_card_set_media_ops_default_pci (card) \ + snd_card_set_media_ops((card), &snd_media_default_pci_ops) +#endif +#if defined(CONFIG_USB ) || defined(CONFIG_USB_MODULE )int snd_media_get_usb_card_info (struct snd_card *card,struct media_device_info *info);
@@ -67,6 +76,13 @@ void __exit snd_media_exit(void);#define snd_card_set_media_ops (card, ops) +#ifdef CONFIG_PCI +#define snd_card_set_media_ops_default_pci (card) +static inline int snd_media_get_pci_card_info (struct snd_card *card, +struct media_device_info *info) +{return 0 ; } +#endif +#if defined(CONFIG_USB ) || defined(CONFIG_USB_MODULE )#define snd_card_set_media_ops_default_usb (card) static inline int snd_media_get_usb_card_info(struct snd_card *card,
sound/core/media.c +36 -0
@@ -18,10 +18,12 @@*/ #include <linux/device.h> +#include <linux/export.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/media.h> +#include <linux/pci.h> #include <linux/string.h> #include <linux/uaccess.h> #include <linux/usb.h>
@@ -329,6 +331,40 @@ static int snd_media_setup_link(struct snd_card *card,return err; } +#ifdef CONFIG_PCI +int snd_media_get_pci_card_info (struct snd_card *card, +struct media_device_info *info) +{ +struct pci_dev *pci; + +if (snd_BUG_ON (!card->dev)) +return -ENXIO ; + pci =to_pci_dev (card->dev); + +if (pci_is_pcie (pci)) { +int pos =pci_find_ext_capability (pci,PCI_EXT_CAP_ID_DSN ); +if (pos) { +u32 eui[2 ]; + +pci_read_config_dword (pci, pos +4 , &eui[0 ]); +pci_read_config_dword (pci, pos +8 , &eui[1 ]); +sprintf (info->serial,"%08x%08x" , eui[1 ], eui[0 ]); + } + } +snprintf (info->bus_info,sizeof (info->bus_info),"%s:%s" , +pci_is_pcie (pci) ?"PCIe" :"PCI" ,pci_name (pci)); + info->hw_revision = pci->revision; + +return 0 ; +} +EXPORT_SYMBOL (snd_media_get_pci_card_info); + +const struct snd_media_card_ops snd_media_default_pci_ops = { + .get_info = snd_media_get_pci_card_info, +}; +EXPORT_SYMBOL (snd_media_default_pci_ops); +#endif +#if defined(CONFIG_USB ) || defined(CONFIG_USB_MODULE )int snd_media_get_usb_card_info (struct snd_card *card,struct media_device_info *info)
sound/pci/hda/hda_intel.c +2 -0
@@ -54,6 +54,7 @@#endif #include <sound/core.h> #include <sound/initval.h> +#include <sound/media.h> #include <linux/vgaarb.h> #include <linux/vga_switcheroo.h> #include <linux/firmware.h>
@@ -3305,6 +3306,7 @@ static int __devinit azx_probe(struct pci_dev *pci, }snd_card_set_dev (card, &pci->dev); +snd_card_set_media_ops_default_pci (card); err =azx_create (card, pci, dev, pci_id->driver_data, &chip);if (err <0 )
Hi Clemens,
At Tue, 28 Aug 2012 00:28:30 +0200,
Quoted 7 lines · Clemens Ladisch
Hi,
these are some tentative patches to allow sound drivers to provide routing information to userspace. (So far, snd-usb-audio has a partial implementation; I haven't yet had time for snd-hda-intel. I haven't even looked at ASoC.)
Thanks for patches. This brought up interesting discussions at Plumbers. We (kind of) agree that the media controller API can be pretty suitable, and even Mark didn't grumble so much against it :) It's a good sign.
Quoted 9 lines
The media controller API <
linux/media.h> allows prividing routing information, but its implementation does not quite fit the sound drivers:
* it allows reconfiguration of links, but not in a way that would be useful for ALSA selector controls;
* it allows drivers to access the entity graph and pipelines, which is not needed;
* it is rather heavyweight.
Quoted 3 lines
Therefore, these patches create their own implementation of the media controller API. In this implementation, all entity and link information is completely static, and more space-efficient.
I think this is fine for USB-audio and HD-audio. We don't expect that the changes are done via media controller API but it'll provide just some mapping. But, possible embedded guys might want to make it configurable. (Well, in that case, they can reimplement the full stack based on the original media controller helper code...) Maybe Mark can give more comments on it.
Quoted 2 lines
For simplicity, the ioctls hook into the ALSA control device instead of creating a new
/dev/media*device.
This is OK, I think. But what about multiple codecs on a single control device? Can they be represented well?
Quoted 5 lines
The separate implementation does not allow sharing of one media controller device in the case of combined audio/video devices. However, separate drivers would already be a problem for HDMI outputs (GPU and sound); it appears we might need some mechanism to connect the topologies of multiple media devices.
The connection between different devices could be done in a different way. For example, we may provide some Linux device tree connection. (This reminds me of a TODO -- the implementation of standard Linux
device model to ALSA components, BTW.)
Quoted 2 lines
TLVs (for jack entities, and for associating controls with entities) are not yet defined.
OK, this is a big missing piece. But it should be relatively easy.
Takashi
Quoted 69 lines
Example output for my simple UA-1A device (not all information is decoded correctly):
$ media-ctl -p -d /dev/snd/controlC5 Opening media device /dev/snd/controlC5 Enumerating entities Found 4 entities Enumerating pads and links Media controller API version 0.0.0Media device information
------------------------
driver snd-usb-audio
model EDIROL UA-1A
serialbus info usb-0000:00:12.2-4.3 hw revision 0x101 driver version 0.0.0Device topology
- entity 1: USB Audio (1 pad, 1 link)
type Node subtype ALSA
device node name/dev/tty(should be hw:5,0,0)
pad0: Source
-> "OT3":0 [ENABLED,IMMUTABLE]- entity 3: OT3 (1 pad, 1 link)
type Unknown subtype Unknown (should be Jack)
pad0: Sink
<- "USB Audio":0 [ENABLED,IMMUTABLE]- entity 4: IT4 (1 pad, 1 link)
type Unknown subtype Unknown
pad0: Source
-> "USB Audio":0 [ENABLED,IMMUTABLE]- entity 7: USB Audio (1 pad, 1 link)
type Node subtype ALSA
device node name/dev/tty
pad0: Sink
<- "IT4":0 [ENABLED,IMMUTABLE]include/linux/media.h | 9 include/sound/core.h | 13 + include/sound/media.h | 116 ++++++++++ include/sound/pcm.h | 6 sound/core/Kconfig | 7 sound/core/Makefile | 1 sound/core/init.c | 4 sound/core/media.c | 425 ++++++++++++++++++++++++++++++++++++++ sound/core/pcm.c | 46 ++++ sound/core/sound.c | 3 sound/pci/hda/hda_intel.c | 2 sound/usb/card.c | 2 sound/usb/mixer.c | 278 ++++++++++++++++++++++++ sound/usb/quirks.c | 4 sound/usb/stream.c | 16 - sound/usb/stream.h | 1 16 files changed, 925 insertions(+), 8 deletions(-)Regards,
Clemens
_______________________________________________
Alsa-devel mailing list
[email protected]
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel
Quoted 6 lines · Takashi Iwai
Quoted 5 lines · Clemens Ladisch
The media controller API <
linux/media.h> allows prividing routing information, but its implementation does not quite fit the sound drivers:
* it allows reconfiguration of links, but not in a way that would be useful for ALSA selector controls
I didn't mention why: it is not possible to enable two links to a sink pad, and neither can one change the state of two links atomically; therefore, an enum control with exactly one active input cannot be modelled. (It might be possible to change the media controller API to allow this.)
Mute controls _could_ be modelled by disabling links, but with all other mixer control types not represented in the media controller API, this doesn't appear to be very useful.
Quoted 2 lines
But what about multiple codecs on a single control device? Can they be represented well?
The driver has to choose the entity IDs so that they don't conflict; something like busnumber<<20 | codecaddress<<10 | nodeid. The USB audio driver will have this problem if there are multiple audio control interfaces, so I guess it will have to include the interface number.
Regards,
Clemens