发布: 搭建V853开发环境
BIN
IMX6ULL/doc_pic/13_V4L2/05-2_搭建V853开发环境.tif
Normal file
@@ -7,7 +7,7 @@
|
||||
* 瑞芯微rk3568平台摄像头控制器MIPI-CSI驱动架构梳理:https://zhuanlan.zhihu.com/p/621470492
|
||||
* MIPI、CSI基础:https://zhuanlan.zhihu.com/p/599531271
|
||||
* 全志T7 CSIC模块:https://blog.csdn.net/suwen8100/article/details/116226366
|
||||
* 全志在线文档:https://v853.docs.aw-ol.com/soft/soft_camera/
|
||||
* 全志在线文档:https://v853.docs.aw-ol.com/soft/soft_camera/
|
||||
* 参考源码: https://gitee.com/juping_zheng1/v85x-mediactrl
|
||||
|
||||
|
||||
@@ -111,3 +111,291 @@ D-PHY接口典型图例如下:
|
||||
|
||||
可以跟瑞芯微的对比一下:https://zhuanlan.zhihu.com/p/599531271
|
||||
|
||||
|
||||
|
||||
## 3. 开发环境搭建
|
||||
|
||||
IMX6ULL、STM32MP157上没有MIPI接口,我们使用V853开发板来讲解MIPI驱动。
|
||||
|
||||
要理解MIPI驱动,核心是subdev、media子系统,全网都没有关于它们的详细而系统的文档。而要想理解一个驱动,必须从这2方面学习:APP怎么使用、驱动如何实现。必须去阅读、分析真实板子的驱动,动手操作。
|
||||
|
||||
### 3.1 下载资料
|
||||
|
||||
V853所有资料都汇总于此:https://forums.100ask.net/t/topic/2986
|
||||
|
||||
获取网盘资料后,按照"01_学习手册"目录中的《100ASK-V853-Pro系统开发手册》安装虚拟机VMWare、打开Ubuntu虚拟机,上传解压源码。
|
||||
|
||||
|
||||
|
||||
### 3.2 编译/运行Hello
|
||||
|
||||
有3套工具链:
|
||||
|
||||
```shell
|
||||
cd ~/tina-v853-open/prebuilt/rootfsbuilt/arm
|
||||
find -name "*gcc"
|
||||
```
|
||||
|
||||

