alsa音频框架

设备节点

声卡设备节点

C0: card 0
D0: device 0
说明:
1)一个声卡,可以有多个逻辑device
2)一个device,有播放,有录音通道
3)每个设备节点对应一个file_operation,因为主设备号一样,所以对应同一个驱动程序。

主设备号对应的file_operation

在这里插入图片描述
major=116,是对应着声卡的主设备号,查阅下snd_fops
在这里插入图片描述
看了snd_fops只有open函数的实现,没有read,write函数实现,猜想其他设备如控制,录音的次设备号不同,很有可能,根据次设备号,实现相应的read,write函数。

snd_open函数实现

150 static int snd_open(struct inode *inode, struct file *file)                     
151 {                                                                               
152         unsigned int minor = iminor(inode);                                     
153         struct snd_minor *mptr = NULL;                                          
154         const struct file_operations *old_fops;                                                                                                  
155         int err = 0;                                                            
156                                                                                 
157         if (minor >= ARRAY_SIZE(snd_minors))                                    
158                 return -ENODEV;                                                 
159         mutex_lock(&sound_mutex);                                               
160         mptr = snd_minors[minor];                                               
161         if (mptr == NULL) {                                                     
162                 mptr = autoload_device(minor);                                  
163                 if (!mptr) {                                                    
164                         mutex_unlock(&sound_mutex);                             
165                         return -ENODEV;                                         
166                 }                                                               
167         }                                                                       
168         old_fops = file->f_op;                                                  
169         file->f_op = fops_get(mptr->f_ops);                                     
170         if (file->f_op == NULL) {                                               
171                 file->f_op = old_fops;                                          
172                 err = -ENODEV;                                                  
173         }                                                                       
174         mutex_unlock(&sound_mutex);                                             
175         if (err < 0)                                                            
176                 return err;            
177                                                                                 
178         if (file->f_op->open) {                                                 
179                 err = file->f_op->open(inode, file);                            
180                 if (err) {                                                      
181                         fops_put(file->f_op);                                   
182                         file->f_op = fops_get(old_fops);                        
183                 }                                                               
184         }                                                                       
185         fops_put(old_fops);                                                     
186         return err;                                                             
187 }                                          

unsigned int minor = iminor(inode); 提取到次设备号minor, mptr = snd_minors[minor];根据设备号找到mptr指针; file->f_op = fops_get(mptr->f_ops); 这样file->fop被重新赋值了,里面有read,write等函数。跟踪snd_minors数组怎么被赋值。

调用流程

snd_ctl_create(card)----------->snd_ctl_create—>snd_ctl_dev_register--------->snd_register_device------>snd_register_device_for_dev

147 int snd_card_create(int idx, const char *xid,                                   
148                     struct module *module, int extra_size,                      
149                     struct snd_card **card_ret)                                 
150 {                                                                               
151         struct snd_card *card; 
...
}

主要实现struct snd_card结构体。

创建接口

创建control接口

snd_card_create(init.c)---->snd_ctl_create(control.c)->

1591 int snd_ctl_create(struct snd_card *card)                                                                                                       
1592 {                                                                               
1593         static struct snd_device_ops ops = {                                    
1594                 .dev_free = snd_ctl_dev_free,                                   
1595                 .dev_register = snd_ctl_dev_register,                           
1596                 .dev_disconnect = snd_ctl_dev_disconnect,                       
1597         };                                                                      
1598                                                                                 
1599         if (snd_BUG_ON(!card))                                                  
1600                 return -ENXIO;                                                  
1601         return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);             
1602 }

说明:
向snd_device_new传递ops。创建control接口。

创建playback,capure接口

snd_card_asihpi_pcm_new–>snd_pcm_new

714 int snd_pcm_new(struct snd_card *card, const char *id, int device,              
 715                 int playback_count, int capture_count,                          
 716                 struct snd_pcm ** rpcm)                                         
 717 {                                                                                                                                               
 718         struct snd_pcm *pcm;                                                    
 719         int err;                                                                
 720         static struct snd_device_ops ops = {                                    
 721                 .dev_free = snd_pcm_dev_free,                                   
 722                 .dev_register = snd_pcm_dev_register,                           
 723                 .dev_disconnect = snd_pcm_dev_disconnect,                       
 724         };                                                                      
 725                                                                                 
 726         if (snd_BUG_ON(!card))                                                  
 727                 return -ENXIO;                                                  
 728         if (rpcm)                                                               
 729                 *rpcm = NULL;                                                   
 730         pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);                                
 731         if (pcm == NULL) {                                                      
 732                 snd_printk(KERN_ERR "Cannot allocate PCM\n");                   
 733                 return -ENOMEM;                                                 
 734         }                                                                       
 735         pcm->card = card;                                                       
 736         pcm->device = device;                                                   
 737         if (id)                                                                 
 738                 strlcpy(pcm->id, id, sizeof(pcm->id));                          
 739         if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) {
 740                 snd_pcm_free(pcm);        
                    741                 return err;                                                     
 742         }                                                                       
 743         if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count)) < 0) {
 744                 snd_pcm_free(pcm);                                              
 745                 return err;                                                     
 746         }                                                                       
 747         mutex_init(&pcm->open_mutex);                                           
 748         init_waitqueue_head(&pcm->open_wait);                                   
 749         if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) {       
 750                 snd_pcm_free(pcm);                                              
 751                 return err;                                                     
 752         }                                                                       
 753         if (rpcm)                                                               
 754                 *rpcm = pcm;                                                    
 755         return 0;                                                               
 756 }                     

