gpt4 book ai didi

linux - 自定义 ALSA 驱动程序不执行 struct snd_pcm_ops 中的开放函数

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:37:41 25 4
gpt4 key购买 nike

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

  • 我的探测函数已执行
  • 执行构造函数
  • 我看到正在执行中断

我通过放置在这些函数中的转储发现了这一点。

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

我加载了原始驱动程序并执行了相同的应用程序,它工作正常。

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

谢谢。

代码如下:

#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 -----------

你看到这里

  • 正在调用探测函数(Probing ...)
  • 启用PCI设备(Enabling PCI device ...)
  • 正在分配的内存区域
  • 中断线(第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);

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

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

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

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

最佳答案

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

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

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

关于linux - 自定义 ALSA 驱动程序不执行 struct snd_pcm_ops 中的开放函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14159161/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com