高通msm-V4L2-Camera驅動淺析1-初識

系列文章

高通msm-V4L2-Camera驅動淺析1-初識
高通msm-V4L2-Camera驅動淺析2-框架詳解
高通msm-V4L2-Camera驅動淺析3-session
高通msm-V4L2-Camera驅動淺析4-stream
高通msm-V4L2-Camera驅動淺析5-buffer

前言

V4L2是 linux 設備設計的一套視頻框架纱昧,網(wǎng)上已經(jīng)有很多博文可以研究學習埃脏。
V4L2源碼路徑:kernel/msm-4.9/drivers/media/v4l2-core
閱讀本文之前煌张,需要對V4L2有一定的了解。

推薦一些不錯的V4L2文章
0.V4L2_htjacky的專欄-CSDN博客
1.v4l2的學習建議和流程解析 - silenceer - 博客園 (cnblogs.com)
2.linux內(nèi)核之 V4L2框架分析_zhc的博客-CSDN博客_v4l2 框架
3.深入學習Linux攝像頭(一)v4l2應用編程_JT同學的博客-CSDN博客_v4l2應用編程
4.linux-V4L2系列博客
5.深入理解Android相機體系結構之七_u012596975的博客-CSDN博客

本文希望從一個高通開發(fā)者的角度虏劲,去研究如何使用V4L2架構實現(xiàn)高通的camera功能。
如果你是高通開發(fā)者团秽,你會怎么寫代碼去實現(xiàn)呢疯趟?

一、V4L2架構和一些關鍵結構體

關鍵結構體

  • v4l2_device:用來描述一個v4l2設備實例锡溯,可以包含多個子設備赶舆,對應的是例如 I2C、CSI祭饭、MIPI 等設備芜茵,它們是從屬于一個 V4L2 device 之下的。
  • v4l2_subdev:用來初始化和控制子設備的方法
  • video_device:創(chuàng)建設備節(jié)點/dev/videoX甜癞,用戶空間和內(nèi)核空間溝通的橋梁
  • videobuf2:視頻緩沖的處理
  • v4l2_fh:文件訪問控制
  • v4l2_ctrl_handler:控制模塊夕晓,提供子設備(主要是 video 和 ISP 設備)在用戶空間的特效操作接口
  • media_device:用于運行時數(shù)據(jù)流的管理,嵌入在 V4L2 device 內(nèi)部

**video_device悠咱、v4l2_device和v4l2_subdev的關系


二蒸辆、Camera應該掛在什么總線上征炼?

Linux的設備和驅動通常都要掛在一種總線上,如I2C總線躬贡,USB總線等谆奥,但在Soc系統(tǒng)中集成的獨立外設控制器是不依附于此類總線的,為了統(tǒng)一性拂玻,Linux發(fā)明了一種虛擬總線——platform總線酸些,相應的設備就是platform_device,驅動就是platform_driver。


Camera也屬于一顆集成的Soc檐蚜,它有很多子設備:sensor感光芯片魄懂,eeprom,flash等闯第,通過MIPI傳輸圖像數(shù)據(jù)市栗,通過I2C控制sensor的行為。
因此咳短,Camera 設備屬于platform_device,掛在platform總線上填帽。

假設我是高通的開發(fā)者,那我是不是應該寫一個platform_device咙好,一個platform_driver篡腌,然后調(diào)用platform_driver_register去初始化?

果不其然勾效,讓我們來看看源碼:

  • platform_device

kernel/msm-4.9/arch/arm64/boot/dts/qcom/msm8937-camera.dtsi

&soc {
    qcom,msm-cam@1b00000 {
        compatible = "qcom,msm-cam";
        reg = <0x1b00000 0x40000>;
        reg-names = "msm-cam";
        status = "ok";
        bus-vectors = "suspend", "svs", "nominal", "turbo";
        qcom,bus-votes = <0 160000000 320000000 320000000>;
    };
}
  • platform_driver
    kernel/msm-4.9/drivers/media/platform/msm/camera_v2/msm.c
