ALSA声卡驱动(二)声卡创建

news/2024/11/25 8:00:03/

文章目录

ALSA声卡驱动(一)初识alsa

目录

  • 文章目录
  • 1、声卡实例
    • 1.1、struct snd_card
    • 1.2、struct snd_devide
  • 2、声卡的创建流程
    • 2.1、创建一个声卡实例
    • 2.2、创建声卡芯片的专用数据
    • 2.3、设置Driver和ID和名字
    • 2.4、创建声卡的功能部件(逻辑设备)
    • 2.5、注册声卡
  • 3、snd_card_create()和snd_card_new()
  • 4、snd_card_register()
  • 总结

1、声卡实例

1.1、struct snd_card

  snd_card可以说是整个ALSA音频驱动最顶层的一个结构,几乎所有与声卡相关的逻辑设备都是在snd_card的管理之下。声卡驱动的第一个动作通常就是创建一个snd_card结构体。
  snd_card结构体定义在头文件include/sound/core.h中:

struct snd_card {int number;         /* number of soundcard (index tosnd_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 withspace */struct module *module;      /* top-level module */void *private_data;     /* private data for soundcard */void (*private_free) (struct snd_card *card); /* callback for freeing ofprivate 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 */int user_ctl_count;     /* count of all 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 snd_info_entry *proc_id; /* the card id */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 shutdownstate */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? */
#ifdef CONFIG_PMunsigned int power_state;   /* power state */wait_queue_head_t power_sleep;
#endif#if IS_ENABLED(CONFIG_SND_MIXER_OSS)struct snd_mixer_oss *mixer_oss;int mixer_oss_change_count;
#endif
};

  struct list_head devices 记录该声卡下所有逻辑设备的链表
  struct list_head controls 记录该声卡下所有的控制单元的链表
  void *private_data 声卡的私有数据,可以在创建声卡时通过参数指定数据的大小

1.2、struct snd_devide

  snd_card结构表示一个声卡,而snd_devide结构来抽象表示一个声卡的逻辑设备。

struct snd_device {                                                                                                                                                                                                                                                           struct list_head list;      /* list of registered devices */struct snd_card *card;      /* card which holds this device */enum snd_device_state state;    /* state of the device */enum snd_device_type type;  /* device type */void *device_data;      /* device structure */struct snd_device_ops *ops; /* operations */
};

  
  
  

2、声卡的创建流程

2.1、创建一个声卡实例

  声卡的创建使用snd_card_create() 函数(注意:现在很多地方都换成了snd_card_new()函数):

struct snd_card *card;
int err;
...
err = snd_card_create(index, id, THIS_MODULE, 0, &card);

  index是一个整数值,表示该声卡的编号。
  id是一个字符串,表示声卡的标识符。
  第四个参数决定在创建声卡实例的时候需要同时额外分配的私有数据大小,私有数据的指针最终会赋值给snd_cardprivate_data数据成员。
  card将返回所创建的snd_card实例指针。

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

  声卡的专用数据主要用于存放声卡的资源信息,例如中断资源、io资源、dma资源等。
  创建的方法有两种:

  • 第一种:给snd_card_create的第四个参数递一个值,让函数自行创建:
//struct mychip 用于保存专用数据
err = snd_card_create(index, id, THIS_MODULE,sizeof(struct mychip), &card);
// 从private_data中取出
struct mychip *chip = card‐>private_data;
  • 第二种:自行创建:
struct mychip {struct snd_card *card;...
};
struct snd_card *card;
struct mychip *chip;
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
...
err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
chip‐>card = card;/* 再把芯片的专有数据注册为声卡的一个低阶设备 */
static int snd_mychip_dev_free(struct snd_device *device)
{return snd_mychip_free(device‐>device_data);
}
static struct snd_device_ops ops = {.dev_free = snd_mychip_dev_free,
};
...
snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);

  注册为低阶设备主要是为了当声卡被注销时,芯片专用数据所占用的内存可以被自动地释放。

2.3、设置Driver和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);

  snd_carddriver域保存着芯片的ID字符串,用户空间的alsa-lib会使用到该字符串,必须保证ID的唯一性。
  shortname更多的是用于打印信息;
  longname域则会出现在 /proc/asound/cards中。

2.4、创建声卡的功能部件(逻辑设备)

  声卡的每一种部件的创建最终都会调用snd_device_new() 来生成一个snd_device实例,并把这个实例链接到snd_carddevices链表中。
  通常alsa-driver会提供一些常用部件的创建函数,不必直接调用snd_device_new() ,比如:

PCM     —>  snd_pcm_new()
RAWMIDI   —>  snd_rawmidi_new()
CONTROL   —>  snd_ctl_create()
TIMER     —>  snd_timer_new()
INFO      —>  snd_card_proc_new()
JACK      —>   snd_jack_new()

2.5、注册声卡

err = snd_card_register(card);
if (err < 0) {snd_card_free(card);return err;
}

  经过以上的创建步骤之后,声卡的逻辑结构如下图所示:
在这里插入图片描述

3、snd_card_create()和snd_card_new()

  snd_card_create() 函数在新的内核版本中被替换成了snd_card_new() 函数,定义在sound/core/init.c中:

/***  snd_card_new - create and initialize a soundcard structure*  @parent: the parent device object*  @idx: card index (address) [0 ... (SNDRV_CARDS-1)]*  @xid: card identification (ASCII string)*  @module: top level module for locking*  @extra_size: allocate this extra size after the main soundcard structure*  @card_ret: the pointer to store the created card instance**  Creates and initializes a soundcard structure.**  The function allocates snd_card instance via kzalloc with the given*  space for the driver to use freely.  The allocated struct is stored*  in the given card_ret pointer.**  Return: Zero if successful or a negative error code.*/
int snd_card_new(struct device *parent, int idx, const char *xid,                                                                                                                                                                                                             struct module *module, int extra_size,struct snd_card **card_ret)

  根据extra_size参数的大小分配内存,该内存区通常作为芯片的私有数据使用:

    if (extra_size < 0)extra_size = 0;card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);if (!card)return -ENOMEM;if (extra_size > 0)card->private_data = (char *)card + sizeof(struct snd_card);

  拷贝声卡ID字符串:

    if (xid)strlcpy(card->id, xid, sizeof(card->id)); 

  如果传入的声卡编号为-1,自动分配一个新的索引号:

    if (idx < 0) /* first check the matching module-name slot */idx = get_slot_from_bitmask(idx, module_slot_match, module);if (idx < 0) /* if not matched, assign an empty slot */idx = get_slot_from_bitmask(idx, check_empty_slot, module);

  初始化snd_card结构中必要的字段:

    card->dev = parent;card->number = idx;card->module = module;INIT_LIST_HEAD(&card->devices);init_rwsem(&card->controls_rwsem);rwlock_init(&card->ctl_files_rwlock);INIT_LIST_HEAD(&card->controls);INIT_LIST_HEAD(&card->ctl_files);spin_lock_init(&card->files_lock);INIT_LIST_HEAD(&card->files_list);
#ifdef CONFIG_PMinit_waitqueue_head(&card->power_sleep);
#endif

  建立逻辑设备: Control

/* the control interface cannot be accessed from the user space until *//* snd_cards_bitmask and snd_cards are set with snd_card_register */err = snd_ctl_create(card);if (err < 0) {dev_err(parent, "unable to register control minors\n");goto __error;}

  建立proc文件中的info节点:通常就是 /proc/asound/card0

    err = snd_info_card_create(card);if (err < 0) {dev_err(parent, "unable to create card info\n");goto __error_ctl;}

  返回创建的snd_card对象:

struct snd_card *card;
...
*card_ret = card;

4、snd_card_register()

  snd_card_register() 函数也定义在 /sound/core/init.c中:

/***  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.**  Return: Zero otherwise a negative error code if the registration failed.*/
int snd_card_register(struct snd_card *card)

  创建sysfs下的设备:

    if (!card->registered) {err = device_add(&card->card_dev);                                                                                                                                                                                                                                    if (err < 0)return err;card->registered = true;}

  通过snd_device_register_all() 注册所有挂在该声卡下的逻辑设备, snd_device_register_all() 实际上是通过snd_carddevices链表,遍历所有的snd_device,并且调用snd_deviceops->dev_register() 来实现各自设备的注册的:

if ((err = snd_device_register_all(card)) < 0)return err;

  最后就是建立一些相应的proc和sysfs下的文件或属性节点:

    if (*card->id) {/* make a unique id name from the given string */char tmpid[sizeof(card->id)];memcpy(tmpid, card->id, sizeof(card->id));snd_card_set_id_no_lock(card, tmpid, tmpid);} else {/* create an id from either shortname or longname */const char *src;src = *card->shortname ? card->shortname : card->longname;snd_card_set_id_no_lock(card, src,retrieve_id_from_card_name(src));}snd_cards[card->number] = card;                                                                                                                                                                                                                                           init_info_for_card(card);			//前面都是在填充,这里建立节点

  另外,设备对应的class/sound/sound_core.c中创建:

static char *sound_devnode(struct device *dev, umode_t *mode)
{if (MAJOR(dev->devt) == SOUND_MAJOR)return NULL;return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev));
}static int __init init_soundcore(void)
{int rc; rc = init_oss_soundcore();if (rc)return rc; sound_class = class_create(THIS_MODULE, "sound");if (IS_ERR(sound_class)) {cleanup_oss_soundcore();return PTR_ERR(sound_class);}   sound_class->devnode = sound_devnode;return 0;
}

  由此可见,声卡的class将会出现在文件系统的 /sys/class/sound/ 下面,并且, sound_devnode() 也决定了相应的设备节点也将会出现在 /dev/snd/ 下面
  
  
  
  

总结

  声卡实例snd_cardsnd_card_new() 函数创建,指定了声卡的编号、标识符和私有数据等。然后填充DriverID还有shortnamelongname。紧接着创建声卡所需的逻辑设备,包括control、pcm等,最后将声卡注册到内核中,会在/proc和sysfs中生成相应的节点。
  
  


http://www.ppmy.cn/news/193497.html

相关文章

linux系统声卡安装教程,Linux操作系统声卡驱动的安装与配置

一般的声卡驱动是支持windows的&#xff0c;linux很少&#xff0c;所以安装声卡驱动很麻烦。 Linux下安装声卡驱动&#xff0c;用的是alsa&#xff0c;它就好像是万能的一样&#xff0c;可以支持很多类型的声卡&#xff0c;如&#xff1a; AC97 CodecALC100,100PALC200,200PALC…

petalinux2022.2在ubantu20.04下的安装

1.Petalinux的下载路径 Downloads 这个是下载petalinux的官网路径。默认是2022.2版本&#xff0c;后期更新的均是以petalinux2022.2版本做的更新。 2.安装流程 在官网下载完成之后&#xff0c;会得到一个名为petalinux-v2022.2-10141622-installer.run的文件&#xff0c;这个文…

解决win10声卡驱动不兼容问题和成功安装战神k650-i5-d2上的Sound Blaster Cinema2在win10系统上

安装win10后&#xff0c;偶尔会出现蓝屏&#xff0c;经过我的发现&#xff0c;每次听歌用扬声器并且长时间。都会发生蓝屏 1 . 所以怀疑声卡驱动VIA HD Audio&#xff08;Win 8.1&#xff09;与系统不兼容。 2 .干脆重新安装声卡驱动。在网上找到与win10兼容的VIAHDAud_v11_11…

linux alsa 不创建声卡能否创建pcm设备,Linux ALSA声卡驱动之一:声卡的创建

1. struct snd_card 1.1. snd_card是什么 snd_card可以说是整个ALSA音频驱动最顶层的一个结构&#xff0c;整个声卡的软件逻辑结构开始于该结构&#xff0c;几乎所有与声音相关的逻辑设备都是在snd_card的管理之下&#xff0c;声卡驱动的第一个动作通常就是创建一个snd_card结构…

Fedora Core下声卡驱动全功略(转)

Fedora Core下声卡驱动全功略(转) 1.了解你的声卡 声卡如同计算机的喉舌和耳朵&#xff0c;负责计算机音频的输入、信号转换、输出的工作&#xff0c;有了声卡&#xff0c;我们才能通过电脑欣赏美妙的音乐&#xff0c;才能对着话筒怒吼。99年后&#xff0c;随着计算机的进一步…

计算机设备管理器驱动,驱动技巧:解决设备管理器中声卡驱动安装不正确的问题...

分类&#xff1a;声卡驱动 问题&#xff1a;设备管理器中声卡驱动安装不正确 描述&#xff1a;电脑没有声音&#xff0c;有部分朋友是因为声卡驱动没有正确安装&#xff0c;除了我们常见到的设备管理器出现黄色感叹号之外&#xff0c;另一种情况就是让一般人很难发现的问题&…

ALSA声卡驱动二之声卡的创建

1. struct snd_card 1.1. snd_card是什么 snd_card可以说是整个ALSA音频驱动最顶层的一个结构&#xff0c;整个声卡的软件逻辑结构开始于该结构&#xff0c;几乎所有与声音相关的逻辑设备都是在snd_card的管理之下&#xff0c;声卡驱动的第一个动作通常就是创建一个snd_card结构…

红帽子 linux 声卡驱动,RedHat Linux系统下安装ALSA驱动的方法

RedHat Linux系统下安装ALSA驱动的方法 发布时间:2014-04-30 22:42:42来源:红联作者:velcbo 比较适合老一些的电脑配置,本人也有一台2002年购买的电脑,一直完好的现在,主板是LEGEND QDI K7E-A,声卡是VIA VT82C686B,芯片集成AC’97,采用RedHat Linux系统。 刚开始用Redhat…