国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

PCIE學(xué)習(xí)系列 五(Linux之PCIe設(shè)備驅(qū)動開發(fā)框架)

這篇具有很好參考價(jià)值的文章主要介紹了PCIE學(xué)習(xí)系列 五(Linux之PCIe設(shè)備驅(qū)動開發(fā)框架)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

概述

本文講述一個開源的PCIe設(shè)備驅(qū)動,通過這個例子可以基本上理解所有的PCIe設(shè)備驅(qū)動。后續(xù)也會做關(guān)于Linux各類驅(qū)動的文章。

通過前面的學(xué)習(xí),我們知道PCIe設(shè)備訪問之前需要先做枚舉。一般來說,PCI設(shè)備的枚舉操作不需要我們來做,BIOS或者系統(tǒng)初始化時(shí)已經(jīng)做好了,當(dāng)系統(tǒng)枚舉完所有設(shè)備之后,PCI設(shè)備就會添加進(jìn)系統(tǒng),在Linux下使用 “l(fā)spci” 就能看到系統(tǒng)掃描到的所有PCI設(shè)備,我們只需要關(guān)注PCI設(shè)備driver的實(shí)現(xiàn)就好了。

在Linux源碼中隨便找了一個開源代碼,tsi721(一款PCIe轉(zhuǎn)RapidIO芯片)的一些源碼,基本上一個普通的PCIE設(shè)備驅(qū)動模型都是這樣的,其中在加上一些設(shè)備獨(dú)有的處理流程。

那么PCIe驅(qū)動的入口在哪呢?

當(dāng)系統(tǒng)枚舉到的PCI設(shè)備的vendor id和device id與driver中的id匹配上之后,就會調(diào)用driver中的probe函數(shù)。

static const struct pci_device_id tsi721_pci_tbl[] = {
    { PCI_DEVICE(PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_TSI721) },
    { 0, }  /* terminate list */
};

MODULE_DEVICE_TABLE(pci, tsi721_pci_tbl);

static struct pci_driver tsi721_driver = {
    .name       = "tsi721",
    .id_table   = tsi721_pci_tbl,
    .probe      = tsi721_probe,
    .remove     = tsi721_remove,
    .shutdown   = tsi721_shutdown,
};

module_pci_driver(tsi721_driver);

PCIe設(shè)備驅(qū)動不是通過name匹配,而是通過id去匹配的,當(dāng)驅(qū)動與設(shè)備匹配上之后,就會執(zhí)行tsi721_probe函數(shù),一般的PCIe驅(qū)動基本上會用到以下步驟:

驅(qū)動加載流程

  1. pci_enable_device(pdev); 使能pci設(shè)備

  2. pci_resource_len(pdev, BAR_0);獲取pci設(shè)備的資源大小,這是枚舉時(shí)得到的值

  3. pci_request_regions(pdev, DRV_NAME); 申請pci設(shè)備資源

  4. pci_ioremap_bar(pdev, BAR_0); 映射虛擬內(nèi)存

  5. pci_set_master(pdev); 設(shè)置pci設(shè)備為master,master模式才能主動發(fā)起數(shù)據(jù)傳輸

  6. pci_enable_msi(pdev); 使能MSI中斷

  7. request_irq(priv->pdev->irq, tsi721_irqhandler,(priv->flags & TSI721_USING_MSI) ? 0 : IRQF_SHARED,DRV_NAME, (void *)priv); 注冊中斷處理函數(shù)

    初始化流程中關(guān)于PCIe的就基本上完成了,其余還有關(guān)于具體業(yè)務(wù)的初始化,下面可以結(jié)合源碼看看。

