Part of this article refers to the blog from Droidphone (http://blog.csdn.net/droidphone/article/details/6271122), about Alsa writing a very good article, just a few examples. This article is a combination of examples to analyze the ALSA audio driver.
Development environment: ubuntu10.04
Target board: linux-2.6.37 (view Linux kernel information via command uname-r)
Compiler: arm-none-linux-gnueabi-(None on behalf of compiler creator, such as: FSL for Freescale, the kernel to talk about Eabi,oabi, in fact, compared to the way the system calls, of course, we say that the system is limited to arm systems)
Next, the first thing we need to understand is the ALSA overall architecture, the frame composition is as follows:
In the kernel device driver layer, ALSA provides alsa-driver, and at the application layer, ALSA provides us with alsa-lib, as long as the application calls Alsa-lib provided API (this board/usr/lib/libasound.so.2 and libasound.so.2.0.0 Alsa-lib Library Asound), you can complete the control of the underlying audio hardware. In kernel space, ALSA-SOC is actually a further encapsulation of alsa-driver, and he provides some column-enhanced functionality for embedded devices.
Next we look at the device files and the SYS system interface:
We can see the following device files:
ControlC0 Control for sound card 1, such as channel selection, mixing, microphone control, etc.
ControlC1 Control for sound card 2, such as channel selection, mixing, microphone control, etc.
Midic0d0 for playing MIDI audio (my driver does not have)
PCMC0D0C-PCM Device for sound card 1 recording (tvp5158 audio capture)
PCMC0D1C-PCM Device for sound card 1 recording (tlv320aic3x audio capture)
PCMC0D1P-PCM Device for sound card 1 playback (tlv320aic3x audio output)
pcmc1d0p-PCM device for sound card 2 playback (HDMI audio output)
Seq--〉 Sequencer (My driver does not have)
Timer--〉 Timer
It can be seen that there are 2 sound cards, sound card 1 has 2 recording devices and a playback device, sound card 2 has only one playback device
Where c0d0 represents the device in sound card 0 0,pcmc0d0c The last C represents the capture,pcmc0d0p last p for playback, these are the naming rules in Alsa-driver.
From the above analysis can be seen, my sound card hangs 7 devices (actually here the device is the actual device logic classification), according to the actual ability of the sound card, the driver can actually hang more kinds of devices, in include/sound/core.h, defined the following device types:
typedef int __bitwise snd_device_type_t; #define Sndrv_dev_toplevel ((__force snd_device_type_t) 0) #define Sndrv_d Ev_control ((__force snd_device_type_t) 1)//control type # define SNDRV_DEV_LOWLEVEL_PRE ((__force snd_device_type_t) 2) #d Efine Sndrv_dev_lowlevel_normal ((__force snd_device_type_t) 0x1000) #define SNDRV_DEV_PCM (__force Snd_devic e_type_t) 0x1001)//PCM type # define Sndrv_dev_rawmidi ((__force snd_device_type_t) 0x1002) #define Sndrv_dev_timer ((__force snd_device_type_t) 0x1003)//Timer type # define Sndrv_dev_sequencer ((__force snd_device_type_t) 0x1004)// Sequencer Type # define SNDRV_DEV_HWDEP ((__force snd_device_type_t) 0x1005) #define SNDRV_DEV_INFO ((__force snd_ device_type_t) 0x1006) #define Sndrv_dev_bus ((__force snd_device_type_t) 0x1007) #define Sndrv_dev_codec ((__force snd_device_type_t) 0x1008)//Decoder type # define Sndrv_dev_jack ((__force snd_device_type_t) 0x1009) #defi NE sndrv_dev_lowlevel ((__force snd_device_type_t) 0x2000)
Here we begin to analyze the code:
First of all, we have two sound cards, then how come these two sound cards?
First you should know the sound card creation process:
<1> understanding the structure of a sound card struct Snd_card (Snd_card is defined in the header file: include/sound/core.h)
struct Snd_card {int number; /* Number of soundcard (Index to snd_cards) */char id[16]; /* ID string of this card */char driver[16]; /* Driver name */char shortname[32]; /* Short name of this soundcard */char longname[80]; /* Name of this soundcard */char mixername[80]; /* Mixer Name */char components[128]; /* Card delimited with space */struct module *module; /* Top-level module */void *private_data; /* Private data for soundcard */void (*private_free) (struct snd_card *card); /* Callback for freeing of private data */struct list_head devices; /* devices */unsigned int last_numid; /* Last used numeric ID */struct Rw_semaphore controls_rwsem; /* Controls List Lock */rwlock_t Ctl_files_rwlock; /* Ctl_files list lock */int controls_count; /* Count of all controls */int user_ctl_count; /* Count of all user controls */struct List_head controls; /* All controls for this card */struct list_head ctl_files; /* Active Control files */struct snd_info_entry *proc_root; /* root for soundcard specific files */struct snd_info_entry *proc_id; /* The card ID */struct proc_dir_entry *proc_root_link; /* Number link to Real ID */struct list_head files_list; /* All files associated to the this card */struct snd_shutdown_f_ops *s_f_ops; /* file operations in the Shutdown state */spinlock_t Files_lock; /* Lock the files for this card */int shutdown; /* This card is going down */int free_on_last_close; /* Free in context of file_release */wait_queue_head_t shutdown_sleep; struct device *dev; /* Device assigned to the This card */struct device *card_dev; /* CARDX object for SYSFS */#ifdef config_pm unsigned int power_state; /* Power state */struct mutex power_lock; /* Power Lock */wait_queue_head_t power_sleep; #endif # if defined (Config_snd_mixer_oss) | | Defined (config_snd_mixer_oss_module) struct Snd_mixer_oss *mixer_oss; int mixer_oss_change_count; #endif};
struct List_head devices records the list of all logical devices under the sound card
struct List_head controls record the list of all control units under the sound card
void *private_data The private data of a sound card, you can specify the size of the data by parameter when you create the sound card
<2> create an instance of a sound card
The ASOC first registers the platform driver, waits for the platform device to arrive, when the driver discovers the corresponding device, calls the driver probe, then calls Snd_soc_register_card to create the sound card, the sound card private data, the device driver ID name, Create a functional part of your sound card (such as PCM, mixer, Midi,control, etc.) and register your sound card.
1> Registered Platform Driver
/* ASOC platform driver */static struct Platform_driver soc_driver = { . Driver = { . Name = "Soc-audio",
.owner = this_module, . PM = &soc_pm_ops, }, . Probe = Soc_probe, . Remove = Soc_remove,};
static int __init snd_soc_init (void) {#ifdef Config_debug_fs debugfs_root = Debugfs_create_dir ("Asoc", NULL); if (Is_err (debugfs_root) | |!debugfs_root) {PRINTK (kern_warning "asoc:failed to create Debugfs dire Ctory\n "); Debugfs_root = NULL; } if (!debugfs_create_file ("Codecs", 0444, Debugfs_root, NULL, &codec_list_fops)) Pr_warn ("A soc:failed to create CODEC list Debugfs file\n "); if (!debugfs_create_file ("Dais", 0444, Debugfs_root, NULL, &dai_list_fops)) Pr_warn ("Asoc:fail Ed to create DAI list Debugfs file\n "); if (!debugfs_create_file ("Platforms", 0444, Debugfs_root, NULL, &platform_list_fops)) Pr_warn (" asoc:failed to create platform list Debugfs file\n "); #endif return Platform_driver_register (&soc_driver);} Module_init (snd_soc_init), static void __exit snd_soc_exit (void) {#ifdef CONFIG_DEBUG_FS debugfs_remove_recursive ( Debugfs_root); #endif PLATFOrm_driver_unregister (&soc_driver);} Module_exit (Snd_soc_exit);
The Snd_soc_init (sound/soc/soc-core.c) function is primarily to create Debugfs file system interface and platform device-driven registration (platform_driver_register).
Here we explain the Debugfs, as the name implies, is a virtual file system for kernel debugging, kernel developers exchange data through Debugfs and user space. Similar virtual file systems, such as PROCFS and SYSFS, are not actually stored on the hard disk, but are built after the Linux kernel is running. User space Mount Debugfs file system to a directory via Mount-t Debugfs debugfs/a, view a directory:
In the directory we found ASOC This folder, in this folder contains several files we created codecs, dais, platforms:
2> Registration Platform Equipment (related to the specific platform, we ti Leonardo da Vinci series Chip)
static int __init ti81xx_dvr_soc_init (void) {int ret; Ti81xx_pdev0 = Platform_device_alloc ("Soc-audio", 0); if (!ti81xx_pdev0) Return-enomem; Platform_set_drvdata (Ti81xx_pdev0, &ti81xx_dvr_snd_card0); ret = Platform_device_add (ti81xx_pdev0); if (ret) {PRINTK (kern_err "Can ' t add Soc Platform device\n"); Platform_device_put (TI81XX_PDEV0); return ret; } TI81XX_PDEV1 = Platform_device_alloc ("Soc-audio", 1); if (!TI81XX_PDEV1) {platform_device_put (ti81xx_pdev0); Return-enomem; } platform_set_drvdata (Ti81xx_pdev1, &ti81xx_dvr_snd_card1); ret = Platform_device_add (TI81XX_PDEV1); if (ret) {PRINTK (kern_err "Can ' t add Soc Platform device\n"); Platform_device_put (TI81XX_PDEV0); Platform_device_put (TI81XX_PDEV1); return ret; } return ret;} static void __exit ti81xx_dvr_soc_exit (void) {platform_device_unregister (ti81xx_pdev0); Platform_device_unregIster (TI81XX_PDEV1);} Module_init (Ti81xx_dvr_soc_init); Module_exit (Ti81xx_dvr_soc_exit);
The Ti81xx_dvr_soc_init (Sound/soc/davinci) function is primarily to create two platform devices. The Platform_device_alloc () function allocates space for the platform device, the Platform_set_drvdata () function sets the private data of the platform device, and the Platform_device_add () function adds the platform device to the platform bus.
The realization of 3> probe
First look at the above two code discovery has "Soc-audio" this string, this string determines the driver and device matching, and found that two platform devices registered. When the platform driver matches a platform device, it calls once porbe, because it registers two platform devices with the same name, and all probe are called two times. This is the application of two sound card drivers.
/* Probes a new socdev */static int soc_probe (struct platform_device *pdev) { struct Snd_soc_card *card = platform_get_ Drvdata (Pdev); int ret = 0; /* Bodge While we unpick instantiation */ Card->dev = &pdev->dev; Init_list_head (&card->dai_dev_list); Init_list_head (&card->codec_dev_list); Init_list_head (&card->platform_dev_list); PRINTK (kern_warning "Soc Audio probe!\n"); ret = Snd_soc_register_card (card); if (ret! = 0) { dev_err (&pdev->dev, "Failed to register card\n"); return ret; } return 0;}
4> Sound card creation
The main analysis of the Snd_soc_register_card () function.
Embedded Driver Development---Linux ALSA audio driver (i)