Linux ALSA驱动之二:声卡的创建流程 上

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,内容安全 1000次 1年
对象存储 OSS,恶意文件检测 1000次 1年
简介: Linux ALSA驱动之二:声卡的创建流程 上

Linux ALSA驱动之二:声卡的创建流程 上


1、struct snd_card

1.1、snd_card是啥

       snd_card可以说是整个ALSA音频驱动最顶层的一个结构,整个声卡的软件逻辑结构开始于该结构,几乎所有与声音相关的逻辑设备都是在snd_card的管理之下,声卡驱动的第一个动作通常就是创建一个snd_card结构体。因此我们也从 struct snd_card的讲解开始。

1.2、snd_card定义

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 irq_descr[32];           /* Interrupt description */
  char mixername[80];           /* mixer name */
  char components[128];       /* card components 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 */
  struct device ctl_dev;        /* control device */
  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 */
  size_t user_ctl_alloc_size; // current memory allocation by 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 proc_dir_entry *proc_root_link;  /* number link to real id */
  struct list_head files_list;  /* all files associated to 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 */
  struct completion *release_completion;
  struct device *dev;           /* device assigned to this card */
  struct device card_dev;       /* cardX object for sysfs */
  const struct attribute_group *dev_groups[4]; /* assigned sysfs attr */
  bool registered;            /* card_dev is registered? */
  bool managed;             /* managed via devres */
  bool releasing;             /* during card free process */
  int sync_irq;             /* assigned irq, used for PCM sync */
  wait_queue_head_t remove_sleep;
  size_t total_pcm_alloc_bytes; /* total amount of allocated buffers */
  struct mutex memory_mutex;      /* protection for the above */
#ifdef CONFIG_SND_DEBUG
  struct dentry *debugfs_root;    /* debugfs root for card */
#endif
#ifdef CONFIG_PM
  unsigned int power_state;     /* power state */
  atomic_t power_ref;
  wait_queue_head_t power_sleep;
  wait_queue_head_t power_ref_sleep;
#endif
#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
  struct snd_mixer_oss *mixer_oss;
  int mixer_oss_change_count;
#endif
};

对于每个声卡,都需要有一个snd_card结构体来描述。它记录着声卡的信息并管理声卡的所有设备。其中几个比较重要的成员:

       int number                          声卡的序号,通常为0。

       struct list_head devices     记录该声卡下所有逻辑设备的链表。

       struct list_head controls    记录该声卡下所有的控制单元的链表。

       void *private_data             声卡的私有数据,可以在创建声卡时通过参数指定数据的大小。

       bool registered                  声卡是否在系统中注册了。

2、声卡创建流程

2.1、创建一个card实例

struct snd_card *card;
snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
            THIS_MODULE, sizeof(struct snd_dw_hdmi), &card);

2.2、创建声卡的芯片专用数据

       设置该声卡的一些资源信息,例如:中断、IO、DMA等。有两种方式进行创建。

1)、作为声卡的private_data

       在创建声卡的时候传入外部数据长度。

struct mychip {
          struct snd_card *card;
          ....
};
err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
                     sizeof(struct mychip), &card);
struct mychip *chip = card->private_data;
chip->card = card;

2)、作为声卡的一个子设备

       在snd_device_new中指定extra_size为0。

static int snd_mychip_dev_free(struct snd_device *device)
{
    return snd_mychip_free(device->device_data);
}
struct snd_card *card;
struct mychip *chip;
err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
                    0, &card);
.....
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
chip->card = card;
static struct snd_device_ops ops = {
    .dev_free = snd_mychip_dev_free,
};
....
snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);

声卡注销时,会调用snd_mychip_dev_free, 自动释放内存。

       snd_device_new不会给芯片专用数据device_data分配空间,因此在调用之前,必须为芯片专用分配空间,在ops的dev_free中定义析构函数对芯片专用数据进行析构。dev_free会在调用snd_card_free时自动调用。对于用户自定义的 device、type可以使用SNDRV_DEV_LOWLEVEL。

       snd_mychip_dev_free() 是用来free前面kzmalloc的空间。

2.3、设置驱动ID和名字

    strcpy(card->driver, “My Chip”);
    strcpy(card->shortname, “My Own Chip 123”);
    sprintf(card->longname, “%s at 0x%lx irq %i”,
        card->shortname, chip->ioport, chip->irq)
  strncpy(card->driver, shortname, sizeof(card->driver));
  strncpy(card->shortname, shortname, sizeof(card->shortname));
  strncpy(card->longname, longname, sizeof(card->longname));

2.4、创建声卡功能逻辑部件,如PCM,mixer, MIDI

       每一种部件的创建最终会调用snd_device_new()来生成一个snd_device实例,并把该实例链接到snd_card的devices链表中。通常,alsa-driver的已经提供了一些常用的部件的创建函数,而不必直接调用snd_device_new(),比如: snd_pcm_new()。

2.5、注册声卡

/* register it */
err = snd_card_register(card);
if (err < 0) {
    pk_error("failed to register pc-midi sound card: error %d\n",
        err);
  goto fail_register;
}


相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
相关文章
|
1月前
|
监控 安全 Java
linux服务器上启动framework应用程序流程
【10月更文挑战第17天】在Linux服务器上启动Framework应用程序需经过准备工作、部署、启动、监控及访问五个步骤。首先确保服务器满足系统要求并安装依赖项;接着上传应用文件,编译构建,配置参数;然后通过脚本、命令行或系统服务启动应用;启动后检查日志,监控性能;最后确认访问地址,验证应用运行状态。具体操作应参照应用文档。
|
1月前
|
监控 Java Linux
linux服务器上启动framework应用程序流程
【10月更文挑战第18天】在 Linux 服务器上启动框架应用程序的流程包括:准备工作(确保访问权限、上传部署文件、了解启动要求)、检查依赖项、配置环境变量、切换到应用程序目录、启动应用程序、监控启动过程以及验证应用程序是否正常运行。具体步骤可能因应用程序类型和框架而异。
|
3月前
|
Java Linux API
Linux设备驱动开发详解2
Linux设备驱动开发详解
44 6
|
3月前
|
消息中间件 算法 Unix
Linux设备驱动开发详解1
Linux设备驱动开发详解
50 5
|
3月前
|
Ubuntu NoSQL Linux
Linux内核和驱动
Linux内核和驱动
29 2
|
2月前
|
Linux API
Linux里的高精度时间计时器(HPET)驱动 【ChatGPT】
Linux里的高精度时间计时器(HPET)驱动 【ChatGPT】
|
3月前
|
网络协议 Linux 网络安全
在Linux中,我们都知道FTP协议有两种工作模式,它们的大概的⼀个工作流程是怎样的?
在Linux中,我们都知道FTP协议有两种工作模式,它们的大概的⼀个工作流程是怎样的?
|
3月前
|
缓存 网络协议 Linux
在Linux中,当用户在浏览器当中输入⼀个网站,计算机对dns解释经过那些流程?
在Linux中,当用户在浏览器当中输入⼀个网站,计算机对dns解释经过那些流程?
|
3月前
|
Linux
【linux】【驱动】<specifier>-map-pass-thru讲解
【linux】【驱动】<specifier>-map-pass-thru讲解
22 0
|
3月前
|
Linux
【linux】【驱动】phy接口类型
【linux】【驱动】phy接口类型
19 0