static int tsi721_probe(struct pci_dev *pdev,
                  const struct pci_device_id *id)
{
    struct tsi721_device *priv;
    int err;

    priv = kzalloc(sizeof(struct tsi721_device), GFP_KERNEL);
    if (!priv) {
        err = -ENOMEM;
        goto err_exit;
    }

    err = pci_enable_device(pdev); // 使能pci設(shè)備
    if (err) {
        tsi_err(&pdev->dev, "Failed to enable PCI device");
        goto err_clean;
    }

    priv->pdev = pdev;

#ifdef DEBUG
    {
        int i;

        for (i = 0; i < PCI_STD_NUM_BARS; i++) {
            tsi_debug(INIT, &pdev->dev, "res%d %pR",
                  i, &pdev->resource[i]);
        }
    }
#endif
    /*
     * Verify BAR configuration
     */

    /* BAR_0 (registers) must be 512KB+ in 32-bit address space */
    if (!(pci_resource_flags(pdev, BAR_0) & IORESOURCE_MEM) ||
        pci_resource_flags(pdev, BAR_0) & IORESOURCE_MEM_64 ||
        pci_resource_len(pdev, BAR_0) < TSI721_REG_SPACE_SIZE) {// 獲取pci設(shè)備bar0的資源大小,這是枚舉時(shí)得到的值
        tsi_err(&pdev->dev, "Missing or misconfigured CSR BAR0");
        err = -ENODEV;
        goto err_disable_pdev;
    }

    /* BAR_1 (outbound doorbells) must be 16MB+ in 32-bit address space */
    if (!(pci_resource_flags(pdev, BAR_1) & IORESOURCE_MEM) ||
        pci_resource_flags(pdev, BAR_1) & IORESOURCE_MEM_64 ||
        pci_resource_len(pdev, BAR_1) < TSI721_DB_WIN_SIZE) {
        tsi_err(&pdev->dev, "Missing or misconfigured Doorbell BAR1");
        err = -ENODEV;
        goto err_disable_pdev;
    }

    /*
     * BAR_2 and BAR_4 (outbound translation) must be in 64-bit PCIe address
     * space.
     * NOTE: BAR_2 and BAR_4 are not used by this version of driver.
     * It may be a good idea to keep them disabled using HW configuration
     * to save PCI memory space.
     */

    priv->p2r_bar[0].size = priv->p2r_bar[1].size = 0;

    if (pci_resource_flags(pdev, BAR_2) & IORESOURCE_MEM_64) {
        if (pci_resource_flags(pdev, BAR_2) & IORESOURCE_PREFETCH)
            tsi_debug(INIT, &pdev->dev,
                 "Prefetchable OBW BAR2 will not be used");
        else {
            priv->p2r_bar[0].base = pci_resource_start(pdev, BAR_2);// 獲取bar2的起始地址
            priv->p2r_bar[0].size = pci_resource_len(pdev, BAR_2);// 獲取bar2的起始長度
        }
    }

    if (pci_resource_flags(pdev, BAR_4) & IORESOURCE_MEM_64) {
        if (pci_resource_flags(pdev, BAR_4) & IORESOURCE_PREFETCH)
            tsi_debug(INIT, &pdev->dev,
                 "Prefetchable OBW BAR4 will not be used");
        else {
            priv->p2r_bar[1].base = pci_resource_start(pdev, BAR_4);// 獲取bar4的起始地址
            priv->p2r_bar[1].size = pci_resource_len(pdev, BAR_4);// 獲取bar4的起始長度
        }
    }

    err = pci_request_regions(pdev, DRV_NAME); // 申請pci設(shè)備資源
    if (err) {
        tsi_err(&pdev->dev, "Unable to obtain PCI resources");
        goto err_disable_pdev;
    }

    pci_set_master(pdev);			// 設(shè)置pci設(shè)備為master模式

    priv->regs = pci_ioremap_bar(pdev, BAR_0); // 映射虛擬內(nèi)存
    if (!priv->regs) {
        tsi_err(&pdev->dev, "Unable to map device registers space");
        err = -ENOMEM;
        goto err_free_res;
    }

    priv->odb_base = pci_ioremap_bar(pdev, BAR_1);// 映射虛擬內(nèi)存
    if (!priv->odb_base) {
        tsi_err(&pdev->dev, "Unable to map outbound doorbells space");
        err = -ENOMEM;
        goto err_unmap_bars;
    }

    /* Configure DMA attributes. */
    if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
        err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); // 設(shè)置dma掩碼
        if (err) {
            tsi_err(&pdev->dev, "Unable to set DMA mask");
            goto err_unmap_bars;
        }

        if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
            tsi_info(&pdev->dev, "Unable to set consistent DMA mask");
    } else {
        err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
        if (err)
            tsi_info(&pdev->dev, "Unable to set consistent DMA mask");
    }

    BUG_ON(!pci_is_pcie(pdev));

    /* Clear "no snoop" and "relaxed ordering" bits. */
    pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
        PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN, 0);

    /* Override PCIe Maximum Read Request Size setting if requested */
    if (pcie_mrrs >= 0) {
        if (pcie_mrrs <= 5)
            pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
                    PCI_EXP_DEVCTL_READRQ, pcie_mrrs << 12);
        else
            tsi_info(&pdev->dev,
                 "Invalid MRRS override value %d", pcie_mrrs);
    }

    /* Set PCIe completion timeout to 1-10ms */
    pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL2,
                       PCI_EXP_DEVCTL2_COMP_TIMEOUT, 0x2);

    /*
     * FIXUP: correct offsets of MSI-X tables in the MSI-X Capability Block
     */
    pci_write_config_dword(pdev, TSI721_PCIECFG_EPCTL, 0x01);
    pci_write_config_dword(pdev, TSI721_PCIECFG_MSIXTBL,
                        TSI721_MSIXTBL_OFFSET);
    pci_write_config_dword(pdev, TSI721_PCIECFG_MSIXPBA,
                        TSI721_MSIXPBA_OFFSET);
    pci_write_config_dword(pdev, TSI721_PCIECFG_EPCTL, 0);
    /* End of FIXUP */

    tsi721_disable_ints(priv);

    tsi721_init_pc2sr_mapping(priv);
    tsi721_init_sr2pc_mapping(priv);

    if (tsi721_bdma_maint_init(priv)) {
        tsi_err(&pdev->dev, "BDMA initialization failed");
        err = -ENOMEM;
        goto err_unmap_bars;
    }

    err = tsi721_doorbell_init(priv);
    if (err)
        goto err_free_bdma;

    tsi721_port_write_init(priv);

    err = tsi721_messages_init(priv);
    if (err)
        goto err_free_consistent;

    err = tsi721_setup_mport(priv);
    if (err)
        goto err_free_consistent;

    pci_set_drvdata(pdev, priv);
    tsi721_interrupts_init(priv);

    return 0;

