diff options
Diffstat (limited to 'drivers/media/video/au0828/au0828-video.c')
-rw-r--r-- | drivers/media/video/au0828/au0828-video.c | 118 |
1 files changed, 100 insertions, 18 deletions
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c index 162fd5f9d448..e41e4ad5cc40 100644 --- a/drivers/media/video/au0828/au0828-video.c +++ b/drivers/media/video/au0828/au0828-video.c | |||
@@ -122,6 +122,7 @@ static void au0828_irq_callback(struct urb *urb) | |||
122 | { | 122 | { |
123 | struct au0828_dmaqueue *dma_q = urb->context; | 123 | struct au0828_dmaqueue *dma_q = urb->context; |
124 | struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq); | 124 | struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq); |
125 | unsigned long flags = 0; | ||
125 | int rc, i; | 126 | int rc, i; |
126 | 127 | ||
127 | switch (urb->status) { | 128 | switch (urb->status) { |
@@ -139,9 +140,9 @@ static void au0828_irq_callback(struct urb *urb) | |||
139 | } | 140 | } |
140 | 141 | ||
141 | /* Copy data from URB */ | 142 | /* Copy data from URB */ |
142 | spin_lock(&dev->slock); | 143 | spin_lock_irqsave(&dev->slock, flags); |
143 | rc = dev->isoc_ctl.isoc_copy(dev, urb); | 144 | rc = dev->isoc_ctl.isoc_copy(dev, urb); |
144 | spin_unlock(&dev->slock); | 145 | spin_unlock_irqrestore(&dev->slock, flags); |
145 | 146 | ||
146 | /* Reset urb buffers */ | 147 | /* Reset urb buffers */ |
147 | for (i = 0; i < urb->number_of_packets; i++) { | 148 | for (i = 0; i < urb->number_of_packets; i++) { |
@@ -576,7 +577,7 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb) | |||
576 | p += 4; | 577 | p += 4; |
577 | au0828_isocdbg("Video frame %s\n", | 578 | au0828_isocdbg("Video frame %s\n", |
578 | (fbyte & 0x40) ? "odd" : "even"); | 579 | (fbyte & 0x40) ? "odd" : "even"); |
579 | if (!(fbyte & 0x40)) { | 580 | if (fbyte & 0x40) { |
580 | /* VBI */ | 581 | /* VBI */ |
581 | if (vbi_buf != NULL) | 582 | if (vbi_buf != NULL) |
582 | vbi_buffer_filled(dev, | 583 | vbi_buffer_filled(dev, |
@@ -597,6 +598,15 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb) | |||
597 | outp = NULL; | 598 | outp = NULL; |
598 | else | 599 | else |
599 | outp = videobuf_to_vmalloc(&buf->vb); | 600 | outp = videobuf_to_vmalloc(&buf->vb); |
601 | |||
602 | /* As long as isoc traffic is arriving, keep | ||
603 | resetting the timer */ | ||
604 | if (dev->vid_timeout_running) | ||
605 | mod_timer(&dev->vid_timeout, | ||
606 | jiffies + (HZ / 10)); | ||
607 | if (dev->vbi_timeout_running) | ||
608 | mod_timer(&dev->vbi_timeout, | ||
609 | jiffies + (HZ / 10)); | ||
600 | } | 610 | } |
601 | 611 | ||
602 | if (buf != NULL) { | 612 | if (buf != NULL) { |
@@ -907,6 +917,57 @@ static int get_ressource(struct au0828_fh *fh) | |||
907 | } | 917 | } |
908 | } | 918 | } |
909 | 919 | ||
920 | /* This function ensures that video frames continue to be delivered even if | ||
921 | the ITU-656 input isn't receiving any data (thereby preventing applications | ||
922 | such as tvtime from hanging) */ | ||
923 | void au0828_vid_buffer_timeout(unsigned long data) | ||
924 | { | ||
925 | struct au0828_dev *dev = (struct au0828_dev *) data; | ||
926 | struct au0828_dmaqueue *dma_q = &dev->vidq; | ||
927 | struct au0828_buffer *buf; | ||
928 | unsigned char *vid_data; | ||
929 | unsigned long flags = 0; | ||
930 | |||
931 | spin_lock_irqsave(&dev->slock, flags); | ||
932 | |||
933 | buf = dev->isoc_ctl.buf; | ||
934 | if (buf != NULL) { | ||
935 | vid_data = videobuf_to_vmalloc(&buf->vb); | ||
936 | memset(vid_data, 0x00, buf->vb.size); /* Blank green frame */ | ||
937 | buffer_filled(dev, dma_q, buf); | ||
938 | } | ||
939 | get_next_buf(dma_q, &buf); | ||
940 | |||
941 | if (dev->vid_timeout_running == 1) | ||
942 | mod_timer(&dev->vid_timeout, jiffies + (HZ / 10)); | ||
943 | |||
944 | spin_unlock_irqrestore(&dev->slock, flags); | ||
945 | } | ||
946 | |||
947 | void au0828_vbi_buffer_timeout(unsigned long data) | ||
948 | { | ||
949 | struct au0828_dev *dev = (struct au0828_dev *) data; | ||
950 | struct au0828_dmaqueue *dma_q = &dev->vbiq; | ||
951 | struct au0828_buffer *buf; | ||
952 | unsigned char *vbi_data; | ||
953 | unsigned long flags = 0; | ||
954 | |||
955 | spin_lock_irqsave(&dev->slock, flags); | ||
956 | |||
957 | buf = dev->isoc_ctl.vbi_buf; | ||
958 | if (buf != NULL) { | ||
959 | vbi_data = videobuf_to_vmalloc(&buf->vb); | ||
960 | memset(vbi_data, 0x00, buf->vb.size); | ||
961 | vbi_buffer_filled(dev, dma_q, buf); | ||
962 | } | ||
963 | vbi_get_next_buf(dma_q, &buf); | ||
964 | |||
965 | if (dev->vbi_timeout_running == 1) | ||
966 | mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10)); | ||
967 | spin_unlock_irqrestore(&dev->slock, flags); | ||
968 | } | ||
969 | |||
970 | |||
910 | static int au0828_v4l2_open(struct file *filp) | 971 | static int au0828_v4l2_open(struct file *filp) |
911 | { | 972 | { |
912 | int ret = 0; | 973 | int ret = 0; |
@@ -976,7 +1037,6 @@ static int au0828_v4l2_open(struct file *filp) | |||
976 | V4L2_FIELD_SEQ_TB, | 1037 | V4L2_FIELD_SEQ_TB, |
977 | sizeof(struct au0828_buffer), fh, NULL); | 1038 | sizeof(struct au0828_buffer), fh, NULL); |
978 | 1039 | ||
979 | |||
980 | return ret; | 1040 | return ret; |
981 | } | 1041 | } |
982 | 1042 | ||
@@ -987,11 +1047,19 @@ static int au0828_v4l2_close(struct file *filp) | |||
987 | struct au0828_dev *dev = fh->dev; | 1047 | struct au0828_dev *dev = fh->dev; |
988 | 1048 | ||
989 | if (res_check(fh, AU0828_RESOURCE_VIDEO)) { | 1049 | if (res_check(fh, AU0828_RESOURCE_VIDEO)) { |
1050 | /* Cancel timeout thread in case they didn't call streamoff */ | ||
1051 | dev->vid_timeout_running = 0; | ||
1052 | del_timer_sync(&dev->vid_timeout); | ||
1053 | |||
990 | videobuf_stop(&fh->vb_vidq); | 1054 | videobuf_stop(&fh->vb_vidq); |
991 | res_free(fh, AU0828_RESOURCE_VIDEO); | 1055 | res_free(fh, AU0828_RESOURCE_VIDEO); |
992 | } | 1056 | } |
993 | 1057 | ||
994 | if (res_check(fh, AU0828_RESOURCE_VBI)) { | 1058 | if (res_check(fh, AU0828_RESOURCE_VBI)) { |
1059 | /* Cancel timeout thread in case they didn't call streamoff */ | ||
1060 | dev->vbi_timeout_running = 0; | ||
1061 | del_timer_sync(&dev->vbi_timeout); | ||
1062 | |||
995 | videobuf_stop(&fh->vb_vbiq); | 1063 | videobuf_stop(&fh->vb_vbiq); |
996 | res_free(fh, AU0828_RESOURCE_VBI); | 1064 | res_free(fh, AU0828_RESOURCE_VBI); |
997 | } | 1065 | } |
@@ -1048,6 +1116,13 @@ static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf, | |||
1048 | if (!res_get(fh, AU0828_RESOURCE_VBI)) | 1116 | if (!res_get(fh, AU0828_RESOURCE_VBI)) |
1049 | return -EBUSY; | 1117 | return -EBUSY; |
1050 | 1118 | ||
1119 | if (dev->vbi_timeout_running == 0) { | ||
1120 | /* Handle case where caller tries to read without | ||
1121 | calling streamon first */ | ||
1122 | dev->vbi_timeout_running = 1; | ||
1123 | mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10)); | ||
1124 | } | ||
1125 | |||
1051 | return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0, | 1126 | return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0, |
1052 | filp->f_flags & O_NONBLOCK); | 1127 | filp->f_flags & O_NONBLOCK); |
1053 | } | 1128 | } |
@@ -1577,10 +1652,15 @@ static int vidioc_streamon(struct file *file, void *priv, | |||
1577 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1); | 1652 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1); |
1578 | } | 1653 | } |
1579 | 1654 | ||
1580 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1655 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
1581 | rc = videobuf_streamon(&fh->vb_vidq); | 1656 | rc = videobuf_streamon(&fh->vb_vidq); |
1582 | else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) | 1657 | dev->vid_timeout_running = 1; |
1658 | mod_timer(&dev->vid_timeout, jiffies + (HZ / 10)); | ||
1659 | } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { | ||
1583 | rc = videobuf_streamon(&fh->vb_vbiq); | 1660 | rc = videobuf_streamon(&fh->vb_vbiq); |
1661 | dev->vbi_timeout_running = 1; | ||
1662 | mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10)); | ||
1663 | } | ||
1584 | 1664 | ||
1585 | return rc; | 1665 | return rc; |
1586 | } | 1666 | } |
@@ -1607,6 +1687,9 @@ static int vidioc_streamoff(struct file *file, void *priv, | |||
1607 | fh, type, fh->resources, dev->resources); | 1687 | fh, type, fh->resources, dev->resources); |
1608 | 1688 | ||
1609 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 1689 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
1690 | dev->vid_timeout_running = 0; | ||
1691 | del_timer_sync(&dev->vid_timeout); | ||
1692 | |||
1610 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); | 1693 | v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); |
1611 | rc = au0828_stream_interrupt(dev); | 1694 | rc = au0828_stream_interrupt(dev); |
1612 | if (rc != 0) | 1695 | if (rc != 0) |
@@ -1621,6 +1704,9 @@ static int vidioc_streamoff(struct file *file, void *priv, | |||
1621 | videobuf_streamoff(&fh->vb_vidq); | 1704 | videobuf_streamoff(&fh->vb_vidq); |
1622 | res_free(fh, AU0828_RESOURCE_VIDEO); | 1705 | res_free(fh, AU0828_RESOURCE_VIDEO); |
1623 | } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { | 1706 | } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { |
1707 | dev->vbi_timeout_running = 0; | ||
1708 | del_timer_sync(&dev->vbi_timeout); | ||
1709 | |||
1624 | videobuf_streamoff(&fh->vb_vbiq); | 1710 | videobuf_streamoff(&fh->vb_vbiq); |
1625 | res_free(fh, AU0828_RESOURCE_VBI); | 1711 | res_free(fh, AU0828_RESOURCE_VBI); |
1626 | } | 1712 | } |
@@ -1723,15 +1809,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) | |||
1723 | return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK); | 1809 | return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK); |
1724 | } | 1810 | } |
1725 | 1811 | ||
1726 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
1727 | static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) | ||
1728 | { | ||
1729 | struct au0828_fh *fh = priv; | ||
1730 | |||
1731 | return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8); | ||
1732 | } | ||
1733 | #endif | ||
1734 | |||
1735 | static struct v4l2_file_operations au0828_v4l_fops = { | 1812 | static struct v4l2_file_operations au0828_v4l_fops = { |
1736 | .owner = THIS_MODULE, | 1813 | .owner = THIS_MODULE, |
1737 | .open = au0828_v4l2_open, | 1814 | .open = au0828_v4l2_open, |
@@ -1775,9 +1852,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { | |||
1775 | .vidioc_s_register = vidioc_s_register, | 1852 | .vidioc_s_register = vidioc_s_register, |
1776 | #endif | 1853 | #endif |
1777 | .vidioc_g_chip_ident = vidioc_g_chip_ident, | 1854 | .vidioc_g_chip_ident = vidioc_g_chip_ident, |
1778 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
1779 | .vidiocgmbuf = vidiocgmbuf, | ||
1780 | #endif | ||
1781 | }; | 1855 | }; |
1782 | 1856 | ||
1783 | static const struct video_device au0828_video_template = { | 1857 | static const struct video_device au0828_video_template = { |
@@ -1840,6 +1914,14 @@ int au0828_analog_register(struct au0828_dev *dev, | |||
1840 | INIT_LIST_HEAD(&dev->vbiq.active); | 1914 | INIT_LIST_HEAD(&dev->vbiq.active); |
1841 | INIT_LIST_HEAD(&dev->vbiq.queued); | 1915 | INIT_LIST_HEAD(&dev->vbiq.queued); |
1842 | 1916 | ||
1917 | dev->vid_timeout.function = au0828_vid_buffer_timeout; | ||
1918 | dev->vid_timeout.data = (unsigned long) dev; | ||
1919 | init_timer(&dev->vid_timeout); | ||
1920 | |||
1921 | dev->vbi_timeout.function = au0828_vbi_buffer_timeout; | ||
1922 | dev->vbi_timeout.data = (unsigned long) dev; | ||
1923 | init_timer(&dev->vbi_timeout); | ||
1924 | |||
1843 | dev->width = NTSC_STD_W; | 1925 | dev->width = NTSC_STD_W; |
1844 | dev->height = NTSC_STD_H; | 1926 | dev->height = NTSC_STD_H; |
1845 | dev->field_size = dev->width * dev->height; | 1927 | dev->field_size = dev->width * dev->height; |