2.5. V4L2 裝置例項¶
每個裝置例項由 struct v4l2_device 表示。非常簡單的裝置可以直接分配此結構,但大多數情況下,您會將此結構嵌入到更大的結構中。
您必須透過呼叫以下函式來註冊裝置例項:
v4l2_device_register(dev,v4l2_dev)。
註冊將初始化 v4l2_device 結構。如果 dev->driver_data 欄位為 NULL,它將被連結到 v4l2_dev 引數。
想要與媒體裝置框架整合的驅動程式需要手動設定 dev->driver_data 以指向嵌入 struct v4l2_device 例項的驅動程式特定裝置結構。這是透過在註冊 V4L2 裝置例項之前呼叫 dev_set_drvdata() 實現的。它們還必須設定 struct v4l2_device mdev 欄位以指向已正確初始化和註冊的 media_device 例項。
如果 v4l2_dev->name 為空,則它將被設定為從 dev 派生的值(驅動程式名稱後跟 bus_id,更準確地說)。如果您在呼叫 v4l2_device_register() 之前設定它,則它將保持不變。如果 dev 為 NULL,則您必須在呼叫 v4l2_device_register() 之前設定 v4l2_dev->name。
您可以使用 v4l2_device_set_name() 根據驅動程式名稱和驅動程式全域性 atomic_t 例項設定名稱。這將生成類似 ivtv0、ivtv1 等名稱。如果名稱以數字結尾,則它將插入一個破折號:cx18-0、cx18-1 等。此函式返回例項編號。
第一個 dev 引數通常是 struct device 指標,指向 pci_dev、usb_interface 或 platform_device。dev 為 NULL 的情況很少見,但在 ISA 裝置或一個裝置建立多個 PCI 裝置時會發生這種情況,從而無法將 v4l2_dev 與特定父級關聯。
您還可以提供一個 notify() 回撥,子裝置可以呼叫該回調來通知您事件。是否需要設定此回撥取決於子裝置。子裝置支援的任何通知都必須在 include/media/subdevice.h 中的標頭中定義。
V4L2 裝置透過呼叫以下函式登出:
如果 dev->driver_data 欄位指向 v4l2_dev,它將被重置為 NULL。登出還將自動從設備註銷所有子裝置。
如果您有一個熱插拔裝置(例如 USB 裝置),則當發生斷開連線時,父裝置將變為無效。由於 v4l2_device 有一個指向該父裝置的指標,因此也必須清除它以標記父裝置已消失。為此,請呼叫
這不會登出子裝置,因此您仍然需要呼叫 v4l2_device_unregister() 函式。如果您的驅動程式不是熱插拔的,則無需呼叫 v4l2_device_disconnect()。
有時您需要迭代特定驅動程式註冊的所有裝置。如果多個裝置驅動程式使用相同的硬體,通常會發生這種情況。例如,ivtvfb 驅動程式是一個幀緩衝驅動程式,它使用 ivtv 硬體。例如,alsa 驅動程式也是如此。
您可以按如下方式迭代所有註冊裝置:
static int callback(struct device *dev, void *p)
{
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
/* test if this device was inited */
if (v4l2_dev == NULL)
return 0;
...
return 0;
}
int iterate(void *p)
{
struct device_driver *drv;
int err;
/* Find driver 'ivtv' on the PCI bus.
pci_bus_type is a global. For USB buses use usb_bus_type. */
drv = driver_find("ivtv", &pci_bus_type);
/* iterate over all ivtv device instances */
err = driver_for_each_device(drv, NULL, p, callback);
put_driver(drv);
return err;
}
有時您需要保持裝置例項的執行計數器。這通常用於將裝置例項對映到模組選項陣列的索引。
推薦的方法如下:
static atomic_t drv_instance = ATOMIC_INIT(0);
static int drv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
{
...
state->instance = atomic_inc_return(&drv_instance) - 1;
}
如果您有多個裝置節點,則很難知道何時可以安全地為熱插拔設備註銷 v4l2_device。為此,v4l2_device 具有引用計數支援。每當呼叫 video_register_device() 時,引用計數就會增加,每當釋放該裝置節點時,引用計數就會減少。當引用計數達到零時,將呼叫 v4l2_device release() 回撥。您可以在那裡進行最終清理。
如果建立了其他裝置節點(例如 ALSA),您也可以透過呼叫以下函式手動增加和減少引用計數:
或
由於初始引用計數為 1,因此您還需要在 disconnect() 回撥(對於 USB 裝置)或 remove() 回撥(對於例如 PCI 裝置)中呼叫 v4l2_device_put(),否則引用計數將永遠不會達到 0。
2.5.1. v4l2_device 函式和資料結構¶
-
struct v4l2_device¶
V4L2 裝置驅動程式的主要結構
定義:
struct v4l2_device {
struct device *dev;
struct media_device *mdev;
struct list_head subdevs;
spinlock_t lock;
char name[36];
void (*notify)(struct v4l2_subdev *sd, unsigned int notification, void *arg);
struct v4l2_ctrl_handler *ctrl_handler;
struct v4l2_prio_state prio;
struct kref ref;
void (*release)(struct v4l2_device *v4l2_dev);
};
成員
dev指向
struct device的指標。mdev指向
struct media_device的指標,可以為 NULL。subdevs用於跟蹤已註冊的子裝置
lock鎖定此結構;如果此結構嵌入到更大的結構中,驅動程式也可以使用它。
name唯一的裝置名稱,預設情況下為驅動程式名稱 + 匯流排 ID
notify由某些子裝置呼叫的通知操作。
ctrl_handler控制處理程式。可以為
NULL。prio裝置的優先順序狀態
ref跟蹤對此結構的引用。
release當引用計數變為 0 時呼叫的釋放函式。
描述
V4L2 裝置的每個例項都應建立 v4l2_device 結構,無論是獨立的還是嵌入到更大的結構中。
它允許輕鬆訪問子裝置(參見 v4l2-subdev.h)並提供基本的 V4L2 裝置級支援。
注意
dev->driver_data 指向此結構。
如果沒有父裝置,則 dev 可能為
NULL
-
void v4l2_device_get(struct v4l2_device *v4l2_dev)¶
獲取 V4L2 裝置引用
引數
struct v4l2_device *v4l2_dev指向
v4l2_device結構的指標
描述
這是一個輔助例程,旨在增加 v4l2_dev 指向的 v4l2_device 結構的使用計數。
-
int v4l2_device_put(struct v4l2_device *v4l2_dev)¶
釋放 V4L2 裝置引用
引數
struct v4l2_device *v4l2_dev指向
v4l2_device結構的指標
描述
這是一個輔助例程,旨在減少 v4l2_dev 指向的 v4l2_device 結構的使用計數。
-
int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)¶
初始化 v4l2_dev 並使 dev->driver_data 指向 v4l2_dev。
引數
struct device *dev指向
device結構的指標struct v4l2_device *v4l2_dev指向
v4l2_device結構的指標
描述
注意
在極少數情況下(ISA 裝置),dev 可能為 NULL。在這種情況下,呼叫者必須在呼叫此函式之前填充 v4l2_dev->name 欄位。
-
int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename, atomic_t *instance)¶
可選函式,用於初始化
v4l2_device結構的 name 欄位
引數
struct v4l2_device *v4l2_dev指向
v4l2_device結構的指標const char *basename裝置名稱的基本名稱
atomic_t *instance指向具有裝置驅動程式的例項用法的靜態 atomic_t 變數的指標。
描述
v4l2_device_set_name() 使用驅動程式名稱和驅動程式全域性 atomic_t 例項初始化 v4l2_device 結構的 name 欄位。
此函式將遞增例項計數器並返回名稱中使用的例項值。
首次呼叫此函式時,name 欄位將設定為 foo0,此函式返回 0。如果名稱以數字結尾(例如 cx18),則名稱將設定為 cx18-0,因為 cx180 看起來會非常奇怪。
示例
static atomic_t drv_instance = ATOMIC_INIT(0);
...
instance = v4l2_device_set_name(&v4l2_dev, “foo”, &drv_instance);
-
void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)¶
將 V4L2 裝置狀態更改為已斷開連線。
引數
struct v4l2_device *v4l2_dev指向
struct v4l2_device的指標
描述
應在 USB 父裝置斷開連線時呼叫。由於父裝置消失,這可確保 v4l2_dev 沒有無效的父指標。
注意
此函式將 v4l2_dev->dev 設定為 NULL。
-
void v4l2_device_unregister(struct v4l2_device *v4l2_dev)¶
登出所有子裝置以及與 v4l2_dev 相關的任何其他資源。
引數
struct v4l2_device *v4l2_dev指向
struct v4l2_device的指標
-
v4l2_device_register_subdev¶
v4l2_device_register_subdev (v4l2_dev, sd)
向 v4l2 設備註冊子裝置。
引數
v4l2_dev指向
v4l2_device結構的指標sd指向
struct v4l2_subdev的指標
描述
註冊後,子裝置模組將被標記為正在使用。
如果模組不再載入任何註冊嘗試,則會返回錯誤。
-
void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)¶
從 v4l2 設備註銷子裝置。
-
int __v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev, bool read_only)¶
為標記有
V4L2_SUBDEV_FL_HAS_DEVNODE標誌的 v4l2 裝置的所有子設備註冊裝置節點。
引數
struct v4l2_device *v4l2_dev指向
struct v4l2_device的指標bool read_only子裝置只讀標誌。True 以只讀模式註冊子裝置裝置節點,false 以允許完全訪問子裝置使用者空間 API。
-
int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev)¶
註冊具有對子裝置使用者空間操作的無限制訪問許可權的子裝置裝置節點
引數
struct v4l2_device *v4l2_dev指向
struct v4l2_device的指標
描述
在內部呼叫 __v4l2_device_register_subdev_nodes()。有關更多詳細資訊,請參見其文件。
-
int v4l2_device_register_ro_subdev_nodes(struct v4l2_device *v4l2_dev)¶
以只讀模式註冊子裝置裝置節點
引數
struct v4l2_device *v4l2_dev指向
struct v4l2_device的指標
描述
在內部呼叫 __v4l2_device_register_subdev_nodes()。有關更多詳細資訊,請參見其文件。
-
void v4l2_subdev_notify(struct v4l2_subdev *sd, unsigned int notification, void *arg)¶
向 v4l2_device 傳送通知。
引數
struct v4l2_subdev *sd指向
struct v4l2_subdev的指標unsigned int notification通知型別。請注意,通知型別是驅動程式特定的。
void *arg通知的引數。這些引數特定於每種通知型別。
-
bool v4l2_device_supports_requests(struct v4l2_device *v4l2_dev)¶
測試是否支援請求。
引數
struct v4l2_device *v4l2_dev指向
struct v4l2_device的指標
-
v4l2_device_for_each_subdev¶
v4l2_device_for_each_subdev (sd, v4l2_dev)
輔助宏,用於迭代給定
v4l2_device的所有子裝置。
引數
sd指標,宏將使用所有
struct v4l2_subdev指標填充該指標,作為迴圈的迭代器使用。v4l2_devstruct v4l2_device擁有要迭代的子裝置。
描述
此宏迭代 v4l2_dev 裝置擁有的所有子裝置。它充當 for 迴圈迭代器,並執行下一個語句,其中 sd 變數依次指向每個子裝置。
-
__v4l2_device_call_subdevs_p¶
__v4l2_device_call_subdevs_p (v4l2_dev, sd, cond, o, f, args...)
為所有匹配條件的子裝置呼叫指定的操作。
引數
v4l2_devstruct v4l2_device擁有要迭代的子裝置。sd指標,宏將使用所有
struct v4l2_subdev指標填充該指標,作為迴圈的迭代器使用。cond要匹配的條件
ostruct v4l2_subdev_ops中包含 f 的元素的名稱。那裡的每個元素都對一組操作函式進行分組。f如果 cond 匹配,將呼叫的操作函式。操作函式根據
struct v4l2_subdev_ops中的每個元素,按組定義。args...f 的引數。
描述
忽略任何錯誤。
注意
在遍歷子裝置列表時,無法新增或刪除子裝置。
-
__v4l2_device_call_subdevs¶
__v4l2_device_call_subdevs (v4l2_dev, cond, o, f, args...)
為所有匹配條件的子裝置呼叫指定的操作。
引數
v4l2_devstruct v4l2_device擁有要迭代的子裝置。cond要匹配的條件
ostruct v4l2_subdev_ops中包含 f 的元素的名稱。那裡的每個元素都對一組操作函式進行分組。f如果 cond 匹配,將呼叫的操作函式。操作函式根據
struct v4l2_subdev_ops中的每個元素,按組定義。args...f 的引數。
描述
忽略任何錯誤。
注意
在遍歷子裝置列表時,無法新增或刪除子裝置。
-
__v4l2_device_call_subdevs_until_err_p¶
__v4l2_device_call_subdevs_until_err_p (v4l2_dev, sd, cond, o, f, args...)
為所有匹配條件的子裝置呼叫指定的操作。
引數
v4l2_devstruct v4l2_device擁有要迭代的子裝置。sd指標,宏將使用與 v4l2_dev 關聯的所有
struct v4l2_subdev子裝置填充該指標。cond要匹配的條件
ostruct v4l2_subdev_ops中包含 f 的元素的名稱。那裡的每個元素都對一組操作函式進行分組。f如果 cond 匹配,將呼叫的操作函式。操作函式根據
struct v4l2_subdev_ops中的每個元素,按組定義。args...f 的引數。
描述
如果操作為任何子裝置返回除 0 或 -ENOIOCTLCMD 以外的錯誤,則中止並返回該錯誤程式碼,否則返回零。
注意
在遍歷子裝置列表時,無法新增或刪除子裝置。
-
__v4l2_device_call_subdevs_until_err¶
__v4l2_device_call_subdevs_until_err (v4l2_dev, cond, o, f, args...)
為所有匹配條件的子裝置呼叫指定的操作。
引數
v4l2_devstruct v4l2_device擁有要迭代的子裝置。cond要匹配的條件
ostruct v4l2_subdev_ops中包含 f 的元素的名稱。那裡的每個元素都對一組操作函式進行分組。f如果 cond 匹配,將呼叫的操作函式。操作函式根據
struct v4l2_subdev_ops中的每個元素,按組定義。args...f 的引數。
描述
如果操作為任何子裝置返回除 0 或 -ENOIOCTLCMD 以外的錯誤,則中止並返回該錯誤程式碼,否則返回零。
注意
在遍歷子裝置列表時,無法新增或刪除子裝置。
-
v4l2_device_call_all¶
v4l2_device_call_all (v4l2_dev, grpid, o, f, args...)
為所有匹配
v4l2_subdev.grp_id的子裝置呼叫指定的操作,如橋接驅動程式分配的。
引數
v4l2_devstruct v4l2_device擁有要迭代的子裝置。grpidstruct v4l2_subdev->grp_id 要匹配的組 ID。使用 0 匹配所有組。ostruct v4l2_subdev_ops中包含 f 的元素的名稱。那裡的每個元素都對一組操作函式進行分組。f如果 cond 匹配,將呼叫的操作函式。操作函式根據
struct v4l2_subdev_ops中的每個元素,按組定義。args...f 的引數。
描述
忽略任何錯誤。
注意
在遍歷子裝置列表時,無法新增或刪除子裝置。
-
v4l2_device_call_until_err¶
v4l2_device_call_until_err (v4l2_dev, grpid, o, f, args...)
為所有匹配
v4l2_subdev.grp_id的子裝置呼叫指定的操作,如橋接驅動程式分配的,直到發生錯誤。
引數
v4l2_devstruct v4l2_device擁有要迭代的子裝置。grpidstruct v4l2_subdev->grp_id 要匹配的組 ID。使用 0 匹配所有組。ostruct v4l2_subdev_ops中包含 f 的元素的名稱。那裡的每個元素都對一組操作函式進行分組。f如果 cond 匹配,將呼叫的操作函式。操作函式根據
struct v4l2_subdev_ops中的每個元素,按組定義。args...f 的引數。
描述
如果操作為任何子裝置返回除 0 或 -ENOIOCTLCMD 以外的錯誤,則中止並返回該錯誤程式碼,否則返回零。
注意
在遍歷子裝置列表時,無法新增或刪除子裝置。
-
v4l2_device_mask_call_all¶
v4l2_device_mask_call_all (v4l2_dev, grpmsk, o, f, args...)
為組 ID 匹配指定位掩碼的所有子裝置呼叫指定的操作。
引數
v4l2_devstruct v4l2_device擁有要迭代的子裝置。grpmsk要對照
struct v4l2_subdev->grp_id 組 ID 檢查的位掩碼。使用 0 匹配所有組。ostruct v4l2_subdev_ops中包含 f 的元素的名稱。那裡的每個元素都對一組操作函式進行分組。f如果 cond 匹配,將呼叫的操作函式。操作函式根據
struct v4l2_subdev_ops中的每個元素,按組定義。args...f 的引數。
描述
忽略任何錯誤。
注意
在遍歷子裝置列表時,無法新增或刪除子裝置。
-
v4l2_device_mask_call_until_err¶
v4l2_device_mask_call_until_err (v4l2_dev, grpmsk, o, f, args...)
為組 ID 匹配指定位掩碼的所有子裝置呼叫指定的操作。
引數
v4l2_devstruct v4l2_device擁有要迭代的子裝置。grpmsk要對照
struct v4l2_subdev->grp_id 組 ID 檢查的位掩碼。使用 0 匹配所有組。ostruct v4l2_subdev_ops中包含 f 的元素的名稱。那裡的每個元素都對一組操作函式進行分組。f如果 cond 匹配,將呼叫的操作函式。操作函式根據
struct v4l2_subdev_ops中的每個元素,按組定義。args...f 的引數。
描述
如果操作為任何子裝置返回除 0 或 -ENOIOCTLCMD 以外的錯誤,則中止並返回該錯誤程式碼,否則返回零。
注意
在遍歷子裝置列表時,無法新增或刪除子裝置。
-
v4l2_device_has_op¶
v4l2_device_has_op (v4l2_dev, grpid, o, f)
檢查是否任何匹配 grpid 的子裝置具有給定的 ops。
引數
v4l2_devstruct v4l2_device擁有要迭代的子裝置。grpidstruct v4l2_subdev->grp_id 要匹配的組 ID。使用 0 匹配所有組。ostruct v4l2_subdev_ops中包含 f 的元素的名稱。那裡的每個元素都對一組操作函式進行分組。f如果 cond 匹配,將呼叫的操作函式。操作函式根據
struct v4l2_subdev_ops中的每個元素,按組定義。
-
v4l2_device_mask_has_op¶
v4l2_device_mask_has_op (v4l2_dev, grpmsk, o, f)
檢查是否任何匹配組掩碼的子裝置具有給定的 ops。
引數
v4l2_devstruct v4l2_device擁有要迭代的子裝置。grpmsk要對照
struct v4l2_subdev->grp_id 組 ID 檢查的位掩碼。使用 0 匹配所有組。ostruct v4l2_subdev_ops中包含 f 的元素的名稱。那裡的每個元素都對一組操作函式進行分組。f如果 cond 匹配,將呼叫的操作函式。操作函式根據
struct v4l2_subdev_ops中的每個元素,按組定義。