Chinaunix首页 | 论坛 | 博客

OS

  • 博客访问: 2280595
  • 博文数量: 691
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2660
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-05 12:49
个人简介

不浮躁

文章分类

全部博文(691)

文章存档

2019年(1)

2017年(12)

2016年(99)

2015年(207)

2014年(372)

分类: 嵌入式

2015-02-05 20:05:40

1,首先来明确这个设备节点的由来。这个节点代表声卡的控制接口。

设备的路径:/dev/snd/controlC0

 

由于基本的linux的操作是由ioctl进行用户空间和内核空间的数据交互已达到实现控制。那么就看看这个设备的由来。

static int snd_ctl_dev_register(struct snd_device *device)

{

   struct snd_card *card = device->device_data;

   int err, cardnum;

   char name[16];

 

   if (snd_BUG_ON(!card))

       return -ENXIO;

   cardnum = card->number;

   if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))

       return -ENXIO;

   sprintf(name, "controlC%i", cardnum);

   if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,

                     &snd_ctl_f_ops, card, name)) < 0)

       return err;

   return 0;

}

   首先先来认识一下snd_ctl_f_ops

static const struct file_operations snd_ctl_f_ops =

{

      .owner                = THIS_MODULE,

      .read                   = snd_ctl_read,

      .open                   = snd_ctl_open,

      .release                = snd_ctl_release,

      .llseek                  = no_llseek,

      .poll                    = snd_ctl_poll,

      .unlocked_ioctl     = snd_ctl_ioctl,

      .compat_ioctl        = snd_ctl_ioctl_compat,

      .fasync                = snd_ctl_fasync,

};

最后调用snd_register_device这个函数,这个函数就是注册了设备的节点,其中涉及到了设备节点的创建和管理,在另一篇文章中有介绍。但是这里要注意snd_minors[ ]这个数组,这个数组其实是

struct snd_minor {

   int type;                          /* SNDRV_DEVICE_TYPE_XXX */

   int card;                          /* card number */

   int device;                    /* device number */

   const struct file_operations *f_ops;   /* file operations */

   void *private_data;                /* private data for f_ops->open */

   struct device *dev;                /* device for sysfs */

};

经过函数的调用跟踪发现创建节点的函数更具dev->devt这个识别节点。这个参数就是创建节点时候MKDEV宏使用的结果,并且把这个结果传递给底下创建节点的函数:

vfs_mknod(nd.path.dentry->d_inode, dentry, mode, dev->devt);

Ps:以上的代码还请参考另外一篇文章。

 

这里加上一点理解:

Major minor的关系,Major代表了一类设备,minor代表了一类设备下具体的哪一种代表了控制接口的具体实列。Open函数就是这样的一个函数确定了到底是使用哪个minor,代表着主设备下的某一个从设备,并调用相关的read write iotcl等相关函数。

 

回到函数中再看看函数:

/**

 * snd_register_device_for_dev - Register the ALSA device file for the card

 * @type: the device type, SNDRV_DEVICE_TYPE_XXX

 * @card: the card instance

 * @dev: the device index

 * @f_ops: the file operations

 * @private_data: user pointer for f_ops->open()

 * @name: the device file name

 * @device: the &struct device to link this new device to

 *

 * Registers an ALSA device file for the given card.

 * The operators have to be set in reg parameter.

 *

 * Returns zero if successful, or a negative error code on failure.

 */

int snd_register_device_for_dev(int type, struct snd_card *card, int dev,

               const struct file_operations *f_ops,

               void *private_data,

               const char *name, struct device *device)

{

……

minor = snd_kernel_minor(type, card, dev);

……

snd_minors[minor] = preg;

……

preg->dev = device_create(sound_class, device, MKDEV(major, minor),

private_data, "%s", name);

……

return 0;

}

 

static int snd_kernel_minor(int type, struct snd_card *card, int dev)

