Linux 自定义ALSA驱动程序不执行struct snd_pcm_ops中的打开函数

Linux 自定义ALSA驱动程序不执行struct snd_pcm_ops中的打开函数,linux,driver,alsa,Linux,Driver,Alsa,我正在尝试使用ALSA创建自己的自定义声音驱动程序。到目前为止,我已成功加载模块,我的意思是: 我的探测功能被执行 构造函数被执行 我看到正在执行中断 我通过在这些函数中放置的转储文件发现了这一点 但是,当我尝试在应用程序中使用snd_pcm_open()函数连接到驱动程序时,我没有看到我在struct snd_pcm_ops中存储的.open()函数中添加的转储。因此,出于某种原因,我的应用程序中没有看到我的驱动程序 我加载了原始驱动程序并执行了相同的应用程序,它运行良好 你知道为什么我的

我正在尝试使用ALSA创建自己的自定义声音驱动程序。到目前为止,我已成功加载模块,我的意思是:

  • 我的探测功能被执行
  • 构造函数被执行
  • 我看到正在执行中断
我通过在这些函数中放置的转储文件发现了这一点

但是,当我尝试在应用程序中使用snd_pcm_open()函数连接到驱动程序时,我没有看到我在struct snd_pcm_ops中存储的.open()函数中添加的转储。因此,出于某种原因,我的应用程序中没有看到我的驱动程序

我加载了原始驱动程序并执行了相同的应用程序,它运行良好

你知道为什么我的驱动程序无法从用户空间访问吗

多谢各位

代码如下:

#include <linux/fs.h>
#include <linux/module.h>                         // MOD_DEVICE_TABLE,
#include <linux/init.h>
#include <linux/pci.h>                            // pci_device_id,
#include <linux/interrupt.h>
#include <linux/version.h>                        // KERNEL_VERSION,
#include <iso646.h>
#include <linux/kobject.h>
#include <linux/slab.h>
#include <linux/delay.h>

#include <asm/io.h> 
#include <asm/uaccess.h>                          // copy_to_user,

#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>

#include <linux/time.h>

MODULE_LICENSE("GPL");
// vendor and device id of the PCI device
#define VENDOR_ID 0x8086
#define DEVICE_ID 0x2415

/*************** DATA **********************/
/* module parameters (see "Module Parameters") */
/* SNDRV_CARDS: maximum number of cards supported by this module */
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;

#define BARS 6
enum bars{bar0=0, bar1=1, bar2=2, bar3=3, bar4=4, bar5=5};

#define IOREG_0 0
#define IOREG_1 1

/*OFFSETS TO REGISTER*/
#define GLOBAL_STATUS_REGISTER_OFFSET 0x30

struct mem_regions
{
    unsigned int start_addr;
    unsigned int end_addr;
    unsigned int mem_len;
    unsigned int bar;
    unsigned int flag;

    void __iomem *mem_mapped_addr;
};

struct mychip {
    struct snd_card *card;
    struct pci_dev *pci;

    unsigned long port;
    int irq;

    struct mem_regions memregs[6];

    struct snd_pcm *pcm;
    struct snd_pcm_substream *substream;
};
/*******************************************/

/******************** FUNCTION PROTOTYPES *********************************/
static int __devinit snd_mychip_create(struct snd_card *card,
                       struct pci_dev *pci,
                       struct mychip **rchip);

static int snd_mychip_free(struct mychip *chip);                       

static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id);

static int __devinit snd_mychip_probe(struct pci_dev *pci,
                      const struct pci_device_id *pci_id);

static void snd_mychip_remove(struct pci_dev *pci);

static int snd_mychip_dev_free(struct snd_device *device);

static int reserve_mem_regions(struct mychip *chip);
static void clear_mem_regions(struct mychip *chip);

static void memdump(struct mychip *chip);

/* ------------ PCM functions ------------- */

/* ---- constructor ---- */
static int __devinit snd_pcm_constructor(struct mychip *chip);

/* ---- destructor ---- */
static void snd_pcm_destructor(struct snd_pcm *pcm);

/* ----  file operations fcns ---- */
static int snd_pcm_playback_open(struct snd_pcm_substream *substream);
static int snd_pcm_playback_close(struct snd_pcm_substream *substream);
static int snd_pcm_capture_open(struct snd_pcm_substream *substream);
static int snd_pcm_capture_close(struct snd_pcm_substream *substream);
/*snd_pcm_lib_ioctl();*/
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
             struct snd_pcm_hw_params *hw_params);
