Linux 自定义ALSA驱动程序不执行struct snd_pcm_ops中的打开函数
我正在尝试使用ALSA创建自己的自定义声音驱动程序。到目前为止,我已成功加载模块,我的意思是:Linux 自定义ALSA驱动程序不执行struct snd_pcm_ops中的打开函数,linux,driver,alsa,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)
你看这里
- 正在调用探测函数(探测…)
- 启用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