Anybody who has spent any amount of time working through the Video4Linux2 APIspecification will have certainly noted that V4L2 makes heavy use ofthe ioctl() interface. Perhaps more than just about any othertype 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 tooperate video hardware outside of its well-supported modes can lead to poorperformance at best, and often no performance at all. So there is noalternative to exposing many of the hardware's features and quirks to theend application.
Traditionally, video drivers have included ioctl() functions ofapproximately the same length as a Neal Stephenson novel; while thefunctions often come to more satisfying conclusions than the novels, theydo tend to drag a lot in the middle. So the V4L2 API was changed in2.6.18; the interminable ioctl() function has been replaced with alarge 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 possiblecallbacks.
What has really happened is that the long ioctl() function hasbeen moved into drivers/media/video/videodev.c. This code handlesthe movement of data between user and kernel space and dispatchesindividual ioctl() calls to the driver. To use it, the driverneed only use video_ioctl2() as its ioctl() method in thevideo_device structure. Actually, most drivers should be able touse it as unlocked_ioctl() instead; the locking within theVideo4Linux2 layer can handle it, and drivers should have proper locking inplace as well.
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_QUERYCAP ioctl(), whichasks a simple "who are you and what can you do?" question. Implementing itis mandatory for V4L2 drivers. In this function, as with all other V4L2callbacks, the priv argument is the contents of file->private_data field; the usual practice is to point it atthe driver's internal structure representing the device at open()time.
The driver should respond by filling in thestructure cap and returning the usual "zero or negative errorcode" value. On successful return, the V4L2 layer will take care ofcopying the response back into user space.
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]; };
The driver field should be filled in with the name of the devicedriver, while the card field should have a description of thehardware behind this particular device. Not all drivers bother with thebus_info field; those that do usually use something like:
sprintf(cap->bus_info, "PCI:%s", pci_name(&my_dev));
The version field holds a version number for the driver. Thecapabilities field is a bitmask describing various things that thedriver can do:
The final field (reserved) should be left alone. The V4L2specification requires that reserved be set to zero, but, sincevideo_ioctl2() sets the entire structure to zero, that is nicelytaken care of.
A fairly typical implementation can be found in the "vivi" driver:
static int vidioc_querycap (struct file *file, void *priv, struct v4l2_capability *cap) { strcpy(cap->driver, "vivi"); strcpy(cap->card, "vivi"); cap->version = VIVI_VERSION; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; return 0; }
Given the presence of this call, one would expect that applications woulduse it and avoid asking specific devices to perform functions that they arenot capable of. In your editor's limited experience, however, applicationstend not to pay much attention to the VIDIOC_QUERYCAP call.
Another callback, which is optional and not often implemented, is:
int (*vidioc_log_status) (struct file *file, void *priv);
This function, implementing VIDIOC_LOG_STATUS, is intended to be adebugging aid for video application writers. When called, it should printinformation describing the current status of the driver and its hardware.This information should be sufficiently verbose to help a confusedapplication developer figure out why the video display is coming up blank.Your editor would also recommend, however, that it be moderated with a callto printk_ratelimit() to keep it from being used to slow thesystem and fill the logfiles with junk.
The next installment will start in on the remaining 77 callbacks. Inparticular, we will begin to look at the long process of negotiating a setof operating modes with the hardware.