Video4Linux2 part 3: Basic ioctl() handling
V4L2 第三部分:基本ioctl()處理
Anybody who has spent any amount of time working through the Video4Linux2 API specification will have certainly noted that V4L2 makes heavy use of the ioctl() interface. Perhaps more than just about any other type of peripheral, video hardware has a vast number of knobs to tweak. Video streams have many parameters associated with them, and, often, there is quite a bit of processing done in the hardware. Trying to operate video hardware outside of its well-supported modes can lead to poor performance at best, and often no performance at all. So there is no alternative to exposing many of the hardware's features and quirks to the end application.
只要是在V4L2 API規格文檔上面花費了一定數量時間的人,都一定會發現:V4L2使用了很多ioctl()介面。不僅外設有很多種,視頻硬體也都有很多旋鈕要需要我們去擰。視頻流上關聯了很多參數,相應地,硬體內部就需要做一點處理。試著讓硬體工作在它支援良好的模式之外,會導致效能很差,通常沒什麼效能可言。因此,我們沒有替代方案,只能暴露很多硬體特性和機關,給終端應用程式。
Traditionally, video drivers have included ioctl() functions of approximately the same length as a Neal Stephenson novel; while the functions often come to more satisfying conclusions than the novels, they do tend to drag a lot in the middle. So the V4L2 API was changed in 2.6.18; the interminable ioctl() function has been replaced with a large set of callbacks which implement the individual ioctl() functions. There are, in fact, 79 of them in 2.6.19-rc3. Fortunately, most drivers need not implement all - or even most - of the possible callbacks.
傳統上,視頻驅動包含的ioctl()函數差不多跟Neal Stephenson的小說一樣長;這些函數比小說的效果更好:它們在中間故意拖拉的更長。因此V4L2 API從2.6.18開始更改了;這些沒完沒了的ioctl()函數被一組回呼函數替代了,這些回呼函數可以用來實現ioctl()的功能。事實上,2.6.19-rc3一共有79個回呼函數。幸運的是,大多數驅動不需要實現全部回調,或者大部分回呼函數都不需要去實現。
What has really happened is that the long ioctl() function has been moved into drivers/media/video/videodev.c. This code handles the movement of data between user and kernel space and dispatches individual ioctl() calls to the driver. To use it, the driver need only use video_ioctl2() as its ioctl() method in the video_device structure. Actually, most drivers should be able to use it as unlocked_ioctl() instead; the locking within the Video4Linux2 layer can handle it, and drivers should have proper locking in place as well.
事實上,大部分ioctl()函數已經被移到drivers/media/video/videodev.c中去了。這些代碼處理了使用者空間和核心空間資料的搬遷,和私人的ioctl()調度。要使用它,驅動只需使用video_ioctl2()作為它的ioctl()方法,對結構體video_device中的ioctl()進行賦值。事實上,大部分驅動也可以使用unlocked_ioctl()作為它的ioctl()方法;V4L2的加鎖操作能夠處理它,驅動本來就有合適的地方加鎖的。
The first callback your driver is likely to implement is:
int (*vidioc_querycap)(struct file *file, void *priv, struct v4l2_capability *cap);
This function handles the VIDIOC_QUERYCAPioctl(), which asks a simple "who are you and what can you do?" question. Implementing it is mandatory for V4L2 drivers. In this function, as with all other V4L2 callbacks, the priv argument is the contents of file->private_data field; the usual practice is to point it at the driver's internal structure representing the device at open() time.
第一個要實現的回呼函數很可能是這個:
int (*vidioc_querycap)(struct file *file, void *priv, struct v4l2_capability *cap);
這個函數處理VIDIOC_QUERYCAPioctl(),它總是問“你是誰你能做什麼”這個問題。實現它是必須的。這個函數內,priv入參就是 file->private_data成員變數,通常是指向驅動的內部的一個結構體,代表open()時開啟的裝置。
The driver should respond by filling in the structure cap and returning the usual "zero or negative error code" value. On successful return, the V4L2 layer will take care of copying the response back into user space.
驅動響應的時候,應該填充結構體cap,並且返回0或者負值的錯誤碼。成功返回時,V4L2層負責將響應拷貝到使用者空間。
The v4l2_capability structure (defined in <linux/videodev2.h>) looks like this:
struct v4l2_capability
{
__u8 driver[16]; /* i.e. "bttv" */
__u8 card[32]; /* i.e. "Hauppauge WinTV" */
__u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */
__u32 version; /* should use KERNEL_VERSION() */
__u32 capabilities; /* Device capabilities */
__u32 reserved[4];
};
v4l2_capability結構體定義在<linux/videodev2.h>,如下所示:
struct v4l2_capability
{
__u8 driver[16]; /* i.e. "bttv" */
__u8 card[32]; /* i.e. "Hauppauge WinTV" */
__u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */
__u32 version; /* should use KERNEL_VERSION() */
__u32 capabilities; /* Device capabilities */
__u32 reserved[4];
};
The driver field should be filled in with the name of the device driver, while the card field should have a description of the hardware behind this particular device. Not all drivers bother with the bus_info field; those that do usually use something like:
sprintf(cap->bus_info, "PCI:%s", pci_name(&my_dev));
driver這個成員變數應該填寫裝置驅動的名字,card成員變數應該填寫緊隨特定裝置的硬體描述。不是所有的驅動都關注bus_info成員變數;關注該成員變數,可能會這麼做:
sprintf(cap->bus_info, "PCI:%s", pci_name(&my_dev));