static int snd_pcm_hw_free(struct snd_pcm_substream *substream);
static int snd_pcm_prepare(struct snd_pcm_substream *substream);
static int snd_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
static snd_pcm_uframes_t snd_pcm_pointer(struct snd_pcm_substream *substream);

/* ---------------------------------------- */

/**************************************************************************/

/************************* IMPLEMENTATION *******************************/
/*prototyped*/
static int snd_mychip_free(struct mychip *chip)
{
    /* disable hardware here if any */
    //.... /* (not implemented in this document) */

    /* release the irq */
    if (chip->irq >= 0)
        free_irq(chip->irq, chip);

    /* release the I/O ports & memory */
    /*pci_release_regions(chip->pci);*/
    clear_mem_regions(chip);

    /* disable the PCI entry */
    pci_disable_device(chip->pci);

    /* release the data */
    kfree(chip);
    return 0;
}

/*prototyped*/
static int snd_mychip_dev_free(struct snd_device *device)
{
    return snd_mychip_free(device->device_data);
}

/*prototyped*/
static void snd_mychip_remove(struct pci_dev *pci)
{
  /*Clear the card data and PCI data*/
  snd_card_free(pci_get_drvdata(pci));
  pci_set_drvdata(pci, NULL);
}

/* constructor -- see "Constructor" sub-section *//*prototyped*/
static int __devinit snd_mychip_probe(struct pci_dev *pci,
                  const struct pci_device_id *pci_id)
{
    static int dev;
    struct snd_card *card;
    struct mychip *chip;
    int err;

    printk(KERN_ERR "Probing ...\n");

    /* (1) Check and increment the device index */
    if (dev >= SNDRV_CARDS)
        return -ENODEV;
    if (!enable[dev]) {
        dev++;
        return -ENOENT;
    }

    /* (2) Create a card instance */
    err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card);
    if (err < 0)
        return err;

    /* (3) Create a main component */
    /* chip-specific constructor: allocate PCI resources */
    err = snd_mychip_create(card, pci, &chip);
    if (err < 0) {
        snd_card_free(card);
        return err;
    }

    /* (4) Set driver ID and name strings */
    strcpy(card->driver, "My Chip");
    strcpy(card->shortname, "My Own Chip 123");
    sprintf(card->longname, "%s at 0x%lx irq %i",
        card->shortname, chip->port, chip->irq);

    /* (5) Create other components PCM, mixers, MIDI etc */
    /* implemented later */

    /* (6) Register card instance */
    err = snd_card_register(card);
    if (err < 0) {
        snd_card_free(card);
        return err;
    }

    /* (7) Set the PCI driver data */
    pci_set_drvdata(pci, card);
    dev++;

    /*Call PCM constructor*/
    err = snd_pcm_constructor(chip);
    if(err < 0)
        printk(KERN_ERR "Failed to execute PCM constructor!\n");

    printk(KERN_ERR "Probing done!\n");

    return 0;
}

/*prototyped*/
static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id)
{
    struct mychip *chip = dev_id;
    struct timeval timeval;
    unsigned int status = 0;

    static int executed = 0;

    do_gettimeofday(&timeval);

    if(executed < 10)
    {

    /*get the global status register*/
    status = ioread32((void*)chip->memregs[IOREG_0].mem_mapped_addr + GLOBAL_STATUS_REGISTER_OFFSET);

    status = ioread32((void*)chip->memregs[IOREG_1].mem_mapped_addr + GLOBAL_STATUS_REGISTER_OFFSET);

    printk(KERN_ERR "\n---------- ISR -----------\n");

    executed ++;
    }

    return IRQ_HANDLED;
}

/* chip-specific constructor *//*prototyped*/
static int __devinit snd_mychip_create(struct snd_card *card,
                   struct pci_dev *pci,
                   struct mychip **rchip)
{
    struct mychip *chip;
    int err;
    static struct snd_device_ops ops = {
           .dev_free = snd_mychip_dev_free,
    };

    printk(KERN_ERR "Enabling PCI device ...");

    *rchip = NULL;

