2.5. V4L2 裝置例項

每個裝置例項由 struct v4l2_device 表示。非常簡單的裝置可以直接分配此結構,但大多數情況下,您會將此結構嵌入到更大的結構中。

您必須透過呼叫以下函式來註冊裝置例項:

註冊將初始化 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 例項設定名稱。這將生成類似 ivtv0ivtv1 等名稱。如果名稱以數字結尾,則它將插入一個破折號:cx18-0cx18-1 等。此函式返回例項編號。

第一個 dev 引數通常是 struct device 指標,指向 pci_devusb_interfaceplatform_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 裝置級支援。

注意

  1. dev->driver_data 指向此結構。

  2. 如果沒有父裝置,則 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 設備註銷子裝置。

引數

struct v4l2_subdev *sd

指向 struct v4l2_subdev 的指標

描述

注意

如果未註冊子裝置,也可以呼叫此函式。在這種情況下,它將不執行任何操作。

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_dev

struct v4l2_device 擁有要迭代的子裝置。

描述

此宏迭代 v4l2_dev 裝置擁有的所有子裝置。它充當 for 迴圈迭代器,並執行下一個語句,其中 sd 變數依次指向每個子裝置。

__v4l2_device_call_subdevs_p

__v4l2_device_call_subdevs_p (v4l2_dev, sd, cond, o, f, args...)

為所有匹配條件的子裝置呼叫指定的操作。

引數

v4l2_dev

struct v4l2_device 擁有要迭代的子裝置。

sd

指標,宏將使用所有 struct v4l2_subdev 指標填充該指標,作為迴圈的迭代器使用。

cond

要匹配的條件

o

struct 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_dev

struct v4l2_device 擁有要迭代的子裝置。

cond

要匹配的條件

o

struct 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_dev

struct v4l2_device 擁有要迭代的子裝置。

sd

指標,宏將使用與 v4l2_dev 關聯的所有 struct v4l2_subdev 子裝置填充該指標。

cond

要匹配的條件

o

struct 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_dev

struct v4l2_device 擁有要迭代的子裝置。

cond

要匹配的條件

o

struct 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_dev

struct v4l2_device 擁有要迭代的子裝置。

grpid

struct v4l2_subdev->grp_id 要匹配的組 ID。使用 0 匹配所有組。

o

struct 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_dev

struct v4l2_device 擁有要迭代的子裝置。

grpid

struct v4l2_subdev->grp_id 要匹配的組 ID。使用 0 匹配所有組。

o

struct 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_dev

struct v4l2_device 擁有要迭代的子裝置。

grpmsk

要對照 struct v4l2_subdev->grp_id 組 ID 檢查的位掩碼。使用 0 匹配所有組。

o

struct 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_dev

struct v4l2_device 擁有要迭代的子裝置。

grpmsk

要對照 struct v4l2_subdev->grp_id 組 ID 檢查的位掩碼。使用 0 匹配所有組。

o

struct 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_dev

struct v4l2_device 擁有要迭代的子裝置。

grpid

struct v4l2_subdev->grp_id 要匹配的組 ID。使用 0 匹配所有組。

o

struct 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_dev

struct v4l2_device 擁有要迭代的子裝置。

grpmsk

要對照 struct v4l2_subdev->grp_id 組 ID 檢查的位掩碼。使用 0 匹配所有組。

o

struct v4l2_subdev_ops 中包含 f 的元素的名稱。那裡的每個元素都對一組操作函式進行分組。

f

如果 cond 匹配,將呼叫的操作函式。操作函式根據 struct v4l2_subdev_ops 中的每個元素,按組定義。