static const struct of_device_id msm_dt_match[] = {
    {.compatible = "qcom,msm-cam"},
    {}
};
MODULE_DEVICE_TABLE(of, msm_dt_match);

static struct platform_driver msm_driver = {
    .probe = msm_probe,
    .driver = {
        .name = "msm",
        .owner = THIS_MODULE,
        .of_match_table = msm_dt_match,
    },
};
  • platform_driver_register
static int __init msm_init(void)
{
    return platform_driver_register(&msm_driver);
}

static void __exit msm_exit(void)
{
    platform_driver_unregister(&msm_driver);
}
module_init(msm_init);
module_exit(msm_exit);
MODULE_DESCRIPTION("MSM V4L2 Camera");
MODULE_LICENSE("GPL v2");

注冊成功了嘹悼,就可以在sys/bus/platform找到相應的設備和驅動:


platform總線會調(diào)用match函數(shù)去匹配驅動和設備,一旦匹配成功葵第,就會調(diào)用probe函數(shù)绘迁。
一般compatible = "qcom,msm-cam"節(jié)點匹配設備和驅動。

匹配成功了卒密,就會調(diào)用msm_probe函數(shù)去做實現(xiàn)一些功能缀台。

作為開發(fā)者,我應該在msm_probe實現(xiàn)什么功能呢哮奇?platform只是虛擬的膛腐,我們還是要回歸現(xiàn)實。

現(xiàn)實中鼎俘,camera是用來拍照哲身,錄視頻的,
那么我是不是應該把camera定義為一個v4l2_device實例贸伐,
子設備比如sensor勘天,eeprom我就定義為v4l2_subdev,歸v4l2_device統(tǒng)一管理;

同時一個 V4L2 device 下屬可能有非常多同類型的子設備(兩個或者多個 sensor脯丝、ISP 等)商膊,
那么在設備運行的時候我怎么知道我的數(shù)據(jù)流需要用到哪一個類型的哪一個子設備呢。
這個時候就輪到 media_device出手了宠进,它為這一坨的子設備建立一條虛擬的連線晕拆,建立起來一個運行時的 pipeline(管道),并且可以在運行時動態(tài)改變材蹬、管理接入的設備实幕。

另外,如果內(nèi)核空間要和用戶空間溝通堤器,我們還應該初始化 video_device

msm_probe函數(shù)應該完成v4l2_device昆庇,media_device,video_device等相關結構體的初始化工作

三、MSM V4L2 Camera驅動的初始化

3.1 一些V4L2相關變量

kernel/msm-4.9/drivers/media/platform/msm/camera_v2/msm.c

//v4l2_device實例
static struct v4l2_device *msm_v4l2_dev;

static struct v4l2_fh  *msm_eventq;

struct msm_video_device {
    struct video_device *vdev;
    atomic_t opened;
    struct mutex video_drvdata_mutex;
};
struct msm_video_device *pvdev = NULL;

3.2 在msm_probe進行初始化

  • msm_probe
