PCI resource management
这部分主要完成azx chip 特定的construtor/destructor,以及PCI entries.
首先这里涉及到几个重要的函数:
struct azx{}
static int azx_free(struct azx *chip)
statci int azx_create(…) //azx芯片特定的constructor
azx_create(struct snd_card *card,
struct pci_dev *pci,
int dev,
unsigned int driver_caps,
const struct hda_controller_ops *hda_ops,
struct azx **rchip)
下面讲解函数azx_create()里的主要内容
err = pci_enable_device(pci)
这个函数是初始化PCI entry
**hda = kzalloc(sizeof(hda), GFP_KERNEL);
这一句对应《write alsa》里的chip = kzalloc(sizeof(chip),GFP_KERNEL)那是不是就说明这里的hda 就对应 文档里面的chip
后面怎么又来一句:chip = &hda->chip???
position 相关
err = snd_device_new()
然后发现 write alsa driver文档中的snd_mychio_create()函数里面关于PCI相关的几个函数都在 hda_intel.c的azx_first_init()函数中,是不是说明这个函数就是用来设置pci resource相关内容的,主要函数有以下几个:
err = pci_request_regions(pci, “ICH HD audio”);
这是PCI resource的一个allocation,这里的ICH HD audio就是 My Chip,
chip->addr = pci_resource_start(pci, 0);
这里的addr就是文档里面提到的IO Port address
pci_set_dma_mask(pci, DMA_BIT_MASK(32));
check PCI availability
关于resource allocation的一些主要内容
关于I/O port address & irqs的分配是通过内核标准函数来完成的,现假设这个PCI device有一个8 byte的IO Port , 以及一个interrupt,在struct azx{}里面会有如下几个项:struct snd_card *card, unsigned long addr(这个就是IO port addr), int irq;
对于一个IO Port(addr)来说,我们需要有一个resource pointer来指向标准的resource management, 关于port address 以及resource pointer会自动通过kzalloc()来初始化,不需要我们重置;
对于一个irq来说,需要有一个独立的irq number, 在实际的分配之前,先要初始化该值为-1,0值表示有效。
I/O port的分配一般如下所示
err = pci_request_regions(pci, "ICH HD audio");
if (err < 0)
return err;
chip->region_requested = 1;
chip->addr = pci_resource_start(pci, 0);
chip->remap_addr = pci_ioremap_bar(pci, 0);
if (chip->remap_addr == NULL) {
dev_err(card->dev, "ioremap error\n");
return -ENXIO;
}
中断资源的分配在azx_acquire_irq()中,
if (request_irq(pci->irq, snd_mychip_interrupt,IRQF_SHARED, KBUILD_MODNAME, chip))
if (request_irq(chip->pci->irq, azx_interrupt,
chip->msi ? 0 : IRQF_SHARED,
KBUILD_MODNAME, chip)) {
dev_err(chip->card->dev,
"unable to grab IRQ %d, disabling device\n",
chip->pci->irq);
if (do_disconnect)
snd_card_disconnect(chip->card);
return -1;
}
chip->irq = chip->pci->irq;
在pci bus上,interrupts 可以被shared,所以 IRQF_SHARED 被用来当作request_irq()的中断标志
memory-mapped region的管理和IO port部分的管理差不多
struct mychip {
....
unsigned long iobase_phys;
void __iomem *iobase_virt;
};
and the allocation would be like below:
if ((err = pci_request_regions(pci, "My Chip")) < 0) {
kfree(chip);
return err;
}
chip->iobase_phys = pci_resource_start(pci, 0);
chip->iobase_virt = ioremap_nocache(chip->iobase_phys,
pci_resource_len(pci, 0));
and the corresponding destructor would be:
static int snd_mychip_free(struct mychip *chip)
{
....
if (chip->iobase_virt)
iounmap(chip->iobase_virt);
....
pci_release_regions(chip->pci);
....
}
在azx chip中的表示如下
unsigned long addr;
void __iomem *remap_addr;
chip->addr = pci_resource_start(pci, 0);
chip->remap_addr = pci_ioremap_bar(pci, 0);
PCI Entries
就是一些pci_device_id 和一些device table。