{

   int minor;

 

   switch (type) {

      case SNDRV_DEVICE_TYPE_SEQUENCER:

      case SNDRV_DEVICE_TYPE_TIMER:

          minor = type;

          break;

 

 

 

      case SNDRV_DEVICE_TYPE_CONTROL:

          if (snd_BUG_ON(!card))

              return -EINVAL;

          minor = SNDRV_MINOR(card->number, type);

              break;

case SNDRV_DEVICE_TYPE_HWDEP:

case SNDRV_DEVICE_TYPE_RAWMIDI:

case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:

case SNDRV_DEVICE_TYPE_PCM_CAPTURE:

          if (snd_BUG_ON(!card))

              return -EINVAL;

          minor = SNDRV_MINOR(card->number, type + dev);

              break;

      default:

          return -EINVAL;

   }

   if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS))

       return -EINVAL;

return minor;

}      

   确定minor的数值的函数就是这个函数了,在确定之后就是创建。可以看见在最上层函数调用的时候传递下来的参数为:SNDRV_DEVICE_TYPE_CONTROLminorcardnumtype所决定,并且办数组中的某一个数组成员在调用函数中使用。

 

2,初始化CONTROL节点

应该说知道了结果但是不知道原因,还是有点麻木,总好像少了什么。所以再看看创建函数的调用关系。

不具体介绍一些初始化函数的中的具体事宜,其实sound相关的函数中涉及了很多的结构体变量等等,没有一一仔细的查看。这里只是简单介绍一下调用的关系。

A)注册初始化函数

int snd_card_create(int idx, const char *xid,

          struct module *module, int extra_size,

          struct snd_card **card_ret)

|->

   /* the control interface cannot be accessed from the user space until */

   /* snd_cards_bitmask and snd_cards are set with snd_card_register */

   snd_ctl_create (struct snd_card *card))

 

注意:以上snd_ctl_create这个函数并没有调用到snd_ctl_dev_register,这个函数只是把dev这个结构体初始化,其中ops函数指针指向了snd_device_ops ops。这个opsstatic的,函数退出后还是存在。可以再以后的函数中通过函数指针找到并调用。初始化dev结构,并且挂上carddev list,为了今后使用。

 

 

B)调用初始化函数

最后为了找到调用点即ops-> dev_register。还要从其他的文件切入。

static void snd_soc_instantiate_card(struct snd_soc_card *card)

   |->

/**

   * snd_card_register - register the soundcard

   * @card: soundcard structure

   *

   * This function registers all the devices assigned to the soundcard.

   * Until calling this, the ALSA control interface is blocked from the

   * external accesses.  Thus, you should call this function at the end

   * of the initialization of the card.

   *

   * Returns zero otherwise a negative error code if the registrain failed.

   */

   看到原版注释了,control interface是在这个函数调用以后才能使用。

   int snd_card_register(struct snd_card *card)

       |->

      /*

      * register all the devices on the card.

      * called from init.c

      */

      int snd_device_register_all(struct snd_card *card)

 

C

   以上分别看了和介绍了:调用和初始化注册函数的两部分。在函数执行流程的时候一定要保证先注册,后调用的原则,否则就是一场空。这个机制怎么完成的,还要涉及其他的部分逻辑。

   snd_soc_instantiate_card函数中有这样的一段代码:

   if (codec_dev->probe) {

       ret = codec_dev->probe(pdev);

       if (ret < 0)

           goto cpu_dai_err;

   }

   其中snd_soc_codec_device *codec_dev = card->socdev->codec_dev; codec_dev就是soc_codec_dev_wm9713,其中的probewm9713_soc_probe

   wm9713_soc_probe

   |-> int snd_soc_new_pcms(struct snd_soc_device *socdev,

|                                         int idx, const char *xid)

   |      |->

   |      int snd_card_create(int idx, const char *xid,

   |                             struct module *module, int extra_size,

   |                             struct snd_card **card_ret)

   |-> int snd_card_register(struct snd_card *card)

阅读(5329) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~