ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

AbstractThis article provides an in-depth analysis of the core driver implementation mechanism of the Loopback sound card (simple, without involving low-level hardware drivers) from the perspective of character device driver development, based on the Linux kernel 6.8.0 and the QEMU simulation environment with AArch64 architecture. It focuses on the registration management of device nodes and the operational mechanism of PCM device nodes in kernel mode.1. ALSA Device Driver Framework Initialization Functionalsa_sound_initCode Path:linux-6.8/sound/core/sound.cALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

The core function of alsa_sound_init is to register the main device number and establish a basic device framework, providing underlying support for the subsequent loading and operation of audio devices. alsa_sound_init requests a main device number for character devices (fixed at 116), serving as a unified entry point for all ALSA audio devices. Subsequent logical devices such as PCM (playback/recording) and Control (mixer control) are mounted under this main device as secondary device numbers.

1. snd_open looks up the corresponding device operation set from the global array snd_minors using the secondary device number (which is snd_pcm_f_ops).

2. Initializes the /proc/asound directory to expose ALSA internal status and debugging information (such as sound card list, device status, etc.).ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers3. register_chrdev uses the sound card’s main device numberCONFIG_SND_MAJOR registers 256 secondary devices, each of which is added to the linked list array cdev_map based on the device number, and each secondary device’s struct file_operations is registered as snd_fops.ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers4. When any sound card node under /dev/snd is opened, chrdev_open will first find the corresponding struct cdev in cdev_map using the device number, assign cdev to inode->i_cdev, replace fops with filp->ops (which is snd_pcm_f_ops), and call filp->f_op->open(inode, filp).After that, all ops operations of this device node correspond to snd_pcm_f_ops instead of snd_fops.

2. Creating Sound Card and PCM Device Registration (Using Loopback as an Example)

The Loopback sound card and device are created in the loopback_probe function.

1. alsa_card_loopback_init’s main task is to register the loopback driver and device to the platform bus, with the subsequent registration of the loopback sound card and PCM device completed in its probe function.

Code Path:sound/drivers/aloop.c

ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

2. Calls platform_device_register_simple to register the loopback device to the platform bus. When the device is registered, it will match the previously registered loopback driver through the platform bus. Since the enable array only has the first element set to 1 by default, the platform_device_register_simple function is effectively called only once in the loop, resulting in only one Loopback sound card device.

ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device DriversALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

3. After the Loopback device and driver are matched through the platform bus, the probe function loopback_probe is automatically called. This function first creates the sound card snd_card, then creates two PCM devices, numbered 0 and 1, and creates one mixer device.

ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

4. loopback_pcm_new’s main task is to create one snd_pcm device through the function snd_pcm_new. This snd_pcm device contains 8 snd_pcm_substream devices, which are 8 capture and 8 playback sub-audio stream substreams.

ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device DriversThe reason for having 8 is that each element of the following array is 8.ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device DriversALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

Calls the function snd_pcm_set_ops to assign the snd_pcm_ops corresponding to capture and playback snd_pcm_substream to loopback_pcm_ops.

ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers5. Calls the function snd_pcm_new to create the Loopback PCM device.ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

During the process of snd_pcm_new_stream, the playback or capture PCM device will be initialized, and all snd_pcm_substream must be linked to the snd_pcm->streams (which is snd_pcm_str) linked list, calling snd_pcm_stream_proc_init to prepare for creating device nodes and debugging files under /proc.

ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

6. Calls the function snd_device_new to create the PCM device node and snd_minor.

The function snd_device_new is used to create each snd_device corresponding to snd_pcm. Each snd_device under this sound card is bound to card->devices. The struct snd_device_ops is set as the callback function for snd_device, and the pointer to snd_pcm is assigned to dev->device_data. The subsequent sound card registration process will need to use device_data to find the corresponding snd_pcm pointer.

ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device DriversDuring the sound card registration, each snd_device on card->devices will be traversed, and its dev_register function will be called. It can be seen that snd_device_ops’s .dev_register points to snd_pcm_dev_register.7. The function snd_pcm_dev_register and the snd_minors arraya) Actually, PCM devices do not use the struct cdev commonly used in character drivers for management, but use struct snd_minor. snd_minors is an array of pointers of type struct *snd_minor, with each element corresponding to a snd_minor, and each snd_minor represents a snd_pcm (or snd_device), with the index of each element being the device number of the PCM device.ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Driversb) The function snd_register_device will traverse the snd_minors array in order to find an unused snd_minor each time a snd_device is registered. Each snd_minor’s f_ops points to the capture or playback member in snd_pcm_f_ops.ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

c) The snd_pcm_f_ops structure defines the file operation interface for the device (such as .write, .unlocked_ioctl, etc.), exposing the PCM device to user space, allowing applications (such as audio players, recording tools) to access audio devices through device files (such as /dev/snd/pcmC0D0p).

d) private_data is assigned the snd_pcm pointer, which will be used in operations like open to access snd_pcm. With the snd_pcm, one can navigate between various ALSA data structures..

3. Registering the Sound Card

loopback_probe calls snd_card_register to register the loopback sound card after creating the PCM device and PCM sub-devices.

ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

As mentioned earlier, snd_card_register calls snd_device_register_all to traverse all devices on card->devices and execute the function __snd_device_register for each.

ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

1. Device Registration of snd_device

The function __snd_device_register calls the dev_register callback function, which is snd_register_device, to start device registration. The process of snd_register_device has been explained earlier.

ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

4. Testing aplay and arecord Applications Opening (open) PCM Devices

To facilitate observing the kernel call stack during open, dump_stack has been added to loopback_open, as shown below.

ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

To facilitate observing the parameters of the user-space open device node, we used strace to trace the aplay application, and the following kernel call stack information was printed.

ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

1. Analyzing the snd_open function

snd_open is implemented in sound/core/sound.c. Since the ops of the struct cdev corresponding to each secondary device of the sound card are assigned to snd_fops, snd_open serves as the unified entry point for opening all PCM devices. However, this is not permanent; snd_open will replace the fops pointer with the one saved in snd_minors corresponding to the device number through the replace_fops function. The detailed breakdown is as follows:ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

a) snd_open retrieves the snd_minor corresponding to the device number from the array snd_minors.

b) Calls fops_get(mptr->f_ops) to obtain the file_operations corresponding to snd_minor.

c) Calls replace_fops(file, new_fops) to replace the ops of the file pointer with those pointed to by snd_minor, which is snd_pcm_f_ops. After this, the read, mmap, write, ioctl, etc., under this PCM node will use snd_pcm_f_ops.

ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

d) Calls the function file->f_op->open, which is either snd_pcm_capture_open or snd_pcm_playback_open, to continue the open process.

ALSA Driver: An In-Depth Analysis of the ALSA Framework from the Perspective of Device Drivers

e) The functions snd_pcm_playback_open and snd_pcm_capture_open will obtain the snd_pcm pointer saved in private_data through snd_minor and continue the open process by calling snd_pcm_open, snd_pcm_open_substream, and substream->ops->open(substream).

Summary: The ALSA driver (such as snd_aloop) registers multiple character device nodes (such as /dev/snd/*), where PCM devices transmit audio data through read()/write() or mmap (streaming operations of character devices). Control devices adjust volume, switch input sources, etc., through ioctl() (control interface of character devices).

Leave a Comment