4.2.3 azx_probe_work
回顾一下azx_create中最后部分的一行代码:
INIT_DELAYED_WORK(&hda->probe_work, azx_probe_work);
初始化了一个延时work。
再回到azx_probe的最后部分:
if (schedule_probe)
schedule_delayed_work(&hda->probe_work, 0);
azx_probe_work被放到了延时处理的消息列表中去执行。
static void azx_probe_work(struct work_struct *work)
{
struct hda_intel *hda = container_of(work, struct hda_intel, probe_work.work);
azx_probe_continue(&hda->chip);
}
azx_probe_work是通过azx_probe_continue来完成任务的。
static int azx_probe_continue(struct azx *chip)
{
struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
struct hdac_bus *bus = azx_bus(chip);
struct pci_dev *pci = chip->pci;
int dev = chip->dev_index;
int err;
.......
err = azx_first_init(chip);
if (err < 0)
goto out_free;
......
/* create codec instances */
if (bus->codec_mask) {
err = azx_probe_codecs(chip, azx_max_codecs[chip->driver_type]);
if (err < 0)
goto out_free;
}
......
complete_all(&hda->probe_wait);
to_hda_bus(bus)->bus_probing = 0;
hda->probe_retry = 0;
return 0;
}
这段代码中我去除了一些针对特殊设备的特殊处理,以及在初始化失败后尝试再次启动延时work的相关代码。只是想照着主线,推进我们的理解。
这时候我们要面对的就是两个函数azx_first_init和azx_probe_codecs。
4.2.3.1 azx_first_init
static int azx_first_init(struct azx *chip)
{
int dev = chip->dev_index;
struct pci_dev *pci = chip->pci;
struct snd_card *card = chip->card;
struct hdac_bus *bus = azx_bus(chip);
int err;
unsigned short gcap;
unsigned int dma_bits = 64;
#if BITS_PER_LONG != 64
/* Fix up base address on ULI M5461 */
if (chip->driver_type == AZX_DRIVER_ULI) {
u16 tmp3;
pci_read_config_word(pci, 0x40, &tmp3);
pci_write_config_word(pci, 0x40, tmp3 | 0x10);
pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, 0);
}
#endif
// 以下三个函数用来分配和获取IO空间
err = pcim_iomap_regions(pci, 1 << 0, "ICH HD audio");
if (err < 0)
return err;
bus->addr = pci_resource_start(pci, 0);
bus->remap_addr = pcim_iomap_table(pci)[0];
if (chip->driver_type == AZX_DRIVER_SKL)
snd_hdac_bus_parse_capabilities(bus);
/*
* Some Intel CPUs has always running timer (ART) feature and
* controller may have Global time sync reporting capability, so
* check both of these before declaring synchronized time reporting
* capability SNDRV_PCM_INFO_HAS_LINK_SYNCHRONIZED_ATIME
*/
// gts_present是针对get_time_info的特殊处理,在中断的时候同步硬件信息,后续讲到读取音频的时候会用到。
chip->gts_present = false;
#ifdef CONFIG_X86
if (bus->ppcap && boot_cpu_has(X86_FEATURE_ART))
chip->gts_present = true;
#endif
if (chip->msi) {
if (chip->driver_caps & AZX_DCAPS_NO_MSI64) {
dev_dbg(card->dev, "Disabling 64bit MSI\n");
pci->no_64bit_msi = true;
}
if (pci_enable_msi(pci) < 0)
chip->msi = 0;
}
//设置过后,才能从pci总线发送消息到设备
pci_set_master(pci);
// 读取GCAP 注存器信息
gcap = azx_re