[alsa-devel] Unregister a card from userspace?
A sound card driver would normally call snd_soc_register_card() to register its sound card with ALSA.
Is there some way to unregister the card from userspace?
My use case is that I have a card driver I'm working on as a module, and while insmodding it works fine, I can't rmmod it because once snd_soc_register_card() has been called, it has a usage count of 2 and thus cannot be rmmod:ed.
/Ricard
Ricard Wanderlof wrote:
My use case is that I have a card driver I'm working on as a module, and while insmodding it works fine, I can't rmmod it because once snd_soc_register_card() has been called, it has a usage count of 2 and thus cannot be rmmod:ed.
soc_probe_component() adds a reference to each component's driver's module. Maybe putting each component into its own module would help.
Anyway, you should be able to unbind the driver: https://lwn.net/Articles/143397/
Regards, Clemens
On Wed, 4 Nov 2015, Clemens Ladisch wrote:
Ricard Wanderlof wrote:
My use case is that I have a card driver I'm working on as a module, and while insmodding it works fine, I can't rmmod it because once snd_soc_register_card() has been called, it has a usage count of 2 and thus cannot be rmmod:ed.
soc_probe_component() adds a reference to each component's driver's module. Maybe putting each component into its own module would help.
I'd rather not as there's no real gain from it (the constituent drivers cannot be used separately or in any other combination), but perhaps that is the only way to go.
Anyway, you should be able to unbind the driver: https://lwn.net/Articles/143397/
Yes, that works. After unbinding the driver, the usage count drops to 0, and I can successfully rmmod it. So at least that's a workable solution.
It just seems to me that there's something I must have missed, as there should be a mechanism to do this automatically when a module containing a driver is rmmod'ed.
/Ricard
On 11/12/2015 02:07 PM, Ricard Wanderlof wrote:
On Wed, 4 Nov 2015, Clemens Ladisch wrote:
Ricard Wanderlof wrote:
My use case is that I have a card driver I'm working on as a module, and while insmodding it works fine, I can't rmmod it because once snd_soc_register_card() has been called, it has a usage count of 2 and thus cannot be rmmod:ed.
soc_probe_component() adds a reference to each component's driver's module. Maybe putting each component into its own module would help.
I'd rather not as there's no real gain from it (the constituent drivers cannot be used separately or in any other combination), but perhaps that is the only way to go.
Anyway, you should be able to unbind the driver: https://lwn.net/Articles/143397/
Yes, that works. After unbinding the driver, the usage count drops to 0, and I can successfully rmmod it. So at least that's a workable solution.
It just seems to me that there's something I must have missed, as there should be a mechanism to do this automatically when a module containing a driver is rmmod'ed.
The way it works is that the reference count for the modules of the individual components is incremented when they are bound to the card to ensure that they are not removed when still in use. This usually does not affect the reference count on the module of the card and you can still rmmod the module of the card which will unregister the card. This again drops the reference count on the components and you can remove those modules as well.
In your case the components and the card are in the same module and you end up with a cyclic dependency. The card ensures that the reference count of the module for the components is incremented, which in this case is also the cards module, so the cards module reference count is non 0 and you can't rmmod the card module, which means the card won't be unregistered which means the references to the module wont be dropped.
On Thu, 12 Nov 2015, Lars-Peter Clausen wrote:
The way it works is that the reference count for the modules of the individual components is incremented when they are bound to the card to ensure that they are not removed when still in use. This usually does not affect the reference count on the module of the card and you can still rmmod the module of the card which will unregister the card. This again drops the reference count on the components and you can remove those modules as well.
In your case the components and the card are in the same module and you end up with a cyclic dependency. The card ensures that the reference count of the module for the components is incremented, which in this case is also the cards module, so the cards module reference count is non 0 and you can't rmmod the card module, which means the card won't be unregistered which means the references to the module wont be dropped.
Thanks Lars-Peter for that description. It seems that the solution (which is what Clemens and Felipe were actually suggesting) would then be to have two separate modules, one for the low level parts (codec, dai and PCM drivers) and one for the machine driver (containing the card registration).
/Ricard
Hi Ricard,
On 04/11/15 09:36, Ricard Wanderlof wrote:
A sound card driver would normally call snd_soc_register_card() to register its sound card with ALSA.
Is there some way to unregister the card from userspace?
No. ALSA API to deal with cards are in kernel space only.
My use case is that I have a card driver I'm working on as a module, and while insmodding it works fine, I can't rmmod it because once snd_soc_register_card() has been called, it has a usage count of 2 and thus cannot be rmmod:ed.
You have to unregister that card upon freeing your module.
On Mon, 9 Nov 2015, Felipe Ferreri Tonello wrote:
while insmodding it works fine, I can't rmmod it because once snd_soc_register_card() has been called, it has a usage count of 2 and thus cannot be rmmod:ed.
You have to unregister that card upon freeing your module.
But that is precisely the problem. The framework that manages the insertion and deletion of modules notes that my module has a usage count that is > 0 (in my case it is 2, which I'm convinced is because the card has been registered with ALSA), and refuses to free the module. So there is now way any unregister_card call can be made when my module is freed, as due to the usage count it would never even be attempted.
I suppose one way would be to have a specific call into the module which unregisters the card, and the module could then be freed as usual afterwards, but it seems like a bit of a hack.
/Ricard
Hi Richard,
On 10/11/15 07:55, Ricard Wanderlof wrote:
On Mon, 9 Nov 2015, Felipe Ferreri Tonello wrote:
while insmodding it works fine, I can't rmmod it because once snd_soc_register_card() has been called, it has a usage count of 2 and thus cannot be rmmod:ed.
You have to unregister that card upon freeing your module.
But that is precisely the problem. The framework that manages the insertion and deletion of modules notes that my module has a usage count that is > 0 (in my case it is 2, which I'm convinced is because the card has been registered with ALSA), and refuses to free the module. So there is now way any unregister_card call can be made when my module is freed, as due to the usage count it would never even be attempted.
Do you mean that unbind is never called? Well, the framework should call bind/unbind for each user of your module.
How is your architecture? If you use one card for each probe of module then each bind should create one device, right?
On Wed, 11 Nov 2015, Felipe Ferreri Tonello wrote:
But that is precisely the problem. The framework that manages the insertion and deletion of modules notes that my module has a usage count that is > 0 (in my case it is 2, which I'm convinced is because the card has been registered with ALSA), and refuses to free the module. So there is now way any unregister_card call can be made when my module is freed, as due to the usage count it would never even be attempted.
Do you mean that unbind is never called? Well, the framework should call bind/unbind for each user of your module.
Ok, I didn't know that. It's the first time I've been writing an ALSA driver as a loadable module.
How is your architecture? If you use one card for each probe of module then each bind should create one device, right?
In this case, it is a device which is located on the SoC. There is only one instance of it. When the module is loaded, it loads a codec driver with its associated DAI driver, a PCM driver, snd-soc-dummy-dai, and then a machine driver to tie it all together, finally registering the card with ALSA.
Looking in /sys/bus/platform/devices, there seems to be one device created for the codec itself, and one for the machine driver. I don't know if that's right or wrong, the ALSA driver hierarchy works in the sense that I can capture audio from it anyway.
/Ricard
On 11/11/2015 01:59 PM, Ricard Wanderlof wrote:
On Wed, 11 Nov 2015, Felipe Ferreri Tonello wrote:
But that is precisely the problem. The framework that manages the insertion and deletion of modules notes that my module has a usage count that is > 0 (in my case it is 2, which I'm convinced is because the card has been registered with ALSA), and refuses to free the module. So there is now way any unregister_card call can be made when my module is freed, as due to the usage count it would never even be attempted.
Do you mean that unbind is never called? Well, the framework should call bind/unbind for each user of your module.
Ok, I didn't know that. It's the first time I've been writing an ALSA driver as a loadable module.
How is your architecture? If you use one card for each probe of module then each bind should create one device, right?
In this case, it is a device which is located on the SoC. There is only one instance of it. When the module is loaded, it loads a codec driver with its associated DAI driver, a PCM driver, snd-soc-dummy-dai, and then a machine driver to tie it all together, finally registering the card with ALSA.
Looking in /sys/bus/platform/devices, there seems to be one device created for the codec itself, and one for the machine driver. I don't know if that's right or wrong, the ALSA driver hierarchy works in the sense that I can capture audio from it anyway.
Which one is the module you can't unload? The module that contains the machine driver should only have its reference count increment when a playback or capture stream is active so you can't remove it when it is actively in use.
- Lars
On Wed, 11 Nov 2015, Lars-Peter Clausen wrote:
How is your architecture? If you use one card for each probe of module then each bind should create one device, right?
In this case, it is a device which is located on the SoC. There is only one instance of it. When the module is loaded, it loads a codec driver with its associated DAI driver, a PCM driver, snd-soc-dummy-dai, and then a machine driver to tie it all together, finally registering the card with ALSA.
Looking in /sys/bus/platform/devices, there seems to be one device created for the codec itself, and one for the machine driver. I don't know if that's right or wrong, the ALSA driver hierarchy works in the sense that I can capture audio from it anyway.
Which one is the module you can't unload? The module that contains the machine driver should only have its reference count increment when a playback or capture stream is active so you can't remove it when it is actively in use.
As it is currently I've got all drivers in the same module. Since there is only one possible choice for the PCM and DAI drivers when using this particular codec, it seemed pointless to several modules for the constituent parts.
/Ricard
Hi Ricard,
On 11/11/15 12:59, Ricard Wanderlof wrote:
On Wed, 11 Nov 2015, Felipe Ferreri Tonello wrote:
But that is precisely the problem. The framework that manages the insertion and deletion of modules notes that my module has a usage count that is > 0 (in my case it is 2, which I'm convinced is because the card has been registered with ALSA), and refuses to free the module. So there is now way any unregister_card call can be made when my module is freed, as due to the usage count it would never even be attempted.
Do you mean that unbind is never called? Well, the framework should call bind/unbind for each user of your module.
Ok, I didn't know that. It's the first time I've been writing an ALSA driver as a loadable module.
Well, this is not ALSA specific, it really depends on which framework your driver is based on, but they all share similar flow on probe and remove driver.
How is your architecture? If you use one card for each probe of module then each bind should create one device, right?
In this case, it is a device which is located on the SoC. There is only one instance of it. When the module is loaded, it loads a codec driver with its associated DAI driver, a PCM driver, snd-soc-dummy-dai, and then a machine driver to tie it all together, finally registering the card with ALSA.
Looking in /sys/bus/platform/devices, there seems to be one device created for the codec itself, and one for the machine driver. I don't know if that's right or wrong, the ALSA driver hierarchy works in the sense that I can capture audio from it anyway.
What exactly do you want? If it is driver that register and unregister cards based on the user interaction of probing and removing that module from user-space, then you are not looking for a driver. What you are looking for is just a kernel module. The only way of interacting with it is dealing with module_init and module_exit.
On the other hand, if in fact you want a driver, then check sound/drivers/dummy.c for an example. You can also read the Documentation/driver-model/platform.txt for more info.
On Wed, 11 Nov 2015, Felipe Ferreri Tonello wrote:
How is your architecture? If you use one card for each probe of module then each bind should create one device, right?
In this case, it is a device which is located on the SoC. There is only one instance of it. When the module is loaded, it loads a codec driver with its associated DAI driver, a PCM driver, snd-soc-dummy-dai, and then a machine driver to tie it all together, finally registering the card with ALSA.
Looking in /sys/bus/platform/devices, there seems to be one device created for the codec itself, and one for the machine driver. I don't know if that's right or wrong, the ALSA driver hierarchy works in the sense that I can capture audio from it anyway.
What exactly do you want? If it is driver that register and unregister cards based on the user interaction of probing and removing that module from user-space, then you are not looking for a driver. What you are looking for is just a kernel module. The only way of interacting with it is dealing with module_init and module_exit.
What I was aiming for was that when I load this particular module, it ultimately calls snd_soc_register_card in its probe function, so that the device in question becomes available for ALSA once the module has been loaded. And then if I want to remove the driver I simply unload the module which allows it to go away.
The underlying reason for this rigmarole is rather complex, suffice to say at this stage that part of the hardware can be used for other mutually exclusive tasks.
On the other hand, if in fact you want a driver, then check sound/drivers/dummy.c for an example. You can also read the Documentation/driver-model/platform.txt for more info.
Thanks for the pointers Filipe, I'll have a look there.
/Ricard
Hi Ricard,
On 11/11/15 15:33, Ricard Wanderlof wrote:
On Wed, 11 Nov 2015, Felipe Ferreri Tonello wrote:
How is your architecture? If you use one card for each probe of module then each bind should create one device, right?
In this case, it is a device which is located on the SoC. There is only one instance of it. When the module is loaded, it loads a codec driver with its associated DAI driver, a PCM driver, snd-soc-dummy-dai, and then a machine driver to tie it all together, finally registering the card with ALSA.
Looking in /sys/bus/platform/devices, there seems to be one device created for the codec itself, and one for the machine driver. I don't know if that's right or wrong, the ALSA driver hierarchy works in the sense that I can capture audio from it anyway.
What exactly do you want? If it is driver that register and unregister cards based on the user interaction of probing and removing that module from user-space, then you are not looking for a driver. What you are looking for is just a kernel module. The only way of interacting with it is dealing with module_init and module_exit.
What I was aiming for was that when I load this particular module, it ultimately calls snd_soc_register_card in its probe function, so that the device in question becomes available for ALSA once the module has been loaded. And then if I want to remove the driver I simply unload the module which allows it to go away.
You said that the framework that handles the module had the counter to 2 so your unregister card function was never been called, right? I don't understand that part, since it doesn't make sense to load your module into the kernel more then once.
Try to write just a simple module that register/unregister a card on module_init/module_exit, respectively. That should work just fine.
On Thu, 12 Nov 2015, Felipe Ferreri Tonello wrote:
What I was aiming for was that when I load this particular module, it ultimately calls snd_soc_register_card in its probe function, so that the device in question becomes available for ALSA once the module has been loaded. And then if I want to remove the driver I simply unload the module which allows it to go away.
You said that the framework that handles the module had the counter to 2 so your unregister card function was never been called, right? I don't understand that part, since it doesn't make sense to load your module into the kernel more then once.
No, I don't understand why the usage count goes to 2 either.
What the driver does is this:
At module_init time, it registers: a) a platform driver for the actual hardware (in essence, codec) b) a platform device representing the hardware itself, and c) a platform driver which is the ALSA machine driver for the device in question.
The registering of a) and b) cause the device driver for the codec to be initialized by it's probe function getting called. Apart from various hardware initializations, it registers the corresponding PCM driver via snd_soc_register_platform(), and then registers the codec using snd_soc_register_codec() (registering both the codec itself and its DAI, although the latter actually doesn't contain any implementation as the communication is handled directly via DMA rather than over some link like I2S).
In the case of c), there is a device tree entry which corresponds to the device. This in turn causes the the machine driver probe function to be called, which does snd_soc_register_card(), binding together the codec driver, the PCM driver with its DAI, and a dummy CPU DAI.
The final outcome of this is that ALSA outputs a "<codec dai> <-> snd-soc-dummy-dai ampping ok" message in the kernel log.
The device now works as intended. I can arecord from it and get what I expect in the resulting output file.
Doing an lsmod at this point shows a usage count ('Used by') of 2. I don't know if that is just due to snd_soc_register_card, or there is some internal usage count due to the fact that there are a couple of drivers registered at the same time. Certainly there are two hardware devices: one representing the ALSA machine driver, specified in the device tree, and one representing the actual hardware, which is registered at the machine driver probe time.
Unbinding the driver, which is done by doing
cd /sys/bus/platform/drivers/<machine-driver-name>
followed by
echo -n <device-name> > unbind
causes the machine driver 'remove' function to be called, which in turn does snd_soc_unregister_card.
A lot of the complexity is done to fit into the ALSA SoC driver model, where we have
ALSA <-> PCM (DMA) driver <-> CPU DAI <-> CODEC DAI <-> CODEC
even though in this case there are no actual DAI's and the PCM driver simply reads the data directly from the CODEC in memory. In the past I've tried simplifying the hierarchy for a similar system, but it seems all the components have to be there in some form. The only simplification is that the CPU DAI can be snd-soc-dummy-dai, and that the only implementation needed for CODEC DAI is the specification of things like the limitation of the number channels, rates, and formats.
Try to write just a simple module that register/unregister a card on module_init/module_exit, respectively. That should work just fine.
Since the driver uses information from the device tree, it seems that I would need to follow the paradigm of registering a driver, which the Linux device framework then associates with the corresponding device specified in the device tree, in turn calling the probe function. At the moment this driver is the ALSA machine driver.
An alternative would be to let the device tree entry correspond to the codec device, avoiding the need to explicitly create a codec device in the initialization code. I don't know if that would buy much in the end, but it would allow me to do snd_soc_register card() at module init rather than at probe time.
The problem as I see it is that with a usage count != 0, rmmod will not even attempt to unload the driver, hence the module exit function will never be called.
/Ricard
participants (4)
-
Clemens Ladisch
-
Felipe Ferreri Tonello
-
Lars-Peter Clausen
-
Ricard Wanderlof