国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Xilinx Linux 如何理解V4L2的管道驅動程序

454398 ? 來源:賽靈思中文社區論壇 ? 作者:賽靈思中文社區論 ? 2020-09-30 13:44 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

概述

Xilinx提供了完整的V4L2的驅動程序,Xilinx V4L2 driver。處于最頂層的驅動程序是V4L2框架的視頻管道(Video pipeline)驅動程序,也叫橋驅動程序(bridge driver),主要代碼在文件xilinx-vipp.c中。在V4L2框架中,整個視頻管道(Video pipeline)可以通過媒體設備(/dev/media)配置,流媒體可以通過視頻設備(/dev/video)控制。這兩種設備,都是在視頻管道(Video pipeline)驅動程序里創建的。所以,理解V4L2的管道(pipeline)驅動程序是理解Xilinx所有Video IP 在Linux下工作情況的基礎。

3. 文件

3.1. C文件

Xilinx的V4L2的管道(pipeline)驅動程序在下面四個文件中。
1. drivers/media/platform/xilinx/xilinx-vipp.c
2. drivers/media/platform/xilinx/xilinx-vipp.h
3. drivers/media/platform/xilinx/xilinx-dma.c
4. drivers/media/platform/xilinx/xilinx-dma.h

3.2.設備樹(devicetree)

設備樹(devicetree)里含有整個視頻管道(video pipeline)的配置,對應的文檔在Documentation/devicetree/bindings/media/xilinx/xlnx,video.txt。

下面是一個設備樹(devicetree)的例子。

axi_video_cap {
compatible = "xlnx,axi-video";
dmas = , ;
dma-names = "port0", "port1";

ports {
#address-cells = ;
#size-cells = ;

port@0 {
reg = ;
direction = "input";
vcap0_in0: endpoint {
remote-endpoint = ;
};
};
port@1 {
reg = ;
direction = "input";
vcap0_in1: endpoint {
remote-endpoint = ;
};
};
};
};

3.3. 函數調用關系圖

xvipp 函數調用關系圖

xvipp 函數調用關系圖

4.主要函數

4.1. 函數xvip_composite_probe()

函數xvip_composite_probe是整個驅動的入口,主要工作是初始化驅動的數據結構xvip_composite_device里的通用數據,包括lock、list(entities和dmas),再調用了xvip_composite_v4l2_init()和xvip_graph_init(),最后調用platform_set_drvdata設置平臺設備platform_device里的當前設備的數據指針。

4.2. 函數xvip_composite_v4l2_init()

函數xvip_composite_v4l2_init做的事情比較簡單,只是初始化了struct media_device,設置了設備版本和model名稱、dev/mdev指針,就調用了v4l2_device_register()注冊V4L2設備。

xvip_composite_v4l2_init的關鍵代碼如下:
xdev->media_dev.dev = xdev->dev;
strlcpy(xdev->media_dev.model, "Xilinx Video Composite Device",
sizeof(xdev->media_dev.model));
xdev->media_dev.hw_revision = 0;
media_device_init(&xdev->media_dev);
xdev->v4l2_dev.mdev = &xdev->media_dev;
ret = v4l2_device_register(xdev->dev, &xdev->v4l2_dev);

4.3. 函數xvip_graph_init

函數xvip_graph_init是最重要的函數,函數調用層次也最深。它首先調用xvip_graph_dma_init根據設備樹(devicetree)里的port信息初始化DMA通道,創建一個DMA的列表;再調用xvip_graph_parse在設備樹(devicetree)里分析子設備節點,根據設備樹里"remote-endpoint"屬性創建一個Entity的列表;最后調用v4l2_async_notifier_register注冊異步處理函數。系統發現各個子設備(subdev)后,調用異步處理函數xvip_graph_notify_bound獲取子設備信息。所有子設備(subdev)都被發現后,調用xvip_graph_notify_complete,為每個entity創建Link和V4L2子設備,并注冊media設備。

xvip_graph_init的關鍵代碼如下:
/* Init the DMA channels. */
ret = xvip_graph_dma_init(xdev);

/* Parse the graph to extract a list of subdevice DT nodes. */
ret = xvip_graph_parse(xdev);

