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,搭建一个在线教育视频课程分享网站。
相关文章
|
2月前
|
Linux API 调度
Linux系统驱动跟裸机驱动的区别
Linux系统驱动跟裸机驱动的区别
31 0
|
2月前
|
消息中间件 Unix Linux
Linux进程间通信(IPC)介绍:详细解析IPC的执行流程、状态和通信机制
Linux进程间通信(IPC)介绍:详细解析IPC的执行流程、状态和通信机制
62 1
|
2月前
|
存储 缓存 Linux
【Shell 命令集合 磁盘维护 】Linux 设置和查看硬盘驱动器参数 hdparm命令使用教程
【Shell 命令集合 磁盘维护 】Linux 设置和查看硬盘驱动器参数 hdparm命令使用教程
38 0
|
5天前
|
存储 监控 Linux
【专栏】如何在 Linux 中列出已安装的驱动器?
【4月更文挑战第28天】在 Linux 中,了解已安装驱动器是系统管理的关键。本文介绍了三种方法:1) 使用 `lsblk` 命令显示设备名、大小和类型;2) `fdisk -l` 命令提供详细分区信息;3) `gnome-disks` 等系统管理工具展示驱动器信息。此外,还讨论了驱动器类型识别、挂载点概念及其应用。通过这些方法,用户能有效地监控和管理 Linux 系统中的驱动器。
|
18天前
|
Linux Go
Linux命令Top 100驱动人生! 面试必备
探索Linux命令不再迷茫!本文分10部分详解20个基础命令,带你由浅入深掌握文件、目录管理和文本处理。 [1]: <https://cloud.tencent.com/developer/article/2396114> [2]: <https://pan.quark.cn/s/865a0bbd5720> [3]: <https://yv4kfv1n3j.feishu.cn/docx/MRyxdaqz8ow5RjxyL1ucrvOYnnH>
70 0
|
1月前
|
Linux
Linux驱动运行灯 Heartbeat
Linux驱动运行灯 Heartbeat
12 0
|
2月前
|
Linux 编译器 Shell
Linux嵌入式系统之Linux嵌入式系统之交叉编译中gcc编译器的工作流程
Linux嵌入式系统之Linux嵌入式系统之交叉编译中gcc编译器的工作流程
18 0
|
2月前
|
Linux
Linux内核中USB设备驱动实现
Linux内核中USB设备驱动实现
28 0
|
Linux Windows
LINUX编译alsa
LINUX编译alsa
94 0