static int msm_probe(struct platform_device *pdev)
{
···省略部分源碼
    struct msm_video_device *pvdev = NULL;
    int rc = 0;

    //為結構體v4l2_device申請內(nèi)存
    msm_v4l2_dev = kzalloc(sizeof(*msm_v4l2_dev),GFP_KERNEL);
    //為結構體msm_video_device申請內(nèi)存吼旧,里面包含video_device結構體
    pvdev = kzalloc(sizeof(struct msm_video_device),GFP_KERNEL);
    //為video_device申請內(nèi)存
    pvdev->vdev = video_device_alloc();

#if defined(CONFIG_MEDIA_CONTROLLER)
    //為media_device申請內(nèi)存
    msm_v4l2_dev->mdev = kzalloc(sizeof(struct media_device),GFP_KERNEL);
    //初始化media_device
    media_device_init(msm_v4l2_dev->mdev);
    //這里 MSM_CONFIGURATION_NAME "msm_config"
    strlcpy(msm_v4l2_dev->mdev->model, MSM_CONFIGURATION_NAME,
            sizeof(msm_v4l2_dev->mdev->model));
    //記錄父設備
    msm_v4l2_dev->mdev->dev = &(pdev->dev);
    //注冊一個媒體設備元素
    rc = media_device_register(msm_v4l2_dev->mdev);

    //初始化硬件設備端口pad
    if (WARN_ON((rc == media_entity_pads_init(&pvdev->vdev->entity,
            0, NULL)) < 0))
        goto entity_fail;

    pvdev->vdev->entity.function = QCAMERA_VNODE_GROUP_ID;
#endif
    //注冊notify回調(diào)函數(shù)凰锡,通常用于子設備傳遞事件,這些事件可以是自定義事件
    msm_v4l2_dev->notify = msm_sd_notify;
    //video_device中記錄msm_v4l2_dev
    pvdev->vdev->v4l2_dev = msm_v4l2_dev;
    //注冊一個v4l2_device實例
    rc = v4l2_device_register(&(pdev->dev), pvdev->vdev->v4l2_dev);
    //v4l2_device實例名稱為"msm-config"
    strlcpy(pvdev->vdev->name, "msm-config", sizeof(pvdev->vdev->name));
    //釋放函數(shù)
    pvdev->vdev->release  = video_device_release;
    //設置v4l2_file_operations
    pvdev->vdev->fops     = &msm_fops;
    //設置ioctl_ops:可以通過設備節(jié)點被用戶空間程序訪問
    pvdev->vdev->ioctl_ops = &g_msm_ioctl_ops;
    //次設備號
    pvdev->vdev->minor     = -1;
    //設備類型
    pvdev->vdev->vfl_type  = VFL_TYPE_GRABBER;
    //注冊一個視頻設備
    rc = video_register_device(pvdev->vdev,VFL_TYPE_GRABBER, -1);
    //初始設備的打開次數(shù)為0
    atomic_set(&pvdev->opened, 0);
    //保存msm_video_device指針信息
    video_set_drvdata(pvdev->vdev, pvdev);
    //申請內(nèi)存
    msm_session_q = kzalloc(sizeof(*msm_session_q), GFP_KERNEL);
    //其他一些相關初始化圈暗,如自旋鎖,等待隊列等待
    msm_init_queue(msm_session_q);
    spin_lock_init(&msm_eventq_lock);
    spin_lock_init(&msm_pid_lock);
    mutex_init(&ordered_sd_mtx);
    mutex_init(&v4l2_event_mtx);
    INIT_LIST_HEAD(&ordered_sd_list);

    return rc;
}
  • 1.為相關結構體分配內(nèi)存
    msm_v4l2_dev = kzalloc(sizeof(*msm_v4l2_dev),GFP_KERNEL);
    pvdev = kzalloc(sizeof(struct msm_video_device),GFP_KERNEL);
    pvdev->vdev = video_device_alloc();

  • 2. 注冊一個媒體設備
    media_device_register(msm_v4l2_dev->mdev);

    media_device結構體有一個model成員裕膀,代表的是:設備型號名稱
    這里我們注冊的媒體設備名稱為:msm_config

    注冊完成之后员串,可以在sys/bus/media/devices/下看到一個media0節(jié)點

  • 3. 注冊一個v4l2_device實例
    v4l2_device_register(&(pdev->dev), pvdev->vdev->v4l2_dev);
    該函數(shù)將會初始化v4l2_device結構體,主要做了如下工作:

    • 初始化管理子設備的雙向鏈表subdevs昼扛,所有注冊到的子設備都需要加入到這個鏈表當中
    • 初始化自旋鎖
    • 初始引用計數(shù)
  • 4.注冊一個視頻設備:video_device
    video_register_device(pvdev->vdev,VFL_TYPE_GRABBER, -1);
    該函數(shù)將會初始化video_device結構體寸齐,主要做了如下工作:

    • 1.檢查設備類型
    • 2.查找空閑的次要節(jié)點、設備節(jié)點號和設備索引
    • 3.初始化字符設備(主設備號為81抄谐,次設備號從0開始)
    • 4.向sysfs注冊設備
