ALSA声卡驱动程序无法调用snd_card_free(..)并且amixer无法看到控件

时间:2015-11-01 18:41:01

标签: c linux-kernel driver kernel-module alsa

我正在尝试使用ALSA开发声卡驱动程序。 我的目标最终是使用:

  • PCM通过I2S。
  • 通过SPI控制音量。

为简单起见,我开始只进行音量控制,没有PCM。 我写了驱动程序并编译但我有两个问题:

  1. 我无法在模块出口中成功调用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中再添加一个声卡和一个新控件

  2. 我现在最大的问题是在加载模块后我确实在/ dev / snd /中看到一个新控件(control1)和一张新卡,但是使用amixer我看不到卡的音量控制。我运行amixer conctrols,我没有看到我的新控件。

  3. 以下是代码:

    #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从站。

0 个答案:

没有答案