|
||||
|
||||
开发板/lib目录的库,来自工具链①,musl的C库比较精简,但是没有glibc完善。编译一般的APP是没问题的,但是编译v4l2-utils时会提示缺乏头文件。
|
||||
|
||||
对于简单的APP,建议使用工具链①:
|
||||
|
||||
对于复杂的APP,如果使用工具链①无法编译,就使用工具链②,它含有glibc要静态链接。
|
||||
|
||||
|
||||
|
||||
使用工具链①:
|
||||
|
||||
```shel
|
||||
export PATH=$PATH:/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/bin
|
||||
export STAGING_DIR=/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/arm-openwrt-linux-muslgnueabi
|
||||
|
||||
arm-openwrt-linux-muslgnueabi-gcc -o hello hello.c
|
||||
```
|
||||
|
||||
|
||||
|
||||
使用工具链②:
|
||||
|
||||
```shell
|
||||
export PATH=$PATH:/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-glibc-gcc-830/toolchain/bin
|
||||
|
||||
export STAGING_DIR=/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-glibc-gcc-830/toolchain/arm-openwrt-linux-gnueabi
|
||||
|
||||
arm-openwrt-linux-gnueabi-gcc -o hello2 hello.c -static
|
||||
```
|
||||
|
||||
|
||||
|
||||
放到板子上去,在Ubuntu执行如下命令:
|
||||
|
||||
```shell
|
||||
adb push hello /root
|
||||
```
|
||||
|
||||
在板子上运行:
|
||||
|
||||
```shell
|
||||
/root/hello
|
||||
```
|
||||
|
||||
|
||||
|
||||
在Ubuntu中无法识别adb设备的解决方法:
|
||||
|
||||
https://blog.csdn.net/xiaowang_lj/article/details/133682416
|
||||
|
||||
```shell
|
||||
sudo vi /etc/udev/rules.d/51-android.rules
|
||||
# 增加如下内容
|
||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="d002",MODE="0666",GROUP="plugdev"
|
||||
|
||||
sudo service udev restart
|
||||
sudo adb kill-server
|
||||
adb devices
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 3.3 更换单板系统
|
||||
|
||||
|
||||
|
||||
#### 3.3.1 重烧系统
|
||||
|
||||
V853开发板出厂自带的系统,里面的文件比如/lib,使用的是musl C库。musl是个精简的C库,功能受限,无法运行v4l-utils。
|
||||
|
||||
我们需要更换系统,新系统使用glibc库,里面已经集成了v41-utils。可以参考"100ASK-V853_Pro系统开发手册.pdf"里《4.5.1 烧录EMMC系统》,烧写GIT仓库里如下文件:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
#### 3.3.2 体验v4l-utils
|
||||
|
||||
在板子上:
|
||||
|
||||
```shell
|
||||
# 先运行camerademo
|
||||
camerademo
|
||||
|
||||
# 否则下面的命令会崩溃
|
||||
media-ctl -p -d /dev/media0
|
||||
media-ctl -d /dev/media0 --print-dot > media0.dot
|
||||
```
|
||||
|
||||
|
||||
|
||||
Ubuntu上:
|
||||
|
||||
```shell
|
||||
sudo apt install xdot
|
||||
adb pull /root/media0.dot
|
||||
dot -Tpng media0.dot -o media0.png
|
||||
```
|
||||
|
||||
|
||||
|
||||
Ubuntu上测试USB摄像头:
|
||||
|
||||
```shell
|
||||
cd ~/v4l-utils-1.20.0
|
||||
./configure
|
||||
make
|
||||
sudo make install
|
||||
|
||||
su root
|
||||
media-ctl -p -d /dev/media0
|
||||
media-ctl -d /dev/media0 --print-dot > uvc_media0.dot
|
||||
dot -Tpng uvc_media0.dot -o uvc_media0.png
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 3.4 自己制作单板系统
|
||||
|
||||
我们的目的是使用v4l-utils,它依赖于glibc库。所以:
|
||||
|
||||
* 步骤1:使用glibc的工具链编译v4l-utils
|
||||
* 步骤2:把编译好的v4l-utils文件放入v853的SDK包里
|
||||
* 步骤3:编译、打包v853映像文件
|
||||
|
||||
#### 3.4.1 编译v4l-utils
|
||||
|
||||
官网:http://linuxtv.org/downloads/v4l-utils
|
||||
|
||||
下载地址:https://linuxtv.org/downloads/v4l-utils/v4l-utils-1.20.0.tar.bz2
|
||||
|
||||
编译命令:
|
||||
|
||||
```shell
|
||||
#export PATH=$PATH:/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/bin
|
||||
#export STAGING_DIR=/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/arm-openwrt-linux-muslgnueabi
|
||||
|
||||
# 使用GLIBC的工具链
|
||||
export PATH=$PATH:/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-glibc-gcc-830/toolchain/bin
|
||||
|
||||
export STAGING_DIR=/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-glibc-gcc-830/toolchain/arm-openwrt-linux-gnueabi
|
||||
|
||||
wget https://linuxtv.org/downloads/v4l-utils/v4l-utils-1.20.0.tar.bz2
|
||||
tar xjf v4l-utils-1.20.0.tar.bz2
|
||||
cd ~/v4l-utils-1.20.0
|
||||
./configure --host=arm-openwrt-linux-gnueabi --prefix=$PWD/tmp --with-udevdir=$PWD/tmp
|
||||
make # 有错也没关系
|
||||
|
||||
make install
|
||||
|
||||
# 在tmp目录下生成了如下文件
|
||||
book@100ask:~/v4l-utils-1.20.0$ ls tmp/
|
||||
bin etc include lib rc_keymaps rules.d sbin share
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 3.4.2 把文件放入SDK
|
||||
|
||||
复制文件:
|
||||
|
||||
```shell
|
||||
#把v4l-utils的tmp/bin, tmp/lib复制到如下目录:
|
||||
# /home/book/tina-v853-open/openwrt/target/v853/v853-100ask/busybox-init-base-files
|
||||
|
||||
cd ~/v4l-utils-1.20.0/tmp
|
||||
cp bin /home/book/tina-v853-open/openwrt/target/v853/v853-100ask/busybox-init-base-files -rf
|
||||
cp lib /home/book/tina-v853-open/openwrt/target/v853/v853-100ask/busybox-init-base-files -rf
|
||||
|
||||
# 删除单板无需使用的文件
|
||||
cd /home/book/tina-v853-open/openwrt/target/v853/v853-100ask/busybox-init-base-files/lib
|
||||
rm *.a
|
||||
rm *.la
|
||||
```
|
||||
|
||||
|
||||
|
||||
修改文件: ~/tina-v853-open/openwrt/package/allwinner/system/busybox-init-base-files/Makefile
|
||||
|
||||
增加以下内容(不增加以下内容的话,在tina-v853-open中make时,会提示找不到依赖文件):
|
||||
|
||||
```shell
|
||||
define Package/$(PKG_NAME)/extra_provides
|
||||
echo 'libstdc++.so.6'
|
||||
endef
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 3.4.3 制作映像
|
||||
|
||||
要自己制作映像文件的话,操作方法如下:
|
||||
|
||||
```shell
|
||||
# 上传SDK,解压得到tina-v853-open目录
|
||||
book@100ask:~$ cat tina-v853-open.tar.gz* | tar xz
|
||||
|
||||
# 下载补丁包
|
||||
book@100ask:~$ git clone https://github.com/DongshanPI/100ASK_V853-PRO_TinaSDK.git
|
||||
book@100ask:~$ cp -rfvd 100ASK_V853-PRO_TinaSDK/* tina-v853-open/
|
||||
book@100ask:~$ cd tina-v853-open/
|
||||
|
||||
# 配置
|
||||
~/tina-v853-open$ source build/envsetup.sh
|
||||
|
||||
# 选择
|
||||
~/tina-v853-open$ lunch
|
||||
ou're building on Linux
|
||||
Lunch menu... pick a combo:
|
||||
1 v853-100ask-tina
|
||||
2 v853-vision-tina
|
||||
Which would you like? [Default v853-100ask]: 1
|
||||
|
||||
# 重新配置使用glibc的工具链
|
||||
~/tina-v853-open$ make menuconfig
|
||||
-> Advanced configuration options (for developers)
|
||||
-> Use external toolchain
|
||||
-> Use host's toolchain
|
||||
-> Toolchain root # 设置为: $(LICHEE_TOP_DIR)/prebuilt/rootfsbuilt/arm/toolchain-sunxi-glibc-gcc-830/toolchain
|
||||
-> Toolchain libc # 选择glibc
|
||||
|
||||
# 编译
|
||||
~/tina-v853-open$ make -j 16
|
||||
|
||||
# 制作映像文件
|
||||
~/tina-v853-open$ pack
|
||||
|
||||
# 提示分区太小
|
||||
ERROR: dl file rootfs.fex size too large
|
||||
ERROR: filename = rootfs.fex
|
||||
ERROR: dl_file_size = 46848 sector
|
||||
ERROR: part_size = 45824 sector
|
||||
update_for_part_info -1
|
||||
ERROR: update mbr file fail
|
||||
ERROR: update_mbr failed
|
||||
|
||||
# 修改分区大小
|
||||
vi ./device/config/chips/v853/configs/100ask/linux-4.9/sys_partition.fex
|
||||
|
||||
[partition]
|
||||
name = rootfs
|
||||
size = 47000 # 从45824改为47000
|
||||
downloadfile = "rootfs.fex"
|
||||
user_type = 0x8000
|
||||
|
||||
# 再重新pack
|
||||
~/tina-v853-open$ pack
|
||||
|
||||
# 得到如下文件:
|
||||
34M /home/book/tina-v853-open/out/v853/100ask/openwrt/v853_linux_100ask_uart0.img
|
||||
```
|
||||
|
||||
配置界面如下图所示:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
IMX6ULL/doc_pic/13_V4L2/media.pdf
Normal file
BIN
IMX6ULL/doc_pic/13_V4L2/pic/57_isp_src1.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/58_isp_src2.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/59_isp_src3.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/01_dts_gc2053.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/02_dts_gc2053_platform_drv.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/03_sensor0_dts.png
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/04_sunxi_mipi_dts.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/05_sunxi_csi_dts.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/06_vin_init.png
Normal file
|
After Width: | Height: | Size: 127 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/07_media0_entity.png
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/08_tdm_dts.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/09_isp_dts.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/10_isp_probe.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/11_sunxi_scaler_dts.png
Normal file
|
After Width: | Height: | Size: 77 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/12_vin_cap_dts.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/13_vin_cap_internal_ops.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/14_toolchain.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/15_v853_image.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/pic/v853/16_menuconfig.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
790806
IMX6ULL/doc_pic/13_V4L2/v853/V853硬件资料/v853-amp-v853s_datasheet_v1.1.pdf
Normal file
139
IMX6ULL/doc_pic/13_V4L2/v853/media0.dot
Normal file
@@ -0,0 +1,139 @@
|
||||
digraph board {
|
||||
rankdir=TB
|
||||
n00000001 [label="{{} | gc2053_mipi\n/dev/v4l-subdev0 | {<port0> 0}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000001:port0 -> n00000023 [style=dashed]
|
||||
n00000001:port0 -> n00000023 [style=dashed]
|
||||
n00000003 [label="vin_cap.0\n/dev/v4l-subdev1", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000003 -> n00000006
|
||||
n00000006 [label="vin_video0\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
|
||||
n0000000a [label="vin_cap.12\n/dev/v4l-subdev2", shape=box, style=filled, fillcolor=yellow]
|
||||
n0000000a -> n0000000d
|
||||
n0000000d [label="vin_video12\n/dev/video12", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000011 [label="sunxi_csi.0\n/dev/v4l-subdev3", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000011 -> n00000017
|
||||
n00000011 -> n00000017
|
||||
n00000014 [label="sunxi_csi.1\n/dev/v4l-subdev4", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000017 [label="sunxi_tdm_rx.0\n/dev/v4l-subdev5", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000017 -> n00000029:port0
|
||||
n00000017 -> n00000029:port0
|
||||
n0000001a [label="sunxi_tdm_rx.1\n/dev/v4l-subdev6", shape=box, style=filled, fillcolor=yellow]
|
||||
n0000001d [label="sunxi_tdm_rx.2\n/dev/v4l-subdev7", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000020 [label="sunxi_tdm_rx.3\n/dev/v4l-subdev8", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000023 [label="sunxi_mipi.0\n/dev/v4l-subdev9", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000023 -> n00000011
|
||||
n00000023 -> n00000011
|
||||
n00000026 [label="sunxi_mipi.1\n/dev/v4l-subdev10", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000029 [label="{{<port0> 0} | sunxi_isp.0\n/dev/v4l-subdev11 | {<port1> 1 | <port2> 2}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000029:port1 -> n0000002d:port0 [style=bold]
|
||||
n00000029:port2 -> n00000047:port0
|
||||
n00000029:port2 -> n0000004a:port0 [style=dashed]
|
||||
n00000029:port2 -> n0000004d:port0 [style=dashed]
|
||||
n00000029:port2 -> n00000050:port0 [style=dashed]
|
||||
n00000029:port2 -> n00000053:port0 [style=dashed]
|
||||
n00000029:port2 -> n00000056:port0 [style=dashed]
|
||||
n00000029:port2 -> n00000059:port0 [style=dashed]
|
||||
n00000029:port2 -> n0000005c:port0 [style=dashed]
|
||||
n00000029:port2 -> n0000005f:port0 [style=dashed]
|
||||
n00000029:port2 -> n00000062:port0 [style=dashed]
|
||||
n00000029:port2 -> n00000065:port0 [style=dashed]
|
||||
n00000029:port2 -> n00000068:port0 [style=dashed]
|
||||
n00000029:port2 -> n0000006b:port0
|
||||
n00000029:port2 -> n0000006e:port0 [style=dashed]
|
||||
n00000029:port2 -> n00000071:port0 [style=dashed]
|
||||
n00000029:port2 -> n00000074:port0 [style=dashed]
|
||||
n0000002d [label="{{<port0> 0} | sunxi_h3a.0\n/dev/v4l-subdev12 | {}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n0000002f [label="{{<port0> 0} | sunxi_isp.1\n/dev/v4l-subdev13 | {<port1> 1 | <port2> 2}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n0000002f:port1 -> n00000033:port0 [style=bold]
|
||||
n0000002f:port2 -> n00000047:port0 [style=dashed]
|
||||
n0000002f:port2 -> n0000004a:port0 [style=dashed]
|
||||
n0000002f:port2 -> n0000004d:port0 [style=dashed]
|
||||
n0000002f:port2 -> n00000050:port0 [style=dashed]
|
||||
n0000002f:port2 -> n00000053:port0 [style=dashed]
|
||||
n0000002f:port2 -> n00000056:port0 [style=dashed]
|
||||
n0000002f:port2 -> n00000059:port0 [style=dashed]
|
||||
n0000002f:port2 -> n0000005c:port0 [style=dashed]
|
||||
n0000002f:port2 -> n0000005f:port0 [style=dashed]
|
||||
n0000002f:port2 -> n00000062:port0 [style=dashed]
|
||||
n0000002f:port2 -> n00000065:port0 [style=dashed]
|
||||
n0000002f:port2 -> n00000068:port0 [style=dashed]
|
||||
n0000002f:port2 -> n0000006b:port0 [style=dashed]
|
||||
n0000002f:port2 -> n0000006e:port0 [style=dashed]
|
||||
n0000002f:port2 -> n00000071:port0 [style=dashed]
|
||||
n0000002f:port2 -> n00000074:port0 [style=dashed]
|
||||
n00000033 [label="{{<port0> 0} | sunxi_h3a.1\n/dev/v4l-subdev14 | {}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000035 [label="{{<port0> 0} | sunxi_isp.2\n/dev/v4l-subdev15 | {<port1> 1 | <port2> 2}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000035:port1 -> n00000039:port0 [style=bold]
|
||||
n00000035:port2 -> n00000047:port0 [style=dashed]
|
||||
n00000035:port2 -> n0000004a:port0 [style=dashed]
|
||||
n00000035:port2 -> n0000004d:port0 [style=dashed]
|
||||
n00000035:port2 -> n00000050:port0 [style=dashed]
|
||||
n00000035:port2 -> n00000053:port0 [style=dashed]
|
||||
n00000035:port2 -> n00000056:port0 [style=dashed]
|
||||
n00000035:port2 -> n00000059:port0 [style=dashed]
|
||||
n00000035:port2 -> n0000005c:port0 [style=dashed]
|
||||
n00000035:port2 -> n0000005f:port0 [style=dashed]
|
||||
n00000035:port2 -> n00000062:port0 [style=dashed]
|
||||
n00000035:port2 -> n00000065:port0 [style=dashed]
|
||||
n00000035:port2 -> n00000068:port0 [style=dashed]
|
||||
n00000035:port2 -> n0000006b:port0 [style=dashed]
|
||||
n00000035:port2 -> n0000006e:port0 [style=dashed]
|
||||
n00000035:port2 -> n00000071:port0 [style=dashed]
|
||||
n00000035:port2 -> n00000074:port0 [style=dashed]
|
||||
n00000039 [label="{{<port0> 0} | sunxi_h3a.2\n/dev/v4l-subdev16 | {}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n0000003b [label="{{<port0> 0} | sunxi_isp.3\n/dev/v4l-subdev17 | {<port1> 1 | <port2> 2}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n0000003b:port1 -> n0000003f:port0 [style=bold]
|
||||
n0000003b:port2 -> n00000047:port0 [style=dashed]
|
||||
n0000003b:port2 -> n0000004a:port0 [style=dashed]
|
||||
n0000003b:port2 -> n0000004d:port0 [style=dashed]
|
||||
n0000003b:port2 -> n00000050:port0 [style=dashed]
|
||||
n0000003b:port2 -> n00000053:port0 [style=dashed]
|
||||
n0000003b:port2 -> n00000056:port0 [style=dashed]
|
||||
n0000003b:port2 -> n00000059:port0 [style=dashed]
|
||||
n0000003b:port2 -> n0000005c:port0 [style=dashed]
|
||||
n0000003b:port2 -> n0000005f:port0 [style=dashed]
|
||||
n0000003b:port2 -> n00000062:port0 [style=dashed]
|
||||
n0000003b:port2 -> n00000065:port0 [style=dashed]
|
||||
n0000003b:port2 -> n00000068:port0 [style=dashed]
|
||||
n0000003b:port2 -> n0000006b:port0 [style=dashed]
|
||||
n0000003b:port2 -> n0000006e:port0 [style=dashed]
|
||||
n0000003b:port2 -> n00000071:port0 [style=dashed]
|
||||
n0000003b:port2 -> n00000074:port0 [style=dashed]
|
||||
n0000003f [label="{{<port0> 0} | sunxi_h3a.3\n/dev/v4l-subdev18 | {}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000041 [label="{{<port0> 0} | sunxi_isp.4\n/dev/v4l-subdev19 | {<port1> 1 | <port2> 2}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000041:port1 -> n00000045:port0 [style=bold]
|
||||
n00000041:port2 -> n00000047:port0 [style=dashed]
|
||||
n00000041:port2 -> n0000004a:port0 [style=dashed]
|
||||
n00000041:port2 -> n0000004d:port0 [style=dashed]
|
||||
n00000041:port2 -> n00000050:port0 [style=dashed]
|
||||
n00000041:port2 -> n00000053:port0 [style=dashed]
|
||||
n00000041:port2 -> n00000056:port0 [style=dashed]
|
||||
n00000041:port2 -> n00000059:port0 [style=dashed]
|
||||
n00000041:port2 -> n0000005c:port0 [style=dashed]
|
||||
n00000041:port2 -> n0000005f:port0 [style=dashed]
|
||||
n00000041:port2 -> n00000062:port0 [style=dashed]
|
||||
n00000041:port2 -> n00000065:port0 [style=dashed]
|
||||
n00000041:port2 -> n00000068:port0 [style=dashed]
|
||||
n00000041:port2 -> n0000006b:port0 [style=dashed]
|
||||
n00000041:port2 -> n0000006e:port0 [style=dashed]
|
||||
n00000041:port2 -> n00000071:port0 [style=dashed]
|
||||
n00000041:port2 -> n00000074:port0 [style=dashed]
|
||||
n00000045 [label="{{<port0> 0} | sunxi_h3a.4\n/dev/v4l-subdev20 | {}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000047 [label="{{<port0> 0} | sunxi_scaler.0\n/dev/v4l-subdev21 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000047:port1 -> n00000003
|
||||
n0000004a [label="{{<port0> 0} | sunxi_scaler.1\n/dev/v4l-subdev22 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n0000004d [label="{{<port0> 0} | sunxi_scaler.2\n/dev/v4l-subdev23 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000050 [label="{{<port0> 0} | sunxi_scaler.3\n/dev/v4l-subdev24 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000053 [label="{{<port0> 0} | sunxi_scaler.4\n/dev/v4l-subdev25 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000056 [label="{{<port0> 0} | sunxi_scaler.5\n/dev/v4l-subdev26 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000059 [label="{{<port0> 0} | sunxi_scaler.6\n/dev/v4l-subdev27 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n0000005c [label="{{<port0> 0} | sunxi_scaler.7\n/dev/v4l-subdev28 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n0000005f [label="{{<port0> 0} | sunxi_scaler.8\n/dev/v4l-subdev29 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000062 [label="{{<port0> 0} | sunxi_scaler.9\n/dev/v4l-subdev30 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000065 [label="{{<port0> 0} | sunxi_scaler.10\n/dev/v4l-subdev31 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000068 [label="{{<port0> 0} | sunxi_scaler.11\n/dev/v4l-subdev32 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n0000006b [label="{{<port0> 0} | sunxi_scaler.12\n/dev/v4l-subdev33 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n0000006b:port1 -> n0000000a
|
||||
n0000006e [label="{{<port0> 0} | sunxi_scaler.13\n/dev/v4l-subdev34 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000071 [label="{{<port0> 0} | sunxi_scaler.14\n/dev/v4l-subdev35 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000074 [label="{{<port0> 0} | sunxi_scaler.15\n/dev/v4l-subdev36 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
}
|
||||
BIN
IMX6ULL/doc_pic/13_V4L2/v853/media0.png
Normal file
|
After Width: | Height: | Size: 161 KiB |
11
IMX6ULL/doc_pic/13_V4L2/v853/uvc_media0.dot
Normal file
@@ -0,0 +1,11 @@
|
||||
digraph board {
|
||||
rankdir=TB
|
||||
n00000001 [label="USB 2.0 Camera: USB 2.0 Camera\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000004 [label="USB 2.0 Camera: USB 2.0 Camera\n/dev/video1", shape=box, style=filled, fillcolor=yellow]
|
||||
n00000008 [label="{{<port0> 0} | Processing 2\n | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n00000008:port1 -> n00000001 [style=bold]
|
||||
n00000008:port1 -> n0000000b:port0 [style=bold]
|
||||
n0000000b [label="{{<port0> 0} | Extension 6\n | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n0000000e [label="{{} | Camera 1\n | {<port0> 0}}", shape=Mrecord, style=filled, fillcolor=green]
|
||||
n0000000e:port0 -> n00000008:port0 [style=bold]
|
||||
}
|
||||
BIN
IMX6ULL/doc_pic/13_V4L2/v853/uvc_media0.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
IMX6ULL/doc_pic/13_V4L2/v853/v853_linux_100ask_uart0_出厂系统.img
Normal file
@@ -486,3 +486,673 @@ v4l2_ioctl_ops.vidioc_prepare_buf
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 5. ISP源码分析
|
||||
|
||||
参考源码: https://gitee.com/juping_zheng1/v85x-mediactrl
|
||||
|
||||

|
||||
|
||||
上图里,只有红框里的函数被调用。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 6. media分析
|
||||
|
||||
参考资料:
|
||||
|
||||
* linux v4l2架构分析——media_device的注册过程分析 https://blog.csdn.net/ismycsdn/article/details/129202760
|
||||
* https://www.linuxtv.org/downloads/v4l-dvb-apis-new/pdf/media.pdf
|
||||
|
||||
|
||||
|
||||
## 7. subdev
|
||||
|
||||
使用:https://blog.csdn.net/qq_34341546/article/details/131129174
|
||||
|
||||
subdev分析比较全面的文章:https://blog.csdn.net/u011037593/article/details/115415136
|
||||
|
||||
linux media子系统分析之media控制器设备:https://zhuanlan.zhihu.com/p/638020445
|
||||
|
||||
内核文档:Linux-4.9.88\Documentation\zh_CN\video4linux\v4l2-framework.txt
|
||||
|
||||
Linux V4L2子系统分析(一): https://blog.csdn.net/u011037593/article/details/115415136
|
||||
|
||||
|
||||
|
||||
主设备可通过v4l2_subdev_call的宏调用从设备提供的方法
|
||||
|
||||
|
||||
|
||||
代码分析参考:
|
||||
|
||||
```shell
|
||||
https://www.cnblogs.com/rongpmcu/p/7662738.html
|
||||
https://www.cnblogs.com/rongpmcu/p/7662741.html
|
||||
https://www.cnblogs.com/rongpmcu/p/7662745.html
|
||||
```
|
||||
|
||||
我的分析:
|
||||
|
||||
```c
|
||||
platform_device: Linux-4.9.88\arch\arm\mach-imx\mach-mx31_3ds.c
|
||||
platform_driver: Linux-4.9.88\drivers\media\platform\soc_camera\soc_camera.c
|
||||
sensor driver: Linux-4.9.88\drivers\media\i2c\soc_camera\ov2640.c
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 8. media
|
||||
|
||||
linux media子系统分析之media控制器设备:https://zhuanlan.zhihu.com/p/638020445
|
||||
|
||||
https://www.kernel.org/doc/html/latest/driver-api/media/mc-core.html
|
||||
|
||||
https://www.kernel.org/doc/html/latest/userspace-api/media/index.html
|
||||
|
||||
【linux kernel】linux media子系统分析之media控制器设备: https://blog.csdn.net/iriczhao/article/details/131276897
|
||||
|
||||
https://docs.kernel.org/driver-api/media/mc-core.html#c.media_device
|
||||
|
||||
|
||||
|
||||
Linux MIPI 摄像头驱动框架编写(RN6752解码芯片): https://www.cnblogs.com/jzcn/p/17823309.html
|
||||
|
||||
Linux Media 子系统链路分析: https://www.cnblogs.com/jzcn/p/17822224.html
|
||||
|
||||
media-ctl调试:生成拓扑和数据流图: https://blog.csdn.net/qq_34341546/article/details/129119359
|
||||
|
||||
|
||||
|
||||
MIPI扫盲——D-PHY介绍(一): https://zhuanlan.zhihu.com/p/638769112?utm_id=0
|
||||
|
||||
|
||||
|
||||
[Linux 基础] -- Linux media 子系统: https://blog.csdn.net/u014674293/article/details/111318314
|
||||
|
||||
|
||||
|
||||
Camera | 3.瑞芯微平台MIPI摄像头常用调试命令 https://zhuanlan.zhihu.com/p/604324755?utm_id=0
|
||||
|
||||
|
||||
|
||||
生成文档:
|
||||
|
||||
```shell
|
||||
sudo apt-get install python3-sphinx
|
||||
cd linux_kernel
|
||||
make htmldocs
|
||||
makd pdfdocs
|
||||
|
||||
生成的文档放在 Documentation/output 文件夹中
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 8.1 基本概念
|
||||
|
||||
参考文档《doc_and_source_for_drivers\IMX6ULL\doc_pic\13_V4L2\media.pdf》之《2.5 Media Controller devices 》
|
||||
|
||||
```shell
|
||||
struct media_device, media_device_register, media_device_unregister
|
||||
|
||||
struct media_entity, The structure is usually embedded into a higher-level structure, such as
|
||||
v4l2_subdev or video_device instances. Drivers initialize entity pads by calling media_entity_pads_init(). Drivers register entities with a media device by calling media_device_register_entity() and unregistered by calling media_device_unregister_entity().
|
||||
|
||||
Interfaces似乎没什么用,给 media_create_intf_link 使用?
|
||||
以后要分析media_ctl打印link的全过程,Interfaces是终点吗?
|
||||
Interfaces are represented by a struct media_interface instance, defined in include/media/
|
||||
media-entity.h. Currently, only one type of interface is defined: a device node. Such interfaces are represented by a struct media_intf_devnode.
|
||||
Drivers initialize and create device node interfaces by calling media_devnode_create() and
|
||||
remove them by calling: media_devnode_remove().
|
||||
|
||||
Pads are represented by a struct media_pad instance, defined in include/media/
|
||||
media-entity.h. Each entity stores its pads in a pads array managed by the entity driver.
|
||||
Drivers usually embed the array in a driver-specific structure.
|
||||
Pads are identified by their entity and their 0-based index in the pads array.
|
||||
Both information are stored in the struct media_pad, making the struct media_pad pointer
|
||||
the canonical way to store and pass link references.
|
||||
Pads have flags that describe the pad capabilities and state.
|
||||
MEDIA_PAD_FL_SINK indicates that the pad supports sinking data. MEDIA_PAD_FL_SOURCE indicates that the pad supports sourcing data.
|
||||
|
||||
Links are represented by a struct media_link instance, defined in include/media/
|
||||
media-entity.h. There are two types of links:
|
||||
1. pad to pad links
|
||||
Drivers create pad to pad links by calling: media_create_pad_link() and remove with
|
||||
media_entity_remove_links().
|
||||
2. interface to entity links
|
||||
Drivers create interface to entity links by calling: media_create_intf_link() and remove with
|
||||
media_remove_intf_links().
|
||||
video_register_device >
|
||||
__video_register_device >
|
||||
video_register_media_controller >
|
||||
media_create_intf_link
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 8.2 Graph traversal
|
||||
|
||||
获得所有的entity:
|
||||
|
||||
```shell
|
||||
media_device_for_each_entity(entity, mdev)
|
||||
```
|
||||
|
||||
|
||||
|
||||
遍历:
|
||||
|
||||
```shell
|
||||
Drivers might also need to iterate over all entities in a graph that can be reached only through
|
||||
enabled links starting at a given entity. The media framework provides a depth-first graph
|
||||
traversal API for that purpose.
|
||||
|
||||
Drivers initiate a graph traversal by calling media_graph_walk_start()
|
||||
The graph structure, provided by the caller, is initialized to start graph traversal at the given entity.
|
||||
Drivers can then retrieve the next entity by calling media_graph_walk_next()
|
||||
When the graph traversal is complete the function will return NULL.
|
||||
|
||||
Helper functions can be used to find a link between two given pads, or a pad
|
||||
connected to another pad through an enabled link media_entity_find_link() and
|
||||
media_entity_remote_pad().
|
||||
|
||||
linux 4.9
|
||||
void media_entity_graph_walk_start(struct media_entity_graph *graph,
|
||||
struct media_entity *entity)
|
||||
linux 5.4
|
||||
void media_graph_walk_start(struct media_graph *graph,
|
||||
struct media_entity *entity)
|
||||
|
||||
Link properties can be modified at runtime by calling media_entity_setup_link()
|
||||
|
||||
When starting streaming, drivers must notify all entities in the pipeline to prevent link states
|
||||
from being modified during streaming by calling media_pipeline_start().
|
||||
Link configuration will fail with -EBUSY by default if either end of the link is a streaming entity.Links that can be modified while streaming must be marked with the MEDIA_LNK_FL_DYNAMIC
|
||||
flag.
|
||||
|
||||
media_device_init initializes the media device prior to its registration. The media device initialization
|
||||
and registration is split in two functions to avoid race conditions and make the media device
|
||||
available to user-space before the media graph has been completed.
|
||||
So drivers need to first initialize the media device, register any entity within the media device, create pad to pad links and then finally register the media device by calling
|
||||
media_device_register() as a final step.
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 9. v853上编译v4l2-utils
|
||||
|
||||
http://linuxtv.org/downloads/v4l-utils
|
||||
|
||||
```shell
|
||||
#export PATH=$PATH:/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/bin
|
||||
|
||||
export PATH=$PATH:/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-glibc-gcc-830/toolchain/bin
|
||||
|
||||
#export STAGING_DIR=/home/book/tina-v853-open/prebuilt/rootfsbuilt/arm/toolchain-sunxi-musl-gcc-830/toolchain/arm-openwrt-linux-muslgnueabi
|
||||
|
||||
sudo apt install autopoint
|
||||
|
||||
cd ~/v4l-utils-1.20.0
|
||||
#./configure --host=arm-openwrt-linux --prefix=$PWD/tmp --with-udevdir=$PWD/tmp
|
||||
./configure --host=arm-openwrt-linux-gnueabi --prefix=$PWD/tmp --with-udevdir=$PWD/tmp LDFLAGS="-static"
|
||||
rm media-ctl
|
||||
make V=1 # 有错也没关系
|
||||
|
||||
# 使用静态链接制作media-ctl
|
||||
cd utils/media-ctl/
|
||||
arm-openwrt-linux-gcc -g -O2 -o media-ctl media-ctl.o options.o ./.libs/libmediactl.a ./.libs/libv4l2subdev.a -static
|
||||
|
||||
make install
|
||||
|
||||
sudo apt install adb
|
||||
|
||||
adb push media-ctl /root
|
||||
|
||||
# 先运行camerademo
|
||||
camerademo
|
||||
# 否则下面的命令会崩溃
|
||||
media-ctl -p -d /dev/media0
|
||||
|
||||
media-ctl -d /dev/media0 --print-dot > media0.dot
|
||||
```
|
||||
|
||||
|
||||
|
||||
Ubuntu上:
|
||||
|
||||
```shell
|
||||
sudo apt install xdot
|
||||
|
||||
dot -Tpng media0.dot -o media0.png
|
||||
```
|
||||
|
||||
|
||||
|
||||
Ubuntu上测试USB摄像头:
|
||||
|
||||
```shell
|
||||
cd ~/v4l-utils-1.20.0
|
||||
./configure
|
||||
make
|
||||
sudo make install
|
||||
|
||||
su root
|
||||
media-ctl -p -d /dev/media0
|
||||
media-ctl -d /dev/media0 --print-dot > uvc_media0.dot
|
||||
dot -Tpng uvc_media0.dot -o uvc_media0.png
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 10. v853驱动分析
|
||||
|
||||
vin.c里注册了一系列的platform_driver:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
这些驱动,对应下图各个entity:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 10.1 sensor
|
||||
|
||||
drivers\media\platform\sunxi-vin\modules\sensor\sensor_helper.c:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
vin.c分析:
|
||||
|
||||
```shell
|
||||
vin_probe
|
||||
vin_md_register_entities(vind, dev->of_node);
|
||||
__vin_register_module(vind, module, j)
|
||||
__vin_subdev_register
|
||||
sd = v4l2_i2c_new_subdev(v4l2_dev, adapter, name, addr, NULL);
|
||||
v4l2_i2c_new_subdev_board
|
||||
client = i2c_new_device(adapter, info); // 导致gc2053_mipi.c的probe被调用
|
||||
|
||||
// i2c_new_device里调用sensor_probe,生成了subdev
|
||||
sd = i2c_get_clientdata(client);
|
||||
v4l2_device_register_subdev(v4l2_dev, sd)
|
||||
|
||||
|
||||
// gc2053_mipi.c的probe被调用
|
||||
sensor_probe
|
||||
info = kzalloc(sizeof(struct sensor_info), GFP_KERNEL);
|
||||
sd = &info->sd;
|
||||
cci_dev_probe_helper(sd, client, &sensor_ops, &cci_drv[i]);
|
||||
v4l2_i2c_subdev_init(sd, client, sensor_ops);
|
||||
i2c_set_clientdata(client, sd);
|
||||
cci_media_entity_init_helper(sd, cci_drv);
|
||||
si->sensor_pads[SENSOR_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
|
||||
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
|
||||
return media_entity_pads_init(&sd->entity, SENSOR_PAD_NUM, si->sensor_pads);
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 10.2 sunxi_mipi
|
||||
|
||||
drivers/media/platform/sunxi-vin/vin-mipi/sunxi_mipi.c
|
||||
|
||||
```c
|
||||
static struct platform_driver mipi_platform_driver = {
|
||||
.probe = mipi_probe,
|
||||
.remove = mipi_remove,
|
||||
.driver = {
|
||||
.name = MIPI_MODULE_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = sunxi_mipi_match,
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
设备树:
|
||||
|
||||

|
||||
|
||||
```shell
|
||||
mipi_probe
|
||||
ret = __mipi_init_subdev(mipi);
|
||||
v4l2_subdev_init(sd, &sunxi_mipi_subdev_ops);
|
||||
|
||||
/*sd->entity->ops = &isp_media_ops;*/
|
||||
mipi->mipi_pads[MIPI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
|
||||
mipi->mipi_pads[MIPI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
|
||||
sd->entity.function = MEDIA_ENT_F_IO_V4L;
|
||||
|
||||
ret = media_entity_pads_init(&sd->entity, MIPI_PAD_NUM, mipi->mipi_pads);
|
||||
```
|
||||
|
||||
上面并没有注册mipi的subdev,在vin.c里:
|
||||
|
||||
```c
|
||||
for (i = 0; i < VIN_MAX_MIPI; i++) {
|
||||
/*Register MIPI subdev */
|
||||
vind->mipi[i].id = i;
|
||||
vind->mipi[i].sd = sunxi_mipi_get_subdev(i);
|
||||
ret = v4l2_device_register_subdev(&vind->v4l2_dev,
|
||||
vind->mipi[i].sd);
|
||||
if (ret < 0)
|
||||
vin_log(VIN_LOG_MD, "mipi%d register fail!\n", i);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 10.3 sunxi_csi
|
||||
|
||||
drivers\media\platform\sunxi-vin\vin-csi\sunxi_csi.c
|
||||
|
||||

|
||||
|
||||
```shell
|
||||
csi_probe
|
||||
__csi_init_subdev(csi);
|
||||
v4l2_subdev_init(sd, &sunxi_csi_subdev_ops);
|
||||
|
||||
csi->csi_pads[CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
|
||||
csi->csi_pads[CSI_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
|
||||
sd->entity.function = MEDIA_ENT_F_IO_V4L;
|
||||
|
||||
ret = media_entity_pads_init(&sd->entity, CSI_PAD_NUM, csi->csi_pads);
|
||||
|
||||
glb_parser[csi->id] = csi;
|
||||
```
|
||||
|
||||
上面并没有注册mipi的subdev,在vin.c里:
|
||||
|
||||
```c
|
||||
for (i = 0; i < VIN_MAX_CSI; i++) {
|
||||
/*Register CSI subdev */
|
||||
vind->csi[i].id = i;
|
||||
vind->csi[i].sd = sunxi_csi_get_subdev(i);
|
||||
ret = v4l2_device_register_subdev(&vind->v4l2_dev,
|
||||
vind->csi[i].sd);
|
||||
if (ret < 0)
|
||||
vin_log(VIN_LOG_MD, "csi%d register fail!\n", i);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 10.4 tdm
|
||||
|
||||
drivers\media\platform\sunxi-vin\vin-tdm\vin_tdm.c
|
||||
|
||||

|
||||
|
||||
```shell
|
||||
tdm_probe
|
||||
ret = __tdm_init_subdev(&tdm->tdm_rx[i]);
|
||||
v4l2_subdev_init(sd, &sunxi_tdm_subdev_ops);
|
||||
sd->grp_id = VIN_GRP_ID_TDM_RX;
|
||||
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
snprintf(sd->name, sizeof(sd->name), "sunxi_tdm_rx.%u", tdm_rx->id);
|
||||
v4l2_set_subdevdata(sd, tdm_rx);
|
||||
|
||||
tdm_rx->tdm_pads[TDM_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
|
||||
tdm_rx->tdm_pads[TDM_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
|
||||
sd->entity.function = MEDIA_ENT_F_IO_V4L;
|
||||
|
||||
ret = media_entity_pads_init(&sd->entity, TDM_PAD_NUM, tdm_rx->tdm_pads);
|
||||
glb_tdm[tdm->id] = tdm;
|
||||
```
|
||||
|
||||
上面并没有注册mipi的subdev,在vin.c里:
|
||||
|
||||
```c
|
||||
for (i = 0; i < VIN_MAX_TDM; i++) {
|
||||
/*Register TDM subdev */
|
||||
vind->tdm[i].id = i;
|
||||
for (j = 0; j < TDM_RX_NUM; j++) {
|
||||
vind->tdm[i].tdm_rx[j].sd = sunxi_tdm_get_subdev(i, j);
|
||||
ret = v4l2_device_register_subdev(&vind->v4l2_dev,
|
||||
vind->tdm[i].tdm_rx[j].sd);
|
||||
if (ret < 0)
|
||||
vin_log(VIN_LOG_MD, "the tdx%d of tdx_rx%d register fail!\n", i, j);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 10.5 sunxi_isp
|
||||
|
||||
drivers/media/platform/sunxi-vin/vin-isp/sunxi_isp.c
|
||||
|
||||

|
||||
|
||||
```shell
|
||||
isp_probe
|
||||
vin_isp_h3a_init
|
||||
v4l2_subdev_init(&stat->sd, &h3a_subdev_ops);
|
||||
snprintf(stat->sd.name, V4L2_SUBDEV_NAME_SIZE, "sunxi_h3a.%u", isp->id);
|
||||
stat->sd.grp_id = VIN_GRP_ID_STAT;
|
||||
stat->sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
v4l2_set_subdevdata(&stat->sd, stat);
|
||||
|
||||
stat->pad.flags = MEDIA_PAD_FL_SINK;
|
||||
stat->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_STATISTICS;
|
||||
|
||||
return media_entity_pads_init(&stat->sd.entity, 1, &stat->pad);
|
||||
|
||||
glb_isp[isp->id] = isp;
|
||||
```
|
||||
|
||||
上面并没有注册mipi的subdev,在vin.c里:
|
||||
|
||||
```c
|
||||
for (i = 0; i < VIN_MAX_ISP; i++) {
|
||||
/*Register ISP subdev */
|
||||
vind->isp[i].id = i;
|
||||
vind->isp[i].sd = sunxi_isp_get_subdev(i);
|
||||
ret = v4l2_device_register_subdev(&vind->v4l2_dev,
|
||||
vind->isp[i].sd);
|
||||
if (ret < 0)
|
||||
vin_log(VIN_LOG_MD, "isp%d register fail!\n", i);
|
||||
#if !defined CONFIG_ISP_SERVER_MELIS
|
||||
/*Register STATISTIC BUF subdev */
|
||||
vind->stat[i].id = i;
|
||||
vind->stat[i].sd = sunxi_stat_get_subdev(i);
|
||||
ret = v4l2_device_register_subdev(&vind->v4l2_dev,
|
||||
vind->stat[i].sd);
|
||||
if (ret < 0)
|
||||
vin_log(VIN_LOG_MD, "stat%d register fail!\n", i);
|
||||
#endif
|
||||
}
|
||||
```
|
||||
|
||||
### 10.6 sunxi_scaler
|
||||
|
||||
drivers\media\platform\sunxi-vin\vin-vipp\sunxi_scaler.c
|
||||
|
||||
```c
|
||||
static const struct of_device_id sunxi_scaler_match[] = {
|
||||
{.compatible = "allwinner,sunxi-scaler",},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver scaler_platform_driver = {
|
||||
.probe = scaler_probe,
|
||||
.remove = scaler_remove,
|
||||
.driver = {
|
||||
.name = SCALER_MODULE_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = sunxi_scaler_match,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||

|
||||
|
||||
```shell
|
||||
scaler_probe
|
||||
__scaler_init_subdev(scaler);
|
||||
v4l2_subdev_init(sd, &sunxi_scaler_subdev_ops);
|
||||
sd->grp_id = VIN_GRP_ID_SCALER;
|
||||
sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
snprintf(sd->name, sizeof(sd->name), "sunxi_scaler.%u", scaler->id);
|
||||
v4l2_set_subdevdata(sd, scaler);
|
||||
|
||||
/*sd->entity->ops = &isp_media_ops;*/
|
||||
scaler->scaler_pads[SCALER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
|
||||
scaler->scaler_pads[SCALER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
|
||||
sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
|
||||
|
||||
ret = media_entity_pads_init(&sd->entity, SCALER_PAD_NUM,
|
||||
scaler->scaler_pads);
|
||||
platform_set_drvdata(pdev, scaler);
|
||||
glb_vipp[scaler->id] = scaler;
|
||||
|
||||
```
|
||||
|
||||
上面并没有注册mipi的subdev,在vin.c里:
|
||||
|
||||
```c
|
||||
for (i = 0; i < VIN_MAX_SCALER; i++) {
|
||||
/*Register SCALER subdev */
|
||||
vind->scaler[i].id = i;
|
||||
vind->scaler[i].sd = sunxi_scaler_get_subdev(i);
|
||||
ret = v4l2_device_register_subdev(&vind->v4l2_dev,
|
||||
vind->scaler[i].sd);
|
||||
if (ret < 0)
|
||||
vin_log(VIN_LOG_MD, "scaler%d register fail!\n", i);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 10.7 vin_cap
|
||||
|
||||
drivers\media\platform\sunxi-vin\vin-video\vin_core.c
|
||||
|
||||
```c
|
||||
static const struct of_device_id sunxi_vin_core_match[] = {
|
||||
{.compatible = "allwinner,sunxi-vin-core",},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver vin_core_driver = {
|
||||
.probe = vin_core_probe,
|
||||
.remove = vin_core_remove,
|
||||
.shutdown = vin_core_shutdown,
|
||||
.driver = {
|
||||
.name = VIN_CORE_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = sunxi_vin_core_match,
|
||||
.pm = &vin_core_runtime_pm_ops,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||

|
||||
|
||||
```shell
|
||||
vin_core_probe
|
||||
ret = vin_initialize_capture_subdev(vinc);
|
||||
struct v4l2_subdev *sd = &vinc->vid_cap.subdev;
|
||||
|
||||
v4l2_subdev_init(sd, &vin_subdev_ops);
|
||||
sd->grp_id = VIN_GRP_ID_CAPTURE;
|
||||
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
snprintf(sd->name, sizeof(sd->name), "vin_cap.%d", vinc->id);
|
||||
|
||||
vinc->vid_cap.sd_pads[VIN_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
|
||||
vinc->vid_cap.sd_pads[VIN_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
|
||||
sd->entity.function = MEDIA_ENT_F_IO_V4L;
|
||||
ret = media_entity_pads_init(&sd->entity, VIN_SD_PADS_NUM,
|
||||
vinc->vid_cap.sd_pads);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sd->entity.ops = &vin_sd_media_ops;
|
||||
sd->internal_ops = &vin_capture_sd_internal_ops;
|
||||
v4l2_set_subdevdata(sd, vinc);
|
||||
|
||||
```
|
||||
|
||||
上面并没有注册mipi的subdev,在vin.c里:
|
||||
|
||||
```c
|
||||
vin_md_register_core_entity
|
||||
sd = &vinc->vid_cap.subdev;
|
||||
v4l2_set_subdev_hostdata(sd, (void *)&vin_pipe_ops);
|
||||
|
||||
ret = v4l2_device_register_subdev(&vind->v4l2_dev, sd);
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 10.8 vin_video0
|
||||
|
||||
drivers/media/platform/sunxi-vin/vin-video/vin_video.c
|
||||
|
||||

|
||||
|
||||
```shell
|
||||
vin_capture_subdev_registered
|
||||
if (vin_init_video(sd->v4l2_dev, &vinc->vid_cap))
|
||||
snprintf(cap->vdev.name, sizeof(cap->vdev.name),
|
||||
"vin_video%d", cap->vinc->id);
|
||||
cap->vdev.fops = &vin_fops;
|
||||
cap->vdev.ioctl_ops = &vin_ioctl_ops;
|
||||
cap->vdev.release = video_device_release_empty;
|
||||
cap->vdev.ctrl_handler = &cap->ctrl_handler;
|
||||
cap->vdev.v4l2_dev = v4l2_dev;
|
||||
cap->vdev.queue = &cap->vb_vidq;
|
||||
cap->vdev.lock = &cap->lock;
|
||||
cap->vdev.flags = V4L2_FL_USES_V4L2_FH;
|
||||
ret = video_register_device(&cap->vdev, VFL_TYPE_GRABBER, cap->vinc->id);
|
||||
|
||||
cap->vd_pad.flags = MEDIA_PAD_FL_SINK;
|
||||
ret = media_entity_pads_init(&cap->vdev.entity, 1, &cap->vd_pad);
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 10.100 疑问
|
||||
|
||||
subdev的v4l2_subdev_ops函数何时被调用?
|
||||
|
||||
sd->internal_ops何时被调用?
|
||||
|
||||
|
||||
|
||||
## 11. 调用过程分析
|
||||
|
||||
### 11.1 link
|
||||
|
||||
|
||||
|
||||
|
||||