類型(type) 名稱(name)
VFL_TYPE_GRABBER video
VFL_TYPE_VBI vbi
VFL_TYPE_RADIO radio
VFL_TYPE_SUBDEV v4l-subdev
VFL_TYPE_SDR swradio
VFL_TYPE_TOUCH v4l-touch

ps: GRABBER在英文中的意思是掠奪者渺鹦,video grabber 即 視頻捕獲器

video_register_device本質上是一個字符設備,注冊完成后,通過如下指令可以查到:

另外蛹含,在sys/class/video4linux/下可以找到我們的設備節(jié)點毅厚。

我們注冊的設備類型為VFL_TYPE_GRABBER,對應的節(jié)點名稱video
第一個注冊的設備從0開始浦箱,以此類推吸耿,因此節(jié)點名稱為video0
視頻設備節(jié)點video0的name為:msm-config
視頻設備節(jié)點video0的主設備號和次設備號為:81:2

同時 udev文件系統(tǒng)會為我們在dev/目錄下創(chuàng)建一個video0節(jié)點,即dev/video0


用戶可以打開dev/video0節(jié)點酷窥,通過IOCTL命令和內(nèi)核空間進行通信咽安。

四、總結

  • camera是一個集成soc蓬推,camera設備掛在platform總線上妆棒,屬于platform_device,相應的驅動是platform_driver.
  • msm_probe函數(shù)完成了v4l2_device,media_device,video_device等相關結構體的初始化工作

本文只寫了msm v4l2驅動是怎么進行初始化的糕珊,一個V4L2驅動應該還要提供其他的功能动分,例如:

  • 數(shù)據(jù)流的創(chuàng)建和刪除:msm_create_stream,msm_delete_stream
  • 會話的創(chuàng)建和刪除:msm_create_session放接,msm_destroy_session
  • 事件分發(fā):msm_post_event等等

Stay hungry刺啦,Stay foolish!

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纠脾,一起剝皮案震驚了整個濱河市玛瘸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌苟蹈,老刑警劉巖糊渊,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異慧脱,居然都是意外死亡渺绒,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門菱鸥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宗兼,“玉大人,你說我怎么就攤上這事氮采∫笊埽” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵鹊漠,是天一觀的道長主到。 經(jīng)常有香客問我,道長躯概,這世上最難降的妖魔是什么登钥? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮娶靡,結果婚禮上牧牢,老公的妹妹穿的比我還像新娘。我一直安慰自己固蛾,他們只是感情好结执,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著艾凯,像睡著了一般献幔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上趾诗,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天蜡感,我揣著相機與錄音蹬蚁,去河邊找鬼。 笑死郑兴,一個胖子當著我的面吹牛犀斋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播情连,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼叽粹,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了却舀?” 一聲冷哼從身側響起虫几,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎挽拔,沒想到半個月后辆脸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡螃诅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年啡氢,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片术裸。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡倘是,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出袭艺,到底是詐尸還是另有隱情辨绊,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布匹表,位于F島的核電站,受9級特大地震影響宣鄙,放射性物質發(fā)生泄漏袍镀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一冻晤、第九天 我趴在偏房一處隱蔽的房頂上張望苇羡。 院中可真熱鬧,春花似錦鼻弧、人聲如沸设江。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽叉存。三九已至,卻和暖如春度帮,著一層夾襖步出監(jiān)牢的瞬間歼捏,已是汗流浹背稿存。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留瞳秽,地道東北人瓣履。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像练俐,于是被迫代替她去往敵國和親袖迎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容