err_free_consistent:
    tsi721_port_write_free(priv);
    tsi721_doorbell_free(priv);
err_free_bdma:
    tsi721_bdma_maint_free(priv);
err_unmap_bars:
    if (priv->regs)
        iounmap(priv->regs);
    if (priv->odb_base)
        iounmap(priv->odb_base);
err_free_res:
    pci_release_regions(pdev);
    pci_clear_master(pdev);
err_disable_pdev:
    pci_disable_device(pdev);
err_clean:
    kfree(priv);
err_exit:
    return err;
}

tsi721_probe調(diào)用tsi721_setup_mport(priv),如下所示,和pcie相關(guān)的就是msi 中斷的使能,中斷函數(shù)的注冊,其他就是芯片具體的業(yè)務(wù)相關(guān)的初始化。

static int tsi721_setup_mport(struct tsi721_device *priv)
{
	struct pci_dev *pdev = priv->pdev;
	int err = 0;
	struct rio_mport *mport = &priv->mport;

	err = rio_mport_initialize(mport);
	if (err)
		return err;

	mport->ops = &tsi721_rio_ops;
	mport->index = 0;
	mport->sys_size = 0; /* small system */
	mport->priv = (void *)priv;
	mport->phys_efptr = 0x100;
	mport->phys_rmap = 1;
	mport->dev.parent = &pdev->dev;
	mport->dev.release = tsi721_mport_release;

	INIT_LIST_HEAD(&mport->dbells);

	rio_init_dbell_res(&mport->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
	rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 3);
	rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 3);
	snprintf(mport->name, RIO_MAX_MPORT_NAME, "%s(%s)",
		 dev_driver_string(&pdev->dev), dev_name(&pdev->dev));

	/* Hook up interrupt handler */

#ifdef CONFIG_PCI_MSI
	if (!tsi721_enable_msix(priv))		// 使能MSI-X中斷
		priv->flags |= TSI721_USING_MSIX;
	else if (!pci_enable_msi(pdev))		// 使能MSI中斷
		priv->flags |= TSI721_USING_MSI;
	else
		tsi_debug(MPORT, &pdev->dev,
			 "MSI/MSI-X is not available. Using legacy INTx.");
