Linux DRM開發人員指南
http://landley.net/kdocs/htmldocs/drm.html
Jesse Barnes
Initial version Intel Corporation
<[email protected]>
Laurent Pinchart
Driver internals Ideas on board SPRL
<[email protected]>
Copyright © 2008-2009, 2012 Intel Corporation, Laurent Pinchart
The contents of this file may be used under the terms of the GNU General Public License version 2 (the "GPL") as distributed in the kernel source COPYING file.
Revision History | ||
---|---|---|
Revision 1.0 | 2012-07-13 | LP |
Added extensive documentation about driver internals. |
目錄
1.簡介
2. DRM内部
驅動程式初始化
- 驅動資訊
- 驅動加載
記憶體管理
- 轉換表管理器(TTM)
- 圖形執行管理器(GEM)
模式設定
- 幀緩沖區建立
- 輸出輪詢
- 鎖定
KMS初始化和清理
- CRTC(struct drm_crtc)
- Plane(struct drm_plane)
- Encoder(struct drm_encoder)
- Connector(struct drm_connector)
- 清理
- 輸出發現和初始化示例
- KMS API函數
模式設定幫助函數
- 幫助函數
- CRTC幫助操作
- Encoder幫助操作
- Connector幫助操作
- Modeset幫助程式功能參考
- fbdev幫助程式功能參考
- 顯示端口幫助程式功能參考
- EDID幫助程式功能參考
- 矩形實用程式參考
- 翻轉工作助手參考
- VMA偏移管理器
KMS屬性
V(垂直) blank
打開/關閉,檔案操作和IOCTL
- 打開和關閉
- 檔案操作
- IOCTL
指令送出和防護
睡眠/喚醒
DMA服務
3.使用者接口
渲染節點
VBlank事件處理
A.DRM驅動程式API
第1章簡介
Linux DRM層包含旨在滿足複雜圖形裝置需求的代碼,通常包含非常适合3D圖形加速的可程式設計管線[pipeline]。核心中的圖形驅動程式可以利用DRM功能來簡化諸如記憶體管理,中斷處理和DMA之類的任務,并為應用程式提供統一的接口。
版本說明:本指南涵蓋了DRM樹中的功能,包括TTM記憶體管理器,輸出配置和模式設定以及新的vblank内部,以及目前核心中的所有正常功能。
[在此處插入典型DRM堆棧的圖]
第2章DRM
本章介紹了與驅動程式作者和開發人員相關的DRM内部,這些從業人員和開發人員緻力于為現有驅動程式添加對最新功能的支援。
首先,我們讨論一些典型的驅動程式初始化要求,例如設定指令緩沖區,建立并初始化輸出配置以及初始化核心服務。後續部分将更詳細地介紹核心内部結構,并提供實施說明和示例。
DRM層為圖形驅動程式提供了多種服務,其中許多服務是由它通過libdrm提供的應用程式接口驅動的,libdrm是包裝大多數DRM ioctl的庫。這些包括vblank事件處理,記憶體管理,輸出管理,幀緩沖區管理,指令送出和防護,挂起/恢複支援以及DMA服務。
驅動程式初始化
每個DRM驅動程式的核心都是drm_driver 結構。驅動程式通常會靜态初始化drm_driver結構,然後将其傳遞給
drm_*_init()
函數之一以在DRM子系統中注冊它。
該drm_driver結構包含了描述驅動程式和功能支援,以及指向方法的DRM核心将調用來實作DRM API靜态資訊。我們将首先浏覽drm_driver靜态資訊字段,然後在以後的部分中較長的描述各個操作。
驅動資訊
驅動功能
驅動程式通過在
driver_features
字段中設定适當的标志來告知DRM核心其要求和支援的功能 。由于這些标志自注冊就會影響DRM核心行為,是以必須将大多數标志在注冊drm_driver 執行個體時便設定。高通對應msm_drv.c裡面的msm_driver結構體
u32 driver_features;
驅動程式功能标志
DRIVER_USE_AGP
驅動程式使用AGP接口,DRM核心将管理AGP資源。
DRIVER_REQUIRE_AGP
驅動程式需要AGP接口才能運作。AGP初始化失敗将成為緻命錯誤。
DRIVER_PCI_DMA
驅動程式具有PCI DMA的功能,将啟用PCI DMA緩沖區到使用者空間的映射。不推薦使用。
DRIVER_SG
驅動程式可以執行分散/收集DMA,将啟用分散/收集緩沖區的配置設定和映射。不推薦使用。
DRIVER_HAVE_DMA
驅動程式支援DMA,将支援使用者空間DMA API。不推薦使用。
DRIVER_HAVE_IRQ,DRIVER_IRQ_SHARED
DRIVER_HAVE_IRQ訓示驅動程式是否具有由DRM Core管理的IRQ處理程式。設定該标志後,核心将支援簡單的IRQ處理程式安裝。安裝過程在“ IRQ注冊”一節中介紹。
DRIVER_IRQ_SHARED訓示裝置和處理程式是否支援共享的IRQ(請注意,這是PCI驅動程式所必需的)。
DRIVER_GEM
驅動程式使用GEM記憶體管理器。
DRIVER_MODESET
驅動程式支援模式設定界面(KMS)。
DRIVER_PRIME
驅動程式實作DRM PRIME緩沖區共享。
DRIVER_RENDER
驅動程式支援專用渲染節點。
主要,次要和更新檔級别
int major;
int minor;
int patchlevel;
DRM核心通過主要,次要和更新檔程式級别的三元組來辨別驅動程式版本。該資訊在初始化時被列印到核心日志中,并通過DRM_IOCTL_VERSION ioctl傳遞到使用者空間。
主編号和次編号也用于驗證[應用程式]通過DRM_IOCTL_SET_VERSION的請求的驅動程式API版本。當驅動程式API在次要版本之間更改時,應用程式可以調用DRM_IOCTL_SET_VERSION以選擇特定版本的API。如果請求的主版本不等于驅動程式主版本,或者所請求的次版本大于驅動程式次版本,則DRM_IOCTL_SET_VERSION調用将傳回錯誤。否則,驅動程式的set_version()方法将被調用來設定請求版本。
名稱,說明和日期
char *name;
char *desc;
char *date;
驅動程式名稱在初始化時被列印到核心日志中,用于IRQ注冊,并通過DRM_IOCTL_VERSION傳遞給使用者空間。
驅動程式描述是一個純資訊性的字元串,它通過DRM_IOCTL_VERSION ioctl傳遞給使用者空間,否則不會被核心使用。
驅動程式日期,格式為YYYYMMDD,用于辨別對驅動程式的最新修改日期。但是,由于大多數驅動程式無法更新它,是以它的值幾乎沒有用。DRM核心在初始化時将其列印到核心日志,并通過DRM_IOCTL_VERSION ioctl将其傳遞到使用者空間。
驅動加載
該
load
方法是驅動程式和裝置初始化的入口點。該方法負責配置設定和初始化驅動程式私有資料,指定支援的性能計數器,執行資源配置設定和映射(例如,擷取時鐘,映射寄存器或配置設定指令緩沖區),初始化記憶體管理器(稱為“記憶體管理”的部分),安裝IRQ處理程式(稱為“ IRQ注冊”的部分),設定垂直消隐處理(稱為“垂直消隐” 的部分),模式設定(稱為“ Mode Setting”的部分)和初始輸出配置(稱為“ KMS初始化和清理”部分)。
注意
如果需要考慮相容性(例如,将驅動程式從“使用者模式設定”轉換為“核心模式設定”),則必須注意防止裝置初始化和控制與目前活動的使用者空間驅動程式不相容。例如,如果正在使用使用者級别模式設定驅動程式,則在加載時執行輸出發現和配置會很成問題。同樣,如果使用了不了解記憶體管理的使用者級驅動程式,則可能需要省略記憶體管理和指令緩沖區設定。這些要求是特定于驅動程式的,是以必須注意使新舊應用程式和庫均能正常工作。
int (*load) (struct drm_device *, unsigned long flags);
該方法有兩個參數,一個指向新建立的drm_device的指針 和标志。這些标志用于傳遞裝置id的driver_data字段,該裝置id對應于傳遞給drm_*_init()的裝置。目前隻有PCI裝置使用此方法,USB和平台DRM驅動程式将其
load
方法,參數标志為0。
驅動程式私有和性能計數器
驅動程式私有挂起(隐藏?)了主要的 drm_device結構,可用于跟蹤裝置特定的各種資訊位,例如寄存器偏移,指令緩沖區狀态,用于挂起/恢複的寄存器狀态等。在加載時,驅動程式可以簡單地配置設定并适當地設定一個drm_device.dev_priv;它應該被釋放和drm_device.dev_priv設定為空當驅動程式被解除安裝。
DRM支援幾個用于粗略性能描述的計數器。該統計計數器系統已棄用,不應使用。如果需要性能監視,則開發人員應調查并可能增強核心性能和跟蹤基礎結構,以導出GPU相關的性能資訊,以供性能監視工具和應用程式使用。
IRQ注冊
DRM核心試圖通過提供
drm_irq_install
和
drm_irq_uninstall
功能來促進IRQ處理程式的注冊和登出。這些功能每個裝置僅支援單個中斷,使用多個IRQ的裝置需要手動處理。
管理IRQ注冊
drm_irq_install和
drm_irq_uninstall
都是通過調用函數
drm_dev_to_irq
擷取裝置的IRQ 。此内聯函數将調用特定于總線的操作以檢索IRQ号。對于平台裝置,
platform_get_irq
(...,0)用于檢索IRQ号。
drm_irq_install
通過調用
irq_preinstall
驅動程式操作啟動。該操作是可選的,必須確定在通過清除所有挂起的中斷标志或禁用中斷時不會觸發中斷。
然後,通過調用
request_irq
來請求IRQ。如果設定了DRIVER_IRQ_SHARED驅動功能标志,則将請求共享(IRQF_SHARED)IRQ。
IRQ處理函數必須作為必需的irq_handler驅動程式操作提供。它會直接傳遞給
request_irq
,所有IRQ處理程式相同的原型。他将作為第二個參數被調用,一個指向DRM裝置的指針。
最後,該函數調用可選的
irq_postinstall
驅動程式操作。該操作通常啟用中斷(vblank中斷除外,vblank中斷是單獨啟用的),但是驅動程式可以選擇在其他時間啟用/禁用中斷。
drm_irq_uninstall與drm_irq_install
相似,用于解除安裝IRQ處理程式。首先喚醒所有等待vblank中斷的程序,以確定它們不會挂起,然後調用可選的
irq_uninstall
驅動程式操作。該操作必須禁用所有硬體中斷。最後,該函數通過調用
free_irq
釋放IRQ。
手動IRQ注冊
需要多個中斷處理程式的驅動程式不能使用托管的IRQ注冊功能。在這種情況下,必須手動注冊和登出IRQ(通常使用
request_irq
和
free_irq
函數,或者它們的devm_ *等效項)。
手動注冊IRQ時,驅動程式不得設定DRIVER_HAVE_IRQ驅動程式功能标志,并且不得提供
irq_handler
驅動程式操作。他們必須在注冊IRQ 時将drm_device
irq_enabled
字段設定為1,并在取消注冊IRQ之後将其清除為0。
記憶體管理器初始化
每個DRM驅動程式都需要一個記憶體管理器,必須在加載時對其進行初始化。DRM目前包含兩個記憶體管理器,即轉換表管理器(TTM)和圖形執行管理器(GEM)。本文檔僅描述GEM記憶體管理器的用法。有關詳細資訊,請參見 “記憶體管理”部分。
雜項裝置配置
配置期間PCI裝置可能需要執行的另一項任務是映射視訊BIOS。在許多裝置上,VBIOS描述裝置配置,LCD面闆時鐘(timing)(如果有),并包含訓示裝置狀态的标志。可以使用pci_map_rom()調用完成BIOS映射,pci_map_rom()是一個便捷函數,負責映射實際的ROM,無論該ROM已被隐藏到記憶體中(通常位于位址0xc0000),還是存在于ROM BAR中的PCI裝置上。請注意,在映射ROM并提取了所有必要的資訊之後,應取消映射。在許多裝置上,ROM位址解碼器與其他BAR共享,是以,将其保留為映射狀态可能會導緻不良行為,如挂起或記憶體損壞。
記憶體管理
現代Linux系統需要大量的圖形記憶體來存儲幀緩沖區,紋理,頂點和其他與圖形相關的資料。考慮到許多資料的動态特性,是以有效地管理圖形記憶體對于圖形堆棧至關重要,并且在DRM基礎架構中發揮着核心作用。
DRM核心包括兩個記憶體管理器,即轉換表映射(TTM)和圖形執行管理器(GEM)。TTM是第一個開發的DRM記憶體管理器,并試圖成為一種适用于所有人的解決方案。它提供了一個單一的使用者空間API,可以滿足所有硬體的需求,同時支援統一記憶體體系結構(UMA)裝置和具有專用視訊RAM的裝置(即大多數離散視訊卡)。這導緻了一個龐大,複雜的代碼片段,結果證明這些代碼難以用于驅動程式開發。
GEM最初是由英特爾贊助的項目,以應對TTM的複雜性。它的設計理念是完全不同的:GEM沒有為每個與圖形記憶體相關的問題提供解決方案,而是确定了驅動程式之間的通用代碼,并建立了一個共享它的支援庫。與TTM相比,GEM的初始化和執行要求更簡單,但沒有視訊RAM管理功能,是以僅限于UMA裝置。
轉換表管理器(TTM)
TTM設計背景和資訊屬于此處。
TTM初始化
警告
本節已過時。
希望支援TTM的驅動程式必須填寫drm_bo_driver結構。該結構包含幾個帶有函數指針的字段,這些函數指針用于初始化TTM,配置設定和釋放記憶體,等待指令完成和栅欄同步以及記憶體遷移。有關用法的示例,請參見radeon_ttm.c檔案。
ttm_global_reference結構由幾個字段組成:
struct ttm_global_reference {
enum ttm_global_types global_type;
size_t size;
void *object;
int (*init) (struct ttm_global_reference *);
void (*release) (struct ttm_global_reference *);
};
整個記憶體管理器應該有一個全局引用結構,而記憶體管理器在運作時為每個對象建立的其他引用結構也應有。您的全局TTM應該具有TTM_GLOBAL_TTM_MEM類型。全局對象的大小字段應為sizeof(struct ttm_mem_global),并且init和release鈎子應指向特定于驅動程式的init和release例程,這可能最終分别調用ttm_mem_global_init和ttm_mem_global_release。
通過調用ttm_global_item_ref()設定并初始化全局TTM記帳結構後,您需要建立一個緩沖區對象TTM,以提供一個供用戶端和核心本身配置設定緩沖區池對象。該對象的類型應為TTM_GLOBAL_TTM_BO,其大小應為sizeof(struct ttm_bo_global)。同樣,可以提供特定于驅動程式的初始化和釋放功能,可能最終分别調用ttm_bo_global_init()和ttm_bo_global_release()。同樣,與前一個對象一樣,ttm_global_item_ref()用于為TTM建立初始引用計數,該計數将調用您的初始化函數。
圖形執行管理器(GEM)
GEM設計方法導緻了記憶體管理器無法在其使用者空間或核心API中提供所有(甚至所有常見)用例的完整覆寫。GEM向使用者空間公開了一組與記憶體相關的标準操作,并向驅動程式提供了一組幫助程式功能,并允許驅動程式使用自己的私有API來實作特定于硬體的操作。[承上啟下的中間層]
GEM-“圖形執行管理器”文章中 介紹了GEM使用者空間API 。盡管有些過時,但該文檔很好地概述了GEM API原則。目前,使用特定于驅動程式的ioctl來實作緩沖區配置設定以及讀寫操作(作為通用GEM API的一部分進行描述)。
GEM與資料無關。它管理抽象緩沖區對象,而無需知道各個緩沖區包含哪些内容。是以,需要了解緩沖區内容或用途(例如緩沖區配置設定或同步原語)的API不在GEM的範圍内,必須使用特定于驅動程式的ioctl來實作。
從根本上講,GEM涉及以下幾種操作:
- 記憶體配置設定和釋放
- 指令執行
- 執行指令時的光圈管理//Aperture management at command execution time
緩沖區對象配置設定相對簡單,并且主要由Linux的shmem層提供,後者提供了支援每個對象的記憶體。
特定于裝置的操作(例如指令執行,固定,緩沖區讀和寫,映射和域所有權轉移)留給特定于驅動程式的ioctl。
GEM初始化
使用GEM的驅動程式必須在struct drm_driver
driver_features
字段中設定DRIVER_GEM位 。然後,DRM核心将在調用
load
操作之前自動初始化GEM核心 。在背景,這将建立DRM記憶體管理器對象,該對象提供用于對象配置設定的位址空間池。
在KMS配置中,如果硬體需要,驅動程式需要在核心GEM初始化之後配置設定和初始化指令環緩沖區。UMA裝置通常具有所謂的“被盜”存儲區,該存儲區為初始幀緩沖區和裝置所需的大而連續的存儲區提供了空間。該空間通常不由GEM管理,必須單獨初始化為它自己的DRM MM對象。
GEM對象建立
GEM将GEM對象的建立和支援它們的記憶體配置設定分為兩個不同的操作。
GEM對象由struct drm_gem_object的執行個體表示 。驅動程式通常需要使用私有資訊來擴充GEM對象,進而建立特定于驅動程式的GEM對象結構類型,以嵌入struct drm_gem_object的執行個體 。
要建立GEM對象,驅動程式會為其特定GEM對象類型的執行個體配置設定記憶體,并通過調用drm_gem_object_init來初始化嵌入的結構drm_gem_object。該函數需要指向DRM裝置的指針,指向GEM對象的指針以及緩沖區對象的大小(以位元組為機關)。
GEM使用shmem配置設定匿名可分頁記憶體。
drm_gem_object_init
将建立所需大小的shmfs檔案,并将其存儲到struct drm_gem_object
filp
字段中。當圖形硬體直接使用系統記憶體時,該記憶體可用作對象的主要存儲,否則用作後備存儲。
驅動程式通過調用
shmem_read_mapping_page_gfp
來負責每個頁面實際的實體頁面配置設定。請注意,它們可以在初始化GEM對象時決定配置設定頁面,或者将配置設定延遲到需要記憶體之前(例如,由于使用者空間記憶體通路而導緻頁面錯誤時,或者驅動程式需要啟動涉及記憶體内容的DMA傳輸時)。
例如,當硬體需要實體上連續的系統記憶體時(例如嵌入式裝置中的常見情況),并不總是需要匿名的可分頁記憶體配置設定。驅動程式可以通過調用
drm_gem_private_object_init
代替
drm_gem_object_init
來初始化沒有shmfs支援的GEM對象(稱為私有GEM對象)。專用GEM對象的存儲必須由驅動程式管理。
不需要使用私有資訊擴充GEM對象的驅動程式可以調用
drm_gem_object_alloc
函數來配置設定和初始化struct drm_gem_object 執行個體。用
drm_gem_object_init
初始化GEM對象後,GEM核心将調用可選的驅動程式操作
gem_init_object
。
int (*gem_init_object) (struct drm_gem_object *obj);
私有GEM對象不存在alloc-and-init函數。
GEM對象生命周期
所有GEM對象均由GEM核心引用計數。引用可以分别通過
calling drm_gem_object_reference
和
drm_gem_object_unreference
申請和釋放。調用者必須持有drm_device
struct_mutex
鎖。為友善起見,GEM提供了
drm_gem_object_reference_unlocked
和
drm_gem_object_unreference_unlocked
功能,無需鎖即可調用它們。
當GEM對象的最後一個引用被釋放時,GEM核心将調用drm_driver
gem_free_object
操作。對于啟用GEM的驅動程式,該操作是必需的,并且必須釋放GEM對象和所有相關資源。
void (*gem_free_object) (struct drm_gem_object *obj);
驅動程式負責釋放所有GEM對象資源,包括GEM核心建立的資源。如果已為對象建立了mmap偏移量(在這種情況下 drm_gem_object ::
map_list
::
map
不為NULL),則必須通過調用
drm_gem_free_mmap_offset
釋放它。必須通過調用
drm_gem_object_release
釋放shmfs後備存儲 (如果尚未建立shmfs後備存儲,也可以安全地調用該函數)。
GEM對象命名
使用者空間和核心之間的通信使用本地句柄,全局名稱或更近期使用檔案描述符來引用GEM對象。所有這些都是32位整數值。通常的Linux核心限制适用于檔案描述符。
GEM句柄是DRM檔案。應用程式通過特定于驅動程式的ioctl擷取GEM對象的句柄,并且可以使用該句柄引用其他标準或特定于驅動程式的ioctl中的GEM對象。關閉DRM檔案句柄将釋放其所有GEM句柄并取消引用關聯的GEM對象。
要為GEM對象驅動程式建立句柄,請調用
drm_gem_handle_create
。該函數擷取指向DRM檔案和GEM對象的指針,并傳回本地唯一的句柄。當不再需要該句柄時,驅動程式通過調用
drm_gem_handle_delete
來删除它 。最後,可以通過調用
drm_gem_object_lookup
來檢索與句柄關聯的GEM對象。
句柄不擁有GEM對象的所有權,它們僅引用在句柄銷毀時将被删除的對象上。為避免洩漏GEM對象,驅動程式必須確定适當地删除其擁有的引用(例如在對象建立時擷取的初始引用),而無需對句柄進行任何特殊考慮。例如,在
dumb_create
操作的實作中結合了GEM對象和句柄建立的特定情況下 ,驅動程式必須在傳回句柄之前删除對GEM對象的初始引用。
GEM名稱在用途上類似于句柄,但不是DRM檔案的本地名稱。它們可以在程序之間傳遞,以全局引用GEM對象。名稱不能直接用于引用DRM API中的對象,應用程式必須分别使用DRM_IOCTL_GEM_FLINK和DRM_IOCTL_GEM_OPEN ioctls将句柄轉換為名稱,并将名稱轉換為句柄。轉換是由DRM核心處理的,不需要任何特定于驅動程式的支援。
與全局名稱相似,GEM檔案描述符也用于跨程序共享GEM對象。它們提供了額外的安全性:由于必須通過UNIX域套接字顯式發送檔案描述符以在應用程式之間共享,是以不能像全局唯一的GEM名稱那樣猜測它們。[GEM名稱可以猜測并調用對應api]
支援GEM檔案描述符(也稱為DRM PRIME API)的驅動程式必須在struct drm_driver
driver_features
字段中設定DRIVER_PRIME位 ,并實作
prime_handle_to_fd
和
prime_fd_to_handle
操作。
int (*prime_handle_to_fd)(struct drm_device *dev,
struct drm_file *file_priv, uint32_t handle,
uint32_t flags, int *prime_fd);
int (*prime_fd_to_handle)(struct drm_device *dev,
struct drm_file *file_priv, int prime_fd,
uint32_t *handle);
這兩個操作将句柄轉換為PRIME檔案描述符,反之亦然。驅動程式必須使用核心dma-buf緩沖區共享架構來管理PRIME檔案描述符。
非GEM驅動程式必須自己實作操作,而GEM驅動程式必須使用
drm_gem_prime_handle_to_fd
和
drm_gem_prime_fd_to_handle
幫助程式功能。這些幫助程式依靠驅動程式
gem_prime_export
和
gem_prime_import
操作從GEM對象(dma-buf exporter role)建立dma-buf執行個體,和從dma-buf執行個體(dma-buf importer role)建立GEM對象。
struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
struct drm_gem_object *obj,
int flags);
struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
struct dma_buf *dma_buf);
對于支援DRM PRIME的GEM驅動程式,這兩個操作是必需的。
DRM PRIME輔助功能參考
驅動程式可以使用輔助功能更簡單的API的條款
drm_gem_prime_export
和
drm_gem_prime_import
實作
gem_prime_export
和
gem_prime_import
。這些函數通過五個較低級别的驅動程式回調實作dma-buf支援:
導出回調:
-
gem_prime_pin
(可選):準備要導出的GEM對象
-
gem_prime_get_sg_table
:提供固定頁面的分散/聚集表
-
gem_prime_vmap
:vmap驅動程式導出的緩沖區// vmap a buffer exported by your driver
-
gem_prime_vunmap
:映射驅動程式導出的緩沖區// vunmap a buffer exported by your driver
導入回調:
-
gem_prime_import_sg_table
(導入):從另一個驅動程式的散點圖/聚集表生成GEM對象
GEM對象映射
由于映射操作相當繁重,是以與通過将緩沖區映射到使用者空間相比,GEM更喜歡通過驅動程式特定的ioctl實作對緩沖區的類似于讀/寫的通路。但是,當需要随機通路緩沖區(例如執行軟體渲染)時,直接通路對象可能會更有效率。
mmap系統調用不能直接用于映射GEM對象,因為它們沒有自己的檔案句柄。目前共存在兩種将GEM對象映射到使用者空間的替代方法。第一種方法使用特定于驅動程式的ioctl進行映射操作,調用
do_mmap
在背景進行 。這通常被認為是可疑的,似乎不建議使用支援GEM的新驅動程式,是以在此不再贅述。
第二種方法在DRM檔案句柄上使用mmap系統調用。
void *mmap(void *addr, size_t length, int prot, int flags, int fd,
off_t offset);
DRM通過mmap offset參數傳遞的僞偏移量辨別要映射的GEM對象。是以,在映射之前,GEM對象必須與假偏移量關聯。為此,驅動程式必須在該對象上調用
drm_gem_create_mmap_offset
。該函數從池中配置設定一個假偏移範圍,并将偏移量除以PAGE_SIZE的值存儲在
obj->map_list.hash.key
中。如果已經為該對象配置設定了僞偏移,則必須小心不要調用
drm_gem_create_mmap_offset
。可以通過将
obj->map_list.map
其設定為non-NULL進行測試 。
配置設定後,假偏移值(
obj->map_list.hash.key << PAGE_SHIFT
)必須以特定于驅動程式的方式傳遞給應用程式,然後可以用作mmap offset參數。
GEM核心提供了一種輔助方法
drm_gem_mmap
來處理對象映射。該方法可以直接設定為mmap檔案操作處理程式。它将基于偏移值查找GEM對象,并将VMA操作設定為 drm_driver
gem_vm_ops
字段。請注意,
drm_gem_mmap
這不會将記憶體映射到使用者空間,而是依賴于驅動程式提供的故障處理程式來單獨映射頁面。
要使用
drm_gem_mmap
,驅動程式必須填充struct drm_driver
gem_vm_ops
字段,一個指向VM操作的指針。
struct vm_operations_struct *gem_vm_ops
struct vm_operations_struct {
void (*open)(struct vm_area_struct * area);
void (*close)(struct vm_area_struct * area);
int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf);
};
在
open
與
close
操作中必須更新GEM對象的引用計數。驅動程式可以直接使用
drm_gem_vm_open
和
drm_gem_vm_close
幫助函數作為打開和關閉處理程式。
fault處理程式負責在發生頁面錯誤時将各個頁面映射到使用者空間。根據記憶體配置設定方案,驅動程式可以在故障時配置設定頁面,或者可以在建立對象時決定為GEM對象配置設定記憶體。
想要預先映射GEM對象而不是處理頁面錯誤的驅動程式可以實作自己的mmap檔案操作處理程式。
Dumb GEM對象
GEM API并未标準化GEM對象的建立,而是将其留給特定于驅動程式的ioctl。雖然對于包含特定于裝置的使用者空間元件(例如在libdrm中)的成熟圖形堆棧來說這不是問題,但此限制使基于DRM的early-boot graphics不必要地複雜。
Dumb GEM對象通過提供一個标準API來建立适合于scanout的Dumb緩沖區,進而在一定程度上緩解了這個問題,然後可以使用它來建立KMS幀緩沖區。
為了支援dumb GEM對象程式必須實作
dumb_create
,
dumb_destroy
和
dumb_map_offset
操作。
-
該int (*dumb_create)(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args);
操作根據struct drm_mode_create_dumb 的寬度,高度和深度參數,建立适合于掃描的GEM對象。它用新建立的GEM對象的句柄及其行間距和大小(以位元組為機關)填充參數的句柄、間距和大小字段。dumb_create
-
dumb_destroy操作會銷毀dumb_create建立的dumb GEM對象。int (*dumb_destroy)(struct drm_file *file_priv, struct drm_device *dev, uint32_t handle);
-
該int (*dumb_map_offset)(struct drm_file *file_priv, struct drm_device *dev, uint32_t handle, uint64_t *offset);
操作将mmap僞偏移與該句柄給定的GEM對象相關聯并傳回。驅動程式必須使用dumb_map_offset
函數關聯虛假偏移量,如“ GEM對象映射”一節中 所述。drm_gem_create_mmap_offset
記憶體一緻性
當映射到裝置或在指令緩沖區中使用時,對象的備份頁面将刷新到記憶體中并标記為寫,以便與GPU保持一緻。同樣,如果在GPU完成渲染對象之後CPU通路對象,則必須使對象與CPU的記憶體視圖保持一緻,通常涉及各種GPU緩存重新整理。該CPU <-> GPU一緻性管理重點由特定于裝置的ioctl提供,該ioctl評估對象的目前域并執行任何必要的重新整理或同步操作以将對象放入所需的一緻性域中(請注意,對象可能很忙,即有效的渲染目标;在這種情況下,在執行任何必要的重新整理操作之前,需要設定域阻塞client端并等待渲染完成)。
指令執行
對于GPU裝置來說,最重要的GEM功能可能是為用戶端提供一個指令執行接口。用戶端程式構造包含對先前配置設定的記憶體對象的引用的指令緩沖區,然後将其送出給GEM。那時,GEM會小心地将所有對象綁定到GTT中,執行緩沖區,并在通路相同緩沖區的用戶端之間提供必要的同步。這通常涉及從GTT中清除某些對象并重新綁定其他對象(這是一項相當昂貴的操作),并提供重定位支援,進而向用戶端隐藏了固定的GTT偏移量。用戶端必須注意不要送出引用比GTT中可容納的對象更多的指令緩沖區;否則GEM将拒絕它們,并且不會進行渲染。同樣,如果緩沖區中的多個對象要求配置設定fence寄存器以進行正确渲染(例如965之前的晶片上的2D Blits),則必須注意不要要求比用戶端可用的更多的fence寄存器。這種資源管理應該從libdrm中的用戶端中抽象出來。
模式設定
驅動程式必須通過
drm_mode_config_init
在DRM裝置上調用來初始化模式設定核心 。該函數将初始化drm_device
mode_config
字段,并且永遠不會失敗。完成後,必須通過初始化以下字段來設定模式配置。
-
幀緩沖區的最小和最大寬度和高度,以像素為機關。int min_width, min_height; int max_width, max_height;
-
模式設定函數。struct drm_mode_config_funcs *funcs;
幀緩沖區建立
struct drm_framebuffer *(*fb_create)(struct drm_device *dev,
struct drm_file *file_priv,
struct drm_mode_fb_cmd2 *mode_cmd);
幀緩沖區是抽象的記憶體對象,它提供像素源以掃描到CRTC[framebuffer -> crtc]。應用程式通過ioctl DRM_IOCTL_MODE_ADDFB(2)顯式請求建立幀緩沖區,并接收不透明的句柄,該句柄可以傳遞給KMS CRTC控制器,平面配置和頁面翻轉功能。
幀緩沖區依靠底層記憶體管理器進行低級記憶體操作。在建立幀緩沖區時,應用程式通過參數傳遞記憶體句柄(或一系列記憶體句柄清單用于多平面模式)
drm_mode_fb_cmd2
。本文檔假定驅動程式使用GEM,是以這些句柄将引用GEM對象。
驅動程式必須首先驗證通過mode_cmd傳遞的請求幀緩沖區參數。特别是在這裡可以捕獲無效的尺寸,像素格式或間距。
如果認為這些參數有效,則驅動程式将進行建立,初始化并傳回struct drm_framebuffer的執行個體。如果需要,可以将執行個體嵌入更大的特定于驅動程式的結構中。驅動必須從
drm_mode_fb_cmd2
參數傳遞的值中
填寫的
width
,
height
,
pitches
,
offsets
,
depth
,
bits_per_pixel
和
pixel_format
字段。他們應該調用
drm_helper_mode_fill_fb_struct
輔助函數來實作。
新的幀緩沖區執行個體的初始化通過調用
drm_framebuffer_init
完成,該調用接收指向DRM幀緩沖區操作的指針(結構 drm_framebuffer_funcs)。請注意,此函數釋出了幀緩沖區,是以從這一點出發,可以從其他線程并發通路它。是以,它必須是驅動程式的幀緩沖區初始化序列中的最後一步。幀緩沖區操作是
-
int (*create_handle)(struct drm_framebuffer *fb, struct drm_file *file_priv, unsigned int *handle);
建立用于底層記憶體對象的幀緩沖區的句柄。如果幀緩沖區使用多平面模式,則句柄将引用與第一個平面關聯的記憶體對象。
驅動程式調用
以建立句柄。drm_gem_handle_create
-
銷毀幀緩沖區對象并釋放所有關聯的資源。驅動程式必須調用void (*destroy)(struct drm_framebuffer *framebuffer);
釋放由DRM核心配置設定給幀緩沖區對象的資源,并且必須確定取消與幀緩沖區關聯的所有記憶體對象的引用。由drm_framebuffer_cleanup
操作建立的句柄由 DRM核心釋放。create_handle
-
此可選操作通知驅動程式,在響應DRM_IOCTL_MODE_DIRTYFB ioctl調用時,幀緩沖區的一個區域發生了變化。int (*dirty)(struct drm_framebuffer *framebuffer, struct drm_file *file_priv, unsigned flags, unsigned color, struct drm_clip_rect *clips, unsigned num_clips);
drm幀緩沖區的生命周期由引用計數控制,驅動程式可以使用
drm_framebuffer_reference
擷取額外的引用
然後再用
drm_framebuffer_unreference
删除引用。對于未删除的最後一個引用的驅動程式專用幀緩沖區(例如,将結構drm_framebuffer嵌入fbdev helper結構中時的fbdev幀緩沖區 ),驅動程式可以在子產品解除安裝時使用
drm_framebuffer_unregister_private
手動清除幀緩沖區 。
輸出輪詢
void (*output_poll_changed)(struct drm_device *dev);
此操作通知驅動程式一個或多個連接配接器的狀态已更改。使用fb助手的驅動程式可以調用
drm_fb_helper_hotplug_event
函數來處理此操作。
鎖定
除了一些具有自己的鎖定的查找結構(隐藏在接口功能後面)之外,大多數模式集狀态還受
dev-<mode_config.lock
互斥鎖和per-crtc鎖的保護,以允許光标更新,頁面翻轉和類似操作與背景任務(例如輸出)同時發生檢測。跨域的操作(如完整模式集)始終會抓住所有鎖。驅動程式需要通過額外的鎖定來保護crtcs之間共享的資源。如果modset功能碰到crtc狀态(例如,用于負載檢測(僅抓取
mode_config.lock
允許實時crtc上的并發螢幕更新),則他們還必須小心始終抓住相關的crtc鎖。
KMS初始化和清理
KMS裝置被抽象并公開為一組,平面(panel),CRTC,編碼器(encoder)和連接配接器(connector)。是以,在初始化模式設定之後,KMS驅動程式必須在加載時建立和初始化所有這些對象。
CRTC(結構drm_crtc)
CRTC是表示晶片一部分的抽象,其中包含指向掃描緩沖區的指針。是以,可用的CRTC數量決定了在任何給定時間可以激活多少個獨立的掃描緩沖區。CRTC結構包含幾個字段來支援此操作:指向某些視訊記憶體的指針(抽象為幀緩沖區對象),顯示模式,以及視訊記憶體中的(x,y)偏移量以支援平移或配置,其中一個視訊存儲器跨越多個CRTC。
CRTC初始化
KMS裝置必須建立并注冊至少一個struct drm_crtc執行個體。該執行個體由驅動程式配置設定并歸零(可能是較大結構的一部分),并通過指向CRTC函數的指針
drm_crtc_init
調用進行注冊。
CRTC操作
設定配置
int (*set_config)(struct drm_mode_set *set);
将新的CRTC配置應用于裝置。該配置指定CRTC,要從中掃描的幀緩沖區,幀緩沖區中的(x,y)位置,顯示模式以及與CRTC一起驅動的一組連接配接器。
如果配置中指定的幀緩沖區為NULL,則驅動程式必須分離所有連接配接到CRTC的編碼器和所有連接配接到這些編碼器的連接配接器,并禁用它們。
在保持模式配置鎖定的情況下調用此操作。
注意
FIXME:set_config應該如何與DPMS[顯示器電源管理信号(Display POWER MANAGEMENT Signalling)]互動?如果CRTC被睡眠,是否應該喚醒?
頁面翻轉
int (*page_flip)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event);
将頁面翻轉安排到CRTC的給定幀緩沖區。在保持模式配置互斥鎖的情況下調用此操作。
頁面翻轉是一種同步機制,可以在垂直消隐(vbank,打無效像素點的時候)期間将CRTC掃描出的幀緩沖區替換為新的幀緩沖區,進而避免撕裂。當應用程式請求翻頁時,DRM核心将驗證新的幀緩沖區是否足夠大,以供CRTC在目前配置的模式下進行掃描,然後使用指向新幀緩沖區的指針調用CRTC的
page_flip
操作。
該
page_flip
實作翻頁操作。一旦任何針對新幀緩沖區的等待渲染目标完成,CRTC将重新程式設計為在下一次垂直重新整理後顯示該幀緩沖區。該操作必須立即傳回,而不必等待渲染或頁面翻轉完成,并且必須阻止任何新的渲染到幀緩沖區,直到頁面翻轉完成。
如果可以成功排程頁面翻轉,則驅動程式必須将該
drm_crtc-<fb
字段設定為指向的新幀緩沖區
fb
。這一點很重要,這樣才能使基于幀緩沖區的引用計數保持平衡。
如果頁面翻轉已經挂起,則
page_flip
操作必須傳回-EBUSY。
為了将頁面翻轉同步到垂直消隐,驅動程式可能需要啟用垂直消隐中斷。它應該為此目的而調用
drm_vblank_get
,并在頁面翻轉完成後調用
drm_vblank_put
。
如果應用程式在翻頁完成時請求得到通知,則将使用指向drm_pending_vblank_event執行個體的非空事件參數調用page_flip操作。翻頁完成後,驅動程式必須調用
drm_send_vblank_event
填寫事件并發送,以喚醒所有等待的程序。這可以用
spin_lock_irqsave(&dev->event_lock, flags);
...
drm_send_vblank_event(dev, pipe, event);
spin_unlock_irqrestore(&dev->event_lock, flags);
注意
FIXME:不需要等待渲染完成的驅動程式是否可以将事件添加到
dev->vblank_event_list
,并讓DRM核心處理所有事情,例如“正常的”垂直消隐事件?
在等待頁面翻轉完成時,驅動程式可以自由使用清單頭
event->base.link
,以将pending事件存儲在特定于驅動程式的清單中。
如果在發出事件信号之前關閉了檔案句柄,則驅動程式必須注意在其
preclose
操作中銷毀該事件 (并在需要時調用
drm_vblank_put
)。
混雜操作
-
将給定的CRTC屬性的值設定為void (*set_property)(struct drm_crtc *crtc, struct drm_property *property, uint64_t value);
。有關屬性的更多資訊,請參見“ KMS屬性”一節。value
-
将伽瑪表應用于裝置上。該操作是可選的。void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start, uint32_t size);
-
不再需要時銷毀CRTC。請參閱“ KMS初始化和清理”部分。void (*destroy)(struct drm_crtc *crtc);
Plane(struct drm_plane)
平面表示可以在掃描過程中與CRTC混合或疊加在CRTC頂部的圖像源。平面與幀緩沖區關聯,以裁剪圖像存儲器(源)的一部分,并可以選擇将其縮放到目标大小。然後将結果與CRTC混合或疊加在CRTC之上。
平面初始化
平面是可選的。要建立平面,KMS驅動程式會配置設定struct drm_plane執行個體 (可能是較大結構的一部分)的執行個體并将其清零,并通過調用
drm_plane_init
進行注冊。該函數采用可與平面關聯的CRTC的位掩碼,指向平面函數的指針以及格式支援的格式的清單。
平面操作
-
int (*update_plane)(struct drm_plane *plane, struct drm_crtc *crtc, struct drm_framebuffer *fb, int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h);
使用給定的CRTC和幀緩沖區啟用并配置平面以。
幀緩沖存儲器坐标源矩形由給定
,src_x
,src_y
和src_w
src_h
參數(如16.16固定點值)。不支援亞像素平面坐标的裝置可以忽略小數部分。
CRTC坐标目标矩形由給定
,crtc_x
,crtc_y
和crtc_w
參數(如整數的值)。裝置将源矩形縮放為目标矩形。如果不支援縮放,并且源矩形大小與目标矩形大小不比對,則驅動程式必須傳回-EINVAL錯誤。crtc_h
-
禁用plane。DRM核心調用此方法以響應将幀緩沖區ID設定為0的DRM_IOCTL_MODE_SETPLANE ioctl調用。CRTC不得處理禁用的平面。int (*disable_plane)(struct drm_plane *plane);
-
不再需要時銷毀Plane。請參閱“ KMS初始化和清理”部分。void (*destroy)(struct drm_plane *plane);
編碼器(struct drm_encoder)
編碼器從CRTC擷取像素資料,并将其轉換為适合任何連接配接着的連接配接器的格式。在某些裝置上,CRTC可能會向多個編碼器發送資料。在那種情況下,多個個編碼器都将從同一個掃描緩沖區接收資料,進而導緻跨連接配接到每個編碼器的連接配接器的“克隆”顯示配置。
編碼器初始化
對于CRTC,KMS驅動程式必須建立,初始化和注冊至少一個struct drm_encoder執行個體。該執行個體由驅動程式配置設定并歸零,可能是較大結構的一部分。
驅動程式必須在注冊編碼器之前初始化struct drm_encoder 的
possible_crtcs
和
possible_clones
字段。這兩個字段分别是:編碼器可以連接配接到的CRTC的位掩碼,用于克隆的同級編碼器。
初始化後,必須調用
drm_encoder_init
注冊編碼器 。該函數擷取指向編碼器功能的指針和編碼器類型。支援的類型是
- DRM_MODE_ENCODER_DAC for VGA and analog on DVI-I/DVI-A
- DRM_MODE_ENCODER_TMDS for DVI, HDMI and (embedded) DisplayPort
- DRM_MODE_ENCODER_LVDS for display panels
- DRM_MODE_ENCODER_TVDAC for TV output (Composite, S-Video, Component, SCART)
- DRM_MODE_ENCODER_VIRTUAL for virtual machine displays
編碼器必須連接配接到CRTC才能使用。DRM驅動程式在初始化時不附加編碼器。應用程式(或實作時的fbdev相容性層)負責将其要使用的編碼器附加到CRTC。
編碼器操作
-
在不再需要時調用銷毀編碼器。請參閱 “ KMS初始化和清理”部分。void (*destroy)(struct drm_encoder *encoder);
-
将給定平面屬性的值設定為void (*set_property)(struct drm_plane *plane, struct drm_property *property, uint64_t value);
。有關屬性的更多資訊,請參見“ KMS屬性”一節。value
連接配接器(struct drm_connector)
連接配接器是裝置上像素資料的最終目的地,通常直接連接配接到外部顯示裝置,例如顯示器或筆記本電腦面闆。一個連接配接器一次隻能連接配接到一個編碼器。連接配接器也是保留有關顯示器資訊的附加結構,是以它包含顯示資料,EDID資料,DPMS和連接配接狀态, 以及有關顯示器支援的模式的資訊的字段。
連接配接器初始化
最後,KMS驅動程式必須建立,初始化,注冊并附加至少一個struct drm_connector執行個體。該執行個體将與其他KMS對象一起建立,并通過設定以下字段進行初始化。
interlace_allowed
連接配接器是否可以處理隔行模式。
doublescan_allowed
連接配接器是否可以處理雙重掃描。
display_info
當檢測到顯示時,顯示資訊由EDID資訊填充。對于非熱插拔顯示器(例如嵌入式系統中的平闆),驅動程式應初始化
display_info.
width_mm
和
display_info.
height_mm
,帶有顯示器實際尺寸的字段。
polled
連接配接器輪詢模式,組合以下屬性
DRM_CONNECTOR_POLL_HPD
連接配接器會生成熱插拔事件,不需要定期進行輪詢。不能将CONNECT和DISCONNECT标志與HPD标志一起設定。
DRM_CONNECTOR_POLL_CONNECT
定期輪詢連接配接器以進行連接配接。
DRM_CONNECTOR_POLL_DISCONNECT
定期輪詢連接配接器是否斷開連接配接。
将不支援連接配接狀态發現的連接配接器設定為0。
然後,使用指向連接配接器功能和連接配接器類型的指針調用
drm_connector_init
來注冊該連接配接器,并通過調用
drm_sysfs_connector_add
将其顯示公開到sysfs 。
支援的連接配接器類型為
- DRM_MODE_CONNECTOR_VGA
- DRM_MODE_CONNECTOR_DVII
- DRM_MODE_CONNECTOR_DVID
- DRM_MODE_CONNECTOR_DVIA
- DRM_MODE_CONNECTOR_Composite
- DRM_MODE_CONNECTOR_SVIDEO
- DRM_MODE_CONNECTOR_LVDS
- DRM_MODE_CONNECTOR_Component
- DRM_MODE_CONNECTOR_9PinDIN
- DRM_MODE_CONNECTOR_DisplayPort
- DRM_MODE_CONNECTOR_HDMIA
- DRM_MODE_CONNECTOR_HDMIB
- DRM_MODE_CONNECTOR_TV
- DRM_MODE_CONNECTOR_eDP
- DRM_MODE_CONNECTOR_VIRTUAL
連接配接器必須連接配接到編碼器上才能使用。對于将連接配接器1:1映射至編碼器的裝置,應在初始化時通過調用
drm_mode_connector_attach_encoder
來連接配接該連接配接器 。驅動程式還必須設定drm_connector
encoder
字段為指向附加的編碼器。
最後,驅動程式必須通過調用
drm_kms_helper_poll_init
來初始化連接配接器狀态更改檢測。如果至少一個連接配接器是可輪詢的,但不能生成熱插拔中斷(由DRM_CONNECTOR_POLL_CONNECT和DRM_CONNECTOR_POLL_DISCONNECT連接配接器标志訓示),則延遲的工作将自動排隊以定期輪詢更改。可以生成熱插拔中斷的連接配接器必須改用DRM_CONNECTOR_POLL_HPD标志進行标記,并且它們的中斷處理程式必須調用
drm_helper_hpd_irq_event
。該功能将延遲的工作進行排序,以檢查所有連接配接器的狀态,但不會進行定期輪詢。
連接配接器操作
注意
除非另有說明,否則所有操作都是強制性的。
DPMS
void (*dpms)(struct drm_connector *connector, int mode);
DPMS操作設定連接配接器的電源狀态。模式參數是以下之一
- DRM_MODE_DPMS_ON
- DRM_MODE_DPMS_STANDBY
- DRM_MODE_DPMS_SUSPEND
- DRM_MODE_DPMS_OFF
在除DPMS_ON模式以外的所有模式下,連接配接器所連接配接的編碼器均應通過适當地驅動其信号,将顯示器置于低功耗模式。如果編碼器上連接配接了多個連接配接器,則應注意不要改變其他顯示器的電源狀态。當所有相關的連接配接器都置于低功耗模式時,應将低功耗模式傳播到編碼器和CRTC。[邏輯類似于suspend/resume]
模式
int (*fill_modes)(struct drm_connector *connector, uint32_t max_width,
uint32_t max_height);
用連接配接器支援的所有模式填充模式清單。如果
max_width
和
max_height
參數不為零,則實作必須忽略大于
max_width
或大于
max_height
的所有模式。
連接配接器還必須以連接配接的顯示器實體尺寸(以毫米為機關)填寫其
display_info
width_mm
和
height_mm
字段。如果該值未知或不适用(例如,對于投影儀裝置),則應将字段設定為0。
連接配接狀态
如果支援,則通過輪詢或熱插拔事件更新連接配接狀态(請參閱參考資料
polled
)。狀态值通過ioctls報告給使用者空間,并且不能在驅動程式内部使用,因為狀态值隻能從使用者空間調用
drm_mode_getconnector
來初始化 。
enum drm_connector_status (*detect)(struct drm_connector *connector,
bool force);
檢查連接配接器上是否連接配接了任何東西。force參數在輪詢時設定為false,在根據使用者請求檢查連接配接器時設定為true。在自動探測期間,驅動程式可以使用force來避免昂貴的、破壞性的操作。
如果連接配接器已連接配接東西,則傳回connector_status_connected;如果未連接配接任何東西,則傳回connector_status_disconnected;如果連接配接狀态未知,則傳回connector_status_unknown。
如果連接配接狀态确實被探測為已連接配接,驅動程式應該隻傳回connector_status_connected。無法檢測連接配接狀态或連接配接狀态探測失敗的連接配接器應該傳回connector_status_unknown。
混雜項
-
将給定連接配接器屬性的值設定為void (*set_property)(struct drm_connector *connector, struct drm_property *property, uint64_t value);
。有關屬性 的更多資訊,請參見“ KMS屬性”一節。value
-
不再需要時銷毀連接配接器。請參閱 “ KMS初始化和清理”。void (*destroy)(struct drm_connector *connector);
清理
DRM核心管理其對象的生存周期。當不再需要某個對象時,核心調用其destroy函數,該函數必須清除并釋放為該對象配置設定的所有資源。每個
drm_*_init
調用必須與相應的
drm_*_cleanup
調用相比對,以清理CRTC(
drm_crtc_cleanup
),平面(
drm_plane_cleanup
),編碼器(
drm_encoder_cleanup
)和連接配接器(
drm_connector_cleanup
)。此外,在調用drm_connector_cleanup之前,必須通過調用drm_sysfs_connector_remove來删除添加到sysfs中的連接配接器。
連接配接器狀态更改檢測必須通過調用
drm_kms_helper_poll_fini
進行清理。
輸出發現和初始化示例
void intel_crt_init(struct drm_device *dev)
{
struct drm_connector *connector;
struct intel_output *intel_output;
intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
if (!intel_output)
return;
connector = &intel_output->base;
drm_connector_init(dev, &intel_output->base,
&intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
drm_encoder_init(dev, &intel_output->enc, &intel_crt_enc_funcs,
DRM_MODE_ENCODER_DAC);
drm_mode_connector_attach_encoder(&intel_output->base,
&intel_output->enc);
/* Set up the DDC bus. */
intel_output->ddc_bus = intel_i2c_create(dev, GPIOA, "CRTDDC_A");
if (!intel_output->ddc_bus) {
dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
"failed.\n");
return;
}
intel_output->type = INTEL_OUTPUT_ANALOG;
connector->interlace_allowed = 0;
connector->doublescan_allowed = 0;
drm_encoder_helper_add(&intel_output->enc, &intel_crt_helper_funcs);
drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
drm_sysfs_connector_add(connector);
}
在上面的示例(取自i915驅動程式)中,建立了CRTC,連接配接器和編碼器組合。還建立了特定于裝置的i2c總線,以擷取EDID資料并執行螢幕檢測。完成該過程後,将向sysfs注冊新連接配接器,使其屬性對應用程式可用。
KMS API函數
名稱
drm_modeset_lock_all —擷取所有模式集鎖
概要
void fsfuncdrm_modeset_lock_all ( dev);
struct drm_device * dev;
參數
dev
DRM裝置
描述
此函數具有所有模式集鎖定,适用于尚未實作更細粒度的方案的情況。
名稱
drm_modeset_unlock_all —删除所有模式集鎖
概要
void fsfuncdrm_modeset_unlock_all ( dev);
struct drm_device * dev;
參數
dev
裝置
名稱
drm_warn_on_modeset_not_all_locked —檢查是否已鎖定所有模式設定鎖
概要
void fsfuncdrm_warn_on_modeset_not_all_locked ( dev);
struct drm_device * dev;
參數
dev
裝置
名稱
drm_mode_object_find —查找具有靜态生存期的drm對象
概要
struct drm_mode_object * fsfuncdrm_mode_object_find ( dev,
id,
type);
struct drm_device * dev;
uint32_t id;
uint32_t type;
參數
dev
DRM裝置
id
模式對象的ID
type
模式對象的類型
描述
請注意,framebuffer不能用這個函數查找——因為它們是引用計數的,是以需要特殊處理。
名稱
drm_framebuffer_init —初始化幀緩沖區
概要
int fsfuncdrm_framebuffer_init ( dev,
fb,
funcs);
struct drm_device * dev;
struct drm_framebuffer * fb;
const struct drm_framebuffer_funcs * funcs;
參數
dev
DRM裝置
fb
要初始化的幀緩沖區
funcs
...具有這些功能
描述
為幀緩沖區的父模式對象配置設定一個ID,設定其模式函數和裝置檔案,并将其添加到主fd清單中。
重要
此功能将釋出fb,并使其可供其他使用者并發通路。這意味着此時必須完全設定fb -由于所有fb屬性在其生命周期内都是不變的,是以無需進一步鎖定,而僅需要正确的引用計數即可。
傳回
成功為零,失敗為錯誤代碼。
名稱
drm_framebuffer_lookup —查找drm幀緩沖區并擷取引用
概要
struct drm_framebuffer * fsfuncdrm_framebuffer_lookup ( dev,
id);
struct drm_device * dev;
uint32_t id;
參數
dev
DRM裝置
id
fb對象的ID
描述
如果成功,這将擷取對幀緩沖區的附加引用-調用者需要確定最終再次取消對傳回的幀緩沖區的引用。
名稱
drm_framebuffer_unreference —取消引用幀緩沖區
概要
void fsfuncdrm_framebuffer_unreference ( fb);
struct drm_framebuffer * fb;
參數
fb
幀緩沖區以取消引用
描述
此功能将fb的refcount遞減,并在其降至零時釋放它。
名稱
drm_framebuffer_reference —增加fb引用
概要
void fsfuncdrm_framebuffer_reference ( fb);
struct drm_framebuffer * fb;
參數
fb
幀緩沖區
名稱
drm_framebuffer_unregister_private —查找IDR中登出私有fb
概要
void fsfuncdrm_framebuffer_unregister_private ( fb);
struct drm_framebuffer * fb;
參數
fb
要取消注冊的fb
描述
驅動程式需要在清理驅動程式私有的幀緩沖區時調用它,例如那些用于fbdev的幀緩沖區。請注意,調用者必須持有自己的引用,即對象不能通過這個調用被銷毀(因為它會導緻鎖定反轉)。
名稱
drm_framebuffer_cleanup —删除一個幀緩沖對象
概要
void fsfuncdrm_framebuffer_cleanup ( fb);
struct drm_framebuffer * fb;
參數
fb
要删除幀緩沖區
描述
清理對使用者建立的幀緩沖區的引用。該功能旨在從驅動程式-> destroy回調中使用。
請注意,這個函數并沒有将fb從活動usuage中移除——如果它仍然在任何地方使用,則會出現hilarity,因為使用者空間可以在id上調用getfb并傳回-EINVAL。顯然,不關心驅動程式解除安裝時間。
同樣,不會從查找idr中删除幀緩沖區-對于使用者建立的幀緩沖區,這将在rmfb ioctl中發生。對于驅動程式專用對象(例如,對于fbdev),驅動程式需要顯式調用drm_framebuffer_unregister_private。
名稱
drm_framebuffer_remove —删除和取消引用幀緩沖區對象
概要
void fsfuncdrm_framebuffer_remove (fb);
struct drm_framebuffer * fb;
參數
fb
删除幀緩沖區
描述
在
dev
的mode_config中掃描所有CRTC和平面。如果他們使用
fb
,将其删除,并将其設定為NULL。然後删除對傳入的幀緩沖區的引用。可能會占用模式設定鎖。
請注意,如果調用方持有對幀緩沖區的最後一個引用,則此函數可優化清除操作。在這種情況下,還可以確定不使用模式集鎖定。
名稱
drm_crtc_init —初始化新的CRTC對象
概要
int fsfuncdrm_crtc_init ( dev,
crtc,
funcs);
struct drm_device * dev;
struct drm_crtc * crtc;
const struct drm_crtc_funcs * funcs;
參數
dev
DRM裝置
crtc
需要初始化的CRTC對象
funcs
新CRTC的回調函數
描述
建立一個新對象作為驅動程式crtc對象的基礎部分。
傳回
成功為零,失敗為錯誤代碼。
名稱
drm_crtc_cleanup —清理核心crtc用法
概要
void fsfuncdrm_crtc_cleanup ( crtc);
struct drm_crtc * crtc;
參數
crtc
進行清理的CRTC
描述
此功能清除
crtc
并從DRM模式設定核心中将其删除。請注意,該函數“不會 ”釋放crtc結構本身,這是調用者的責任。
名稱
drm_mode_probed_add —将模式添加到連接配接器的探測模式清單
概要
void fsfuncdrm_mode_probed_add ( connector,
mode);
struct drm_connector * connector;
struct drm_display_mode * mode;
參數
connector
連接配接器新模式
mode
模式資料
描述
添加
mode
到
connector
的模式清單以供以後使用。
名稱
drm_connector_init —初始化預配置設定的連接配接器
概要
int fsfuncdrm_connector_init ( dev,
connector,
funcs,
connector_type);
struct drm_device * dev;
struct drm_connector * connector;
const struct drm_connector_funcs * funcs;
int connector_type;
參數
dev
DRM裝置
connector
初始化連接配接器
funcs
此連接配接器的回調
connector_type
使用者可見的連接配接器類型
描述
初始化預配置設定的連接配接器。連接配接器應細分為驅動程式連接配接器對象的一部分。
傳回
成功為零,失敗為錯誤代碼。
名稱
drm_connector_cleanup —清理一個初始化的連接配接器
概要
void fsfuncdrm_connector_cleanup ( connector);
struct drm_connector * connector;
參數
connector
要清理連接配接器
描述
清理連接配接器,但不釋放對象。
名稱
drm_plane_init —初始化一個新的平面對象
概要
int fsfuncdrm_plane_init ( dev,
plane,
possible_crtcs,
funcs,
formats,
format_count,
priv);
struct drm_device * dev;
struct drm_plane * plane;
unsigned long possible_crtcs;
const struct drm_plane_funcs * funcs;
const uint32_t * formats;
uint32_t format_count;
bool priv;
參數
dev
DRM裝置
plane
平面對象初始化
possible_crtcs
可能的CRTC的位掩碼
funcs
新plane的回調
formats
支援的格式數組(
DRM_FORMAT_
*)
format_count
格式中的元素數
priv
plane是私人的(從使用者空間隐藏)?
描述
初始化一個新對象,該對象建立為驅動程式平面對象的基礎部分。
傳回
成功為零,失敗為錯誤代碼。
名稱
drm_plane_cleanup —清理核心平面的使用
概要
void fsfuncdrm_plane_cleanup ( plane);
struct drm_plane * plane;
參數
plane
準備清理的plane
描述
此功能清除
plane
并從DRM模式設定核心中将其删除。請注意,該函數*不會*釋放平面結構本身,這是調用者的責任。
名稱
drm_plane_force_disable —強制禁用plane
概要
void fsfuncdrm_plane_force_disable ( plane);
struct drm_plane * plane;
參數
plane
準備禁用plane
描述
強制禁用plane。
在銷毀平面的目前幀緩沖區以及恢複fbdev模式時使用。
名稱
drm_mode_create —建立新的顯示模式
概要
struct drm_display_mode * fsfuncdrm_mode_create ( dev);
struct drm_device * dev;
參數
dev
DRM裝置
描述
建立一個新的drm_display_mode,給它一個ID,然後傳回它。
傳回
成功時指向新模式的指針,錯誤時指向NULL。
名稱
drm_mode_destroy —删除模式
概要
void fsfuncdrm_mode_destroy ( dev,
mode);
struct drm_device * dev;
struct drm_display_mode * mode;
參數
dev
DRM裝置
mode
準備删除的模式
描述
釋放
mode
的唯一辨別符,然後釋放它。
名稱
drm_mode_create_dvi_i_properties —建立特定于DVI-I的連接配接器屬性
概要
int fsfuncdrm_mode_create_dvi_i_properties ( dev);
struct drm_device * dev;
參數
dev
DRM裝置
描述
第一次建立DVI-I連接配接器時由驅動程式調用。
名稱
drm_mode_create_tv_properties —建立TV特定的連接配接器屬性
概要
int fsfuncdrm_mode_create_tv_properties ( dev,
num_modes,
modes[]);
struct drm_device * dev;
int num_modes;
char * modes[];
參數
dev
DRM裝置
num_modes
支援的不同TV格式(模式)的數量
modes[]
包含每種格式名稱的字元串的指針數組
描述
由驅動的TV初始化例程調用,此函數為給定裝置建立TV特定的連接配接器屬性。調用者負責配置設定格式名稱清單,并将其傳遞給此例程。
名稱
drm_mode_create_scaling_mode_property-建立縮放模式屬性
概要
int fsfuncdrm_mode_create_scaling_mode_property ( dev);
struct drm_device * dev;
參數
dev
DRM裝置
描述
第一次需要時由驅動程式調用,必須将其連接配接到所需的連接配接器。
名稱
drm_mode_create_dirty_info_property-建立髒屬性
概要
int fsfuncdrm_mode_create_dirty_info_property ( dev);
struct drm_device * dev;
參數
dev
DRM裝置
描述
第一次需要時由驅動程式調用,必須将其連接配接到所需的連接配接器。
名稱
drm_mode_set_config_internal —輔助調用-> set_config函數
概要
int fsfuncdrm_mode_set_config_internal (set);
struct drm_mode_set * set;
參數
set
模式設定配置
描述
這是一個小助手包裝内部調用到->set_config驅動程式接口。
名稱
drm_format_num_planes —擷取指定格式的平面數
概要
int fsfuncdrm_format_num_planes (format);
uint32_t format;
參數
format
像素格式(DRM_FORMAT_ *)
傳回
指定的像素格式使用的平面數。
名稱
drm_format_plane_cpp —确定每個像素的位元組值
概要
int fsfuncdrm_format_plane_cpp (format,
plane);
uint32_t format;
int plane;
參數
format
像素格式(DRM_FORMAT_ *)
plane
平面索引
傳回
指定平面的每個像素的位元組值。
名稱
drm_format_horz_chroma_subsampling —擷取水準色度子采樣因子
概要
int fsfuncdrm_format_horz_chroma_subsampling (format);
uint32_t format;
參數
format
像素格式(DRM_FORMAT_ *)
傳回
指定像素格式的水準色度子采樣因子。
名稱
drm_format_vert_chroma_subsampling —擷取垂直色度子采樣因子
概要
int fsfuncdrm_format_vert_chroma_subsampling (format);
uint32_t format;
參數
format
像素格式(DRM_FORMAT_ *)
傳回
指定像素格式的垂直色度子采樣因子。
名稱
drm_mode_config_init —初始化DRM mode_configuration結構
概要
void fsfuncdrm_mode_config_init (dev);
struct drm_device * dev;
參數
dev
DRM裝置
描述
初始化
dev
的mode_config結構,用于跟蹤的圖形配置
dev
。
由于這會初始化模式集鎖定,是以無法進行鎖定。因為這應該在單線程時初始化,是以沒有問題,確定安全是驅動的問題。
名稱
drm_mode_config_cleanup-釋放DRM mode_config資訊
概要
void fsfuncdrm_mode_config_cleanup (dev);
struct drm_device * dev;
參數
dev
DRM裝置
描述
釋放與此DRM裝置關聯的所有連接配接器和CRTC,然後釋放幀緩沖區和關聯的緩沖區對象。
請注意,由于驅動/裝置拆卸/應該/在單線程時操作,,是以不需要鎖定。確定這項操作正确是驅動的工作。
FIXME
tongshi 清理所有懸空的使用者緩沖區對象
模式設定助手功能
驅動程式提供DRM API實作CRTC,編碼器和連接配接器的功能。它們(DRM_API)由DRM核心和ioctl處理程式調用以處理裝置狀态更改和配置請求。由于實作這些功能通常需要特定于驅動程式的邏輯,是以可以使用中間層幫助程式功能來避免重複樣闆代碼。
DRM核心包含一個中間層實作。中間層提供了幾個CRTC,編碼器和連接配接器功能的實作(從中間層的頂部調用),這些功能可預處理請求并調用驅動程式提供的較低級功能(在中間層的底部) 。例如,該
drm_crtc_helper_set_config
函數可用于填充struct drm_crtc_funcs 的
set_config
字段。調用時,它将把
set_config
操作拆分為更小,更簡單的操作,并調用驅動程式進行處理。
要使用中間層,驅動程式調用
drm_crtc_helper_add
,
drm_encoder_helper_add
以及
drm_connector_helper_add
功能安裝他們中間層底部的操作處理,并填寫 drm_crtc_funcs, drm_encoder_funcs和 drm_connector_funcs結構的指針到中間層頂API函數。最好在注冊相應的KMS對象之後立即安裝中間層底部操作處理程式。
中間層未在CRTC,編碼器和連接配接器操作之間劃分。要使用它,驅動程式必須為所有三個KMS實體提供底層功能。
輔助功能
-
該int drm_crtc_helper_set_config(struct drm_mode_set *set);
輔助函數是一個CRTCdrm_crtc_helper_set_config
的實作。它首先嘗試通過調用連接配接器set_config
best_encoder
幫助程式,來找到每個連接配接器的最佳編碼器。
找到合适的編碼器後,幫助函數将調用
mode_fixup
編碼器和CRTC幫助操作來調整請求的模式;或者完全拒絕它,在這種情況下,錯誤将傳回給應用程式。如果模式調整後的新配置與目前配置相同,則輔助功能将傳回而不執行任何其他操作。
如果調整後的模式與目前模式相同,但需要對幀緩沖區進行更改,則該
函數将調用CRTCdrm_crtc_helper_set_config
幫助操作。如果從目前模式的調整模式的不同,或者如果mode_set_base
輔助操作未提供時,則輔助函數通過調用prepare、mode_set和commit CRTC和編碼器幫助操作來執行完整的模式集序列。mode_set_base
-
該void drm_helper_connector_dpms(struct drm_connector *connector, int mode);
輔助函數是一個連接配接器dpms實作,它跟蹤連接配接器的電源狀态。要使用該功能,驅動程式必須為CRTC和編碼器提供drm_helper_connector_dpms
dpms
輔助函數,以将DPMS狀态應用于裝置。
中間層不跟蹤CRTC和編碼器的電源狀态。
輔助操作是以可以被相同于目前活動的模式的模式調用。dpms
-
該int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
輔助函數是一個連接配接器drm_helper_probe_single_connector_modes
fill_modes
實作,它更新連接配接器的連接配接狀态,然後通過調用連接配接器get_modes助手操作檢索模式清單。
該功能會濾除大于
和max_width
指定的模式 。然後,它調用連接配接器 幫助程式操作max_height
為所探測清單中的每種模式,以檢查該模式是否對連接配接器有效。mode_valid
CRTC輔助操作
-
bool (*mode_fixup)(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode);
讓CRTC調整請求的模式或完全拒絕它。如果模式被接受(可能在調整之後),則此操作傳回true;如果模式被拒絕,則傳回false。
如果該
操作無法合理使用,則應拒絕該模式。在這種情況下,“合理”的定義目前是模糊的。一種可能的行為是,當将固定模式面闆與能夠縮放的硬體一起使用時,将調整後的模式設定為面闆定時。另一行為是接受任何輸入模式并将其調整為硬體支援的最接近模式(FIXME:這需要澄清)。mode_fixup
-
将目前幀緩沖區(存儲在int (*mode_set_base)(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb)
crtc->fb
中)上的CRTC 移到位置(x,y)。幀緩沖區,x位置或y位置中的任何一個都可能已被修改。
此輔助操作是可選的。如果未提供,該
功能将退回到drm_crtc_helper_set_config
幫助程式操作。mode_set
注意
FIXME:為什麼x和y作為參數傳遞,因為可以通過
和 通路它們crtc->x
?crtc->y
-
準備CRTC以進行模式設定。驗證請求的模式後,将調用此操作。驅動程式使用它來執行設定新模式之前所需的裝置特定操作。void (*prepare)(struct drm_crtc *crtc);
-
設定新的模式,位置和幀緩沖區。根據裝置要求,該模式可以由驅動程式在内部存儲并在int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *old_fb);
commit
操作中應用,或立即程式設計到硬體。
如果
成功,則操作傳回0;如果發生錯誤,則傳回負錯誤代碼。mode_set
-
送出模式。設定新模式後将調用此操作。傳回時,裝置必須使用新模式并可以完全操作。void (*commit)(struct drm_crtc *crtc);
編碼器輔助操作
-
讓編碼器調整請求的模式或完全拒絕它。如果模式被接受(可能在調整之後),則此操作傳回true;如果模式被拒絕,則傳回false。有關允許的調整的說明,請參見 mode_fixup CRTC輔助操作。bool (*mode_fixup)(struct drm_encoder *encoder, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode);
-
準備編碼器以進行模式設定。驗證請求的模式後,将調用此操作。驅動程式使用它來執行設定新模式之前所需的裝置特定操作。void (*prepare)(struct drm_encoder *encoder);
-
設定新模式。根據裝置要求,該模式可以由驅動程式在内部存儲并在void (*mode_set)(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode);
操作中應用,或立即程式設計到硬體。commit
-
送出模式。設定新模式後将調用此操作。傳回時,裝置必須使用新模式并可以完全操作。void (*commit)(struct drm_encoder *encoder);
連接配接器輔助操作
-
傳回一個指向此連接配接器的最佳編碼器的指針。連接配接器1:1映射到編碼器的裝置隻需傳回到關聯的編碼器指針即可。此操作是強制性的。struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
-
int (*get_modes)(struct drm_connector *connector);
使用drm_add_edid_modes解析EDID資料,或者直接為每個支援的模式調用drm_mode_probed_add,以填充連接配接器的probed_modes清單,并傳回它已檢測到的模式數目。此操作是強制性的。
手動添加模式時,驅動程式會通過調用
來建立每個模式,必須填寫以下字段。drm_mode_create
-
__u32 type;
模式類型位掩碼,組合
DRM_MODE_TYPE_BUILTIN
不曾用過?
DRM_MODE_TYPE_CLOCK_C
不曾用過?
DRM_MODE_TYPE_CRTC_C
不曾用過?
DRM_MODE_TYPE_PREFERRED-連接配接器的首選模式
不曾用過?
DRM_MODE_TYPE_DEFAULT
不曾用過?
DRM_MODE_TYPE_USERDEF
不曾用過?
DRM_MODE_TYPE_DRIVER
該模式已由驅動程式建立(與使用者建立的模式相反)。
驅動程式必須為他們建立的所有模式設定DRM_MODE_TYPE_DRIVER位,并為首選模式設定DRM_MODE_TYPE_PREFERRED位。
-
像素時鐘頻率(kHz)__u32 clock;
-
水準和垂直時序資訊__u16 hdisplay, hsync_start, hsync_end, htotal; __u16 vdisplay, vsync_start, vsync_end, vtotal;
Active Front Sync Back Region Porch Porch <-----------------------><----------------><-------------><--------------> //| // | // |.................. ................ _______________ <----- [hv]display -----> <------------- [hv]sync_start ------------> <--------------------- [hv]sync_end ---------------------> <-------------------------------- [hv]total ----------------------------->
-
未知__u16 hskew; __u16 vscan;
-
__u32 flags;
模式标志,組合包含
DRM_MODE_FLAG_PHSYNC
水準同步為高電平有效
DRM_MODE_FLAG_NHSYNC
水準同步為低電平有效
DRM_MODE_FLAG_PVSYNC
垂直同步高電平有效
DRM_MODE_FLAG_NVSYNC
垂直同步為低電平有效
DRM_MODE_FLAG_INTERLACE
模式隔行
DRM_MODE_FLAG_DBLSCAN
模式使用雙重掃描
DRM_MODE_FLAG_CSYNC
模式使用複合同步
DRM_MODE_FLAG_PCSYNC
複合同步高電平有效
DRM_MODE_FLAG_NCSYNC
複合同步低電平有效
DRM_MODE_FLAG_HSKEW
提供hskew(未使用?)
DRM_MODE_FLAG_BCAST
不曾用過?
DRM_MODE_FLAG_PIXMUX
不曾用過?
DRM_MODE_FLAG_DBLCLK
不曾用過?
DRM_MODE_FLAG_CLKDIV2
?
請注意,如果連接配接器的
或interlace_allowed
字段設定為0 ,則标記為INTERLACE或DBLSCAN标志的模式将被doublescan_allowed
濾除 。drm_helper_probe_single_connector_modes
-
模式名稱。填充相應的字段後,驅動程式必須調用drm_mode_set_name來填充來自hdisplay、vdisplay和interlace标志的模式名,然後填充相應的字段。char name[DRM_DISPLAY_MODE_LEN];
值由vrefresh
drm_helper_probe_single_connector_modes
計算 。
解析EDID資料時,
填寫連接配接器drm_add_edid_modes
display_info
和width_mm
字段。手動建立模式時,如果尚未設定字段,則height_mm
輔助操作必須設定get_modes
display_info
和width_mm
字段(例如,初始化時在将固定大小的面闆連接配接到連接配接器)。模式height_mm
和width_mm
字段僅在EDID解析期間在内部使用,在手動建立模式時不應設定。height_mm
-
-
int (*mode_valid)(struct drm_connector *connector, struct drm_display_mode *mode);
驗證模式對于連接配接器是否有效。對于支援的模式,傳回MODE_OK;對于不支援的模式,傳回枚舉drm_mode_status值(MODE_ *)之一。此操作是強制性的。
由于模式拒絕原因目前不用于立即删除不受支援的模式,是以實作可以傳回MODE_BAD,而不管模式無效的确切原因是什麼。
注意
注意,mode_valid helper操作隻對裝置檢測到的模式調用,而不會對使用者通過CRTC set_config操作設定的模式調用。
模式設定輔助函數參考
名稱
drm_helper_move_panel_connectors_to_head —将面闆移到連接配接器清單的最前面
概要
void fsfuncdrm_helper_move_panel_connectors_to_head (dev);
struct drm_device * dev;
參數
dev
進行操作的drm裝置
描述
某些使用者空間假定第一個連接配接的連接配接器是主顯示屏,應該在其中顯示例如登入螢幕。對于筆記本電腦,這應該是主面闆。使用此功能可将所有(eDP / LVDS)面闆排序到連接配接器清單的最前面,而不必費力地嘗試按正确的順序對其進行初始化。
名稱
drm_helper_probe_single_connector_modes —擷取完整的顯示模式集
概要
int fsfuncdrm_helper_probe_single_connector_modes (connector,
maxX,
maxY);
struct drm_connector * connector;
uint32_t maxX;
uint32_t maxY;
參數
connector
需要探測的連接配接器
maxX
模式的最大寬度
maxY
模式的最大高度
鎖定
調用者必須持有模式配置鎖。
基于
connector
實作的幫助程式回調,嘗試檢測所有有效模式。模式将首先被添加到連接配接器的probed_modes清單,然後剔除不符合的(基于有效性和
maxX
,
maxY
參數),其餘投入正常模式清單。
打算用作->
probe
connector
回調的通用實作,為用crtc輔助函數進行輸出模式過濾和檢測的驅動程式所使用 。
傳回
在
connector
上找到的模式數量。
名稱
drm_helper_encoder_in_use —檢查是否正在使用給定的編碼器
概要
bool fsfuncdrm_helper_encoder_in_use ( encoder);
struct drm_encoder * encoder;
參數
encoder
需要檢測的編碼器
鎖定
調用者必須持有模式配置鎖。
周遊
encoders
對應的
DRM裝置的mode_config,看看它是否正在使用中。
傳回
如果
encoder
屬于mode_config,則為true,否則為false。
名稱
drm_helper_crtc_in_use —檢查給定的CRTC是否在mode_config中
概要
bool fsfuncdrm_helper_crtc_in_use ( crtc);
struct drm_crtc * crtc;
參數
crtc
需要檢查的CRTC
鎖定
調用者必須持有模式配置鎖。
周遊
crtc對應的
DRM裝置的mode_config,看看它是否正在使用中。
傳回
如果
crtc
屬于mode_config,則為true,否則為false。
名稱
drm_helper_disable_unused_functions —禁用未使用的對象
概要
void fsfuncdrm_helper_disable_unused_functions (dev);
struct drm_device * dev;
參數
dev
對應的DRM
鎖定
調用者必須持有模式配置鎖。
如果連接配接器或CRTC不屬于
dev的
mode_config的一部分,則可以通過調用其dpms函數将其關閉,以将其關閉。
名稱
drm_crtc_helper_set_mode —設定模式的内部輔助
概要
bool fsfuncdrm_crtc_helper_set_mode ( crtc,
mode,
x,
y,
old_fb);
struct drm_crtc * crtc;
struct drm_display_mode * mode;
int x;
int y;
struct drm_framebuffer * old_fb;
參數
crtc
需要處理的CRTC
mode
需要使用的mode
x
進入surface的水準偏移
y
進入surface的垂直偏移
old_fb
舊的幀緩沖區,用于清理
鎖定
調用者必須持有模式配置鎖。
嘗試
crtc
上設定
mode
。
crtc
在嘗試設定模式之前,這是一個内部輔助功能,驅動程式可以用來更新屬性,要求在新的配置中禁用和重新啟用整個輸出管道。例如,用于更改是否在hdmi連結上啟用了音頻,或用于更改面闆fitter或抖動屬性。
drm_crtc_helper_set_config
輔助函數也調用它 來驅動模式設定序列。
傳回
如果成功設定了模式,則為true,否則為false。
名稱
drm_crtc_helper_set_config-從使用者空間設定新配置
概要
int fsfuncdrm_crtc_helper_set_config ( set);
struct drm_mode_set * set;
參數
set
模式設定配置
鎖定
調用者必須持有模式配置鎖。
在
set
中設定由上層提供的新配置(來自使用者空間的ioctl調用或内部的fbdev支援代碼,例如fbdev支援代碼),并啟用他。這是驅動程式的主要輔助函數,它使用crtc輔助函數實作核心模式設定,這些驅動程式使用crtc幫助程式功能以及各種->
prepare
,->
modeset
和->
commit
helper回調來實作核心模式設定。
傳回
成功傳回0,失敗傳回-ERRNO。
名稱
drm_helper_connector_dpms —連接配接器dpms輔助實作
概要
void fsfuncdrm_helper_connector_dpms ( connector,
mode);
struct drm_connector * connector;
int mode;
參數
connector
受控制的連接配接器
mode
DPMS模式
描述
這是crtc輔助程式架構提供的用于實作DPMS連接配接器屬性的主要幫助程式功能。它為輸出網格中的所有編碼器和crtcs計算新的所需DPMS狀态,并适當地調用驅動程式提供的->
dpms
回調。
fbdev輔助程式參考
fb幫助程式功能可用于在drm核心模式設定驅動程式之上提供fbdev。它們可以獨立于許多驅動程式用來實作核心模式設定接口的crtc helper函數來獨立使用。
初始化完成需要有三個步驟
drm_fb_helper_init
,
drm_fb_helper_single_add_all_connectors
和
drm_fb_helper_initial_config
。要求比預設行為更高的驅動程式可以使用自己的代碼覆寫第二步。拆卸通過
drm_fb_helper_fini
完成。
在運作時,驅動程式應通過從其-> lastclose回調中進行調用
drm_fb_helper_restore_fbdev_mode
來還原fbdev控制台 。他們還應該通過調用
drm_fb_helper_hotplug_event
來通知fb輔助程式有關輸出配置更新的資訊。為了更輕松地與drm_crtc_helper.c中的輸出輪詢代碼內建,模式集代碼被提供一個-> output_poll_changed回調。
fb幫助程式庫導出的所有其他函數均可用于由驅動程式實作fbdev驅動程式接口。
名稱
drm_fb_helper_single_add_all_connectors —将所有連接配接器添加到fbdev仿真助手
概要
int fsfuncdrm_fb_helper_single_add_all_connectors (fb_helper);
struct drm_fb_helper * fb_helper;
參數
fb_helper
用drm_fb_helper_init初始化的fbdev
描述
此函數将添加所有可用的連接配接器,以與給定的fb_helper一起使用。這是一個單獨的步驟,允許驅動程式自由地将連接配接器配置設定給fbdev,例如,如果某些連接配接器保留用于特殊目的或不足以用于fbcon。
由于這是釋出fbdev之前的初始設定的一部分,是以不需要鎖定。
名稱
drm_fb_helper_debug_enter —-> fb_debug_enter的實作
概要
int fsfunc drm_fb_helper_debug_enter (info);
struct fb_info * info;
參數
info
fbdev由輔助函數注冊
名稱
drm_fb_helper_debug_leave —-> fb_debug_leave的實作
概要
int fsfunc drm_fb_helper_debug_leave (info);
struct fb_info * info;
參數
info
fbdev由輔助函數注冊
名稱
drm_fb_helper_restore_fbdev_mode —恢複fbdev配置
概要
bool fsfunc drm_fb_helper_restore_fbdev_mode (fb_helper);
struct drm_fb_helper * fb_helper;
參數
fb_helper
fbcon(fbconfig?)恢複
描述
使用此幫助程式在kms頂部實作fbcon時,應從驅動程式的drm-> lastclose回調中調用此函數。這樣可以確定當X(x11,顯示的上層server)死了時,使用者不會看到黑屏。
名稱
drm_fb_helper_blank —-> fb_blank的實作
概要
int fsfunc drm_fb_helper_blank (blank,
info);
int blank;
struct fb_info * info;
參數
blank
所需的消隐狀态
info
fbdev由輔助函數注冊
名稱
drm_fb_helper_init —初始化一個drm_fb_helper結構
概要
int fsfunc drm_fb_helper_init ( dev,
fb_helper,
crtc_count,
max_conn_count);
struct drm_device * dev;
struct drm_fb_helper * fb_helper;
int crtc_count;
int max_conn_count;
參數
dev
DRM裝置
fb_helper
驅動程式配置設定的fbdev助手結構進行初始化
crtc_count
此fbdev仿真中支援的crtcs的最大數量
max_conn_count
最大連接配接器數
描述
這将使用給定的限制為fbdev幫助程式配置設定結構。請注意,這還不會(通過驅動程式接口)接觸硬體,也不會注冊fbdev。 這僅在
drm_fb_helper_initial_config完成,
是為了允許驅動程式對确切的初始化順序進行更多控制。
驅動程式必須在調用
drm_fb_helper_initial_config
之前設定fb_helper-> funcs 。
傳回
如果一切正常,則為零,否則為非零。
名稱
drm_fb_helper_setcmap —-> fb_setcmap的實作
概要
int fsfuncdrm_fb_helper_setcmap ( cmap,
info);
struct fb_cmap * cmap;
struct fb_info * info;
參數
cmap
要設定的cmap
info
fbdev由輔助函數注冊
名稱
drm_fb_helper_check_var —-> fb_check_var的實作
概要
int fsfuncdrm_fb_helper_check_var ( var,
info);
struct fb_var_screeninfo * var;
struct fb_info * info;
參數
var
螢幕資訊檢查
info
fbdev由輔助函數注冊
名稱
drm_fb_helper_set_par —-> fb_set_par的實作
概要
int fsfuncdrm_fb_helper_set_par ( info);
struct fb_info * info;
參數
info
fbdev由輔助函數注冊
描述
這将使fbcon進行模式初始化,并在初始化時由fbdev核心在注冊驅動程式時進行調用,然後再通過hotplug回調進行調用。
名稱
drm_fb_helper_pan_display —-> fb_pan_display的實作
概要
int fsfuncdrm_fb_helper_pan_display ( var,
info);
struct fb_var_screeninfo * var;
struct fb_info * info;
參數
var
更新的螢幕資訊
info
fbdev由助手注冊
名稱
drm_fb_helper_fill_fix —初始化固定的fbdev資訊
概要
void fsfuncdrm_fb_helper_fill_fix ( info,
pitch,
depth);
struct fb_info * info;
uint32_t pitch;
uint32_t depth;
參數
info
fbdev由助手注冊
pitch
所需pitch
depth
所需深度
描述
幫助程式可填充固定的fbdev資訊,這些資訊對于非加速的fbdev仿真非常有用。支援加有其他限制的加速方法的驅動程式需要設定自己的限制。
驅動程式應從其-> fb_probe回調中調用此代碼(或等效的安裝代碼)。
名稱
drm_fb_helper_fill_var —初始化變量fbdev資訊
概要
void fsfuncdrm_fb_helper_fill_var ( info,
fb_helper,
fb_width,
fb_height);
struct fb_info * info;
struct drm_fb_helper * fb_helper;
uint32_t fb_width;
uint32_t fb_height;
參數
info
fbdev執行個體設定
fb_helper
fb幫助程式執行個體用作模闆
fb_width
所需的fb寬度
fb_height
所需的fb高度
描述
根據給定的fb幫助程式執行個體和fb_helper-> fb中配置設定的drm幀緩沖區設定變量fbdev元資訊。
在配置設定了fbdev後備存儲幀緩沖區之後,驅動程式應從其-> fb_probe回調中調用此代碼(或等效的安裝代碼)。
名稱
drm_fb_helper_initial_config —設定合理的初始連接配接器配置
概要
bool fsfuncdrm_fb_helper_initial_config ( fb_helper,
bpp_sel);
struct drm_fb_helper * fb_helper;
int bpp_sel;
參數
fb_helper
fb_helper裝置結構
bpp_sel
用于幀緩沖區配置的bpp值
描述
掃描CRTC和連接配接器,并嘗試将初始設定放在一起。目前,這是所有源頭的克隆配置,其中有一個新的framebuffer對象作為後備存儲。
請注意,這還會注冊fbdev,是以允許使用者空間通過fbdev接口調用驅動程式。
該函數将調用-> fb_probe回調,以使驅動程式配置設定和初始化fbdev資訊結構以及用于支援fbdev的drm幀緩沖區。
drm_fb_helper_fill_var
和
drm_fb_helper_fill_fix
作為幫助程式來設定fbdev info結構的簡單預設值。
傳回
如果一切正常,則為零,否則為非零。
名稱
drm_fb_helper_hotplug_event —通過探測附加到fb的所有輸出來響應熱插拔通知
概要
int fsfuncdrm_fb_helper_hotplug_event ( fb_helper);
struct drm_fb_helper * fb_helper;
争論
fb_helper
drm_fb_helper
描述
通知輸出配置的更改後,掃描連接配接到fb_helper的連接配接器,并嘗試将設定彙總在一起。
在運作時調用,使用模式配置鎖可以檢查/更改模式集配置。必須從程序上下文運作(這通常意味着輸出輪詢工作或從驅動程式的熱插拔中斷啟動的工作項)。
注意,驅動程式必須確定這僅是fb已完全設定後的唯一調用,即在調用drm_fb_helper_initial_config之後。
傳回
成功時傳回0,否則傳回非零錯誤代碼。
名稱
struct drm_fb_helper_funcs — fbdev仿真庫的驅動程式回調
概要
struct drm_fb_helper_funcs {
void (* gamma_set) (struct drm_crtc *crtc, u16 red, u16 green,u16 blue, int regno);
void (* gamma_get) (struct drm_crtc *crtc, u16 *red, u16 *green,u16 *blue, int regno);
int (* fb_probe) (struct drm_fb_helper *helper,struct drm_fb_helper_surface_size *sizes);
bool (* initial_config) (struct drm_fb_helper *fb_helper,struct drm_fb_helper_crtc **crtcs,struct drm_display_mode **modes,bool *enabled, int width, int height);
};
成員
gamma_set
在給定的crtc上設定給定的gamma lut寄存器。
gamma_get
讀取給定crtc上給gamma lut寄存器,該寄存器用于在強制恢複fbdev(例如kdbg)時儲存目前lut。
fb_probe
驅動程式回調以配置設定和初始化fbdev資訊結構。此外,它還需要配置設定用于支援fbdev的drm幀緩沖區。
initial_config
設定初始fbdev顯示配置
描述
fbdev仿真幫助程式庫使用的驅動程式回調。
(DP)顯示端口幫助程式功能參考
這些功能包含各種抽象級别的一些通用邏輯和幫助程式,用于處理Display Port接收器裝置和相關内容,例如DP輔助通道傳輸,在DP輔助通道上讀取EDID,解碼某些DPCD塊,...
名稱
struct i2c_algo_dp_aux_data —基于dp aux算法的i2c的驅動程式接口結構
概要
struct i2c_algo_dp_aux_data {
bool running;
u16 address;
int (* aux_ch) (struct i2c_adapter *adapter,int mode, uint8_t write_byte,uint8_t *read_byte);
};
成員
running
由算法設定的值,訓示i2c是否正在進行或i2c總線是否處于靜态
address
目前正在進行傳輸的i2c目标位址
aux_ch
驅動程式回調以傳輸i2c有效負載的單個位元組
名稱
i2c_dp_aux_add_bus —使用輔助通道幫助程式注冊i2c擴充卡
概要
int fsfunci2c_dp_aux_add_bus ( adapter);
struct i2c_adapter * adapter;
參數
adapter
i2c擴充卡進行注冊
描述
這将注冊一個使用dp aux通道作為傳輸基礎的i2c擴充卡。驅動程式需要填寫i2c_algo_dp_aux_data結構并将其存儲在algo_data成員的
adapter
參數中。i2c over dp aux算法将使用它來驅動硬體。
傳回
成功時為0,失敗時為-ERRNO。
EDID輔助功能參考
名稱
drm_edid_is_valid —完整性檢查EDID資料
概要
bool fsfuncdrm_edid_is_valid ( edid);
struct edid * edid;
參數
edid
EDID資料
描述
完整檢查整個EDID記錄(包括擴充名)
名稱
drm_probe_ddc —
概要
bool fsfuncdrm_probe_ddc ( adapter);
struct i2c_adapter * adapter;
争論
adapter
-未描述-
描述
\ param擴充卡:i2c裝置擴充卡\成功傳回1
名稱
drm_get_edid —擷取EDID資料(如果有)
概要
struct edid * fsfuncdrm_get_edid ( connector,
adapter);
struct drm_connector * connector;
struct i2c_adapter * adapter;
參數
connector
我們正在探索的連接配接器
adapter
用于DDC的i2c擴充卡
描述
如有可能,撥入給定的i2c通道以擷取EDID資料。如果找到,将其連接配接到連接配接器。
傳回edid資料;如果找不到,則傳回NULL。
名稱
drm_match_cea_mode —查找與給定模式比對的CEA模式
概要
u8 fsfuncdrm_match_cea_mode ( to_match);
const struct drm_display_mode * to_match;
參數
to_match
顯示模式
描述
傳回該模式的CEA視訊ID(VIC);如果不是CEA-861模式,則傳回0。
名稱
drm_edid_to_eld —從EDID生成ELD
概要
void fsfuncdrm_edid_to_eld ( connector,
edid);
struct drm_connector * connector;
struct edid * edid;
參數
connector
對應于HDMI / DP接收器的接口
edid
需要解析的EDID
描述
填充ELD(類似于EDID的資料)緩沖區以傳遞給音頻驅動程式。
一些ELD字段留給圖形驅動程式調用方
-Conn_Type-HDCP-Port_ID
名稱
drm_edid_to_sad —從EDID中提取SAD
概要
int fsfuncdrm_edid_to_sad ( edid,
sads);
struct edid * edid;
struct cea_sad ** sads;
争論
edid
需要解析的EDID
sads
将設定為提取到的SAD的指針
描述
查找CEA EDID塊并從中提取SAD(短音頻描述符)。
注意
傳回的指針需要kfreed
傳回找到的SAD數或錯誤時傳回負數。
名稱
drm_edid_to_speaker_allocation —從EDID中提取揚聲器配置設定的資料塊
概要
int fsfuncdrm_edid_to_speaker_allocation ( edid,
sadb);
struct edid * edid;
u8 ** sadb;
參數
edid
需要解析的EDID
sadb
指向揚聲器子產品的指針
描述
查找CEA EDID塊,并從中提取揚聲器配置設定資料塊。
注意
傳回的指針需要kfreed
傳回找到的揚聲器配置設定塊數或錯誤時傳回負數。
名稱
drm_av_sync_delay — HDMI / DP接收器音頻-視訊同步延遲(以毫秒為機關)
概要
int fsfuncdrm_av_sync_delay ( connector,
mode);
struct drm_connector * connector;
struct drm_display_mode * mode;
參數
connector
與HDMI / DP接收器關聯的連接配接器
mode
顯示模式
名稱
drm_select_eld —從多個HDMI / DP接收器中選擇一個ELD
概要
struct drm_connector * fsfuncdrm_select_eld ( encoder,
mode);
struct drm_encoder * encoder;
struct drm_display_mode * mode;
參數
encoder
編碼器剛剛更改了顯示模式
mode
調整後的顯示模式
描述
一個編碼器可能與多個HDMI / DP接收器關聯。現在,已對該政策進行了寫死,以僅使用第一個HDMI / DP接收器的ELD。
名稱
drm_detect_hdmi_monitor —檢測顯示器是否為hdmi。
概要
bool fsfuncdrm_detect_hdmi_monitor ( edid);
struct edid * edid;
參數
edid
顯示器的EDID資訊
描述
根據CEA-861-B解析CEA擴充名。如果HDMI,則傳回true,否則傳回false,否則傳回未知。
名稱
drm_detect_monitor_audio —檢查螢幕音頻功能
概要
bool fsfuncdrm_detect_monitor_audio ( edid);
struct edid * edid;
參數
edid
顯示器的EDID資訊
描述
顯示器應具有CEA擴充塊。如果顯示器具有“基本音頻”,但沒有CEA音頻塊,則僅是“基本音頻”。如果有任何音頻擴充塊和支援的音頻格式,則即使在EDID中未定義“基本音頻”,也至少要假定“基本音頻”支援。
名稱
drm_rgb_quant_range_selectable — RGB量化範圍可以選擇嗎?
概要
bool fsfuncdrm_rgb_quant_range_selectable ( edid);
struct edid * edid;
參數
edid
顯示器的EDID資訊
描述
檢查顯示器是否報告支援的RGB量化範圍選擇。然後可以使用AVI資訊幀通知螢幕使用了哪個量化範圍(完整或有限)。
名稱
drm_add_edid_modes —從EDID資料添加模式(如果有)
概要
int fsfuncdrm_add_edid_modes ( connector,
edid);
struct drm_connector * connector;
struct edid * edid;
參數
connector
我們正在探索的連接配接器
edid
顯示器的EDID資訊
描述
将指定的模式添加到連接配接器的模式清單中。
傳回添加的模式數量,如果找不到則傳回0。
名稱
drm_add_modes_noedid —為沒有EDID的連接配接器添加模式
概要
int fsfuncdrm_add_modes_noedid ( connector,
hdisplay,
vdisplay);
struct drm_connector * connector;
int hdisplay;
int vdisplay;
參數
connector
我們正在探索的連接配接器
hdisplay
水準顯示極限
vdisplay
垂直顯示限制
描述
将指定的模式添加到連接配接器的模式清單中。僅當hdisplay / vdisplay不超過給定限制時,才會添加它。
傳回添加的模式數量,如果找不到則傳回0。
名稱
drm_hdmi_avi_infoframe_from_display_mode —用來自DRM顯示模式的資料填充HDMI AVI資訊幀
概要
int fsfuncdrm_hdmi_avi_infoframe_from_display_mode ( frame,
mode);
struct hdmi_avi_infoframe * frame;
const struct drm_display_mode * mode;
參數
frame
HDMI AVI資訊框
mode
DRM顯示模式
描述
成功傳回0,失敗傳回負錯誤代碼。
名稱
drm_hdmi_vendor_infoframe_from_display_mode —用來自DRM顯示模式的資料填充HDMI資訊幀
概要
int fsfuncdrm_hdmi_vendor_infoframe_from_display_mode ( frame,
mode);
struct hdmi_vendor_infoframe * frame;
const struct drm_display_mode * mode;
參數
frame
HDMI供應商資訊框
mode
DRM顯示模式
描述
請注意,僅在使用4k或立體3D模式時才需要發送HDMI供應商資訊幀。是以,當提供任何其他模式作為輸入時,此函數将傳回-EINVAL,該錯誤可以安全地忽略。
成功傳回0,失敗傳回負錯誤代碼。
矩形實用程式參考
實用程式功能可幫助管理矩形區域以進行裁剪,縮放等計算。
名稱
struct drm_rect —二維矩形
概要
struct drm_rect {
int x1;
int y1;
int x2;
int y2;
};
成員
x1
水準起始坐标(含)
11
垂直起始坐标(含)
2倍
水準結束坐标(不包括)
22
垂直結束坐标(不包括)
名稱
drm_rect_adjust_size —調整矩形的大小
概要
void fsfuncdrm_rect_adjust_size ( r,
dw,
dh);
struct drm_rect * r;
int dw;
int dh;
參數
r
要調整的矩形
dw
水準調整
dh
垂直調整
描述
改變矩形
r
的大小由
dw
在水準方向上,并且通過
dh
在垂直方向上,同時保持
r
的中心固定不動。
正
dw
和
dh
增加大小,負值減少它。
名稱
drm_rect_translate —平移矩形
概要
void fsfuncdrm_rect_translate ( r,
dx,
dy);
struct drm_rect * r;
int dx;
int dy;
參數
r
要翻譯的矩形
dx
水準翻譯
dy
垂直翻譯
描述
移動矩形
r,dx
在水準方向上 ,
dy
在垂直方向上移動矩形。
名稱
drm_rect_downscale —縮小矩形
概要
void fsfuncdrm_rect_downscale ( r,
horz,
vert);
struct drm_rect * r;
int horz;
int vert;
參數
r
要縮小的矩形
horz
水準縮小系數
vert
垂直縮小系數
描述
矩形的坐标
r
除以
horz
和
vert
。
名稱
drm_rect_width —确定矩形的寬度
概要
int fsfuncdrm_rect_width ( r);
const struct drm_rect * r;
參數
r
傳回寬度的矩形
傳回
矩形的寬度。
名稱
drm_rect_height —确定矩形的高度
概要
int fsfuncdrm_rect_width (r);
const struct drm_rect * r;
參數
r
傳回高度的矩形
傳回
矩形的高度。
名稱
drm_rect_visible —确定矩形是否可見
概要
int fsfuncdrm_rect_height ( r);
const struct drm_rect * r;
參數
r
傳回可見性的矩形
傳回
true
如果矩形可見,
false
否則。
名稱
drm_rect_equals —确定兩個矩形是否相等
概要
bool fsfuncdrm_rect_equals ( r1,
r2);
const struct drm_rect * r1;
const struct drm_rect * r2;
參數
r1
第一個矩形
r2
第二個矩形
傳回
true
如果矩形相等,
false
否則。
名稱
drm_rect_intersect —與兩個矩形相交
概要
bool fsfuncdrm_rect_intersect ( r1,
r2);
struct drm_rect * r1;
const struct drm_rect * r2;
參數
r1
第一個矩形
r2
第二個矩形
描述
計算矩形
r1
和的交點
r2
。
r1
将被相交處覆寫。
傳回
true
如果矩形
r1
在操作後仍然可見,
false
否則。
名稱
drm_rect_clip_scaled —執行縮放的剪輯操作
概要
bool fsfuncdrm_rect_clip_scaled ( src,
dst,
clip,
hscale,
vscale);
struct drm_rect * src;
struct drm_rect * dst;
const struct drm_rect * clip;
int hscale;
int vscale;
參數
src
源視窗矩形
dst
目标視窗矩形
clip
剪輯矩形
hscale
水準比例因子
vscale
垂直比例因子
描述
用矩形
clip
剪輯矩形
dst
。裁剪矩形
src
以相同數量乘以
hscale
和
vscale
。
傳回
true
如果矩形
dst
在裁剪後仍然可見,
false
否則
名稱
drm_rect_calc_hscale —計算水準縮放因子
概要
int fsfuncdrm_rect_calc_hscale ( src,
dst,
min_hscale,
max_hscale);
const struct drm_rect * src;
const struct drm_rect * dst;
int min_hscale;
int max_hscale;
參數
src
源視窗矩形
dst
目标視窗矩形
min_hscale
最小允許水準縮放比例
max_hscale
最大允許水準縮放比例
描述
将水準縮放系數計算為(
src
寬度)/(
dst
寬度)。
傳回
水準縮放因子或超出範圍的錯誤。
名稱
drm_rect_calc_vscale —計算垂直比例因子
概要
int fsfuncdrm_rect_calc_vscale ( src,
dst,
min_vscale,
max_vscale);
const struct drm_rect * src;
const struct drm_rect * dst;
int min_vscale;
int max_vscale;
參數
src
源視窗矩形
dst
目标視窗矩形
min_vscale
最小允許垂直縮放系數
max_vscale
最大允許垂直縮放比例
描述
将垂直縮放系數計算為(
src
高度)/(
dst
高度)。
傳回
垂直比例因子或超出範圍的錯誤值。
名稱
drm_rect_calc_hscale_relaxed —計算水準縮放因子
概要
int fsfuncdrm_rect_calc_hscale_relaxed ( src,
dst,
min_hscale,
max_hscale);
struct drm_rect * src;
struct drm_rect * dst;
int min_hscale;
int max_hscale;
參數
src
源視窗矩形
dst
目标視窗矩形
min_hscale
最小允許水準縮放比例
max_hscale
最大允許水準縮放比例
描述
将水準縮放系數計算為(
src
寬度)/(
dst
寬度)。
如果計算出的比例因子小于
min_vscale
,則減小矩形的高度以
dst
進行補償。
如果計算出的比例因子大于
max_vscale
,則減小矩形的高度以
src
進行補償。
傳回
水準縮放因子。
名稱
drm_rect_calc_vscale_relaxed —計算垂直比例因子
概要
int fsfuncdrm_rect_calc_vscale_relaxed ( src,
dst,
min_vscale,
max_vscale);
struct drm_rect * src;
struct drm_rect * dst;
int min_vscale;
int max_vscale;
參數
src
源視窗矩形
dst
目标視窗矩形
min_vscale
最小允許垂直縮放系數
max_vscale
最大允許垂直縮放比例
描述
将垂直縮放系數計算為(
src
高度)/(
dst
高度)。
如果計算出的比例因子小于
min_vscale
,則減小矩形的高度以
dst
進行補償。
如果計算出的比例因子大于
max_vscale
,則減小矩形的高度以
src
進行補償。
傳回
垂直比例因子。
名稱
drm_rect_debug_print —列印矩形資訊
概要
void fsfuncdrm_rect_debug_print ( r,
fixed_point);
const struct drm_rect * r;
bool fixed_point;
參數
r
要列印的矩形
fixed_point
矩形為16.16定點格式
翻轉工作助手參考
在flip / vblank之後,可以使工作排隊以從工作隊列上下文中運作。通常,這可以用于将幀緩沖區,滑鼠bo等的取消引用推遲到vblank之後。這些API都是安全的(無鎖),最多可同時有一個生産者和一個消費者。通過将排隊的工作送出到單個工作隊列來確定單使用者方面。
名稱
struct drm_flip_work —翻轉工作隊列
概要
struct drm_flip_work {
const char * name;
atomic_t pending;
atomic_t count;
drm_flip_func_t func;
struct work_struct worker;
};
成員
name
調試名稱
pending
排隊但未送出的項目數
count
承諾項目數
func
為每個已送出項目調用回調函數
worker
調用func的工作隊列對象
名稱
drm_flip_work_queue —工作隊列
概要
void fsfuncdrm_flip_work_queue ( work,
val);
struct drm_flip_work * work;
void * val;
參數
work
翻轉工作
val
要排隊的值
描述
隊列工作,該工作随後将在
drm_flip_work_commit
調用後在工作隊列上運作(傳遞回drm_flip_func_t func)。
名稱
drm_flip_work_commit —送出排隊的工作
概要
void fsfuncdrm_flip_work_commit ( work,
wq);
struct drm_flip_work * work;
struct workqueue_struct * wq;
參數
work
翻轉工作
wq
在其上運作排隊的工作的工作隊列
描述
觸發先前排隊的工作
drm_flip_work_queue
以在工作隊列上運作。典型的用法是(通過
drm_flip_work_queue
)在任何點(通過vblank irq和/或之前)對工作進行排隊,然後從vblank irq送出排隊的工作。
名稱
drm_flip_work_init —初始化翻轉工作
概要
int fsfuncdrm_flip_work_init ( work,
size,
name,
func);
struct drm_flip_work * work;
int size;
const char * name;
drm_flip_func_t func;
參數
work
初始化的翻轉工作
size
最大隊列深度
name
調試名稱
func
回調工作功能
描述
初始化/配置設定用于翻轉作業的資源
傳回
成功為零,失敗為錯誤代碼。
名稱
drm_flip_work_cleanup —清理翻轉工作
概要
void fsfuncdrm_flip_work_cleanup ( work);
struct drm_flip_work * work;
參數
work
需要清理filp-work
描述
銷毀配置設定給filp-work的資源
VMA偏移管理器
vma-manager負責将依賴于驅動程式的任意記憶體區域映射到線性使用者位址空間。它為調用方提供偏移量,然後可以在drm裝置的address_space上使用它。注意不要重疊區域,适當調整它們的大小,并且不要因不一緻的僞造vm_pgoff字段而混淆mm-core。驅動程式不應将其用于VMEM中的對象放置。該管理器僅應用于管理到線性使用者空間VM的映射。
我們使用drm_mm作為後端來管理對象配置設定。但是它針對配置設定/釋放調用(而非查找)進行了高度優化。是以,我們使用rb-tree[紅黑樹]來加速偏移量查找。
您不得在單個address_space上使用多個偏移量管理器。否則,mm-core将無法拆除記憶體映射,因為VM将不再是線性的。在這種情況下,請使用VM_NONLINEAR并實作您自己的偏移量管理器。
此偏移量管理器适用于基于頁面的位址。也就是說,每個參數和傳回碼(除外
drm_vma_node_offset_addr
)都以頁數而不是位元組數給出。這意味着對象大小和偏移量必須始終與頁面對齊(通常)。如果要擷取給定偏移量的有效的基于位元組的使用者空間位址,請參見
drm_vma_node_offset_addr
。
除了偏移量管理,vma偏移量管理器還處理通路管理。對于每個允許通路給定節點的開放檔案上下文,必須調用
drm_vma_node_allow
。否則,
mmap
對該節點偏移的開放檔案的調用将失敗并傳回-EACCES。要再次撤消通路權限,請使用
drm_vma_node_revoke
。但是,如果需要,調用者負責銷毀已經存在的映射。
名稱
drm_vma_offset_manager_init —初始化新的偏移量管理器
概要
void fsfuncdrm_vma_offset_manager_init ( mgr,
page_offset,
size);
struct drm_vma_offset_manager * mgr;
unsigned long page_offset;
unsigned long size;
參數
mgr
管理對象
page_offset
可用存儲區的偏移量(基于頁面)
size
可用位址空間範圍的大小(基于頁面)
描述
初始化一個新的偏移量管理器。可用于管理器的偏移量和區域大小以
page_offset
和
size
給出。兩者機關都為頁碼,而不是位元組。
從管理器添加/删除節點在内部被鎖定,并且可以防止并發通路。但是,節點配置設定和銷毀留給調用方。調用vma-manager時,必須始終保證引用了給定節點。
名稱
drm_vma_offset_manager_destroy —銷毀偏移量管理器
概要
void fsfuncdrm_vma_offset_manager_destroy ( mgr);
struct drm_vma_offset_manager * mgr;
參數
mgr
管理對象
描述
銷毀先前通過
drm_vma_offset_manager_init
建立的對象管理器 。在銷毀管理器之前,調用者必須删除所有配置設定的節點。否則,drm_mm将拒絕釋放請求的資源。
調用此函數後,不得再通路此管理器。
名稱
drm_vma_offset_lookup —在偏移空間中查找節點
概要
struct drm_vma_offset_node * fsfuncdrm_vma_offset_lookup ( mgr,
start,
pages);
struct drm_vma_offset_manager * mgr;
unsigned long start;
unsigned long pages;
參數
mgr
管理對象
start
對象的起始位址(基于頁面)
pages
對象大小(基于頁面)
描述
查找具有給定起始位址和對象大小的節點。這将傳回給定節點的_best_比對項。也就是說,
start
隻要該節點指向整個有效區域(給定的頁面數為
pages
),就可以指向某個有效區域中的某個位置并傳回給定的節點。
傳回
如果找不到合适的節點,則傳回NULL。否則,将傳回最佳比對。調用者有責任確定在調用者通路節點之前不會破壞該節點。
名稱
drm_vma_offset_lookup_locked —在偏移空間中查找節點
概要
struct drm_vma_offset_node * fsfuncdrm_vma_offset_lookup_locked ( mgr,
start,
pages);
struct drm_vma_offset_manager * mgr;
unsigned long start;
unsigned long pages;
參數
mgr
管理對象
start
對象的起始位址(基于頁面)
pages
對象大小(基于頁面)
描述
與
drm_vma_offset_lookup
相同,但要求調用者手動鎖定偏移量查找。請參閱
drm_vma_offset_lock_lookup
示例。
傳回
如果找不到合适的節點,則傳回NULL。否則,将傳回最佳比對。
名稱
drm_vma_offset_add —将偏移量節點添加到管理器
概要
int fsfuncdrm_vma_offset_add ( mgr,
node,
pages);
struct drm_vma_offset_manager * mgr;
struct drm_vma_offset_node * node;
unsigned long pages;
參數
mgr
管理對象
node
要添加的節點
pages
使用者空間可見的配置設定大小(以頁數為機關)
描述
将節點添加到offset-manager。如果已添加節點,則不執行任何操作,并傳回0。
pages
是對象的大小(以頁數為機關)。成功執行此調用後,您可以通路節點的偏移量,直到再次将其删除為止。
如果此調用失敗,則可以安全地重試該操作或調用
drm_vma_offset_remove
。但是,在這種情況下,不需要清理。
pages
不需要與要映射的基礎記憶體對象大小相同。它僅限制了使用者空間可以映射到其位址空間的大小。
傳回
成功時為0,失敗時為負錯誤代碼。
名稱
drm_vma_offset_remove —從管理器中删除偏移節點
概要
void fsfuncdrm_vma_offset_remove ( mgr,
node);
struct drm_vma_offset_manager * mgr;
struct drm_vma_offset_node * node;
參數
mgr
管理對象
node
要删除的節點
描述
從偏移管理器中删除節點。如果之前未添加節點,則不會執行任何操作。此調用傳回後,偏移量和大小将為0,直到
drm_vma_offset_add
再次配置設定新的偏移量為止。輔助函數類似于
drm_vma_node_start
,
drm_vma_node_offset_addr
如果沒有配置設定偏移量,它将傳回0。
名稱
drm_vma_node_allow-将打開檔案添加到允許的使用者清單中
概要
int fsfuncdrm_vma_node_allow ( node,
filp);
struct drm_vma_offset_node * node;
struct file * filp;
參數
node
修改節點
filp
開放檔案以添加
描述
添加
filp
到此節點允許的打開檔案清單。如果
filp
已在此清單中,則引用計數将增加。
允許的使用者清單保留在
drm_vma_offset_add
和
drm_vma_offset_remove
調用之間。如果該節點目前未添加到任何偏移量管理器中,您甚至可以調用它。
在銷毀節點之前,您必須删除所有打開檔案的次數與添加它們的次數相同。否則,您将洩漏記憶體。
這是在内部禁止并發通路的。
傳回
成功時為0,内部失敗時為負錯誤代碼(記憶體不足)
名稱
drm_vma_node_revoke —從允許的使用者清單中删除打開檔案
概要
void fsfuncdrm_vma_node_revoke ( node,
filp);
struct drm_vma_offset_node * node;
struct file * filp;
參數
node
修改節點
filp
打開檔案删除
描述
減少
filp
上允許的打開檔案清單
node
中的ref-count 。如果引用計數降至零,
filp
則從清單中删除。你必須調用此一次,每
drm_vma_node_allow
上
filp
。
這是在内部禁止并發通路的。
如果
filp
不在清單中,則什麼也不做。
名稱
drm_vma_node_is_allowed —檢查是否授予打開檔案通路權限
概要
bool fsfuncdrm_vma_node_is_allowed ( node,
filp);
struct drm_vma_offset_node * node;
struct file * filp;
參數
node
要檢查的節點
filp
打開檔案進行檢查
描述
在目前
node
搜尋清單是否
filp
在允許的打開檔案清單中(請參閱參考資料
drm_vma_node_allow
)。
這是在内部禁止并發通路的。
傳回
真的,如果
filp
在清單上
名稱
drm_vma_offset_exact_lookup —按确切位址查找節點
概要
struct drm_vma_offset_node * fsfuncdrm_vma_offset_exact_lookup ( mgr,
start,
pages);
struct drm_vma_offset_manager * mgr;
unsigned long start;
unsigned long pages;
參數
mgr
管理對象
start
起始位址(基于頁面,而非基于位元組)
pages
對象大小(基于頁面)
描述
與
drm_vma_offset_lookup
節點相同,但不允許向節點偏移。它僅傳回具有給定起始位址的确切對象。
傳回
節點位于确切的起始位址
start
。
名稱
drm_vma_offset_lock_lookup-鎖定查找以供擴充私人使用
概要
void fsfuncdrm_vma_offset_lock_lookup ( mgr);
struct drm_vma_offset_manager * mgr;
參數
mgr
管理對象
描述
鎖定VMA Manager以進行擴充查找。
_locked
按住此鎖定僅允許* VMA函數調用。在通過
drm_vma_offset_unlock_lookup
釋放鎖定之前,所有其他上下文都無法通路VMA 。
如果您需要在重新釋放此鎖之前引用
drm_vma_offset_lookup_locked
傳回的對象,請使用此方法 。
除擴充查找外,不得将此鎖用于任何其他用途。按住此鎖定時,不得調用任何其他VMA幫助器。
注意
持有此鎖,您處于原子上下文中!
例
drm_vma_offset_lock_lookup(mgr);
node = drm_vma_offset_lookup_locked(mgr);
if (node)
kref_get_unless_zero(container_of(node, sth, entr));
drm_vma_offset_unlock_lookup(mgr);
名稱
drm_vma_offset_unlock_lookup —解鎖查找以供擴充私人使用
概要
void fsfuncdrm_vma_offset_unlock_lookup ( mgr);
struct drm_vma_offset_manager * mgr;
參數
mgr
管理對象
描述
釋放查找鎖定。請參閱
drm_vma_offset_lock_lookup
以擷取更多資訊。
名稱
drm_vma_node_reset —初始化或重置節點對象
概要
void fsfuncdrm_vma_node_reset ( node);
struct drm_vma_offset_node * node;
參數
node
要初始化或重置的節點
描述
将節點重置為其初始狀态。在與任何VMA偏移管理器一起使用之前,必須先調用它。
不得在已配置設定的節點上調用此方法,否則會洩漏記憶體。
名稱
drm_vma_node_start —傳回基于頁面的尋址的起始位址
概要
unsigned long fsfuncdrm_vma_node_start ( node);
struct drm_vma_offset_node * node;
參數
node
要檢查的節點
描述
傳回給定節點的起始位址。可以用作VMA偏移管理器提供的線性VM空間中的偏移。請注意,這隻能用于基于頁面的尋址。如果您需要為使用者空間映射提供适當的偏移量,則必須應用“ << PAGE_SHIFT ”或使用
drm_vma_node_offset_addr
輔助程式。
傳回
node
用于基于頁面的尋址的 起始位址。如果節點未配置設定偏移量,則為0。
名稱
drm_vma_node_size —傳回大小(基于頁面)
概要
unsigned long fsfuncdrm_vma_node_size ( node);
struct drm_vma_offset_node * node;
參數
node
要檢查的節點
描述
以給定節點的頁面數形式傳回大小。這與傳遞給
drm_vma_offset_add
的大小相同。如果沒有為節點配置設定偏移量,則為0。
傳回
node
頁數的 大小。如果節點未配置設定偏移量,則為0。
名稱
drm_vma_node_has_offset —檢查是否将節點添加到偏移管理器
概要
bool fsfuncdrm_vma_node_has_offset ( node);
struct drm_vma_offset_node * node;
參數
node
要檢查的節點
傳回
如果先前已為節點配置設定了偏移并将其添加到vma偏移管理器,則為true。
名稱
drm_vma_node_offset_addr —傳回使用者空間mmap的已清理偏移量
概要
__u64 fsfuncdrm_vma_node_offset_addr ( node);
struct drm_vma_offset_node * node;
參數
node
連結偏移節點
描述
與相同,
drm_vma_node_start
但傳回位址作為有效偏移量,可在期間用于使用者空間映射
mmap
。不能在未連結的節點上調用它。
傳回
node
基于位元組的尋址的 偏移量。如果節點未配置設定對象,則為0。
名稱
drm_vma_node_unmap —取消映射偏移量節點
概要
void fsfuncdrm_vma_node_unmap ( node,
file_mapping);
struct drm_vma_offset_node * node;
struct address_space * file_mapping;
參數
node
偏移節點
file_mapping
位址空間取消映射
node
從
描述
取消映射給定偏移節點的所有使用者空間映射。映射必須與
file_mapping
位址空間關聯。如果不存在偏移量或位址空間無效,則不執行任何操作。
此呼叫已解鎖。調用方必須保證
drm_vma_offset_remove
不會在此節點上同時調用。
名稱
drm_vma_node_verify_access — TTM的通路驗證幫助器
概要
int fsfuncdrm_vma_node_verify_access ( node,
filp);
struct drm_vma_offset_node * node;
struct file * filp;
參數
node
偏移節點
filp
打開檔案
描述
這将檢查是否
filp
授予對的通路權限
node
。它與
drm_vma_node_is_allowed
相同, 但很适合 TTM
verify_access
回調的插入助手。
傳回
如果授予通路權限,則為0,否則為-EACCES。
KMS屬性
驅動程式可能需要向應用程式公開除前幾節所述之外的其他參數。KMS支援将屬性附加到CRTC,連接配接器和平面,并提供使用者空間API來列出,擷取和設定屬性值。
屬性由唯一定義屬性用途的名稱辨別,并存儲關聯的值。對于除blob屬性以外的所有屬性類型,該值為64位無符号整數。
KMS區分屬性和屬性執行個體。驅動程式首先建立屬性,然後建立這些屬性的各個執行個體并将其與對象關聯。一個屬性可以被執行個體化多次并與不同的對象關聯。值存儲在屬性執行個體中,所有其他屬性資訊存儲在屬性中,并在屬性的所有執行個體之間共享。
每個屬性的建立類型都會影響KMS核心處理該屬性的方式。支援的屬性類型是:
DRM_MODE_PROP_RANGE
範圍屬性報告其最小和最大允許值。KMS核心将驗證應用程式設定的值是否在該範圍内。
DRM_MODE_PROP_ENUM
枚舉屬性采用從0到該屬性定義的枚舉值的數量的數字值減去1,并将自由格式的字元串名稱與每個值相關聯。應用程式可以檢索已定義的值-名稱對的清單,并使用數值來擷取和設定屬性執行個體值。
DRM_MODE_PROP_BITMASK
位掩碼屬性是枚舉屬性,它另外将所有枚舉值限制在0..63範圍内。位掩碼屬性執行個體值組合了該屬性定義的一個或多個枚舉位。
DRM_MODE_PROP_BLOB
Blob屬性存儲二進制Blob,沒有任何格式限制。二進制Blob被建立為KMS獨立對象,并且Blob屬性執行個體值存儲其關聯的Blob對象的ID。
Blob屬性僅用于連接配接器EDID屬性,不能由驅動程式建立。
要建立屬性驅動程式,請根據屬性類型調用以下函數之一。所有屬性建立函數均采用屬性标志和名稱以及特定于類型的參數。
-
用給定的最小值和最大值建立一個range屬性。struct drm_property *drm_property_create_range(struct drm_device *dev, int flags, const char *name, uint64_t min, uint64_t max);
-
建立一個枚舉的屬性。該struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags, const char *name, const struct drm_prop_enum_list *props, int num_values);
參數指向props
值-名稱對的數組。num_values
-
建立一個位掩碼屬性。該struct drm_property *drm_property_create_bitmask(struct drm_device *dev, int flags, const char *name, const struct drm_prop_enum_list *props, int num_values);
參數指向props
值-名稱對的數組。num_values
可以另外将屬性建立為不可變的,在這種情況下,它們對于應用程式将是隻讀的,但可以由驅動程式進行修改。要建立不可變屬性,驅動程式必須在屬性建立時設定DRM_MODE_PROP_IMMUTABLE标志。
如果在屬性建立時沒有值名稱對數組可用于枚舉或範圍屬性,驅動程式可以使用該
drm_property_create
函數建立屬性,并通過調用該
drm_property_add_enum
函數手動添加枚舉值名稱對 。必須注意通過
flags
參數正确指定屬性類型。
建立屬性後,驅動程式可以通過調用
drm_object_attach_property
将屬性執行個體附加到CRTC,連接配接器和平面對象 。該函數擷取指向目标對象的指針,指向先前建立的屬性的指針和初始執行個體值。
垂直Blanking
垂直消隐在圖形渲染中起主要作用。為了實作無撕裂顯示,使用者必須将頁面翻轉和/或渲染與垂直消隐同步。DRM API提供了ioctl來執行與垂直消隐同步的頁面翻轉,并等待垂直消隐。
DRM核心處理大多數垂直消隐管理邏輯,其中包括濾除虛假中斷,保留無競争的消隐計數器,應對計數器環繞和複位以及保持使用計數。它依靠驅動程式生成垂直消隐中斷,并可選地提供硬體垂直消隐計數器。驅動程式必須執行以下操作。
-
啟用或禁用給定CRTC的垂直消隐中斷。int (*enable_vblank) (struct drm_device *dev, int crtc); void (*disable_vblank) (struct drm_device *dev, int crtc);
-
檢索給定CRTC的垂直消隐計數器的值。如果硬體保持垂直消隐計數器,則應傳回其值。否則,驅動程式可以使用u32 (*get_vblank_counter) (struct drm_device *dev, int crtc);
助手功能來處理此操作。drm_vblank_count
驅動程式必須在
load
操作中通過
drm_vblank_init
調用來初始化垂直消隐處理核心 。該函數會将struct drm_device
vblank_disable_allowed
字段設定 為0。這将使垂直消隐中斷永久啟用,直到第一個模式設定操作(其中
vblank_disable_allowed
設定為1)為止。其背後的原因尚不清楚。
調用drm_vblank_init後,
驅動程式可以将字段設定為1,以便從頭開始動态管理垂直消隐中斷。
垂直消隐中斷可以由DRM核心或驅動程式本身啟用(例如,處理頁面翻轉操作)。DRM核心維護垂直消隐使用計數,以確定在使用者仍需要中斷時不禁用這些中斷。要增加使用次數,驅動請調用
drm_vblank_get
。傳回時,保證将使能垂直消隐中斷。
要減少使用計數驅動程式,請調用
drm_vblank_put
。僅當使用計數降至零時,DRM核心才會通過排程計時器在延遲後禁用垂直消隐中斷。可通過vblankoffdelay子產品參數或
drm_vblank_offdelay
全局變量通路該延遲,并以毫秒為機關表示。其預設值為5000毫秒。
當發生垂直消隐中斷時,驅動程式隻需要調用該
drm_handle_vblank
函數即可解決該中斷。
必須通過
drm_vblank_cleanup
在驅動程式
unload
操作處理程式中調用來釋放 由
drm_vblank_init
配置設定的資源。
打開/關閉,檔案操作和IOCTL
打開和關閉
int (*firstopen) (struct drm_device *);
void (*lastclose) (struct drm_device *);
int (*open) (struct drm_device *, struct drm_file *);
void (*preclose) (struct drm_device *, struct drm_file *);
void (*postclose) (struct drm_device *, struct drm_file *);
打開和關閉處理程式。這些方法都不是強制性的。
firstopen
僅當應用程式打開沒有其他打開的檔案句柄的裝置時,DRM核心才會為舊版UMS(使用者模式設定)驅動程式調用 該方法。UMS驅動程式可以實作它以擷取裝置資源。KMS驅動程式不能使用該方法,而必須在該
load
方法中擷取資源。
同樣
lastclose
,對于UMS和KMS驅動程式,當最後一個在裝置上打開了打開檔案句柄的應用程式關閉時,将調用該方法。此外,在子產品解除安裝時或對于可熱插拔的裝置,在拔出裝置時也調用該方法。在
firstopen
和
lastclose
這樣的調用是不平衡的。
每次由應用程式打開裝置時都會調用
open
方法。驅動程式可以使用此方法配置設定每個檔案的私有資料,并将其存儲在struct drm_file
driver_priv
字段中。請注意,該
open
方法是在
firstopen
之前調用的。
關閉操作分為
preclose
和
postclose
方法。
preclose
方法中的,驅動程式必須停止并清除該所有per-file操作。例如,必須取消待處理的垂直消隐和頁面翻轉事件。從
preclose
方法傳回後,不允許對檔案句柄進行按檔案的操作。
最後,該
postclose
方法被稱為關閉操作的最後一步,如果裝置不存在其他打開檔案句柄,則在調用
lastclose
方法之前 調用。在
open
方法中配置設定了每個per-file私有資料的驅動程式應在此處釋放它。
該
lastclose
方法應将CRTC和平面屬性恢複為預設值,以便裝置的後續打開不會繼承先前使用者的狀态。它還可以用于執行延遲的電源開關狀态更改,例如,與vga-switcheroo基礎架構結合使用。除此之外,KMS驅動程式不應進行任何進一步的清理。隻有舊版UMS驅動程式可能需要清理裝置狀态,以便vga控制台或獨立的fbdev驅動程式可以接管。
檔案操作
const struct file_operations *fops
DRM裝置節點的檔案操作。
驅動程式必須定義構成DRM使用者空間API入口點的檔案操作結構,即使其中大多數操作是在DRM核心中實作的也是如此。的
open
,
release
和
ioctl
操作由處理
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
.unlocked_ioctl = drm_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = drm_compat_ioctl,
#endif
實作需要32/64位相容性支援的私有ioctl的驅動程式必須提供自己的
compat_ioctl
處理程式,該處理器處理私有ioctl并調用
drm_compat_ioctl
核心ioctl。
在
read
與
poll
操作讀取DRM事件和輪詢他們提供支援。它們由
.poll = drm_poll,
.read = drm_read,
.llseek = no_llseek
記憶體映射的實作方式取決于驅動程式如何管理記憶體。将使用Pre-GEM驅動程式
drm_mmap
,而将使用支援GEM的驅動程式
drm_gem_mmap
。請參閱 “圖形執行管理器(GEM)”部分。
.mmap = drm_gem_mmap,
DRM API不支援其他檔案操作。
IOCTLS
struct drm_ioctl_desc *ioctls;
int num_ioctls
特定于驅動程式的ioctls描述符表。
特定于驅動程式的ioctl數字從DRM_COMMAND_BASE開始。ioctl描述符表由距基準值的ioctl編号索引。驅動程式可以使用DRM_IOCTL_DEF_DRV()宏來初始化表條目。
DRM_IOCTL_DEF_DRV(ioctl, func, flags)
ioctl
是ioctl名稱。驅動程式必須将DRM _ ## ioctl和DRM_IOCTL _ ## ioctl宏定義為分别偏離DRM_COMMAND_BASE和ioctl編号的ioctl編号。第一個宏是裝置專用的,而第二個宏必須在公共頭檔案中公開給使用者空間。
func
是指向與drm_ioctl_t類型相容的ioctl處理函數的指針。
typedef int drm_ioctl_t(struct drm_device *dev, void *data,
struct drm_file *file_priv);
flags
是以下值的位掩碼組合。它限制了如何調用ioctl。
- DRM_AUTH-僅允許通過身份驗證的呼叫者
- DRM_MASTER-ioctl隻能在主檔案句柄上調用
- DRM_ROOT_ONLY-僅允許具有SYSADMIN功能的呼叫者
- DRM_CONTROL_ALLOW-ioctl隻能在控制裝置上調用
- DRM_UNLOCKED-将在不鎖定DRM全局互斥鎖的情況下調用ioctl處理程式
指令送出和防護
這應該涵蓋一些特定于裝置的指令送出實作。
睡眠/喚醒
DRM核心提供了一些挂起/恢複代碼,但是想要完全挂起/恢複支援的驅動程式應提供save()和restore()函數。這些在挂起,休眠或恢複時間被調用,并且應在挂起或休眠狀态之間執行裝置所需的任何狀态儲存或還原。
int (*suspend) (struct drm_device *, pm_message_t state);
int (*resume) (struct drm_device *);
這些是傳統的挂起和恢複方法。新的驅動程式應該使用自己的總線類型提供的電源管理接口(通常是通過結構的device_driver dev_pm_ops),并設定這些方法為NULL。
DMA服務
這應該涵蓋核心如何支援DMA映射等。這些功能已被棄用,不應使用。
第3章User空間接口
目錄
渲染節點
VBlank事件處理
DRM核心将幾個接口導出到應用程式,這些接口通常旨在通過相應的libdrm包裝函數使用。另外,驅動程式通過ioctl和sysfs檔案導出裝置專用的接口,以供使用者空間驅動程式和支援裝置的應用程式使用。
外部接口包括:記憶體映射,上下文管理,DMA操作,AGP管理,vblank控制,fence管理,記憶體管理和輸出管理。
在這裡介紹通用的ioctl和sysfs布局。我們隻需要進階資訊,因為手冊頁應涵蓋其餘内容。
渲染節點
DRM核心提供了多個字元裝置供使用者空間使用。根據打開哪個裝置,使用者空間可以執行一組不同的操作(主要是ioctl)。主節點始終被建立并稱為<term> card <num> </ term>。此外,還将建立一個稱為<term> controlD <num> </ term>的目前未使用的控制節點。主節點提供所有舊操作,并且曆史上是使用者空間使用的唯一接口。通過KMS,引入了控制節點。但是,尚未編寫計劃的KMS控制界面,是以該控制節點至今仍未使用。
随着螢幕外渲染器和GPGPU應用程式使用的增加,用戶端不再需要運作合成器或圖形伺服器來使用GPU。但是DRM API要求非特權用戶端在通路GPU之前必須先向DRM-Master進行身份驗證。為了避免此步驟并在不進行身份驗證的情況下授予用戶端GPU通路權限,引入了渲染節點。渲染節點僅服務于渲染用戶端,也就是說,無法在渲染節點上釋出模式設定或特權ioctl。僅允許使用非全局渲染指令。如果驅動程式支援渲染節點,則它必須通過<term> DRIVER_RENDER </ term>進行播發 DRM驅動程式功能。如果不支援,則必須将主節點與舊版drmAuth身份驗證過程一起用于渲染用戶端。
如果驅動程式宣告支援渲染節點,則DRM核心将建立一個名為<term> renderD <num> </ term>的單獨渲染節點。每個裝置将有一個渲染節點。除了與PRIME相關的ioctl之外,此節點上均不允許其他ioctl。特别是明确禁止<term> GEM_OPEN </ term>。渲染節點旨在避免緩沖區洩漏,如果用戶端猜測舊界面上的flink名稱或mmap偏移量,則會發生緩沖區洩漏。除此基本界面外,驅動程式必須将其依賴于驅動程式的僅渲染ioctl标記為 <term> DRM_RENDER_ALLOW </ term>是以渲染用戶端可以使用它們。驅動程式作者必須小心,不要在渲染節點上允許任何特權的ioctl。
使用渲染節點,使用者空間現在可以通過基本檔案系統通路模式來控制對渲染節點的通路。不再需要用于在特權的主/舊版節點上對用戶端進行身份驗證的圖形伺服器。相反,用戶端可以打開渲染節點并立即被授予GPU通路權限。用戶端(或伺服器)之間的通信是通過PRIME完成的。不支援從渲染節點到舊版節點的FLINK。新用戶端不得使用不安全的FLINK接口。
除了删除所有模式集/全局圖示外,渲染節點還删除DRM-Master概念。沒有理由将渲染用戶端與DRM-Master關聯,因為它們獨立于任何圖形伺服器。此外,無論如何,它們必須在沒有任何運作主機的情況下工作。如果驅動程式支援渲染節點,則它們必須能夠在沒有主對象的情況下運作。另一方面,如果驅動程式要求用戶端之間的共享狀态對使用者空間可見并且可以在打開檔案邊界之外通路,則它們不支援渲染節點。
VBlank事件處理
DRM核心公開了兩個垂直的空白相關的ioctl:
DRM_IOCTL_WAIT_VBLANK
這以struct drm_wait_vblank結構作為其參數,并在發生指定的vblank事件時用于阻止或請求信号。
DRM_IOCTL_MODESET_CTL
在模式設定之前和之後,應由應用程式級别的驅動程式調用此方法,因為在許多裝置上,垂直空白計數器當時會被重置。在内部,當使用_DRM_PRE_MODESET指令調用ioctl時,DRM會對最後的vblank計數進行快照,以使計數器不會向後移動(使用_DRM_POST_MODESET時将進行處理)。
附錄A.DRM驅動程式API
在此處包括自動生成的API參考(也需要在以上段落中進行參考)。