/* Register the subdevices notifier. */
num_subdevs = xdev->num_subdevs;
subdevs = devm_kcalloc(xdev->dev, num_subdevs, sizeof(*subdevs), GFP_KERNEL);

xdev->notifier.subdevs = subdevs;
xdev->notifier.num_subdevs = num_subdevs;
xdev->notifier.ops = &xvip_graph_notify_ops;
ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier);

4.4. 函數xvip_graph_dma_init

xvip_graph_dma_init()自身比較簡單,先找到第一個"ports"子節點,再找其中的所有"port"節點,并為每個"port"子節點執行xvip_graph_dma_init_one(),從而將每個"port"子節點對應的DMA添加到鏈表dmas中。

xvip_graph_dma_init的關鍵代碼如下:
ports = of_get_child_by_name(xdev->dev->of_node, "ports");

for_each_child_of_node(ports, port) {
ret = xvip_graph_dma_init_one(xdev, port);
}

4.5. 函數xvip_graph_dma_init_one

xvip_graph_dma_init_one()根據設備樹(devicetree)的"port"子節點的配置,找到DMA,并添加到鏈表"xdev->dmas"中。
xvip_graph_dma_init_one先讀取"port"子節點的屬性"direction"和"reg"屬性。Devicetre的"port"節點中,要含有屬性“direction”和"reg"屬性;如果沒有屬性“direction”,會返回錯誤;如果沒有"reg"屬性,代碼會繼續,但是功能會出錯。屬性"direction"的值是"input"或者"output"。
xvip_graph_dma_init_one還為每個port分配struct xvip_dma,再執行xvip_dma_init()。
接下來,xvip_graph_dma_init_one把struct xvip_dma加入到隊列xdev->dmas。
xvip_graph_dma_init_one還根據"direction"的值是"input"或者"output",以及xvip_is_mplane的設置,選擇buffer類型。

xvip_graph_dma_init_one的關鍵代碼如下:
// Read direction and reg properties
ret = of_property_read_string(node, "direction", &direction);

of_property_read_u32(node, "reg", &index);

dma = devm_kzalloc(xdev->dev, sizeof(*dma), GFP_KERNEL);

ret = xvip_dma_init(xdev, dma, type, index);

list_add_tail(&dma->list, &xdev->dmas);

4.6. 函數xvip_dma_init

xvip_dma_init是核心的函數,完成了最關鍵的任務:初始化buffer隊列、申請DMA設備、注冊Video設備。
函數xvip_dma_init()先初始化struct xvip_dma的數據成員,包括dma->lock、dma->pipe.lock、dma->queued_bufs、dma->queued_lock;再根據buffer類型,初始化v4l2_format里的像數點格式,struct v4l2_pix_format pix 或者struct v4l2_pix_format_mplane pix_mp。接下來設置pad.flags為MEDIA_PAD_FL_SINK或者MEDIA_PAD_FL_SOURCE,調用media_entity_pads_init初始化初始化media entity。
函數xvip_dma_init()然后繼續初始化video_device的各種成員和操作函數,包括fops、v4l2_dev、queue、vfl_type、vfl_dir、lock、和ioctl_ops。video_device的fops被設置為xvip_dma_fops,ioctl_ops被設置為xvip_dma_ioctl_ops。
函數xvip_dma_init()再接著初始化buffer隊列struct vb2_queue queue,其中ops被設置為xvip_dma_queue_qops,mem_ops被設置為vb2_dma_contig_memops,執行vb2_queue_init。
函數xvip_dma_init()再接著執行dma_request_chan申請DMA設備,這是一個復雜和核心的函數。dma_request_chan()的第二個參數是DMA通道的名稱,名字是格式是"port%u",比如"port0",也就是設備樹的屬性"dma-names"里的字符串。其中of_dma_request_slave_channel()調用的of_find_property(np, "dmas", NULL),通過屬性"dmas",取得了dma。of_property_count_strings()計算屬性"dma-names"里的字符串個數,也就是DMA的個數。然后根據DMA的個數,為每一個DMA執行of_dma_match_channel()。of_dma_match_channel (dev->of_node, "port%u", )取出"dma-names"的字符串,再和"port%u"對比,這是檢查名字是否對應,如果一致,就用對應的DMA,取得struct of_phandle_args dma_spec,再把struct of_phandle_args dma_spec轉換為struct of_dma *ofdma。of_dma_xlate接下來轉換為struct dma_chan。of_dma_request_slave_channel使用了字符串"dmas"。of_dma_match_channel()使用了字符串"dmas"和"dma-names"。所以Xilinx-vipp.c實現的"xlnx,video"設備的設備樹里的"dmas"和"dma-names","port0"是必須有的固定字符串,不能更改;只有dmas后面的DMA phandle才可以更改。
函數xvip_dma_init()最后執行video_register_device注冊Video設備。

