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

时间:2013-01-04 14:39:19

标签: linux driver alsa

我正在尝试使用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)

我从dmesg得到的输出:

[  227.202006] @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
[  227.202430] -->>> Module init: !!!
[  227.202507] Probing ...
[  227.203959] Enabling PCI device ...
[  227.207882] 
[  227.207882] -----------------------------------
[  227.208097] chip->memregs[i].bar = 0
[  227.208124] chip->memregs[i].start_addr = 0xd100
[  227.208148] chip->memregs[i].end_addr = 0xd1ff
[  227.208174] chip->memregs[i].mem_len = 256
[  227.208198] chip->memregs[i].flag = 0x40101
[  227.208223] chip->memregs[i].mem_mapped_addr = 0x0001d100
[  227.208246] 
[  227.208246] -----------------------------------
[  227.208271] chip->memregs[i].bar = 1
[  227.208294] chip->memregs[i].start_addr = 0xd200
[  227.208318] chip->memregs[i].end_addr = 0xd23f
[  227.208341] chip->memregs[i].mem_len = 64
[  227.208364] chip->memregs[i].flag = 0x40101
[  227.208388] chip->memregs[i].mem_mapped_addr = 0x0001d200
[  227.208410] 
[  227.208410] -----------------------------------
[  227.208435] chip->memregs[i].bar = 2
.....
[  227.209080] Gain access to PCI IRQ line ... line 5
[  227.209104] Gain access to PCI IO ports ... ports 0x0
[  227.224202] >>> PCM CONSTRUCTOR: running...
[  227.225378] >>> PCM CONSTRUCTOR: ... exiting.
[  227.225403] Probing done!
[  227.295404] 
[  227.295404] ---------- ISR -----------
[  227.313297] 
[  227.313297] ---------- ISR -----------
[  227.327248] 
[  227.327248] ---------- ISR -----------
[  227.344968] 
[  227.344968] ---------- ISR -----------
[  227.351703] 
[  227.351703] ---------- ISR -----------
[  227.360189] 
[  227.360189] ---------- ISR -----------
[  227.371751] 
[  227.371751] ---------- ISR -----------
[  227.387809] 
[  227.387809] ---------- ISR -----------
[  227.396767] 
[  227.396767] ---------- ISR -----------
[  227.413297] 
[  227.413297] ---------- ISR -----------

你在这里看到了

  • 调用探测功能(探测......)
  • 启用PCI设备(启用PCI设备......)
  • 正在分配的内存区域
  • 中断线(第5行)
  • PCM构造函数(&gt;&gt;&gt; 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);

我试着打开我的设备。如果你注意上面的驱动代码,playback_open()函数应该printk()一些消息,应该返回-10。我是故意这样做的。但我的应用程序显示snd_pcm_open()的结果是OK(我的意思是零)。所以看起来我的应用程序没有看到我的驱动程序,但试图使用其他东西。

我也将所有声音放在当前正在加载的模块中:

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

以下是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是原始模块)。 “我自己的芯片”来自我的司机。

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

1 个答案:

答案 0 :(得分:0)

您的问题是,在调用snd_card_register之后,您正在调用PCM构造函数。 只有在创建用户空间后才能注册声卡设备。

您的代码中甚至还有一条评论告诉您正确的位置:

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