mirror of https://gitee.com/openkylin/linux.git
201 lines
5.3 KiB
XML
201 lines
5.3 KiB
XML
<title>V4L2 Driver Programming</title>
|
|
|
|
<!-- This part defines the interface between the "videodev"
|
|
module and individual drivers. -->
|
|
|
|
<para>to do</para>
|
|
<!--
|
|
<para>V4L2 is a two-layer driver system. The top layer is the "videodev"
|
|
kernel module. When videodev initializes it registers as character device
|
|
with major number 81, and it registers a set of file operations. All V4L2
|
|
drivers are really clients of videodev, which calls V4L2 drivers through
|
|
driver method functions. V4L2 drivers are also written as kernel modules.
|
|
After probing the hardware they register one or more devices with
|
|
videodev.</para>
|
|
|
|
<section id="driver-modules">
|
|
<title>Driver Modules</title>
|
|
|
|
<para>V4L2 driver modules must have an initialization function which is
|
|
called after the module was loaded into kernel, an exit function whis is
|
|
called before the module is removed. When the driver is compiled into the
|
|
kernel these functions called at system boot and shutdown time.</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
#include <linux/module.h>
|
|
|
|
/* Export information about this module. For details and other useful
|
|
macros see <filename>linux/module.h</filename>. */
|
|
MODULE_DESCRIPTION("my - driver for my hardware");
|
|
MODULE_AUTHOR("Your name here");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
static void
|
|
my_module_exit (void)
|
|
{
|
|
/* Free all resources allocated by my_module_init(). */
|
|
}
|
|
|
|
static int
|
|
my_module_init (void)
|
|
{
|
|
/* Bind the driver to the supported hardware, see
|
|
<link linkend="driver-pci"> and
|
|
<link linkend="driver-usb"> for examples. */
|
|
|
|
return 0; /* a negative value on error, 0 on success. */
|
|
}
|
|
|
|
/* Export module functions. */
|
|
module_init (my_module_init);
|
|
module_exit (my_module_exit);
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>Users can add parameters when kernel modules are inserted:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
include <linux/moduleparam.h>
|
|
|
|
static int my_option = 123;
|
|
static int my_option_array[47];
|
|
|
|
/* Export the symbol, an int, with access permissions 0664.
|
|
See <filename>linux/moduleparam.h</filename> for other types. */
|
|
module_param (my_option, int, 0644);
|
|
module_param_array (my_option_array, int, NULL, 0644);
|
|
|
|
MODULE_PARM_DESC (my_option, "Does magic things, default 123");
|
|
</programlisting>
|
|
</informalexample>
|
|
|
|
<para>One parameter should be supported by all V4L2 drivers, the minor
|
|
number of the device it will register. Purpose is to predictably link V4L2
|
|
drivers to device nodes if more than one video device is installed. Use the
|
|
name of the device node followed by a "_nr" suffix, for example "video_nr"
|
|
for <filename>/dev/video</filename>.</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
/* Minor number of the device, -1 to allocate the first unused. */
|
|
static int video_nr = -1;
|
|
|
|
module_param (video_nr, int, 0444);
|
|
</programlisting>
|
|
</informalexample>
|
|
</section>
|
|
|
|
<section id="driver-pci">
|
|
<title>PCI Devices</title>
|
|
|
|
<para>PCI devices are initialized like this:</para>
|
|
|
|
<informalexample>
|
|
<programlisting>
|
|
typedef struct {
|
|
/* State of one physical device. */
|
|
} my_device;
|
|
|
|
static int
|
|
my_resume (struct pci_dev * pci_dev)
|
|
{
|
|
/* Restore the suspended device to working state. */
|
|
}
|
|
|
|
static int
|
|
my_suspend (struct pci_dev * pci_dev,
|
|
pm_message_t state)
|
|
{
|
|
/* This function is called before the system goes to sleep.
|
|
Stop all DMAs and disable interrupts, then put the device
|
|
into a low power state. For details see the kernel
|
|
sources under <filename>Documentation/power</filename>. */
|
|
|
|
return 0; /* a negative value on error, 0 on success. */
|
|
}
|
|
|
|
static void
|
|
my_remove (struct pci_dev * pci_dev)
|
|
{
|
|
my_device *my = pci_get_drvdata (pci_dev);
|
|
|
|
/* Describe me. */
|
|
}
|
|
|
|
static int
|
|
my_probe (struct pci_dev * pci_dev,
|
|
const struct pci_device_id * pci_id)
|
|
{
|
|
my_device *my;
|
|
|
|
/* Describe me. */
|
|
|
|
/* You can allocate per-device data here and store a pointer
|
|
to it in the pci_dev structure. */
|
|
my = ...;
|
|
pci_set_drvdata (pci_dev, my);
|
|
|
|
return 0; /* a negative value on error, 0 on success. */
|
|
}
|
|
|
|
/* A list of supported PCI devices. */
|
|
static struct pci_device_id
|
|
my_pci_device_ids [] = {
|
|
{ PCI_VENDOR_ID_FOO, PCI_DEVICE_ID_BAR,
|
|
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
|
|
{ 0 } /* end of list */
|
|
};
|
|
|
|
/* Load our module if supported PCI devices are installed. */
|
|
MODULE_DEVICE_TABLE (pci, my_pci_device_ids);
|
|
|
|
static struct pci_driver
|
|
my_pci_driver = {
|
|
.name = "my",
|
|
.id_table = my_pci_device_ids,
|
|
|
|
.probe = my_probe,
|
|
.remove = my_remove,
|
|
|
|
/* Power management functions. */
|
|
.suspend = my_suspend,
|
|
.resume = my_resume,
|
|
};
|
|
|
|
static void
|
|
my_module_exit (void)
|
|
{
|
|
pci_unregister_driver (&my_pci_driver);
|
|
}
|
|
|
|
static int
|
|
my_module_init (void)
|
|
{
|
|
return pci_register_driver (&my_pci_driver);
|
|
}
|
|
</programlisting>
|
|
</informalexample>
|
|
</section>
|
|
|
|
<section id="driver-usb">
|
|
<title>USB Devices</title>
|
|
<para>to do</para>
|
|
</section>
|
|
<section id="driver-registering">
|
|
<title>Registering V4L2 Drivers</title>
|
|
|
|
<para>After a V4L2 driver probed the hardware it registers one or more
|
|
devices with the videodev module.</para>
|
|
</section>
|
|
<section id="driver-file-ops">
|
|
<title>File Operations</title>
|
|
<para>to do</para>
|
|
</section>
|
|
<section id="driver-internal-api">
|
|
<title>Internal API</title>
|
|
<para>to do</para>
|
|
</section>
|
|
-->
|