4.7. 函數xvip_graph_parse

函數xvip_graph_parse先調用xvip_graph_parse_one,找到直接的remote_port;然后再為每一個找到的remote_port執行一次xvip_graph_parse_one。

4.8. 函數xvip_graph_parse_one

xvip_graph_parse_one()里先調用of_graph_get_next_endpoint(node, ep)取得下一個endpoint,然后再調用of_graph_get_remote_port_parent(ep) 得到remote_port的父節點。of_graph_get_next_endpoint(node, ep)會先嘗試找子節點ports,再找到子節點port,然后再在子節點port里找endpoint;讀取路徑是 { ports { port {endpoint } } },其中ports是可選的。endpoint是port的子節點,不管其內部的屬性名稱,所以也可以用屬性名稱remote-endpoint。of_graph_get_remote_port_parent(ep)通過調用of_graph_get_remote_endpoint()得到remote_port,再調用of_graph_get_port_parent()得到父節點。of_graph_get_remote_endpoint()里讀取了設備樹里的"remote-endpoint"屬性。
xvip_graph_parse_one()再調用xvip_graph_find_entity(),在xdev->entities里檢查是否已經包含對應的entity,如果已經包含,則跳過后續處理;如果沒沒有,則找到的remote_port的父節點,存放到鏈表xdev->entities,并執行操作xdev->num_subdevs++。
最后xdev->entities里包含了所有entity。后來xvip_graph_notify_complet會根據xdev->entities,為每個entity創建一個設備。

4.9. 函數xvip_graph_notify_bound

系統發現子設備(subdev)后,調用異步處理函數xvip_graph_notify_bound獲取子設備信息。xvip_graph_notify_bound根據設備樹節點,匹配實體(entity)和子設備(subdev);匹配成功后,再把子設備(subdev)的指針保存到實體(entity)。

xvip_graph_notify_bound的關鍵代碼如下:
entity->entity = &subdev->entity;
entity->subdev = subdev;

4.10. 函數xvip_graph_notify_complete

系統所有子設備(subdev)都被發現后,Linux會調用xvip_graph_notify_complete。xvip_graph_notify_complete調用xvip_graph_build_one為每個entity創建Link;調用xvip_graph_build_dma做Create links for DMA channels;并為每個實體(entity)注冊V4L2子設備v4l2_device_register_subdev_nodes ;最后調用media_device_register注冊media設備。

4.11. 函數xvip_graph_build_one

函數xvip_graph_build_dma在每個entity及其遠端模塊之間創建Link。
函數xvip_graph_build_one先調用函數of_graph_get_next_endpoint從設備的設備樹里找到下一個endpoint(struct device_node)。與之前描述一樣,of_graph_get_next_endpoint的讀取路徑是 { ports { port {endpoint} } },endpoint是port的子節點,不管其內部的屬性名稱,所以也可以用屬性名稱remote-endpoint。函數xvip_graph_build_dma接著調用v4l2_fwnode_parse_link,得到對應的link(struct v4l2_fwnode_link)。接著根據link中的端口號(local_port)取得pad信息,判斷出是否是目的端(sink)端口;如果是目的端(sink)端口,則忽略。另外還忽略DMA,它由xvip_graph_build_dma處理。接下來再調用函數xvip_graph_find_entity,根據link中的遠端節點(remote_node),得到遠端的entity。最后調用media_create_pad_link,當前entity作為源端(source),遠端entity作為目的端(sink)的media_entity和media_pad,創建媒體pad的鏈接(link)

