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