说明:
向snd_device_new传递ops。
创建pcm的playback和capture接口。

创建节点和绑定操作函数

pcm设备节点和操作函数

sound/core/pcm.c

976 static int snd_pcm_dev_register(struct snd_device *device)                      
 977 {                                                                               
 978         int cidx, err;                                                          
 979         struct snd_pcm_substream *substream;                                                                                                    
 980         struct snd_pcm_notify *notify;                                          
 981         char str[16];                                                           
 982         struct snd_pcm *pcm;                                                    
 983         struct device *dev;                                                     
 984                                                                                 
 985         if (snd_BUG_ON(!device || !device->device_data))                        
 986                 return -ENXIO;                                                  
 987         pcm = device->device_data;                                              
 988         mutex_lock(&register_mutex);                                            
 989         err = snd_pcm_add(pcm);                                                 
 990         if (err) {                                                              
 991                 mutex_unlock(&register_mutex);                                  
 992                 return err;                                                     
 993         }                                                                       
 994         for (cidx = 0; cidx < 2; cidx++) {                                      
 995                 int devtype = -1;                                               
 996                 if (pcm->streams[cidx].substream == NULL)                       
 997                         continue;                                               
 998                 switch (cidx) {                                                 
 999                 case SNDRV_PCM_STREAM_PLAYBACK:                                 
1000                         sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);
1001                         devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;        
1002                         break;                                                  
1003                 case SNDRV_PCM_STREAM_CAPTURE:                                  
1004                         sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);
1005                         devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;                
1006                         break;                                                  
1007                 }                                                               
1008                 /* device pointer to use, pcm->dev takes precedence if          
1009                  * it is assigned, otherwise fall back to card's device         
1010                  * if possible */                                               
1011                 dev = pcm->dev;                                                 
1012                 if (!dev)                                                       
1013                         dev = snd_card_get_device_link(pcm->card);              
1014                 /* register pcm */                                              
1015                 err = snd_register_device_for_dev(devtype, pcm->card,           
1016                                                   pcm->device,                  
1017                                                   &snd_pcm_f_ops[cidx],         
1018                                                   pcm, str, dev);               
1019                 if (err < 0) {                                                  
1020                         list_del(&pcm->list);                                   
1021                         mutex_unlock(&register_mutex);                          
1022                         return err;                                                                                                             
1023                 }                                                               
1024                 snd_add_device_sysfs_file(devtype, pcm->card, pcm->device,      
1025                                           &pcm_attrs);                          
1026                 for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
1027                         snd_pcm_timer_init(substream);                          
1028         }                                                                       
1029                                                                                 
1030         list_for_each_entry(notify, &snd_pcm_notify_list, list)                 
1031                 notify->n_register(pcm);                                        
1032                                                                                 
1033         mutex_unlock(&register_mutex);                                          
1034         return 0;                                                               
1035 }  

将名字pcmC0D0c或者pcmC0D0p保存到str里,操作函数在snd_pcm_f_ops里,然后通过 snd_register_device_for_dev传递进去。对/dev/pcmC0D0c操作调用snd_pcm_f_ops操作接口。

CONTROL设备节点和操作函数

sound/core/control.c

1524 static int snd_ctl_dev_register(struct snd_device *device)                      
1525 {                                                                               
1526         struct snd_card *card = device->device_data;                            
1527         int err, cardnum;                                                       
1528         char name[16];                                                          
1529                                                                                 
1530         if (snd_BUG_ON(!card))                                                  
1531                 return -ENXIO;                                                  
1532         cardnum = card->number;                                                 
1533         if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))                  
1534                 return -ENXIO;                                                  
1535         sprintf(name, "controlC%i", cardnum);                                   
1536         if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,     
1537                                        &snd_ctl_f_ops, card, name)) < 0)        
1538                 return err;                                                     
1539         return 0;                                                               
1540 } 

将名字controlC0保存到name里,操作函数在snd_ctl_f_ops里,然后通过 snd_register_device传递进去。对/dev/controlC0操作调用snd_ctl_f_ops操作接口。

register函数何时被调用?

snd_pcm_dev_register和snd_ctl_dev_register何时被调用?
在snd_card_register函数时,这两个函数被调用。

写声卡驱动步骤

分配、设置、注册snd_card结构体:
a. snd_card_create //里面会创建控制接口
b. snd_pcm_new //里面创建playback,capture接口
c. snd_card_register

音频驱动框架

soud/core/sound.c: 实现了最顶层的file_operations,它起中转作用
soud/core/control.c: 实现了控制接口的file_operations
sound/core/pcm_native.c 实现了playbac,capture的file_operations

流程分析

流程分析

字符设备驱动步骤

1)构造file_operations结构体

  .open=drv_open
   .read=drv_read
   .write=drv_write

2)告诉内核

register_chrdev(major,fops)

3)创建设备节点

class_create
device_create

class_create在 /sys/class下创建目录,device_create在/dev目录下床架设备节点。

大概步骤如下:

cdev_init(&dev->cdev, &cdevdemo_fops);
dev->cdev.owner = THIS_MODULE;
err = cdev_add(&dev->cdev, devno, 1);
cdevdemo_class = class_create(THIS_MODULE, "cdevdemo");
device_create(cdevdemo_class, NULL, MKDEV(cdevdemo_major, 0), NULL, "cdevdemo");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值