4.12. 函數xvip_graph_build_dma

函數xvip_graph_build_dma為DMA模塊及其遠端模塊之間創建Link。
函數xvip_graph_build_dma先調用函數of_graph_get_next_endpoint從設備的設備樹里找到下一個endpoint(struct device_node)。函數xvip_graph_build_dma接著調用v4l2_fwnode_parse_link,得到對應的link(struct v4l2_fwnode_link),根據link中的端口號(local_port),找到對應的DMA(struct xvip_dma)。接下來再調用函數xvip_graph_find_entity,根據link中的遠端節點(remote_node),得到遠端的entity。然后設置源端(source)/目的端(sink)的media_entity和media_pad,最后調用media_create_pad_link創建媒體pad的鏈接(link)。

4.13. 函數xvip_graph_find_dma

函數xvip_graph_build_dma根據指定的port號,在xdev->dmas里找DMA,如果找到,就返回對應的的struct xvip_dma的指針。

4.14. 函數xvip_graph_find_entity

函數xvip_graph_find_entity根據指定的設備節點(struct device_node),在xdev->entities里找entity,如果找到,就返回對應的的struct xvip_graph_entity的指針。

5. 關鍵數據

5.1. subdevs

其中subdevs是一個指針,指向(struct v4l2_async_subdev *)的數組(是指針數組),包含了這個設備下的所有subdev的指針,根據遍歷xdev->entities填滿這個數組。xdev->entities由processedxvip_graph_parse_one()根據設備樹找到相關的子設備填充。

5.2. group ID

組ID(struct v4l2_subdev里有成員grp_id。v4l2_subdev_init()里把其初始化為0。Xilinx沒有設置grp_id,所以都是0.)

5.3. xvip_graph_notify_ops

xvip_graph_notify_ops指向bound和complete函數,如果成功匹配設備,.bound()回調函數將會被調用,當所有的子設備全部被加載完畢之后,.complete() 回調函數就會被調用:

6. 后續任務

還有很多代碼可以分析,比如HDMI RX的驅動、TPG的驅動、m2m的驅動。