    /* initialize the PCI entry */
    err = pci_enable_device(pci);
    if (err < 0)
        return err;
    /* check PCI availability (28bit DMA) */
    if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 ||
        pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) {
        printk(KERN_ERR "error to set 28bit mask DMA\n");
        pci_disable_device(pci);
        return -ENXIO;
    }

    chip = kzalloc(sizeof(*chip), GFP_KERNEL);
    if (chip == NULL) {
        pci_disable_device(pci);
        return -ENOMEM;
    }

    /* initialize the stuff */
    chip->card = card;
    chip->pci = pci;
    chip->irq = -1;

    err = reserve_mem_regions(chip);
    if (err < 0) {
        kfree(chip);
        pci_disable_device(pci);
        return err;
    }

    /* (1) PCI resource allocation */
    if (request_irq(pci->irq, snd_mychip_interrupt,
            IRQF_SHARED, "My Chip", chip)) {
        printk(KERN_ERR "cannot grab irq %d\n", pci->irq);
        snd_mychip_free(chip);
        return -EBUSY;
    }
    chip->irq = pci->irq;

    printk(KERN_ERR "Gain access to PCI IRQ line ... line %d\n", pci->irq);
    printk(KERN_ERR "Gain access to PCI IO ports ... ports 0x%x\n", (unsigned int)chip->port);

    /* (2) initialization of the chip hardware */
    /*   (not implemented in this document) */

    err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
    if (err < 0) {
        snd_mychip_free(chip);
        return err;
    }

    snd_card_set_dev(card, &pci->dev);

    *rchip = chip;
    return 0;
}    

static void memdump(struct mychip *chip)
{
    int i;

    for(i=0; i<BARS; i++)
    {
        printk(KERN_ERR "\n-----------------------------------\n");
        printk(KERN_ERR "chip->memregs[i].bar = %d\n", chip->memregs[i].bar);
        printk(KERN_ERR "chip->memregs[i].start_addr = 0x%x\n", chip->memregs[i].start_addr);
        printk(KERN_ERR "chip->memregs[i].end_addr = 0x%x\n", chip->memregs[i].end_addr);
        printk(KERN_ERR "chip->memregs[i].mem_len = %d\n", chip->memregs[i].mem_len);
        printk(KERN_ERR "chip->memregs[i].flag = 0x%x\n", chip->memregs[i].flag);
        printk(KERN_ERR "chip->memregs[i].mem_mapped_addr = 0x%p\n", chip->memregs[i].mem_mapped_addr);
}
}

static int reserve_mem_regions(struct mychip *chip)
{
    int res = 0;
    int i=0;

    res = pci_request_regions(chip->pci, "My Chip");
    if (res < 0) {
        return res;
    }

    for(i=0; i<BARS; i++)
    {
        chip->memregs[i].bar = i;
        chip->memregs[i].start_addr = pci_resource_start( chip->pci, i );
        chip->memregs[i].end_addr = pci_resource_end( chip->pci, i );
        chip->memregs[i].mem_len = pci_resource_len( chip->pci, i );
        chip->memregs[i].flag = pci_resource_flags( chip->pci, i );
        chip->memregs[i].mem_mapped_addr = pci_iomap(chip->pci, i, 0);
    }

    memdump(chip);

    return res;
}


static void clear_mem_regions(struct mychip *chip)
{
    int i = 0;
    for(i=0; i<BARS; i++)
    {
        chip->memregs[i].bar = 0xFFFF;
        chip->memregs[i].start_addr = 0;
        chip->memregs[i].end_addr = 0;
        chip->memregs[i].mem_len = 0;
        chip->memregs[i].flag = 0xFFFF;

        pci_iounmap(chip->pci, chip->memregs[i].mem_mapped_addr);
        chip->memregs[i].mem_mapped_addr = NULL;
    }
    pci_release_regions(chip->pci);
}

/* ------------ PCM functions ------------- */    
static struct snd_pcm_hardware snd_hardware_setup =
{
    .info =         (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
                 SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP_VALID |
                 SNDRV_PCM_INFO_PAUSE |
                 SNDRV_PCM_INFO_RESUME),
    .formats =      SNDRV_PCM_FMTBIT_S16_LE,
    .rates =        SNDRV_PCM_RATE_8000_48000,
    .rate_min =     8000,
    .rate_max =     48000,
    .channels_min =     2,
    .channels_max =     2,
    .buffer_bytes_max = 128 * 1024,
    .period_bytes_min = 32,
    .period_bytes_max = 128 * 1024,
    .periods_min =      1,
    .periods_max =      1024,
    .fifo_size =        0,
};

