修改ALSA支持的最大pcm device个数——一次usb声卡不识别问题

在android或linux电子设备设备中,通常都有一个主声卡,通过cat /proc/asound/cards可以查看当前设备的声卡情况

以我的平台为例:

可以看到我的平台只有一个主声卡

命令cat /proc/asound/pcm 可以看到声卡下面所有的pcm devices,显示了平台所有的playback和capture能力

而当有外置声卡如插上一个usb声卡的时候,就能多出一个card 1的设备,

某次项目反馈说平台不识别usb声卡,插上之后没有看到多出的声卡设备,查了一下原来是alsa对于最大支持的声卡设备和每个声卡下面挂载的pcm device设备都做了限制。alsa默认最大只支持8个card设备。

每种设备在注册时会调用

int snd_register_device(int type, struct snd_card *card, int dev,
			const struct file_operations *f_ops,
			void *private_data, struct device *device)
{
	int minor;
	int err = 0;
	struct snd_minor *preg;

	if (snd_BUG_ON(!device))
		return -EINVAL;

	preg = kmalloc(sizeof *preg, GFP_KERNEL);
	if (preg == NULL)
		return -ENOMEM;
	preg->type = type;
	preg->card = card ? card->number : -1;
	preg->device = dev;
	preg->f_ops = f_ops;
	preg->private_data = private_data;
	preg->card_ptr = card;
	mutex_lock(&sound_mutex);
	minor = snd_find_free_minor(type, card, dev);
	if (minor < 0) {
		err = minor;
		goto error;
	}

	preg->dev = device;
	device->devt = MKDEV(major, minor);
	err = device_add(device);
	if (err < 0)
		goto error;

	snd_minors[minor] = preg;
 error:
	mutex_unlock(&sound_mutex);
	if (err < 0)
		kfree(preg);
	return err;
}
EXPORT_SYMBOL(snd_register_device);

注册时创建设备节点通过调用snd_find_free_minor获取一个空闲的minor

#define SNDRV_OS_MINORS			256

#define SNDRV_MINOR_DEVICES		32
#define SNDRV_MINOR_CARD(minor)		((minor) >> 5)
#define SNDRV_MINOR_DEVICE(minor)	((minor) & 0x001f)
#define SNDRV_MINOR(card, dev)		(((card) << 5) | (dev))

/* these minors can still be used for autoloading devices (/dev/aload*) */
#define SNDRV_MINOR_CONTROL		0	/* 0 */
#define SNDRV_MINOR_GLOBAL		1	/* 1 */
#define SNDRV_MINOR_SEQUENCER		1	/* SNDRV_MINOR_GLOBAL + 0 * 32 */
#define SNDRV_MINOR_TIMER		33	/* SNDRV_MINOR_GLOBAL + 1 * 32 */

#ifndef CONFIG_SND_DYNAMIC_MINORS
#define SNDRV_MINOR_COMPRESS		2	/* 2 - 3 */
#define SNDRV_MINOR_HWDEP		4	/* 4 - 7 */
#define SNDRV_MINOR_RAWMIDI		8	/* 8 - 15 */
#define SNDRV_MINOR_PCM_PLAYBACK	16	/* 16 - 23 */
#define SNDRV_MINOR_PCM_CAPTURE		24	/* 24 - 31 */


static int snd_find_free_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:
	case SNDRV_DEVICE_TYPE_COMPRESS:
		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;
	if (snd_minors[minor])
		return -EBUSY;
	return minor;
}

虽然平台只有一个主声卡,但是由于card 0下面挂载的pcm 设备有8个而且第8个设备刚好具有capture能力,导致所有能用的minor都被占满了,再插上一个usb声卡设备就注册不上了

#define SNDRV_MINOR(card, dev)        (((card) << 5) | (dev))

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

card->number为0 SNDRV_MINOR_PCM_CAPTURE的type对应为24,在注册第8个dev时,SNDRV_MINOR计算的返回值为32

当usb声卡插上并开始注册的时候card->numbe为1,注册SNDRV_MINOR_CONTROL type时32已经被占了,导致声卡注册失败

 

最初看到这个问题的改法就是简单的改了alsa定义了这几个宏,用于增大alsa对于这里pcm device的限制,修改如下:

diff --git a/include/sound/minors.h b/include/sound/minors.h
old mode 100644
new mode 100755
index 5978f9a8c8b2..8169e507596a
--- a/include/sound/minors.h
+++ b/include/sound/minors.h
@@ -23,10 +23,10 @@
 
 #define SNDRV_OS_MINORS			256
 
-#define SNDRV_MINOR_DEVICES		32
-#define SNDRV_MINOR_CARD(minor)		((minor) >> 5)
-#define SNDRV_MINOR_DEVICE(minor)	((minor) & 0x001f)
-#define SNDRV_MINOR(card, dev)		(((card) << 5) | (dev))
+#define SNDRV_MINOR_DEVICES		64
+#define SNDRV_MINOR_CARD(minor)		((minor) >> 6)
+#define SNDRV_MINOR_DEVICE(minor)	((minor) & 0x003f)
+#define SNDRV_MINOR(card, dev)		(((card) << 6) | (dev))
 
 /* these minors can still be used for autoloading devices (/dev/aload*) */
 #define SNDRV_MINOR_CONTROL		0	/* 0 */

后来发现alsa实际上用一个内核配置项用于配置最大声卡数的,CONFIG_SND_DYNAMIC_MINORS,alsa的解释为:

Dynamic device file minor numbers (EXPERIMENTAL) found in sound/core/Kconfig
The configuration item CONFIG_SND_DYNAMIC_MINORS:

prompt: Dynamic device file minor numbers (EXPERIMENTAL)
type: bool
depends on: CONFIG_SND && CONFIG_EXPERIMENTAL
defined in sound/core/Kconfig
found in Linux kernels: 2.6.16–2.6.17
Help text
If you say Y here, the minor numbers of ALSA device files in /dev/snd/ are allocated dynamically. This allows you to have more than 8 sound cards, but requires a dynamic device file system like udev.

If you are unsure about this, say N here.

同时我们也可以清楚的看到alsa对支持设备数做限制的地方:

/* number of supported soundcards */
#ifdef CONFIG_SND_DYNAMIC_MINORS
#define SNDRV_CARDS CONFIG_SND_MAX_CARDS
#else
#define SNDRV_CARDS 8		/* don't change - minor numbers */
#endif

#define CONFIG_SND_MAJOR	116	/* standard configuration */

内核打开这个配置项就可以解除限制了

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值