#endif /* CONFIG_PCI_MSI */

	err = tsi721_request_irq(priv); // 中斷注冊,展開即為 request_irq

	if (err) {
		tsi_err(&pdev->dev, "Unable to get PCI IRQ %02X (err=0x%x)",
			pdev->irq, err);
		return err;
	}

#ifdef CONFIG_RAPIDIO_DMA_ENGINE
	err = tsi721_register_dma(priv);
	if (err)
		goto err_exit;
#endif
	/* Enable SRIO link */
	iowrite32(ioread32(priv->regs + TSI721_DEVCTL) |
		  TSI721_DEVCTL_SRBOOT_CMPL,
		  priv->regs + TSI721_DEVCTL);

	if (mport->host_deviceid >= 0)
		iowrite32(RIO_PORT_GEN_HOST | RIO_PORT_GEN_MASTER |
			  RIO_PORT_GEN_DISCOVERED,
			  priv->regs + (0x100 + RIO_PORT_GEN_CTL_CSR));
	else
		iowrite32(0, priv->regs + (0x100 + RIO_PORT_GEN_CTL_CSR));

	err = rio_register_mport(mport);
	if (err) {
		tsi721_unregister_dma(priv);
		goto err_exit;
	}

	return 0;

err_exit:
	tsi721_free_irq(priv);
	return err;
}

驅(qū)動加載初始化的代碼就結(jié)束了。

驅(qū)動卸載流程

當(dāng)驅(qū)動卸載時(shí)會調(diào)用到tsi721_remove函數(shù),其流程基本上就是probe的逆向操作。

  1. free_irq(priv->pdev->irq, (void *)priv); 釋放中斷
  2. iounmap(priv->regs); 地址解映射
  3. pci_disable_msi(priv->pdev);失能msi中斷
  4. pci_release_regions(pdev);釋放申請的資源
  5. pci_clear_master(pdev); 清除設(shè)備master屬性
  6. pci_disable_device(pdev);失能pci設(shè)備

下面一起看看源碼

static void tsi721_remove(struct pci_dev *pdev)
{
    struct tsi721_device *priv = pci_get_drvdata(pdev);

    tsi_debug(EXIT, &pdev->dev, "enter");

    tsi721_disable_ints(priv);
    tsi721_free_irq(priv);					// 釋放中斷
    flush_scheduled_work();
    rio_unregister_mport(&priv->mport);

    tsi721_unregister_dma(priv);
    tsi721_bdma_maint_free(priv);
    tsi721_doorbell_free(priv);
    tsi721_port_write_free(priv);
    tsi721_close_sr2pc_mapping(priv);

    if (priv->regs)
        iounmap(priv->regs);				// 地址解映射
    if (priv->odb_base)
        iounmap(priv->odb_base);
#ifdef CONFIG_PCI_MSI
    if (priv->flags & TSI721_USING_MSIX)
        pci_disable_msix(priv->pdev);		// 失能msi-x中斷
    else if (priv->flags & TSI721_USING_MSI)
        pci_disable_msi(priv->pdev);		// 失能msi中斷
#endif
    pci_release_regions(pdev);				// 釋放申請的資源
    pci_clear_master(pdev);					// 清除設(shè)備master屬性
    pci_disable_device(pdev);				// 失能pci設(shè)備
    pci_set_drvdata(pdev, NULL);
    kfree(priv);
    tsi_debug(EXIT, &pdev->dev, "exit");
}

至此關(guān)于PCIe設(shè)備驅(qū)動的卸載就完成了。

以上就是一個PCIe設(shè)備的基本驅(qū)動框架。文章來源地址http://www.zghlxwxcb.cn/news/detail-754549.html

