[alsa-devel] alsactl init - implementation and more..
Hi,
some developers probably already noted, I commited to alsactl utility (alsa-utils package) initial implementation of soundcard initialization stuff aka 'alsactl init'. The basic idea was to "reuse" nice udev configuration style and modify it to ALSA purposes. I hope that I ended up with a syntax which is easy understandable and configuration can be created with minimal effort. Please, look to 'man 7 alsactl_init' for more details and to alsa-utils/alsactl/init directory for example files. Note that the runtime evaluation of commands can be modified using environment variables like udev does. Just try 'alsactl -E CMD=help init' or 'CMD=help alsactl init'. Hardware can be detected using sysfs. For older kernel, I'm plannig to add some compatibility layer to read at least ATTR{subsystem_vendor} and ATTR{subsystem_device} information from procfs (codec files). Also, a way to gather working configurations for specific hardware is required. A nice script alsa-info.sh is already in the alsa-driver package, so I just created a simple persistent "file" dabatase on www.alsa-project.org: http://www.alsa-project.org/cardinfo-db/ and modified alsa-info.sh to use this database for the contents upload by default. Developers can download whole database in a tar package to extract necessary information using command line text tools and use this database also for other purposes (HDA codec graphing and so).
More ideas, corrections, opinions are welcome.
Jaroslav
----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.
At Wed, 13 Aug 2008 12:59:32 +0200 (CEST), Jaroslav Kysela wrote:
Hi,
some developers probably already noted, I commited to alsactl utility (alsa-utils package) initial implementation of soundcard initialization stuff aka 'alsactl init'.
Yeah, looks good.
The basic idea was to "reuse" nice udev configuration style and modify it to ALSA purposes. I hope that I ended up with a syntax which is easy understandable and configuration can be created with minimal effort. Please, look to 'man 7 alsactl_init' for more details and to alsa-utils/alsactl/init directory for example files.
The card-specific configs shouldn't be read from 00main, but read from its file, i.e. 50hda. That is, the config files are to be simply added / removed without modifying the existing file.
One missing feature is to store the values in dB unit. That would be more robust and commonly used over different hardwares than raw values, even if they have different resolutions. Also, enum value strings are missing.
Another would-be-nice feature is one command to do both init and restore. First initialize the hardware, then restore (overwrite) the setting from the asound.state if already eixsts. This is what udev needs to call.
Note that the runtime evaluation of commands can be modified using environment variables like udev does. Just try 'alsactl -E CMD=help init' or 'CMD=help alsactl init'. Hardware can be detected using sysfs. For older kernel, I'm plannig to add some compatibility layer to read at least ATTR{subsystem_vendor} and ATTR{subsystem_device} information from procfs (codec files).
In the case of HD-audio, there could be still a bit pain. Some hardwares cannot be detected via PCI SSID but only via codec SSID (PKU) or codec revision ID which aren't exposed via sysfs. But, I guess this is a rare case and the mixer settings are likely same among these devices with the same PCI SSID.
Also, a way to gather working configurations for specific hardware is required. A nice script alsa-info.sh is already in the alsa-driver package, so I just created a simple persistent "file" dabatase on www.alsa-project.org: http://www.alsa-project.org/cardinfo-db/ and modified alsa-info.sh to use this database for the contents upload by default. Developers can download whole database in a tar package to extract necessary information using command line text tools and use this database also for other purposes (HDA codec graphing and so).
This is a good action, indeed.
thanks,
Takashi
On Wed, 13 Aug 2008, Takashi Iwai wrote:
At Wed, 13 Aug 2008 12:59:32 +0200 (CEST), Jaroslav Kysela wrote:
Hi,
some developers probably already noted, I commited to alsactl utility (alsa-utils package) initial implementation of soundcard initialization stuff aka 'alsactl init'.
Yeah, looks good.
Thanks.
The basic idea was to "reuse" nice udev configuration style and modify it to ALSA purposes. I hope that I ended up with a syntax which is easy understandable and configuration can be created with minimal effort. Please, look to 'man 7 alsactl_init' for more details and to alsa-utils/alsactl/init directory for example files.
The card-specific configs shouldn't be read from 00main, but read from its file, i.e. 50hda. That is, the config files are to be simply added / removed without modifying the existing file.
I'm not sure if it's useful for our purposes. The 00main also contains some "global" configuration (like SYSFS_DEVICE setup and more variables can be added in future) and my initial (not saying that it's optimal) configuration assumes that first file lookup is a driver name.
If you like to add extra configuration files in a directory, I would enhance 'INCLUDE' executer code to check, if the source path is directory and then include all files from it. But for the standard "database" purposes, I don't see a reason to check every file and skip contents of large files just after parsing first lines with false condition.
Note that the difference between udev and 'alsactl init' is that udev do not know which event will come from kernel - in this case is necessary to trace whole database, but 'alsactl init' is designed for 'one shot' run like a supporting tool for udev and/or /etc/init.d startup script.
One missing feature is to store the values in dB unit. That would be more robust and commonly used over different hardwares than raw values, even if they have different resolutions. Also, enum value strings are missing.
Yes, for initial implementation I ommited to add some these extra features. Anyway, if hardware and driver are correctly identified, these helpers are not much useful. But for "universal" initialization they make sense. I'll add them.
Another would-be-nice feature is one command to do both init and restore. First initialize the hardware, then restore (overwrite) the setting from the asound.state if already eixsts. This is what udev needs to call.
I'm not sure. The restore action will always overwrite all 'init' values (at least when control identifier list is not changed in the driver). Probably, I would prefer a buildin procedure like 'if restore fails then do init'. What about 'alsactl boot' action name?
Note that the runtime evaluation of commands can be modified using environment variables like udev does. Just try 'alsactl -E CMD=help init' or 'CMD=help alsactl init'. Hardware can be detected using sysfs. For older kernel, I'm plannig to add some compatibility layer to read at least ATTR{subsystem_vendor} and ATTR{subsystem_device} information from procfs (codec files).
In the case of HD-audio, there could be still a bit pain. Some hardwares cannot be detected via PCI SSID but only via codec SSID (PKU) or codec revision ID which aren't exposed via sysfs. But, I guess this is a rare case and the mixer settings are likely same among these devices with the same PCI SSID.
What about this patch to allow CARDINFO{components} matching:
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 529bd5f..4f32911 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -588,7 +588,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, struct hda_codec **codecp) { struct hda_codec *codec; - char component[13]; + char component[31]; int err;
if (snd_BUG_ON(!bus)) @@ -693,7 +693,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, snd_hda_create_hwdep(codec); #endif
- sprintf(component, "HDA:%08x", codec->vendor_id); + sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); snd_component_add(codec->bus->card, component);
if (codecp)
The only limitation is that components variable in snd_ctl_card_info has only 80 chars. Only first two codecs can be identified.
Thanks for your review, Jaroslav
----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.
At Wed, 13 Aug 2008 16:04:47 +0200 (CEST), Jaroslav Kysela wrote:
On Wed, 13 Aug 2008, Takashi Iwai wrote:
At Wed, 13 Aug 2008 12:59:32 +0200 (CEST), Jaroslav Kysela wrote:
Hi,
some developers probably already noted, I commited to alsactl utility (alsa-utils package) initial implementation of soundcard initialization stuff aka 'alsactl init'.
Yeah, looks good.
Thanks.
The basic idea was to "reuse" nice udev configuration style and modify it to ALSA purposes. I hope that I ended up with a syntax which is easy understandable and configuration can be created with minimal effort. Please, look to 'man 7 alsactl_init' for more details and to alsa-utils/alsactl/init directory for example files.
The card-specific configs shouldn't be read from 00main, but read from its file, i.e. 50hda. That is, the config files are to be simply added / removed without modifying the existing file.
I'm not sure if it's useful for our purposes. The 00main also contains some "global" configuration (like SYSFS_DEVICE setup and more variables can be added in future) and my initial (not saying that it's optimal) configuration assumes that first file lookup is a driver name.
If you like to add extra configuration files in a directory, I would enhance 'INCLUDE' executer code to check, if the source path is directory and then include all files from it. But for the standard "database" purposes, I don't see a reason to check every file and skip contents of large files just after parsing first lines with false condition.
Of course, it's a question how fine-grained each file should be. But in general, modifying the default configuration just for adding a new, fairly independent item is a bad idea. In my scenario: you want to add the support for a new hardware -- fine, just add the file without changing anything else. This would make the maintenance a lot easier (imagine you maintain a distro package).
If scanning too many files really matters, then they can be concatenated at appropriate timing.
Another would-be-nice feature is one command to do both init and restore. First initialize the hardware, then restore (overwrite) the setting from the asound.state if already eixsts. This is what udev needs to call.
I'm not sure. The restore action will always overwrite all 'init' values (at least when control identifier list is not changed in the driver). Probably, I would prefer a buildin procedure like 'if restore fails then do init'. What about 'alsactl boot' action name?
The init makes sense in the case when the driver is updated and some new controls. Then the newly added controls are set up properly, then the other values are overwritten via restore.
Note that the runtime evaluation of commands can be modified using environment variables like udev does. Just try 'alsactl -E CMD=help init' or 'CMD=help alsactl init'. Hardware can be detected using sysfs. For older kernel, I'm plannig to add some compatibility layer to read at least ATTR{subsystem_vendor} and ATTR{subsystem_device} information from procfs (codec files).
In the case of HD-audio, there could be still a bit pain. Some hardwares cannot be detected via PCI SSID but only via codec SSID (PKU) or codec revision ID which aren't exposed via sysfs. But, I guess this is a rare case and the mixer settings are likely same among these devices with the same PCI SSID.
What about this patch to allow CARDINFO{components} matching:
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 529bd5f..4f32911 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -588,7 +588,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, struct hda_codec **codecp) { struct hda_codec *codec;
- char component[13];
char component[31]; int err;
if (snd_BUG_ON(!bus))
@@ -693,7 +693,7 @@ int __devinit snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, snd_hda_create_hwdep(codec); #endif
- sprintf(component, "HDA:%08x", codec->vendor_id);
sprintf(component, "HDA:%08x,%08x,%08x", codec->vendor_id, codec->subsystem_id, codec->revision_id); snd_component_add(codec->bus->card, component);
if (codecp)
The only limitation is that components variable in snd_ctl_card_info has only 80 chars. Only first two codecs can be identified.
This would work in most cases, yes.
Takashi
On Wed, Aug 13, 2008 at 04:18:16PM +0200, Takashi Iwai wrote:
Of course, it's a question how fine-grained each file should be. But in general, modifying the default configuration just for adding a new, fairly independent item is a bad idea. In my scenario: you want to add the support for a new hardware -- fine, just add the file without changing anything else. This would make the maintenance a lot easier
Yeah, I can see embedded people liking this too - a relatively small proportion of machines end up submitting their code to mainline for various reasons and carrying patches is no fun.
(imagine you maintain a distro package).
Or use one, for that matter - if you've got local changes then you need to resolve the conflicts between them and the distro versions on every upgrade.
I'm not sure. The restore action will always overwrite all 'init' values (at least when control identifier list is not changed in the driver). Probably, I would prefer a buildin procedure like 'if restore fails then do init'. What about 'alsactl boot' action name?
The init makes sense in the case when the driver is updated and some new controls. Then the newly added controls are set up properly, then the other values are overwritten via restore.
I've not looked at the new code yet but it would be *really* nice to have a format where only the control names are used.
On Wed, 13 Aug 2008, Takashi Iwai wrote:
At Wed, 13 Aug 2008 16:04:47 +0200 (CEST), Jaroslav Kysela wrote:
The card-specific configs shouldn't be read from 00main, but read from its file, i.e. 50hda. That is, the config files are to be simply added / removed without modifying the existing file.
I'm not sure if it's useful for our purposes. The 00main also contains some "global" configuration (like SYSFS_DEVICE setup and more variables can be added in future) and my initial (not saying that it's optimal) configuration assumes that first file lookup is a driver name.
If you like to add extra configuration files in a directory, I would enhance 'INCLUDE' executer code to check, if the source path is directory and then include all files from it. But for the standard "database" purposes, I don't see a reason to check every file and skip contents of large files just after parsing first lines with false condition.
Of course, it's a question how fine-grained each file should be. But in general, modifying the default configuration just for adding a new, fairly independent item is a bad idea. In my scenario: you want to add the support for a new hardware -- fine, just add the file without changing anything else. This would make the maintenance a lot easier (imagine you maintain a distro package).
If scanning too many files really matters, then they can be concatenated at appropriate timing.
My idea is to have a default database (which should be quite optimized for parser) and distro specific addons install to a directory as you suggested. So, something like (in alsactl init syntax) in 00main:
INCLUDE="addon"
Tree:
/usr/share/alsa/init/addon/Acer_XY80 /usr/share/alsa/init/addon/Acer_ZY91
etc...
The 00main file might remain (just to handle global specific configuration).
Eventualy, another INCLUDE can be placed before the default database processing to override the default database.
Another would-be-nice feature is one command to do both init and restore. First initialize the hardware, then restore (overwrite) the setting from the asound.state if already eixsts. This is what udev needs to call.
I'm not sure. The restore action will always overwrite all 'init' values (at least when control identifier list is not changed in the driver). Probably, I would prefer a buildin procedure like 'if restore fails then do init'. What about 'alsactl boot' action name?
The init makes sense in the case when the driver is updated and some new controls. Then the newly added controls are set up properly, then the other values are overwritten via restore.
Upgrading a driver is quite specific process. In this case would be probably better to read saved state and compare it to the actual driver controls. If something differs, call init and then restore with force flag. At least, the init procedure would be skipped (almost every boot time) if all controls are present in the state file.
So, I'm proposing this 'alsactl boot' behaviour:
1) read /etc/asound.state 2) if the state does not exist run 'alsactl init' and exit 3) if the state exists but controls do not match these in driver, run 'alsactl init' 4) run 'alsactl restore'
Opinions?
Jaroslav
----- Jaroslav Kysela perex@perex.cz Linux Kernel Sound Maintainer ALSA Project, Red Hat, Inc.
At Wed, 13 Aug 2008 19:26:25 +0200 (CEST), Jaroslav Kysela wrote:
On Wed, 13 Aug 2008, Takashi Iwai wrote:
At Wed, 13 Aug 2008 16:04:47 +0200 (CEST), Jaroslav Kysela wrote:
The card-specific configs shouldn't be read from 00main, but read from its file, i.e. 50hda. That is, the config files are to be simply added / removed without modifying the existing file.
I'm not sure if it's useful for our purposes. The 00main also contains some "global" configuration (like SYSFS_DEVICE setup and more variables can be added in future) and my initial (not saying that it's optimal) configuration assumes that first file lookup is a driver name.
If you like to add extra configuration files in a directory, I would enhance 'INCLUDE' executer code to check, if the source path is directory and then include all files from it. But for the standard "database" purposes, I don't see a reason to check every file and skip contents of large files just after parsing first lines with false condition.
Of course, it's a question how fine-grained each file should be. But in general, modifying the default configuration just for adding a new, fairly independent item is a bad idea. In my scenario: you want to add the support for a new hardware -- fine, just add the file without changing anything else. This would make the maintenance a lot easier (imagine you maintain a distro package).
If scanning too many files really matters, then they can be concatenated at appropriate timing.
My idea is to have a default database (which should be quite optimized for parser) and distro specific addons install to a directory as you suggested. So, something like (in alsactl init syntax) in 00main:
INCLUDE="addon"
Tree:
/usr/share/alsa/init/addon/Acer_XY80 /usr/share/alsa/init/addon/Acer_ZY91
etc...
They should use number-scheme, too.
The 00main file might remain (just to handle global specific configuration).
Eventualy, another INCLUDE can be placed before the default database processing to override the default database.
Yes, sometimes we need a replacement and sometime an additional setup.
Another would-be-nice feature is one command to do both init and restore. First initialize the hardware, then restore (overwrite) the setting from the asound.state if already eixsts. This is what udev needs to call.
I'm not sure. The restore action will always overwrite all 'init' values (at least when control identifier list is not changed in the driver). Probably, I would prefer a buildin procedure like 'if restore fails then do init'. What about 'alsactl boot' action name?
The init makes sense in the case when the driver is updated and some new controls. Then the newly added controls are set up properly, then the other values are overwritten via restore.
Upgrading a driver is quite specific process. In this case would be probably better to read saved state and compare it to the actual driver controls. If something differs, call init and then restore with force flag. At least, the init procedure would be skipped (almost every boot time) if all controls are present in the state file.
FYI, the force flag is already used as default in the current alsactl.
So, I'm proposing this 'alsactl boot' behaviour:
- read /etc/asound.state
- if the state does not exist run 'alsactl init' and exit
- if the state exists but controls do not match these in driver, run 'alsactl init'
- run 'alsactl restore'
That would work although init can be done always when you run alsactl restore anyway.
Takashi
participants (3)
-
Jaroslav Kysela
-
Mark Brown
-
Takashi Iwai