C0: card 0
D0: device 0
说明:
1)一个声卡,可以有多个逻辑device
2)一个device,有播放,有录音通道
3)每个设备节点对应一个file_operation,因为主设备号一样,所以对应同一个驱动程序。
major=116,是对应着声卡的主设备号,查阅下snd_fops
看了snd_fops只有open函数的实现,没有read,write函数实现,猜想其他设备如控制,录音的次设备号不同,很有可能,根据次设备号,实现相应的read,write函数。
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结构体。
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接口。
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接口。
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(®ister_mutex);
989 err = snd_pcm_add(pcm);
990 if (err) {
991 mutex_unlock(®ister_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(®ister_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(®ister_mutex);
1034 return 0;
1035 }
将名字pcmC0D0c或者pcmC0D0p保存到str里,操作函数在snd_pcm_f_ops里,然后通过 snd_register_device_for_dev传递进去。对/dev/pcmC0D0c操作调用snd_pcm_f_ops操作接口。
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操作接口。
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");