/* ---- operator structs ---- */
static struct snd_pcm_ops snd_pcm_playback_ops = {
    .open =     snd_pcm_playback_open,
    .close =    snd_pcm_playback_close,
    .ioctl =    snd_pcm_lib_ioctl,
    .hw_params =    snd_pcm_hw_params,
    .hw_free =  snd_pcm_hw_free,
    .prepare =  snd_pcm_prepare,
    .trigger =  snd_pcm_trigger,
    .pointer =  snd_pcm_pointer,
};

static struct snd_pcm_ops snd_pcm_capture_ops = {
    .open =     snd_pcm_capture_open,
    .close =    snd_pcm_capture_close,
    .ioctl =    snd_pcm_lib_ioctl,
    .hw_params =    snd_pcm_hw_params,
    .hw_free =  snd_pcm_hw_free,
    .prepare =  snd_pcm_prepare,
    .trigger =  snd_pcm_trigger,
    .pointer =  snd_pcm_pointer,
};

/* ----  file operations fcns ---- */
static int snd_pcm_capture_open(struct snd_pcm_substream *substream)
{
    struct mychip *chip = snd_pcm_substream_chip(substream);
    struct snd_pcm_runtime *runtime = substream->runtime;
    int err = -10;

    printk(KERN_ERR ">>> snd_pcm_capture_open()\n");

    runtime->hw = snd_hardware_setup;
    chip->substream = substream;

    return err;
};

static int snd_pcm_capture_close(struct snd_pcm_substream *substream)
{
    int err = -10;

    printk(KERN_ERR ">>> snd_pcm_capture_close()\n");

    return err;
};

static int snd_pcm_playback_open(struct snd_pcm_substream *substream)
{
    struct mychip *chip = snd_pcm_substream_chip(substream);
    struct snd_pcm_runtime *runtime = substream->runtime;
    int err = -10;

    printk(KERN_ERR ">>> snd_pcm_playback_open()\n");

    runtime->hw = snd_hardware_setup;
    chip->substream = substream;

    return err;
};

static int snd_pcm_playback_close(struct snd_pcm_substream *substream)
{
    int err = -10;

    printk(KERN_ERR ">>> snd_pcm_playback_close()\n");

    return err;
};

/*snd_pcm_lib_ioctl();*/
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
             struct snd_pcm_hw_params *hw_params)
{
    int err = 0;
    return err;
};

static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
{
    int err = 0;
    return err;
};

static int snd_pcm_prepare(struct snd_pcm_substream *substream)
{
    int err = 0;
    return err;
};

static int snd_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
    int err = 0;
    return err;
};

static snd_pcm_uframes_t snd_pcm_pointer(struct snd_pcm_substream *substream)
{
    int err = 0;
    return err;
};

/* ---- constructor ---- */
static int __devinit snd_pcm_constructor(struct mychip *chip)
{
    struct snd_pcm *pcm = NULL;
    int err = 0;

    printk(KERN_ERR ">>> PCM CONSTRUCTOR: running...\n");

    err = snd_pcm_new(chip->card, "My Own Chip", 0, 1, 1, &pcm);
    if(err < 0)
    {
        printk(KERN_ERR ">>> PCM CONSTRUCTOR: Failed to execute snd_pcm_new()!\n");
        return err;
    }
    pcm->private_data = chip;
    pcm->private_free = snd_pcm_destructor;

    strcpy(pcm->name, "My Own Chip");
    chip->pcm = pcm;

    /*set operators*/
    snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_pcm_playback_ops);
    snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_pcm_capture_ops);

    /*stream preallocation of buffers*/
    err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 64*1024);
    if(err < 0)
    {
        printk(KERN_ERR ">>> PCM CONSTRUCTOR: Failed to execute snd_pcm_lib_preallocate_pages_for_all()!\n");
    return err;
    }

    printk(KERN_ERR ">>> PCM CONSTRUCTOR: ... exiting.\n");

    return 0;   
}

/* ---- destructor ---- */
static void snd_pcm_destructor(struct snd_pcm *pcm)
{
    /*
    struct mychip *chip = snd_pcm_chip(pcm);
    */
}

