日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁 > 嵌入式 > 嵌入式分享
[導(dǎo)讀]Xilinx提供了完整的V4L2的驅(qū)動(dòng)程序,Xilinx V4L2 driver。處于最頂層的驅(qū)動(dòng)程序是V4L2框架的視頻管道(Video pipeline)驅(qū)動(dòng)程序,也叫橋驅(qū)動(dòng)程序(bridge driver),主要代碼在文件xilinx-vipp.c中。在V4L2框架中,整個(gè)視頻管道(Video pipeline)可以通過媒體設(shè)備(/dev/media)配置,流媒體可以通過視頻設(shè)備(/dev/video)控制。這兩種設(shè)備,都是在視頻管道(Video pipeline)驅(qū)動(dòng)程序里創(chuàng)建的。所以,理解V4L2的管道(pipeline)驅(qū)動(dòng)程序是理解Xilinx所有Video IP 在Linux下工作情況的基礎(chǔ)。

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

3. 文件

3.1. C文件

Xilinx的V4L2的管道(pipeline)驅(qū)動(dòng)程序在下面四個(gè)文件中。

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.設(shè)備樹(devicetree)

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

下面是一個(gè)設(shè)備樹(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. 函數(shù)調(diào)用關(guān)系圖

xvipp 函數(shù)調(diào)用關(guān)系圖

4.主要函數(shù)

4.1. 函數(shù)xvip_composite_probe()

函數(shù)xvip_composite_probe是整個(gè)驅(qū)動(dòng)的入口,主要工作是初始化驅(qū)動(dòng)的數(shù)據(jù)結(jié)構(gòu)xvip_composite_device里的通用數(shù)據(jù),包括lock、list(entities和dmas),再調(diào)用了xvip_composite_v4l2_init()和xvip_graph_init(),最后調(diào)用platform_set_drvdata設(shè)置平臺(tái)設(shè)備platform_device里的當(dāng)前設(shè)備的數(shù)據(jù)指針。

4.2. 函數(shù)xvip_composite_v4l2_init()

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

xvip_composite_v4l2_init的關(guān)鍵代碼如下:

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. 函數(shù)xvip_graph_init

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

xvip_graph_init的關(guān)鍵代碼如下:

/* 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. 函數(shù)xvip_graph_dma_init

xvip_graph_dma_init()自身比較簡單,先找到第一個(gè)"ports"子節(jié)點(diǎn),再找其中的所有"port"節(jié)點(diǎn),并為每個(gè)"port"子節(jié)點(diǎn)執(zhí)行xvip_graph_dma_init_one(),從而將每個(gè)"port"子節(jié)點(diǎn)對(duì)應(yīng)的DMA添加到鏈表dmas中。

xvip_graph_dma_init的關(guān)鍵代碼如下:

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. 函數(shù)xvip_graph_dma_init_one

xvip_graph_dma_init_one()根據(jù)設(shè)備樹(devicetree)的"port"子節(jié)點(diǎn)的配置,找到DMA,并添加到鏈表"xdev->dmas"中。

xvip_graph_dma_init_one先讀取"port"子節(jié)點(diǎn)的屬性"direction"和"reg"屬性。Devicetre的"port"節(jié)點(diǎn)中,要含有屬性“direction”和"reg"屬性;如果沒有屬性“direction”,會(huì)返回錯(cuò)誤;如果沒有"reg"屬性,代碼會(huì)繼續(xù),但是功能會(huì)出錯(cuò)。屬性"direction"的值是"input"或者"output"。

xvip_graph_dma_init_one還為每個(gè)port分配struct xvip_dma,再執(zhí)行xvip_dma_init()。

接下來,xvip_graph_dma_init_one把struct xvip_dma加入到隊(duì)列xdev->dmas。

xvip_graph_dma_init_one還根據(jù)"direction"的值是"input"或者"output",以及xvip_is_mplane的設(shè)置,選擇buffer類型。

xvip_graph_dma_init_one的關(guān)鍵代碼如下:

// 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. 函數(shù)xvip_dma_init

xvip_dma_init是核心的函數(shù),完成了最關(guān)鍵的任務(wù):初始化buffer隊(duì)列、申請(qǐng)DMA設(shè)備、注冊(cè)Video設(shè)備。

函數(shù)xvip_dma_init()先初始化struct xvip_dma的數(shù)據(jù)成員,包括dma->lock、dma->pipe.lock、dma->queued_bufs、dma->queued_lock;再根據(jù)buffer類型,初始化v4l2_format里的像數(shù)點(diǎn)格式,struct v4l2_pix_format pix 或者struct v4l2_pix_format_mplane pix_mp。接下來設(shè)置pad.flags為MEDIA_PAD_FL_SINK或者M(jìn)EDIA_PAD_FL_SOURCE,調(diào)用media_entity_pads_init初始化初始化media entity。

函數(shù)xvip_dma_init()然后繼續(xù)初始化video_device的各種成員和操作函數(shù),包括fops、v4l2_dev、queue、vfl_type、vfl_dir、lock、和ioctl_ops。video_device的fops被設(shè)置為xvip_dma_fops,ioctl_ops被設(shè)置為xvip_dma_ioctl_ops。

函數(shù)xvip_dma_init()再接著初始化buffer隊(duì)列struct vb2_queue queue,其中ops被設(shè)置為xvip_dma_queue_qops,mem_ops被設(shè)置為vb2_dma_contig_memops,執(zhí)行vb2_queue_init。

函數(shù)xvip_dma_init()再接著執(zhí)行dma_request_chan申請(qǐng)DMA設(shè)備,這是一個(gè)復(fù)雜和核心的函數(shù)。dma_request_chan()的第二個(gè)參數(shù)是DMA通道的名稱,名字是格式是"port%u",比如"port0",也就是設(shè)備樹的屬性"dma-names"里的字符串。其中of_dma_request_slave_channel()調(diào)用的of_find_property(np, "dmas", NULL),通過屬性"dmas",取得了dma。of_property_count_strings()計(jì)算屬性"dma-names"里的字符串個(gè)數(shù),也就是DMA的個(gè)數(shù)。然后根據(jù)DMA的個(gè)數(shù),為每一個(gè)DMA執(zhí)行of_dma_match_channel()。of_dma_match_channel (dev->of_node, "port%u", )取出"dma-names"的字符串,再和"port%u"對(duì)比,這是檢查名字是否對(duì)應(yīng),如果一致,就用對(duì)應(yīng)的DMA,取得struct of_phandle_args dma_spec,再把struct of_phandle_args dma_spec轉(zhuǎn)換為struct of_dma *ofdma。of_dma_xlate接下來轉(zhuǎn)換為struct dma_chan。of_dma_request_slave_channel使用了字符串"dmas"。of_dma_match_channel()使用了字符串"dmas"和"dma-names"。所以Xilinx-vipp.c實(shí)現(xiàn)的"xlnx,video"設(shè)備的設(shè)備樹里的"dmas"和"dma-names","port0"是必須有的固定字符串,不能更改;只有dmas后面的DMA phandle才可以更改。

函數(shù)xvip_dma_init()最后執(zhí)行video_register_device注冊(cè)Video設(shè)備。

4.7. 函數(shù)xvip_graph_parse

函數(shù)xvip_graph_parse先調(diào)用xvip_graph_parse_one,找到直接的remote_port;然后再為每一個(gè)找到的remote_port執(zhí)行一次xvip_graph_parse_one。

4.8. 函數(shù)xvip_graph_parse_one

xvip_graph_parse_one()里先調(diào)用of_graph_get_next_endpoint(node, ep)取得下一個(gè)endpoint,然后再調(diào)用of_graph_get_remote_port_parent(ep) 得到remote_port的父節(jié)點(diǎn)。of_graph_get_next_endpoint(node, ep)會(huì)先嘗試找子節(jié)點(diǎn)ports,再找到子節(jié)點(diǎn)port,然后再在子節(jié)點(diǎn)port里找endpoint;讀取路徑是 { ports { port {endpoint } } },其中ports是可選的。endpoint是port的子節(jié)點(diǎn),不管其內(nèi)部的屬性名稱,所以也可以用屬性名稱remote-endpoint。of_graph_get_remote_port_parent(ep)通過調(diào)用of_graph_get_remote_endpoint()得到remote_port,再調(diào)用of_graph_get_port_parent()得到父節(jié)點(diǎn)。of_graph_get_remote_endpoint()里讀取了設(shè)備樹里的"remote-endpoint"屬性。

xvip_graph_parse_one()再調(diào)用xvip_graph_find_entity(),在xdev->entities里檢查是否已經(jīng)包含對(duì)應(yīng)的entity,如果已經(jīng)包含,則跳過后續(xù)處理;如果沒沒有,則找到的remote_port的父節(jié)點(diǎn),存放到鏈表xdev->entities,并執(zhí)行操作xdev->num_subdevs++。

最后xdev->entities里包含了所有entity。后來xvip_graph_notify_complet會(huì)根據(jù)xdev->entities,為每個(gè)entity創(chuàng)建一個(gè)設(shè)備。

4.9. 函數(shù)xvip_graph_notify_bound

系統(tǒng)發(fā)現(xiàn)子設(shè)備(subdev)后,調(diào)用異步處理函數(shù)xvip_graph_notify_bound獲取子設(shè)備信息。xvip_graph_notify_bound根據(jù)設(shè)備樹節(jié)點(diǎn),匹配實(shí)體(entity)和子設(shè)備(subdev);匹配成功后,再把子設(shè)備(subdev)的指針保存到實(shí)體(entity)。

xvip_graph_notify_bound的關(guān)鍵代碼如下:

entity->entity = &subdev->entity;

entity->subdev = subdev;

4.10. 函數(shù)xvip_graph_notify_complete

系統(tǒng)所有子設(shè)備(subdev)都被發(fā)現(xiàn)后,Linux會(huì)調(diào)用xvip_graph_notify_complete。xvip_graph_notify_complete調(diào)用xvip_graph_build_one為每個(gè)entity創(chuàng)建Link;調(diào)用xvip_graph_build_dma做Create links for DMA channels;并為每個(gè)實(shí)體(entity)注冊(cè)V4L2子設(shè)備v4l2_device_register_subdev_nodes ;最后調(diào)用media_device_register注冊(cè)media設(shè)備。

4.11. 函數(shù)xvip_graph_build_one

函數(shù)xvip_graph_build_dma在每個(gè)entity及其遠(yuǎn)端模塊之間創(chuàng)建Link。

函數(shù)xvip_graph_build_one先調(diào)用函數(shù)of_graph_get_next_endpoint從設(shè)備的設(shè)備樹里找到下一個(gè)endpoint(struct device_node)。與之前描述一樣,of_graph_get_next_endpoint的讀取路徑是 { ports { port {endpoint} } },endpoint是port的子節(jié)點(diǎn),不管其內(nèi)部的屬性名稱,所以也可以用屬性名稱remote-endpoint。函數(shù)xvip_graph_build_dma接著調(diào)用v4l2_fwnode_parse_link,得到對(duì)應(yīng)的link(struct v4l2_fwnode_link)。接著根據(jù)link中的端口號(hào)(local_port)取得pad信息,判斷出是否是目的端(sink)端口;如果是目的端(sink)端口,則忽略。另外還忽略DMA,它由xvip_graph_build_dma處理。接下來再調(diào)用函數(shù)xvip_graph_find_entity,根據(jù)link中的遠(yuǎn)端節(jié)點(diǎn)(remote_node),得到遠(yuǎn)端的entity。最后調(diào)用media_create_pad_link,當(dāng)前entity作為源端(source),遠(yuǎn)端entity作為目的端(sink)的media_entity和media_pad,創(chuàng)建媒體pad的鏈接(link)

4.12. 函數(shù)xvip_graph_build_dma

函數(shù)xvip_graph_build_dma為DMA模塊及其遠(yuǎn)端模塊之間創(chuàng)建Link。

函數(shù)xvip_graph_build_dma先調(diào)用函數(shù)of_graph_get_next_endpoint從設(shè)備的設(shè)備樹里找到下一個(gè)endpoint(struct device_node)。函數(shù)xvip_graph_build_dma接著調(diào)用v4l2_fwnode_parse_link,得到對(duì)應(yīng)的link(struct v4l2_fwnode_link),根據(jù)link中的端口號(hào)(local_port),找到對(duì)應(yīng)的DMA(struct xvip_dma)。接下來再調(diào)用函數(shù)xvip_graph_find_entity,根據(jù)link中的遠(yuǎn)端節(jié)點(diǎn)(remote_node),得到遠(yuǎn)端的entity。然后設(shè)置源端(source)/目的端(sink)的media_entity和media_pad,最后調(diào)用media_create_pad_link創(chuàng)建媒體pad的鏈接(link)。

4.13. 函數(shù)xvip_graph_find_dma

函數(shù)xvip_graph_build_dma根據(jù)指定的port號(hào),在xdev->dmas里找DMA,如果找到,就返回對(duì)應(yīng)的的struct xvip_dma的指針。

4.14. 函數(shù)xvip_graph_find_entity

函數(shù)xvip_graph_find_entity根據(jù)指定的設(shè)備節(jié)點(diǎn)(struct device_node),在xdev->entities里找entity,如果找到,就返回對(duì)應(yīng)的的struct xvip_graph_entity的指針。

5. 關(guān)鍵數(shù)據(jù)

5.1. subdevs

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

5.2. group ID

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

5.3. xvip_graph_notify_ops

xvip_graph_notify_ops指向bound和complete函數(shù),如果成功匹配設(shè)備,.bound()回調(diào)函數(shù)將會(huì)被調(diào)用,當(dāng)所有的子設(shè)備全部被加載完畢之后,.complete() 回調(diào)函數(shù)就會(huì)被調(diào)用:

6. 后續(xù)任務(wù)

還有很多代碼可以分析,比如HDMI RX的驅(qū)動(dòng)、TPG的驅(qū)動(dòng)、m2m的驅(qū)動(dòng)。

這樣你了解了嗎?

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除( 郵箱:macysun@21ic.com )。
換一批
延伸閱讀

在Zynq MPSoC開發(fā)中,實(shí)現(xiàn)PS端Linux與PL端自定義IP核的AXI互聯(lián)是構(gòu)建高性能異構(gòu)系統(tǒng)的關(guān)鍵環(huán)節(jié)。這種互聯(lián)方式充分發(fā)揮了ARM處理器的軟件優(yōu)勢(shì)與FPGA的硬件加速能力,為復(fù)雜應(yīng)用提供了強(qiáng)大的計(jì)算平臺(tái)。

關(guān)鍵字: Zynq MPSoC Linux

在物聯(lián)網(wǎng)與智能設(shè)備飛速普及的當(dāng)下,嵌入式系統(tǒng)的安全性與穩(wěn)定性愈發(fā)關(guān)鍵。實(shí)時(shí)操作系統(tǒng)(RTOS)憑借其高確定性、低延遲的特性,成為工業(yè)控制、醫(yī)療設(shè)備、航空電子等安全敏感領(lǐng)域的核心支撐。而內(nèi)存保護(hù)單元(MPU)作為硬件級(jí)安全...

關(guān)鍵字: Linux Windows

3月10日消息,2026年開年,一個(gè)名為OpenClaw的開源項(xiàng)目以閃電般的速度席卷了GitHub。它在短短一天內(nèi)就斬獲了9000顆星

關(guān)鍵字: OpenClaw Linux

3月6日消息,在摩根士丹利會(huì)議上,NVIDIA CEO黃仁勛分享了關(guān)于Agentic AI(代理式人工智能)轉(zhuǎn)折點(diǎn)的見解,并將開源軟件OpenClaw評(píng)價(jià)為“當(dāng)代最重磅的軟件發(fā)布”。

關(guān)鍵字: OpenClaw Linux

Linux內(nèi)存管理是操作系統(tǒng)的核心機(jī)制之一,通過虛擬內(nèi)存與物理內(nèi)存的分離設(shè)計(jì),實(shí)現(xiàn)了多進(jìn)程內(nèi)存隔離、高效資源利用和系統(tǒng)穩(wěn)定性保障。

關(guān)鍵字: Linux 內(nèi)存

在Linux系統(tǒng)中,進(jìn)程管理是內(nèi)核的核心功能之一,其核心目標(biāo)是通過高效的調(diào)度機(jī)制和進(jìn)程切換技術(shù),實(shí)現(xiàn)多任務(wù)并發(fā)執(zhí)行。

關(guān)鍵字: Linux CPU

內(nèi)核是操作系統(tǒng)的核心,它作為應(yīng)用程序與硬件設(shè)備之間的"中間人",負(fù)責(zé)進(jìn)程調(diào)度、內(nèi)存管理、硬件通信和系統(tǒng)調(diào)用等關(guān)鍵功能。Linux和Windows作為全球使用最廣泛的兩大操作系統(tǒng),其內(nèi)核設(shè)計(jì)理念、架構(gòu)和運(yùn)行機(jī)制存在本質(zhì)差異...

關(guān)鍵字: Linux Windows

在Linux系統(tǒng)中,當(dāng)開發(fā)者使用mmap()系統(tǒng)調(diào)用將磁盤文件映射到進(jìn)程的虛擬地址空間時(shí),一個(gè)看似簡單的指針操作背后,隱藏著操作系統(tǒng)內(nèi)核與硬件協(xié)同工作的復(fù)雜機(jī)制。這種機(jī)制不僅突破了傳統(tǒng)文件IO的效率瓶頸,更重新定義了內(nèi)存...

關(guān)鍵字: Linux 文件IO 內(nèi)存映射

在Linux驅(qū)動(dòng)開發(fā)領(lǐng)域,持續(xù)集成與持續(xù)部署(CI/CD)流水線通過自動(dòng)化流程將代碼變更快速轉(zhuǎn)化為可靠部署,而KernelCI與LTP測(cè)試套件的深度集成則成為保障驅(qū)動(dòng)穩(wěn)定性的關(guān)鍵技術(shù)組合。本文將從原理分析、應(yīng)用場(chǎng)景及實(shí)現(xiàn)...

關(guān)鍵字: CICD流水線 Linux

在Linux系統(tǒng)中,動(dòng)態(tài)庫(共享庫)是程序運(yùn)行的重要組成部分。當(dāng)程序需要調(diào)用動(dòng)態(tài)庫時(shí),系統(tǒng)必須能夠找到這些庫文件的位置。

關(guān)鍵字: 動(dòng)態(tài)庫 Linux
關(guān)閉