到了這里,關(guān)于PCIE學(xué)習(xí)系列 五(Linux之PCIe設(shè)備驅(qū)動開發(fā)框架)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Linux驅(qū)動開發(fā)筆記(四):設(shè)備驅(qū)動介紹、熟悉雜項(xiàng)設(shè)備驅(qū)動和ubuntu開發(fā)雜項(xiàng)設(shè)備Demo

    Linux驅(qū)動開發(fā)筆記(四):設(shè)備驅(qū)動介紹、熟悉雜項(xiàng)設(shè)備驅(qū)動和ubuntu開發(fā)雜項(xiàng)設(shè)備Demo

    若該文為原創(chuàng)文章,轉(zhuǎn)載請注明原文出處 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/134533533 紅胖子網(wǎng)絡(luò)科技博文大全:開發(fā)技術(shù)集合(包含Qt實(shí)用技術(shù)、樹莓派、三維、OpenCV、OpenGL、ffmpeg、OSG、單片機(jī)、軟硬結(jié)合等等)持續(xù)更新中… 上一篇:《Linux驅(qū)動開發(fā)筆記(三

    2024年02月05日
    瀏覽(50)
  • 4、Linux驅(qū)動開發(fā):設(shè)備-設(shè)備號&設(shè)備號注冊

    4、Linux驅(qū)動開發(fā):設(shè)備-設(shè)備號&設(shè)備號注冊

    ??點(diǎn)擊這里查看所有博文 ??隨著自己工作的進(jìn)行,接觸到的技術(shù)棧也越來越多。給我一個很直觀的感受就是,某一項(xiàng)技術(shù)/經(jīng)驗(yàn)在剛開始接觸的時(shí)候都記得很清楚。往往過了幾個月都會忘記的差不多了,只有經(jīng)常會用到的東西才有可能真正記下來。存在很多在特殊情況下有

    2024年02月15日
    瀏覽(44)
  • Linux驅(qū)動開發(fā)實(shí)戰(zhàn)(一)——設(shè)備驅(qū)動模型

    Linux驅(qū)動開發(fā)實(shí)戰(zhàn)(一)——設(shè)備驅(qū)動模型

    在早期的Linux內(nèi)核中并沒有為設(shè)備驅(qū)動提供統(tǒng)一的設(shè)備模型。隨著內(nèi)核的不斷擴(kuò)大及系統(tǒng)更加復(fù)雜,編寫一個驅(qū)動程序越來越困難,所以在Linux2.6內(nèi)核中添加了一個統(tǒng)一的設(shè)備模型。這樣,寫設(shè)備驅(qū)動程序就稍微容易一些了。本章將對設(shè)備模型進(jìn)行詳細(xì)的介紹。 設(shè)備驅(qū)動模型

    2024年02月16日
    瀏覽(27)
  • 【Linux 設(shè)備驅(qū)動系列 4 -- 設(shè)備樹 64bit 寄存器 reg 屬性描述 】

    address-cells:address要用多少個32位數(shù)來表示; size-cells:size 要用多少個32位數(shù)來表示。 32bit 寄存器 reg 屬性描述 在 Linux 設(shè)備樹(Device Tree)語法中,\\\" reg \\\"和\\\" reg-names \\\"屬性是用于描述設(shè)備資源的主要屬性。 \\\" reg \\\"屬性用于描述設(shè)備的物理地址和大小。它是一個32位或64位的整數(shù)數(shù)

    2024年02月16日
    瀏覽(23)
  • Linux設(shè)備驅(qū)動開發(fā) - 虛擬時(shí)鐘Clock驅(qū)動示例

    Linux設(shè)備驅(qū)動開發(fā) - 虛擬時(shí)鐘Clock驅(qū)動示例

    By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜歡的盆友歡迎點(diǎn)贊和訂閱! 你的喜歡就是我寫作的動力! 很多設(shè)備里面系統(tǒng)時(shí)鐘架構(gòu)極其復(fù)雜,讓學(xué)習(xí)Clock驅(qū)動的盆友頭大。這里我參考S3C2440的clock驅(qū)動寫了一個virtual clock,即虛擬時(shí)鐘驅(qū)動,分別包含clock的provider和

    2023年04月21日
    瀏覽(27)
  • Linux 驅(qū)動學(xué)習(xí)筆記 ——(1)字符設(shè)備驅(qū)動

    Linux 驅(qū)動學(xué)習(xí)筆記 ——(1)字符設(shè)備驅(qū)動

    《【正點(diǎn)原子】I.MX6U嵌入式Linux驅(qū)動開發(fā)指南》學(xué)習(xí)筆記 字符設(shè)備是 Linux 驅(qū)動中最基本的一類設(shè)備驅(qū)動,字節(jié)設(shè)備就是按照字節(jié)流來讀寫的設(shè)備,常見的字符設(shè)備包括:LED、蜂鳴器、按鍵、I2C 以及 SPI 等。 Linux 中一切皆文件,字符設(shè)備驅(qū)動加載成功后會在 /dev 目錄下生成相

    2024年02月08日
    瀏覽(26)
  • Linux -- 字符設(shè)備驅(qū)動--LED的驅(qū)動開發(fā)(初級框架)

    Linux -- 字符設(shè)備驅(qū)動--LED的驅(qū)動開發(fā)(初級框架)

    看原理圖確定引腳,確定引腳輸出什么電平才能點(diǎn)亮 / 熄滅 LED 看主芯片手冊,確定寄存器操作方法:哪些寄存器?哪些位?地址是? 編寫驅(qū)動:先寫框架,再寫硬件操作的代碼 注意 :在芯片手冊中確定的寄存器地址被稱為 物理地址 ,在 Linux 內(nèi)核中無法直接使用。 需要使

    2024年04月28日
    瀏覽(27)
  • 嵌入式Linux驅(qū)動開發(fā) 04:基于設(shè)備樹的驅(qū)動開發(fā)

    嵌入式Linux驅(qū)動開發(fā) 04:基于設(shè)備樹的驅(qū)動開發(fā)

    前面文章 《嵌入式Linux驅(qū)動開發(fā) 03:平臺(platform)總線驅(qū)動模型》 引入了資源和驅(qū)動分離的概念,這篇文章將在前面基礎(chǔ)上更進(jìn)一步,引入設(shè)備樹的概念。 在平臺總線驅(qū)動模型中資源和驅(qū)動已經(jīng)從邏輯上和代碼組織上進(jìn)行了分離,但每次調(diào)整資源還是會涉及到內(nèi)核,所以現(xiàn)

    2024年02月16日
    瀏覽(27)
  • 正點(diǎn)原子嵌入式linux驅(qū)動開發(fā)——Linux 網(wǎng)絡(luò)設(shè)備驅(qū)動

    正點(diǎn)原子嵌入式linux驅(qū)動開發(fā)——Linux 網(wǎng)絡(luò)設(shè)備驅(qū)動

    網(wǎng)絡(luò)驅(qū)動是linux里面驅(qū)動三巨頭之一 ,linux下的網(wǎng)絡(luò)功能非常強(qiáng)大,嵌入式linux中也常常用到網(wǎng)絡(luò)功能。前面已經(jīng)講過了字符設(shè)備驅(qū)動和塊設(shè)備驅(qū)動,本章就來學(xué)習(xí)一下linux里面的 網(wǎng)絡(luò)設(shè)備驅(qū)動 。 本次筆記中討論的都是有線網(wǎng)絡(luò)! 提起網(wǎng)絡(luò),一般想到的硬件就是“網(wǎng)卡”。在

    2024年01月17日
    瀏覽(25)
  • 嵌入式Linux系統(tǒng)中的設(shè)備驅(qū)動開發(fā):從設(shè)備樹到驅(qū)動實(shí)現(xiàn)

    嵌入式Linux系統(tǒng)中的設(shè)備驅(qū)動開發(fā):從設(shè)備樹到驅(qū)動實(shí)現(xiàn)

    大家好,今天給大家介紹 嵌入式Linux系統(tǒng)中的設(shè)備驅(qū)動開發(fā):從設(shè)備樹到驅(qū)動實(shí)現(xiàn) ,文章末尾附有分享大家一個資料包,差不多150多G。里面學(xué)習(xí)內(nèi)容、面經(jīng)、項(xiàng)目都比較新也比較全! 可進(jìn)群免費(fèi)領(lǐng)取。 在嵌入式Linux系統(tǒng)中,設(shè)備驅(qū)動是連接硬件設(shè)備和操作系統(tǒng)之間的橋梁。

    2024年02月19日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包