我正在尝试使用ALSA开发声卡驱动程序。 我的目标最终是使用:
为简单起见,我开始只进行音量控制,没有PCM。 我写了驱动程序并编译但我有两个问题:
我无法在模块出口中成功调用snd_card_free。我尝试存储snd_card指针,该指针在我的自定义" snd_adsp21479_chip"中的模块init中成功分配。结构并使用container_of来获取snd_card,但是module_exit中的卡总是为null(在module_init中它不是null并且已成功分配,我有检查,我也可以在模块init函数中成功调用snd_card_free(card),但没有其他地方)。因此,每次我将模块重新加载到内核时,我最终会在/ dev / snd /和proc / asound / devices中再添加一个声卡和一个新控件
我现在最大的问题是在加载模块后我确实在/ dev / snd /中看到一个新控件(control1)和一张新卡,但是使用amixer我看不到卡的音量控制。我运行amixer conctrols,我没有看到我的新控件。
以下是代码:
#include <linux/wait.h>
#include <sound/control.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#define LOW_SPEED_SPIDEV_SPI_BUS 0
#define LOW_SPEED_SPIDEV_SPI_CS 0
#define LOW_SPEED_SPIDEV_MAX_CLK_HZ 100000
#define SOUND_CARD_NAME "adsp21479"
static struct spi_board_info cal_spi_board_info = {
.modalias = "spidev",
.bus_num = LOW_SPEED_SPIDEV_SPI_BUS,
.chip_select = LOW_SPEED_SPIDEV_SPI_CS,
.max_speed_hz = LOW_SPEED_SPIDEV_MAX_CLK_HZ,
};
static struct spi_device *spi = NULL;
struct snd_adsp21479_chip {
struct spi_device *spi;
struct snd_card *card;
};
/*******************************CONTROL METHODS *******************************/
static int snd_adsp21479_stereo_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info * uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 100;
return 0;
}
static int snd_adsp21479_stereo_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
return 0;
}
static int snd_adsp21479_stereo_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
return 0;
}
static struct snd_kcontrol_new volume_control = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "PCM Playback Volume",
.index = 0,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.info = snd_adsp21479_stereo_info,
.get = snd_adsp21479_stereo_get,
.put = snd_adsp21479_stereo_put
};
static int snd_adsp21479_init(struct spi_device *spi)
{
struct snd_card * card = NULL;
int return_value;
char id[10] = SOUND_CARD_NAME;
struct snd_adsp21479_chip *chip;
pr_info("snd_adsp21479_init start\n");
return_value = snd_card_new(&spi->dev,-1,id,THIS_MODULE,sizeof(struct snd_adsp21479_chip),&card);
if(return_value<0)
{
pr_err("snd_card_new failed\n");
return return_value;
}
if(!card)
{
pr_err("snd_card_new did not allocate card");
return -ENODEV;
}
pr_info("sound card=%p created successfully",card);
chip = card->private_data;
chip->card = card;
chip->spi = spi;
strcpy(card->mixername,"adsp21479 Mixer");
return_value = snd_ctl_add(card,snd_ctl_new1(&volume_control,chip));
if(return_value<0)
{
pr_err("snd_ctl_add faile adding control\n");
return return_value;
}
pr_info("created a mixer control");
static struct snd_device_ops ops = { NULL};
strcpy(card->driver,SOUND_CARD_NAME);
strcpy(card->shortname,SOUND_CARD_NAME);
strcpy(card->longname,"DAQRI ADSP21479 Sound Driver");
//create an ALSA device component
return_value = snd_device_new(card, SNDRV_DEV_LOWLEVEL,chip,&ops);
if(return_value<0)
{
printk(KERN_ALERT"creating an ALSA device component failed");
return return_value;
}
pr_info("created an ASLA device SNDRV_DEV_LOWLEVEL");
return_value = snd_card_register(card);
if(return_value<0)
{
pr_err("snd_card_register failed\n");
return return_value;
}
if(!card)
{
pr_err("card turned into null\n");
}
pr_info("registered sound card\n");
pr_info("adsp21479_snd_driver loaded successfully\n");
return 0;
// card here is always ok, and if I call snd_card_free(card) here it works.
}
static int __init adsp21479_spi_module_init(void)
{
struct spi_master *master=NULL;
int err;
pr_info("module init\n");
err = -ENODEV;
master = spi_busnum_to_master(LOW_SPEED_SPIDEV_SPI_BUS);
pr_info("master=%p\n", master);
if (!master)
{
pr_err("spi_busnum_to_master failed");
return err;
}
spi = spi_new_device(master, &cal_spi_board_info);
pr_info("spi device =%p\n", spi);
if (!spi)
{
pr_err("spi_new_device failed");
return err;
}
pr_info("spi device registered\n");
err = 0;
return snd_adsp21479_init(spi);
}
static void __exit adsp21479_spi_module_exit(void)
{
struct snd_adsp21479_chip *chip;
pr_info("module exit");
if (spi)
{
chip = container_of(&spi,struct snd_adsp21479_chip,spi);
if(chip)
{
pr_info("chip is not null\n");
if(chip->spi == spi)
{
pr_info("spi match\n");
}
pr_info("card = %p",chip->card);
if(chip->card != NULL)
{
pr_info("freeing sound card=%p\n",chip->card); // I never get here, it's always null, or if I store card in a global variable, I get an exception. And if I store it with drv_set_drvdata(&spi->dev,card) in the init function and try to obtain it here with a dev_get_drvdata(&spi->dev); and try to free the card with snd_card_free I get an exception as well.
snd_card_free(chip->card);
}
}
pr_info("unregistering spi device\n");
spi_unregister_device(spi);
}
}
module_init(adsp21479_spi_module_init);
module_exit(adsp21479_spi_module_exit);
/***************************SPI DRIVER METHODS ****************************/
MODULE_LICENSE("GPL"); ///WE NEED TO CHANGE IT LATER MAYBE
MODULE_DESCRIPTION(" Sound driver for the ADSP-21479");
重申一点:这里没有PCM,我只是试图通过SPI来控制音量,而我的控制器并没有显示在amixer中,我也无法释放我的卡。我使用spidev作为SPI BUS主站,此驱动程序用于声卡SPI从站。