編輯:hfy
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Linux
    +關注

    關注

    88

    文章

    11759

    瀏覽量

    219013
  • Xilinx
    +關注

    關注

    73

    文章

    2200

    瀏覽量

    131125
  • 驅動程序
    +關注

    關注

    19

    文章

    869

    瀏覽量

    50457
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    【「Linux 設備驅動開發(第 2 版)」閱讀體驗】Linux內核平臺抽線共和設備驅動程序

    ;&CRG 0xe4 0>; }; 處理SPI和I2C設備尋址 SPI和I2C設備都屬于非內存映射設備,因為它們的地址對CPU來說是不可訪問的,相反,父設備的驅動程序
    發表于 02-03 21:57

    【書籍評測活動NO.67】成為硬核Linux開發者:《Linux 設備驅動開發(第 2 版)》

    ——這便是《Linux 設備驅動開發》。本書從基礎知識出發,分專題透徹講解Linux環境下的設備驅動開發知識,幫助讀者從零構建驅動程序。如今
    發表于 11-17 17:52

    摩爾線程發布圖形顯卡驅動程序v310.120

    8月20日,摩爾線程發布版本號為v310.120的圖形顯卡驅動程序。本次更新帶來多項重大技術升級:新增對Windows 11 24H2版本的正式支持,WDDM驅動同步升級至3.2版本。
    的頭像 發表于 08-21 16:07 ?1377次閱讀

    如何將 GPIO PWM 和 GPIO Capture 驅動程序導入 Linux 內核,實現 PWM 輸出并檢測引腳的變化狀態?

    如何將 GPIO PWM 和 GPIO Capture 驅動程序導入 Linux 內核,實現 PWM 輸出并檢測引腳的變化狀態
    發表于 08-20 08:20

    如何使 ML56-TK 驅動程序適應 Linux 內核?

    如何使 ML56-TK 驅動程序適應 Linux 內核
    發表于 08-20 07:57

    zephyr設備驅動程序模型

    系統中的所有驅動程序。 每種類型的驅動程序(例如 UART、SPI、I2C)都由通用類型 API 支持。 在此模型中,驅動程序驅動程序初始
    的頭像 發表于 07-29 10:34 ?690次閱讀
    zephyr設備<b class='flag-5'>驅動程序</b>模型

    FX3 UVC 無法與 Ubuntu 24.04 Cheese 或 Snapshot 相機應用程序配合使用,怎么處理?

    添加了來自 VLC 的日志以供比較。根據日志,似乎 PipeWire 或 UVC 驅動程序存在一些問題。 我一直在做一些調試,發現對于 Ubuntu 視頻有 3 個類似的控制視頻的組件,V4L2
    發表于 07-16 06:37

    求助,關于55513 Linux驅動程序問題求解

    ; 我們使用 linux 內核 5.4 來構建 fmac 驅動程序,但是當 insmod ko 文件時 brcmfmac 將失敗:brcmfmac:brcmf_sdio_htclk:訪問關閉時鐘失敗
    發表于 07-09 08:02

    摩爾線程發布圖形顯卡驅動程序v300.110.1

    近日,摩爾線程發布版本號為v300.110.1的圖形顯卡驅動程序。本次更新針對近期上市的高人氣游戲《劍星》進行了專項優化,MTT S80在該游戲中的平均幀率提升近80%。
    的頭像 發表于 06-24 18:01 ?1169次閱讀

    ElfBoard技術貼|如何在ELF 2開發板上部署v4l2loopback

    在嵌入式系統開發領域,虛擬視頻設備技術正成為實現多媒體功能創新的關鍵技術支撐。v4l2loopback作為一款功能強大的Linux內核模塊,可以為視頻流處理提供靈活的路由架構,在遠程協作、實時流媒體
    的頭像 發表于 06-05 14:24 ?2083次閱讀
    ElfBoard技術貼|如何在ELF <b class='flag-5'>2</b>開發板上部署<b class='flag-5'>v4l2</b>loopback

    摩爾線程發布圖形顯卡驅動程序v300.110

    近日,摩爾線程發布版本號為v300.110的圖形顯卡驅動程序,為游戲玩家和專業用戶帶來全方位的性能優化與體驗提升,特別在3DMark基準測試工具Steel Nomad中,測試成績顯著提升35%,將MTT S80的性能潛力進一步釋放。
    的頭像 發表于 05-22 17:26 ?1183次閱讀

    摩爾線程Linux驅動v3.0.0發布

    近日,摩爾線程正式推出Linux驅動程序v3.0.0,全面支持圖形顯卡MTT S80和高性能專業顯卡MTT X300。作為v2.7.0RC4之后的重大升級版本,本次更新實現了多項關鍵技
    的頭像 發表于 05-08 11:38 ?1383次閱讀
    摩爾線程<b class='flag-5'>Linux</b><b class='flag-5'>驅動</b><b class='flag-5'>v</b>3.0.0發布

    摩爾線程發布圖形顯卡驅動程序v290.100.2

    近日,摩爾線程發布版本號為v290.100.2的圖形顯卡驅動程序。此次更新在DirectX 12模式下對《巫師3:狂獵》進行了顯著優化,使其游戲平均幀率提升超過80%。同時,新驅動還進一步優化
    的頭像 發表于 04-23 11:20 ?913次閱讀

    Linux環境再升級:PLIN驅動程序正式發布

    PLIN驅動程序現已正式發布,本文將展示如何安裝PLIN驅動程序,以及如何在Linux環境下進行基本的PLIN通信操作,確保您能夠快速掌握并應用這一新工具。
    的頭像 發表于 04-21 15:29 ?1047次閱讀
    <b class='flag-5'>Linux</b>環境再升級:PLIN<b class='flag-5'>驅動程序</b>正式發布

    RTC芯片有Linux PCA2131驅動程序嗎?

    RTC 芯片有 Linux PCA2131驅動程序嗎? 1) 如果沒有,我可以使用任何兼容的驅動程序驅動這個 RTC 芯片嗎? 2) 如果
    發表于 03-31 06:22