日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

intel声卡驱动probe分析--hda_intel.c alsa

發(fā)布時(shí)間:2023/12/29 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 intel声卡驱动probe分析--hda_intel.c alsa 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1. 關(guān)鍵代碼及注釋:

1. intel聲卡初始化流程: /sound/pci/hda/hda_intel.cazx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) {snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, 0, &card); {//創(chuàng)建snd_card的一個(gè)實(shí)例card->dev = parent; card->number = idx; card->module = module; INIT_LIST_HEAD(&card->devices); //初始化聲卡設(shè)備列表#define INIT_LIST_HEAD(ptr) do { \(ptr)->next = (ptr); (ptr)->prev = (ptr); \} while (0)init_rwsem(&card->controls_rwsem); //初始化讀寫鎖rwlock_init(&card->ctl_files_rwlock); //初始化讀寫鎖mutex_init(&card->user_ctl_lock); //初始化鎖INIT_LIST_HEAD(&card->controls); //初始化controls列表INIT_LIST_HEAD(&card->ctl_files); //初始化ctl_files列表spin_lock_init(&card->files_lock); //初始化自旋鎖INIT_LIST_HEAD(&card->files_list); //初始化files_list列表device_initialize(&card->card_dev); //初始化聲卡設(shè)備err = kobject_set_name(&card->card_dev.kobj, "card%d", idx);//the control interface cannot be accessed from the user space until snd_cards_bitmask and snd_cards are set with snd_card_registererr = snd_ctl_create(card);{ snd_device_initialize(&card->ctl_dev, card); //初始化control設(shè)備 dev_set_name(&card->ctl_dev, "controlC%d", card->number);err = snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops); //create an ALSA device component} err = snd_info_card_create(card);{sprintf(str, "card%i", card->number);entry = create_subdir(card->module, str); {entry = snd_info_create_module_entry(mod, name, NULL); {//Creates a new info entry and assigns it to the given module.struct snd_info_entry *entry = snd_info_create_entry(name, parent);}snd_info_register(entry){if (S_ISDIR(entry->mode)) { //判斷是否是目錄p = proc_mkdir_mode(entry->name, entry->mode, root);if (!p) {mutex_unlock(&info_mutex);return -ENOMEM;}} else {const struct file_operations *ops;if (entry->content == SNDRV_INFO_CONTENT_DATA) //判斷entry內(nèi)容是SNDRV_INFO_CONTENT_DATA 1還是SNDRV_INFO_CONTENT_TEXT 0ops = &snd_info_entry_operations;elseops = &snd_info_text_entry_ops;p = proc_create_data(entry->name, entry->mode, root,ops, entry);if (!p) {mutex_unlock(&info_mutex);return -ENOMEM;}proc_set_size(p, entry->size);}}}}} azx_create(card, pci, dev, pci_id->driver_data, &chip){INIT_LIST_HEAD(&chip->pcm_list);INIT_WORK(&hda->irq_pending_work, azx_irq_pending_work);INIT_LIST_HEAD(&hda->list);init_vga_switcheroo(chip);init_completion(&hda->probe_wait);azx_bus_init(chip, model[dev]);{ //HD-audio bus initializationsnd_hdac_bus_init(&bus->core, chip->card->dev, &bus_core_ops, io_ops); {//初始化chip->bus結(jié)構(gòu)體bus->io_ops = io_ops;INIT_LIST_HEAD(&bus->stream_list); //初始化stream_listINIT_LIST_HEAD(&bus->codec_list); //初始化codec_listINIT_WORK(&bus->unsol_work, process_unsol_events);spin_lock_init(&bus->reg_lock);mutex_init(&bus->cmd_mutex);}}snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);{ //create an ALSA device component,把芯片的專有數(shù)據(jù)注冊(cè)為聲卡的一個(gè)低階設(shè)備:struct snd_device *pdev = list_entry(p, struct snd_device, list);//insert the entry in an incrementally sorted list }INIT_WORK(&hda->probe_work, azx_probe_work){azx_probe_continue(&hda->chip){azx_first_init(chip){err = pci_request_regions(chip->pci, "LS HD audio"); //bus->addr = pci_resource_start(chip->pci, 0);bus->remap_addr = pci_ioremap_bar(chip->pci, 0);azx_acquire_irq(chip, 0) {//請(qǐng)求中斷request_irq(chip->pci->irq, azx_interrupt, chip->msi ? 0 : IRQF_SHARED, KBUILD_MODNAME, chip)}gcap = azx_readw(chip, GCAP); dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap);/* allow 64bit DMA address if supported by H/W */if ((gcap & AZX_GCAP_64OK) && !dma_set_mask(chip->card->dev, DMA_BIT_MASK(64)))dma_set_coherent_mask(chip->card->dev, DMA_BIT_MASK(64));else { dma_set_mask(chip->card->dev, DMA_BIT_MASK(32));dma_set_coherent_mask(chip->card->dev, DMA_BIT_MASK(32));} /* read number of streams from GCAP register instead of using* hardcoded value*/chip->capture_streams = (gcap >> 8) & 0x0f;chip->playback_streams = (gcap >> 12) & 0x0f;if (!chip->playback_streams && !chip->capture_streams) {/* gcap didn't give any info, switching to old method */chip->playback_streams = ICH6_NUM_PLAYBACK;chip->capture_streams = ICH6_NUM_CAPTURE;} /* initialize streams */err = azx_init_streams(chip);{ //initialize each stream (aka device) assign the starting bdl address to each stream (device) and initializedir = stream_direction(chip, i);snd_hdac_stream_init(azx_bus(chip), azx_stream(azx_dev), i, dir, tag);{azx_dev->bus = bus;/* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */azx_dev->sd_addr = bus->remap_addr + (0x20 * idx + 0x80);/* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */azx_dev->sd_int_sta_mask = 1 << idx;azx_dev->index = idx;azx_dev->direction = direction;azx_dev->stream_tag = tag;snd_hdac_dsp_lock_init(azx_dev); list_add_tail(&azx_dev->list, &bus->stream_list);} }azx_alloc_stream_pages(chip);{snd_hdac_bus_alloc_stream_pages(azx_bus(chip)){ //snd_hdac_bus_alloc_stream_pages - allocate BDL and other bufferserr = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, BDL_SIZE, &s->bdl); //allocate memory for the BDL for each stream err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, num_streams * 8, &bus->posbuf); //allocate memory for the position bufferlist_for_each_entry(s, &bus->stream_list, list)s->posbuf = (__le32 *)(bus->posbuf.area + s->index * 8);err = bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, PAGE_SIZE, &bus->rb); //single page (at least 4096 bytes) must suffice for both ringbuffes } }azx_init_chip(chip, (probe_only[dev] & 2) == 0); { //初始化pci設(shè)備,reset and start the controller registerssnd_hdac_bus_init_chip(azx_bus(chip), full_reset){ //snd_hdac_bus_init_chip - reset and start the controller registersif (bus->chip_init)return false;/* reset controller */azx_reset(bus, full_reset);/* initialize interrupts */azx_int_clear(bus);azx_int_enable(bus);/* initialize the codec command I/O */snd_hdac_bus_init_cmd_io(bus);{spin_lock_irq(&bus->reg_lock);/* disable ringbuffer DMAs */snd_hdac_chip_writeb(bus, RIRBCTL, 0);snd_hdac_chip_writeb(bus, CORBCTL, 0);hdac_wait_for_cmd_dmas(bus);/* disable unsolicited responses */ snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, 0);spin_unlock_irq(&bus->reg_lock);}/* program the position buffer */if (bus->use_posbuf && bus->posbuf.addr) {snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr);snd_hdac_chip_writel(bus, DPUBASE, upper_32_bits(bus->posbuf.addr));}bus->chip_init = true;}azx_writew(chip, RINTCNT, 0xc0);}snd_hdac_i915_set_bclk(bus);strcpy(card->driver, "HDA-Intel"); //設(shè)置Driver的ID和名字strlcpy(card->shortname, driver_short_names[chip->driver_type], sizeof(card->shortname));snprintf(card->longname, sizeof(card->longname), "%s at 0x%lx irq %i", card->shortname, bus->addr, bus->irq);}/* create codec instances */if (bus->codec_mask) {err = azx_probe_codecs(chip, azx_max_codecs[chip->driver_type]);{robe_codec(chip, c){snd_hdac_bus_send_cmd(bus, cmd); snd_hdac_bus_get_response(bus, addr, &res);snd_hdac_ext_bus_device_init(ebus, addr); {//initialize the HDA extended codec base devicesnd_hdac_device_init(hdev, bus, name, addr); {snd_hdac_bus_add_device(bus, codec);{ //Add a codec to bus list_add_tail(&codec->list, &bus->codec_list); }codec->vendor_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, AC_PAR_VENDOR_ID);codec->subsystem_id = snd_hdac_read_parm(codec, AC_NODE_ROOT, AC_PAR_SUBSYSTEM_ID);err = snd_hdac_refresh_widgets(codec);codec->power_caps = snd_hdac_read_parm(codec, fg, AC_PAR_POWER_STATE);err = get_codec_vendor_name(codec);}ret = snd_hdac_device_register(hdev); {err = device_add(&card->card_dev);err = snd_device_register_all(card)) snd_info_card_register(card); {/* register pending info register the card proc file*/proc_symlink(card->id, snd_proc_root->p, card->proc_root->name);}init_info_for_card(card);{entry = snd_info_create_card_entry(card, "id", card->proc_root);}}}}azx_stop_chip(chip);azx_init_chip(chip, true);}if (err < 0)goto out_free;}err = snd_card_register(chip->card); //注冊(cè)聲卡azx_add_card_list(chip);}}}schedule_work(&hda->probe_work);}
  • 具體注冊(cè)過程:
  • module_init(alsa_card_azx_init)初始化聲卡模塊,會(huì)調(diào)用alsa_card_azx_init函數(shù),在該函數(shù)中去調(diào)用platform_driver_register去注冊(cè)azx_driver,而azx_driver是一個(gè)結(jié)構(gòu)體, 里面存儲(chǔ)有.driver.name = "ls-audio", 發(fā)現(xiàn)一個(gè)變量:cards_limit=1, 感覺像是聲卡數(shù)量限制1個(gè),在alsa_sound_init時(shí)會(huì)調(diào)用到.幾個(gè)細(xì)節(jié): platform_driver_register(&azx_pci_driver){__platform_driver_register(drv, THIS_MODULE){drv->driver.owner = owner;drv->driver.bus = &platform_bus_type;drv->driver.probe = platform_drv_probe;drv->driver.remove = platform_drv_remove;drv->driver.shutdown = platform_drv_shutdown;driver_register(&drv->driver){other = driver_find(drv->name, drv->bus); //查找驅(qū)動(dòng)是否已經(jīng)在總線上注冊(cè),如已注冊(cè),則直接返回ret = bus_add_driver(drv);{ //Add a driver to the bus. 將驅(qū)動(dòng)添加到虛擬總線上。bus = bus_get(drv->bus);klist_init(&priv->klist_devices, NULL, NULL);error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,"%s", drv->name);klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);error = driver_attach(drv);module_add_driver(drv->owner, drv);error = driver_create_file(drv, &driver_attr_uevent);error = driver_add_groups(drv, bus->drv_groups);error = add_bind_files(drv);}ret = driver_add_groups(drv, drv->groups);kobject_uevent(&drv->p->kobj, KOBJ_ADD);}} }
  • 相關(guān)知識(shí)點(diǎn):
  • char *kstrdup(const char *s, gfp_t gfp) //用于通過kmalloc() 申請(qǐng)一段內(nèi)存將形參s的內(nèi)容copy到這段新申請(qǐng)的內(nèi)存中.這個(gè)函數(shù)如果返回null只有兩種情況,一種是新參s為null,一種是沒有申請(qǐng)到內(nèi)存為null snd_hdac_chip_writel /* set the corb size to 256 entries (ULI requires explicitly) */ snd_hdac_chip_writeb(bus, CORBSIZE, 0x02); /* set the corb write pointer to 0 */ snd_hdac_chip_writew(bus, CORBWP, 0); /* reset the corb hw read pointer */ snd_hdac_chip_writew(bus, CORBRP, AZX_CORBRP_RST);/* reset the corb hw read pointer */ snd_hdac_chip_writew(bus, CORBRP, AZX_CORBRP_RST);proc_symlink(card->id, snd_proc_root->p, card->proc_root->name); 創(chuàng)建目錄函數(shù)proc_mkdir()struct proc_dir_entry *proc_mkdir( const char *name, struct proc_dir_entry *parent) 該函數(shù)將創(chuàng)建一個(gè)目錄,父目錄為parent。 創(chuàng)建符號(hào)鏈接函數(shù)proc_symlink()struct proc_dir_entry *proc_symlink( const char *name, struct proc_dir_entry *parent, char *dest) 該函數(shù)在parent目錄下創(chuàng)建一個(gè)名字為name的符號(hào)鏈接文件,鏈接的目標(biāo)是dest。 創(chuàng)建設(shè)備文件函數(shù)proc_mknod()struct proc_dir_entry *proc_mknod( const char *name, mode_t mode, struct proc_dir_entry *parent, kdev_t *rdev) 該函數(shù)在parent目錄下創(chuàng)建一個(gè)名字為name的設(shè)備文件,文件類型和權(quán)限為mode,設(shè)備號(hào)為rdev。 snd_info_create_card_entry(card, "id", card->proc_root); //create an info entry for the given card

    總結(jié)

    以上是生活随笔為你收集整理的intel声卡驱动probe分析--hda_intel.c alsa的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。