saa7134: add notification about TV standard changes
Subsystems (2)
PATCH v2 3/3 saa7134: add notification about TV standard changes
The v4l2 event of type V4L2_EVENT_SIGNALCHANGED is emitted when the current TV standard changes.
Signed-off-by Mikhail Domrachev <[email protected]>
--- drivers/media/pci/saa7134/saa7134-video.c | 125 +++++++++++++++++++++++++++++- drivers/media/pci/saa7134/saa7134.h | 11 +++ 2 files changed, 135 insertions(+), 1 deletion(-)
drivers/media/pci/saa7134/saa7134-video.c +124 -1
@@ -24,6 +24,9 @@#include <linux/list.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/kthread.h> +#include <linux/delay.h> +#include <linux/freezer.h> #include <linux/slab.h> #include <linux/sort.h>
@@ -51,6 +54,7 @@ MODULE_PARM_DESC(noninterlaced,"capture non interlaced video");module_param_string (secam, secam,sizeof (secam),0644 );MODULE_PARM_DESC (secam,"force SECAM variant, either DK,L or Lc" ); +static int saa7134_standard_detector_thread (void *arg); #define dprintk(fmt, arg...) if (video_debug&0x04) \ printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
@@ -2097,6 +2101,17 @@ static int radio_s_tuner(struct file *file, void *priv,return 0 ; } +static int saa7134_subscribe_event (struct v4l2_fh *fh, +const struct v4l2_event_subscription *sub) +{ +if (sub->type ==V4L2_EVENT_SIGNALCHANGED ) { +return v4l2_event_subscribe (fh, sub, +SAA7134_EVENTS_QUEUE_SIZE ,NULL ); + }else { +return v4l2_ctrl_subscribe_event (fh, sub); + } +} +static const struct v4l2_file_operations video_fops = { .owner =THIS_MODULE ,
@@ -2148,7 +2163,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_s_register = vidioc_s_register, #endif .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_subscribe_event = saa7134_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, };
@@ -2317,6 +2332,11 @@ int saa7134_video_init1(struct saa7134_dev *dev)void saa7134_video_fini (struct saa7134_dev *dev) { +if (dev->std_thread.thread && !dev->std_thread.stopped) { +kthread_stop (dev->std_thread.thread); + dev->std_thread.thread =NULL ; + } +/* free stuff */ saa7134_pgtable_free (dev->pci, &dev->pt_cap);saa7134_pgtable_free (dev->pci, &dev->pt_vbi);
@@ -2369,6 +2389,107 @@ int saa7134_video_init2(struct saa7134_dev *dev)v4l2_ctrl_handler_setup (&dev->ctrl_handler);saa7134_tvaudio_setmute (dev);saa7134_tvaudio_setvolume (dev,dev->ctl_volume); + + dev->std_thread.thread =NULL ; + dev->std_thread.stopped =0 ; +atomic_set (&dev->std_thread.scan1,0 ); +atomic_set (&dev->std_thread.scan2,0 ); + + dev->std_thread.thread =kthread_run (saa7134_standard_detector_thread, + dev,"%s" , dev->name); +if (IS_ERR (dev->std_thread.thread)) { +dev_alert (dev->v4l2_dev.dev,"%s: kthread_run(saa7134_standard_detector_thread) failed\n" , + dev->name); + dev->std_thread.thread =NULL ; + dev->std_thread.stopped =1 ; + } +return 0 ; +} + +static const char *saa7134_std_to_str (v4l2_std_id std) +{ +switch (std) { +case V4L2_STD_NTSC : +return "NTSC" ; +case V4L2_STD_PAL : +return "PAL" ; +case V4L2_STD_SECAM : +return "SECAM" ; +default : +return "(no signal)" ; + } +} + +static int saa7134_std_sleep (struct saa7134_dev *dev,int timeout) +{ +int cmp = (atomic_read (&dev->std_thread.scan1) + ==atomic_read (&dev->std_thread.scan2)); + +if (cmp && !kthread_should_stop ()) { +if (timeout <0 ) { +set_current_state (TASK_INTERRUPTIBLE ); +schedule (); + }else { +schedule_timeout_interruptible ( +msecs_to_jiffies (timeout)); + } + } + cmp = (atomic_read (&dev->std_thread.scan1) + !=atomic_read (&dev->std_thread.scan2)); +return cmp; +} + +static int saa7134_standard_detector_thread (void *arg) +{ +struct saa7134_dev *dev = arg; +v4l2_std_id dcstd =0 ; +struct v4l2_event event; +static const int detect_time =10 ;/* msec */ +static const int max_detect_time =2000 ;/* msec */ +int time_spent =0 ; + +set_freezable (); +for (;;) { +saa7134_std_sleep (dev,-1 ); +restart: +if (kthread_should_stop ()) + goto done; +try_to_freeze (); + +atomic_set (&dev->std_thread.scan1, +atomic_read (&dev->std_thread.scan2)); + +if (saa7134_std_sleep (dev, detect_time)) { + time_spent =0 ; + goto restart; + } + time_spent += detect_time; + dcstd =saa7134_read_std (dev); +if (dcstd ==V4L2_STD_ALL && time_spent < max_detect_time) + goto restart; + +dprintk ("Standard detected in %d msecs: %s\n" , time_spent, +saa7134_std_to_str (dcstd)); + time_spent =0 ; + +memset (&event,0 ,sizeof (event)); + event.type =V4L2_EVENT_SIGNALCHANGED ; +memcpy (event.u.data, &dcstd,sizeof (dcstd)); +v4l2_event_queue (dev->video_dev, &event); + } + +done: + dev->std_thread.stopped =1 ; +return 0 ; +} + +static int saa7134_std_do_scan (struct saa7134_dev *dev) +{ +if (dev->std_thread.thread) { +atomic_inc (&dev->std_thread.scan2); +if (!dev->insuspend && !dev->std_thread.stopped) +wake_up_process (dev->std_thread.thread); + }return 0 ; }
@@ -2403,6 +2524,8 @@ void saa7134_irq_video_signalchange(struct saa7134_dev *dev)if (dev->mops && dev->mops->signal_change) dev->mops->signal_change (dev); + +saa7134_std_do_scan (dev); }
drivers/media/pci/saa7134/saa7134.h +11 -0
@@ -342,6 +342,8 @@ struct saa7134_card_ir {#define SAA7134_MAXBOARDS 32#define SAA7134_INPUT_MAX 8 +#define SAA7134_EVENTS_QUEUE_SIZE 10 +/* ----------------------------------------------------------- */ /* Since we support 2 remote types, lets tell them apart */
@@ -450,6 +452,14 @@ struct saa7134_thread {unsigned int stopped; }; +/* tv standard thread status */ +struct saa7134_thread_std { +struct task_struct *thread; +atomic_t scan1; +atomic_t scan2; +unsigned int stopped; +}; +/* buffer for one video/vbi/ts frame */ struct saa7134_buf {/* common v4l buffer stuff -- must be first */
@@ -624,6 +634,7 @@ struct saa7134_dev {/* other global state info */ unsigned int automute;struct saa7134_thread thread; +struct saa7134_thread_std std_thread;struct saa7134_input *input;struct saa7134_input *hw_input;unsigned int hw_mute;
Signature · 1 line
1.8.5.3