// SPDX-License-Identifier: GPL-2.0-only /* * This is a V4L2 PCI Skeleton Driver. It gives an initial skeleton source * for use with other PCI drivers. * * This skeleton PCI driver assumes that the card has an S-Video connector as * input 0 and an HDMI connector as input 1. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. */ #include <linux/types.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/kmod.h> #include <linux/mutex.h> #include <linux/pci.h> #include <linux/interrupt.h> #include <linux/videodev2.h> #include <linux/v4l2-dv-timings.h> #include <media/v4l2-device.h> #include <media/v4l2-dev.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-dv-timings.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-event.h> #include <media/videobuf2-v4l2.h> #include <media/videobuf2-dma-contig.h> MODULE_DESCRIPTION(…) …; MODULE_AUTHOR(…) …; MODULE_LICENSE(…) …; /** * struct skeleton - All internal data for one instance of device * @pdev: PCI device * @v4l2_dev: top-level v4l2 device struct * @vdev: video node structure * @ctrl_handler: control handler structure * @lock: ioctl serialization mutex * @std: current SDTV standard * @timings: current HDTV timings * @format: current pix format * @input: current video input (0 = SDTV, 1 = HDTV) * @queue: vb2 video capture queue * @qlock: spinlock controlling access to buf_list and sequence * @buf_list: list of buffers queued for DMA * @field: the field (TOP/BOTTOM/other) of the current buffer * @sequence: frame sequence counter */ struct skeleton { … }; struct skel_buffer { … }; static inline struct skel_buffer *to_skel_buffer(struct vb2_v4l2_buffer *vbuf) { … } static const struct pci_device_id skeleton_pci_tbl[] = …; MODULE_DEVICE_TABLE(pci, skeleton_pci_tbl); /* * HDTV: this structure has the capabilities of the HDTV receiver. * It is used to constrain the huge list of possible formats based * upon the hardware capabilities. */ static const struct v4l2_dv_timings_cap skel_timings_cap = …; /* * Supported SDTV standards. This does the same job as skel_timings_cap, but * for standard TV formats. */ #define SKEL_TVNORMS … /* * Interrupt handler: typically interrupts happen after a new frame has been * captured. It is the job of the handler to remove the new frame from the * internal list and give it back to the vb2 framework, updating the sequence * counter, field and timestamp at the same time. */ static irqreturn_t skeleton_irq(int irq, void *dev_id) { … } /* * Setup the constraints of the queue: besides setting the number of planes * per buffer and the size and allocation context of each plane, it also * checks if sufficient buffers have been allocated. Usually 3 is a good * minimum number: many DMA engines need a minimum of 2 buffers in the * queue and you need to have another available for userspace processing. */ static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { … } /* * Prepare the buffer for queueing to the DMA engine: check and set the * payload size. */ static int buffer_prepare(struct vb2_buffer *vb) { … } /* * Queue this buffer to the DMA engine. */ static void buffer_queue(struct vb2_buffer *vb) { … } static void return_all_buffers(struct skeleton *skel, enum vb2_buffer_state state) { … } /* * Start streaming. First check if the minimum number of buffers have been * queued. If not, then return -ENOBUFS and the vb2 framework will call * this function again the next time a buffer has been queued until enough * buffers are available to actually start the DMA engine. */ static int start_streaming(struct vb2_queue *vq, unsigned int count) { … } /* * Stop the DMA engine. Any remaining buffers in the DMA queue are dequeued * and passed on to the vb2 framework marked as STATE_ERROR. */ static void stop_streaming(struct vb2_queue *vq) { … } /* * The vb2 queue ops. Note that since q->lock is set we can use the standard * vb2_ops_wait_prepare/finish helper functions. If q->lock would be NULL, * then this driver would have to provide these ops. */ static const struct vb2_ops skel_qops = …; /* * Required ioctl querycap. Note that the version field is prefilled with * the version of the kernel. */ static int skeleton_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { … } /* * Helper function to check and correct struct v4l2_pix_format. It's used * not only in VIDIOC_TRY/S_FMT, but also elsewhere if changes to the SDTV * standard, HDTV timings or the video input would require updating the * current format. */ static void skeleton_fill_pix_format(struct skeleton *skel, struct v4l2_pix_format *pix) { … } static int skeleton_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { … } static int skeleton_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { … } static int skeleton_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { … } static int skeleton_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { … } static int skeleton_s_std(struct file *file, void *priv, v4l2_std_id std) { … } static int skeleton_g_std(struct file *file, void *priv, v4l2_std_id *std) { … } /* * Query the current standard as seen by the hardware. This function shall * never actually change the standard, it just detects and reports. * The framework will initially set *std to tvnorms (i.e. the set of * supported standards by this input), and this function should just AND * this value. If there is no signal, then *std should be set to 0. */ static int skeleton_querystd(struct file *file, void *priv, v4l2_std_id *std) { … } static int skeleton_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings) { … } static int skeleton_g_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings) { … } static int skeleton_enum_dv_timings(struct file *file, void *_fh, struct v4l2_enum_dv_timings *timings) { … } /* * Query the current timings as seen by the hardware. This function shall * never actually change the timings, it just detects and reports. * If no signal is detected, then return -ENOLINK. If the hardware cannot * lock to the signal, then return -ENOLCK. If the signal is out of range * of the capabilities of the system (e.g., it is possible that the receiver * can lock but that the DMA engine it is connected to cannot handle * pixelclocks above a certain frequency), then -ERANGE is returned. */ static int skeleton_query_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings) { … } static int skeleton_dv_timings_cap(struct file *file, void *fh, struct v4l2_dv_timings_cap *cap) { … } static int skeleton_enum_input(struct file *file, void *priv, struct v4l2_input *i) { … } static int skeleton_s_input(struct file *file, void *priv, unsigned int i) { … } static int skeleton_g_input(struct file *file, void *priv, unsigned int *i) { … } /* The control handler. */ static int skeleton_s_ctrl(struct v4l2_ctrl *ctrl) { … } /* ------------------------------------------------------------------ File operations for the device ------------------------------------------------------------------*/ static const struct v4l2_ctrl_ops skel_ctrl_ops = …; /* * The set of all supported ioctls. Note that all the streaming ioctls * use the vb2 helper functions that take care of all the locking and * that also do ownership tracking (i.e. only the filehandle that requested * the buffers can call the streaming ioctls, all other filehandles will * receive -EBUSY if they attempt to call the same streaming ioctls). * * The last three ioctls also use standard helper functions: these implement * standard behavior for drivers with controls. */ static const struct v4l2_ioctl_ops skel_ioctl_ops = …; /* * The set of file operations. Note that all these ops are standard core * helper functions. */ static const struct v4l2_file_operations skel_fops = …; /* * The initial setup of this device instance. Note that the initial state of * the driver should be complete. So the initial format, standard, timings * and video input should all be initialized to some reasonable value. */ static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { … } static void skeleton_remove(struct pci_dev *pdev) { … } static struct pci_driver skeleton_driver = …; module_pci_driver(…) …;