/* ---------------------------------------- */
/* PCI IDs */
static struct pci_device_id snd_mychip_ids[] = {
    { VENDOR_ID, DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
    { 0, }
};
MODULE_DEVICE_TABLE(pci, snd_mychip_ids);

/* pci_driver definition */
static struct pci_driver driver = {
    .name = "My Own Chip",
    .id_table = snd_mychip_ids,
    .probe = snd_mychip_probe,
    .remove = __devexit_p(snd_mychip_remove),
};

/**************** MODULE EXCUTED FUNCTIONS ****************************/
/* module initialization */
static int __init alsa_card_mychip_init(void)
{
    printk(KERN_ERR "\n\n\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
    printk(KERN_ERR "-->>> Module init: !!!");
    return pci_register_driver(&driver);
}

/* module clean up */
static void __exit alsa_card_mychip_exit(void)
{
    pci_unregister_driver(&driver);
    printk(KERN_ERR "-->>> Module exit: ");
}
module_init(alsa_card_mychip_init)
module_exit(alsa_card_mychip_exit)
你看这里

  • 正在调用探测函数(探测…)
  • 启用PCI设备(启用PCI设备…)
  • 正在分配的内存区域
  • 中断行(第5行)
  • PCM构造函数(>>>PCM构造函数:正在运行…)
  • 来自中断处理程序的一些转储
还有我申请表中的几行:

/* Open PCM device for playback. */
rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
if (rc < 0) {
 printf(
         "unable to open pcm device: %s\n",
         snd_strerror(rc));
  exit(1);
}
printf("Device opened ... rc = %d \n", rc);
以下是lspci-v的输出,它将显示音频设备的信息:

00:05.0 Multimedia audio controller: Intel Corporation 82801AA AC'97 Audio Controller (rev 01)
Subsystem: Intel Corporation Device 0000
Flags: bus master, medium devsel, latency 0, IRQ 5
I/O ports at d100 [size=256]
I/O ports at d200 [size=64]
Kernel driver in use: My Own Chip
Kernel modules: snd-nedelinxalsaxpci, snd-intel8x0
我用我的驱动程序构建内核,因为我认为这可能会有所帮助,但事实并非如此(snd-nedelinxalsaxpci是我的驱动程序,snd-intel8x0是原始模块)。“我自己的芯片”来自我的司机

我不知道还能给你什么其他信息。
非常感谢你的支持

您的问题是在调用
snd\u card\u register
后调用PCM构造函数。 声卡设备只有在创建后注册,用户空间才能访问它们

您的代码中甚至有一条注释,告诉您执行此操作的正确位置:

/*(5)创建其他组件PCM、混音器、MIDI等*/

我猜PCM设备没有正确注册,或者您的代码没有打开正确的PCM设备。但是很难说没有看到代码。嗨,我现在就放代码。我知道这真的很混乱,可能在某些地方没有意义,但这只是一个实验,我看不出明显的原因。设备是否与aplay-l一起列出?不,未列出:这是我在aplay-l****播放硬件设备列表****后得到的结果。您是否可以确定显示实际执行了哪个
printk
s?
Module                  Size  Used by
...
alsa                   13273  0 //this is my driver
snd_ac97_codec        105592  0 
snd_pcm                80357  2 alsa,snd_ac97_codec
snd_page_alloc         14036  1 snd_pcm
ac97_bus               12670  1 snd_ac97_codec
snd_seq_midi           13132  0 
snd_rawmidi            25382  1 snd_seq_midi
snd_seq_midi_event     14475  1 snd_seq_midi
snd_seq                51256  2 snd_seq_midi,snd_seq_midi_event
snd_timer              24503  2 snd_pcm,snd_seq
snd_seq_device         14137  3 snd_seq_midi,snd_rawmidi,snd_seq
snd                    62027  7 alsa,snd_ac97_codec,snd_pcm,snd_rawmidi,
snd_seq,snd_timer,snd_seq_device
soundcore              14599  1 snd
00:05.0 Multimedia audio controller: Intel Corporation 82801AA AC'97 Audio Controller (rev 01)
Subsystem: Intel Corporation Device 0000
Flags: bus master, medium devsel, latency 0, IRQ 5
I/O ports at d100 [size=256]
I/O ports at d200 [size=64]
Kernel driver in use: My Own Chip
Kernel modules: snd-nedelinxalsaxpci, snd-intel8x0