|  | <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 __devexit | 
|  | my_remove               (struct pci_dev *               pci_dev) | 
|  | { | 
|  | my_device *my = pci_get_drvdata (pci_dev); | 
|  |  | 
|  | /* Describe me. */ | 
|  | } | 
|  |  | 
|  | static int __devinit | 
|  | 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   = __devexit_p (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> | 
|  | --> | 
|  |  | 
|  | <!-- | 
|  | Local Variables: | 
|  | mode: sgml | 
|  | sgml-parent-document: "v4l2.sgml" | 
|  | indent-tabs-mode: nil | 
|  | End: | 
|  | --> |