From 6e46daba562e44eee3009e4055a016a1c4bbb378 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 7 Feb 2013 13:39:09 -0300 Subject: [media] em28xx: use v4l2_disable_ioctl() to disable ioctls VIDIOC_QUERYSTD, VIDIOC_G/S_STD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of checking the device type and returning -ENOTTY inside the ioctl functions, use v4l2_disable_ioctl() to disable the ioctls VIDIOC_QUERYSTD, VIDIOC_G_STD and VIDIOC_S_STD if the device is a camera. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 32bd7de5dec1..d1e6ba62e06c 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -959,8 +959,6 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) struct em28xx *dev = fh->dev; int rc; - if (dev->board.is_webcam) - return -ENOTTY; rc = check_dev(dev); if (rc < 0) return rc; @@ -976,8 +974,6 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm) struct em28xx *dev = fh->dev; int rc; - if (dev->board.is_webcam) - return -ENOTTY; rc = check_dev(dev); if (rc < 0) return rc; @@ -994,8 +990,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) struct v4l2_format f; int rc; - if (dev->board.is_webcam) - return -ENOTTY; if (*norm == dev->norm) return 0; rc = check_dev(dev); @@ -1899,6 +1893,13 @@ int em28xx_register_analog_devices(struct em28xx *dev) dev->vdev->queue = &dev->vb_vidq; dev->vdev->queue->lock = &dev->vb_queue_lock; + /* disable inapplicable ioctls */ + if (dev->board.is_webcam) { + v4l2_disable_ioctl(dev->vdev, VIDIOC_QUERYSTD); + v4l2_disable_ioctl(dev->vdev, VIDIOC_G_STD); + v4l2_disable_ioctl(dev->vdev, VIDIOC_S_STD); + } + /* register v4l2 video video_device */ ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]); -- cgit v1.2.3 From 66df67b764f6013e557ac41aa9e9474c87a9a99b Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 7 Feb 2013 13:39:10 -0300 Subject: [media] em28xx: disable tuner related ioctls for video and VBI devices without tuner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Disable the ioctls VIDIOC_G_TUNER, VIDIOC_S_TUNER, VIDIOC_G_FREQUENCY and VIDIOC_S_FREQUENCY for video and VBI devices without tuner. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index d1e6ba62e06c..a2216334d6f5 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1899,6 +1899,12 @@ int em28xx_register_analog_devices(struct em28xx *dev) v4l2_disable_ioctl(dev->vdev, VIDIOC_G_STD); v4l2_disable_ioctl(dev->vdev, VIDIOC_S_STD); } + if (dev->tuner_type == TUNER_ABSENT) { + v4l2_disable_ioctl(dev->vdev, VIDIOC_G_TUNER); + v4l2_disable_ioctl(dev->vdev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(dev->vdev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(dev->vdev, VIDIOC_S_FREQUENCY); + } /* register v4l2 video video_device */ ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER, @@ -1917,6 +1923,14 @@ int em28xx_register_analog_devices(struct em28xx *dev) dev->vbi_dev->queue = &dev->vb_vbiq; dev->vbi_dev->queue->lock = &dev->vb_vbi_queue_lock; + /* disable inapplicable ioctls */ + if (dev->tuner_type == TUNER_ABSENT) { + v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_TUNER); + v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_FREQUENCY); + } + /* register v4l2 vbi video_device */ ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]); -- cgit v1.2.3 From c2dcef835e40f5a63b14f6eeada8b08b37da263f Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 7 Feb 2013 13:39:11 -0300 Subject: [media] em28xx: use v4l2_disable_ioctl() to disable ioctls VIDIOC_G_AUDIO and VIDIOC_S_AUDIO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of checking the device type and returning -EINVAL inside the ioctl functions, use v4l2_disable_ioctl() to disable the ioctls VIDIOC_G_AUDIO and VIDIOC_S_AUDIO if the device doesn't support audio. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index a2216334d6f5..346c92aca734 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1130,9 +1130,6 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - if (!dev->audio_mode.has_audio) - return -EINVAL; - switch (a->index) { case EM28XX_AMUX_VIDEO: strcpy(a->name, "Television"); @@ -1173,10 +1170,6 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - - if (!dev->audio_mode.has_audio) - return -EINVAL; - if (a->index >= MAX_EM28XX_INPUT) return -EINVAL; if (0 == INPUT(a->index)->type) @@ -1905,6 +1898,10 @@ int em28xx_register_analog_devices(struct em28xx *dev) v4l2_disable_ioctl(dev->vdev, VIDIOC_G_FREQUENCY); v4l2_disable_ioctl(dev->vdev, VIDIOC_S_FREQUENCY); } + if (!dev->audio_mode.has_audio) { + v4l2_disable_ioctl(dev->vdev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(dev->vdev, VIDIOC_S_AUDIO); + } /* register v4l2 video video_device */ ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER, @@ -1930,6 +1927,10 @@ int em28xx_register_analog_devices(struct em28xx *dev) v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_FREQUENCY); v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_FREQUENCY); } + if (!dev->audio_mode.has_audio) { + v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_AUDIO); + } /* register v4l2 vbi video_device */ ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -- cgit v1.2.3 From 3bc85cce365ca12f98aec150160ed0b84e1af732 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 7 Feb 2013 13:39:12 -0300 Subject: [media] em28xx: use v4l2_disable_ioctl() to disable ioctl VIDIOC_S_PARM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of checking the device type and returning -ENOTTY inside the ioctl function, use v4l2_disable_ioctl() to disable the ioctl VIDIOC_S_PARM if the device is not a camera. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 346c92aca734..2f7c5abad75e 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1044,9 +1044,6 @@ static int vidioc_s_parm(struct file *file, void *priv, struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - if (!dev->board.is_webcam) - return -ENOTTY; - if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1891,6 +1888,8 @@ int em28xx_register_analog_devices(struct em28xx *dev) v4l2_disable_ioctl(dev->vdev, VIDIOC_QUERYSTD); v4l2_disable_ioctl(dev->vdev, VIDIOC_G_STD); v4l2_disable_ioctl(dev->vdev, VIDIOC_S_STD); + } else { + v4l2_disable_ioctl(dev->vdev, VIDIOC_S_PARM); } if (dev->tuner_type == TUNER_ABSENT) { v4l2_disable_ioctl(dev->vdev, VIDIOC_G_TUNER); -- cgit v1.2.3 From 83c8bcce0629239ff9de6625ea74e16a10e8c1f0 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 7 Feb 2013 13:39:13 -0300 Subject: [media] em28xx: disable ioctl VIDIOC_S_PARM for VBI devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VIDIOC_S_PARM doesn't make sense for VBI device nodes, because we don't support selecting the number of read buffers to use. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 2f7c5abad75e..c1f6c59f53aa 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1920,6 +1920,7 @@ int em28xx_register_analog_devices(struct em28xx *dev) dev->vbi_dev->queue->lock = &dev->vb_vbi_queue_lock; /* disable inapplicable ioctls */ + v4l2_disable_ioctl(dev->vdev, VIDIOC_S_PARM); if (dev->tuner_type == TUNER_ABSENT) { v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_TUNER); v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_TUNER); -- cgit v1.2.3 From 1fe184a6accc781e814f15342513794266d73d06 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 7 Feb 2013 13:39:14 -0300 Subject: [media] em28xx: make ioctls VIDIOC_G/S_PARM working for VBI devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the current code V4L2_BUF_TYPE_VIDEO_CAPTURE is accepted only, but for VBI devices only buffer type V4L2_BUF_TYPE_VBI_CAPTURE is used/valid. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index c1f6c59f53aa..e13b777d2cbf 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1024,9 +1024,6 @@ static int vidioc_g_parm(struct file *file, void *priv, struct em28xx *dev = fh->dev; int rc = 0; - if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - p->parm.capture.readbuffers = EM28XX_MIN_BUF; if (dev->board.is_webcam) rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0, @@ -1044,9 +1041,6 @@ static int vidioc_s_parm(struct file *file, void *priv, struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - p->parm.capture.readbuffers = EM28XX_MIN_BUF; return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p); } -- cgit v1.2.3 From 430101bd8b9184496c57a8bffe9fc9d1c2b7732f Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 7 Feb 2013 13:39:15 -0300 Subject: [media] em28xx: remove ioctl VIDIOC_CROPCAP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The em28xx driver doesn't support the VIDIOC_G_CROP and VIDIOC_S_CROP ioctls, so VIDIOC_CROPCAP is useless and has the potential to confuse applications, because it can be interpreted as indicator for cropping support. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 21 --------------------- 1 file changed, 21 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index e13b777d2cbf..ea73dd4e428a 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1364,26 +1364,6 @@ static int vidioc_s_register(struct file *file, void *priv, #endif -static int vidioc_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cc) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - cc->bounds.left = 0; - cc->bounds.top = 0; - cc->bounds.width = dev->width; - cc->bounds.height = dev->height; - cc->defrect = cc->bounds; - cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ - cc->pixelaspect.denominator = 59; - - return 0; -} - static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -1731,7 +1711,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, - .vidioc_cropcap = vidioc_cropcap, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_create_bufs = vb2_ioctl_create_bufs, -- cgit v1.2.3 From aab346187662b3f2a11b1120896f688299c8ba43 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 7 Feb 2013 13:39:16 -0300 Subject: [media] em28xx: get rid of duplicate function vidioc_s_fmt_vbi_cap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vidioc_s_fmt_vbi_cap() is a 100% duplicate of vidioc_g_fmt_vbi_cap() and therefore can be removed. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index ea73dd4e428a..8ddf3009c794 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1480,35 +1480,6 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, return 0; } -static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, - struct v4l2_format *format) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - format->fmt.vbi.samples_per_line = dev->vbi_width; - format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - format->fmt.vbi.offset = 0; - format->fmt.vbi.flags = 0; - format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; - format->fmt.vbi.count[0] = dev->vbi_height; - format->fmt.vbi.count[1] = dev->vbi_height; - memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved)); - - /* Varies by video standard (NTSC, PAL, etc.) */ - if (dev->norm & V4L2_STD_525_60) { - /* NTSC */ - format->fmt.vbi.start[0] = 10; - format->fmt.vbi.start[1] = 273; - } else if (dev->norm & V4L2_STD_625_50) { - /* PAL */ - format->fmt.vbi.start[0] = 6; - format->fmt.vbi.start[1] = 318; - } - - return 0; -} - /* ----------------------------------------------------------- */ /* RADIO ESPECIFIC IOCTLS */ /* ----------------------------------------------------------- */ @@ -1707,7 +1678,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, .vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, - .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap, + .vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, -- cgit v1.2.3 From 7a92de6a4c0c99c97df3f016860fe9597d4284b9 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 7 Feb 2013 13:39:17 -0300 Subject: [media] em28xx: VIDIOC_G_TUNER: remove unneeded setting of tuner type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tuner type is set by the v4l2-core based on the device type. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 8ddf3009c794..e7f6f5745302 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1493,7 +1493,6 @@ static int radio_g_tuner(struct file *file, void *priv, return -EINVAL; strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); -- cgit v1.2.3 From eb17cee275ac5d0bcd31ed2d205051088140ce49 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 7 Feb 2013 13:39:18 -0300 Subject: [media] em28xx: remove obsolete device state checks from the ioctl functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v4l2_device_disconnect() is called when the device is disconnected, so that the v4l2-core rejects all ioctl calls. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 43 --------------------------------- 1 file changed, 43 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index e7f6f5745302..c214305300db 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -799,15 +799,6 @@ const struct v4l2_ctrl_ops em28xx_ctrl_ops = { .s_ctrl = em28xx_s_ctrl, }; -static int check_dev(struct em28xx *dev) -{ - if (dev->disconnected) { - em28xx_errdev("v4l2 ioctl: device not present\n"); - return -ENODEV; - } - return 0; -} - static void get_scale(struct em28xx *dev, unsigned int width, unsigned int height, unsigned int *hscale, unsigned int *vscale) @@ -957,11 +948,6 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; *norm = dev->norm; @@ -972,11 +958,6 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm); @@ -988,13 +969,9 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; struct v4l2_format f; - int rc; if (*norm == dev->norm) return 0; - rc = check_dev(dev); - if (rc < 0) - return rc; if (dev->streaming_users > 0) return -EBUSY; @@ -1101,11 +1078,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; if (i >= MAX_EM28XX_INPUT) return -EINVAL; @@ -1180,11 +1152,6 @@ static int vidioc_g_tuner(struct file *file, void *priv, { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; if (0 != t->index) return -EINVAL; @@ -1200,11 +1167,6 @@ static int vidioc_s_tuner(struct file *file, void *priv, { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; if (0 != t->index) return -EINVAL; @@ -1231,11 +1193,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; if (0 != f->tuner) return -EINVAL; -- cgit v1.2.3 From 35deba32e4bfd5fc16358f960ceb46be097ab3a2 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 7 Feb 2013 13:39:19 -0300 Subject: [media] em28xx: make ioctl VIDIOC_DBG_G_CHIP_IDENT available without CONFIG_VIDEO_ADV_DEBUG selected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VIDIOC_DBG_G_CHIP_IDENT is a "normal" and not an "advanced" debug functionality. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index c214305300db..2ee2957db4bf 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1204,19 +1204,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, return 0; } -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int em28xx_reg_len(int reg) -{ - switch (reg) { - case EM28XX_R40_AC97LSB: - case EM28XX_R30_HSCALELOW: - case EM28XX_R32_VSCALELOW: - return 2; - default: - return 1; - } -} - static int vidioc_g_chip_ident(struct file *file, void *priv, struct v4l2_dbg_chip_ident *chip) { @@ -1239,6 +1226,18 @@ static int vidioc_g_chip_ident(struct file *file, void *priv, return 0; } +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int em28xx_reg_len(int reg) +{ + switch (reg) { + case EM28XX_R40_AC97LSB: + case EM28XX_R30_HSCALELOW: + case EM28XX_R32_VSCALELOW: + return 2; + default: + return 1; + } +} static int vidioc_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) @@ -1662,10 +1661,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_s_frequency = vidioc_s_frequency, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_g_chip_ident = vidioc_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, - .vidioc_g_chip_ident = vidioc_g_chip_ident, #endif }; -- cgit v1.2.3 From fff459e36f70b96f9baf0e538d4bcf9ccddef72a Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 7 Feb 2013 13:39:20 -0300 Subject: [media] em28xx: make ioctl VIDIOC_DBG_G_CHIP_IDENT available for radio devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 2ee2957db4bf..6d261232278c 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1691,6 +1691,7 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_s_frequency = vidioc_s_frequency, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_g_chip_ident = vidioc_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, -- cgit v1.2.3 From 84e902aa05b628b940c4a17ea2c92ec4fbcffc18 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 7 Feb 2013 13:39:21 -0300 Subject: [media] em28xx: do not claim VBI support if the device is a camera MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoids registering a VBI device and streaming in VBI-mode if the device is a camera. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index aaedd11791f2..26d249971a01 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -681,6 +681,11 @@ int em28xx_vbi_supported(struct em28xx *dev) if (disable_vbi == 1) return 0; + if (dev->board.is_webcam) + return 0; + + /* FIXME: check subdevices for VBI support */ + if (dev->chip_id == CHIP_ID_EM2860 || dev->chip_id == CHIP_ID_EM2883) return 1; -- cgit v1.2.3 From 8168532712fe0c662f22180755fb89103a2e6558 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 10 Feb 2013 16:05:11 -0300 Subject: [media] em28xx: introduce #define for maximum supported scaling values (register 0x30-0x33) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The maximum supported scaling value for registers 0x30+0x31 (horizontal scaling) and 0x32+0x33 (vertical scaling) is 0x3fff, which corresponds to 20% of the input frame size. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-reg.h | 2 ++ drivers/media/usb/em28xx/em28xx-video.c | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index 885089e22bcd..0a3cb04fbeae 100644 --- a/drivers/media/usb/em28xx/em28xx-reg.h +++ b/drivers/media/usb/em28xx/em28xx-reg.h @@ -152,6 +152,8 @@ #define EM28XX_R31_HSCALEHIGH 0x31 #define EM28XX_R32_VSCALELOW 0x32 #define EM28XX_R33_VSCALEHIGH 0x33 +#define EM28XX_HVSCALE_MAX 0x3fff /* => 20% */ + #define EM28XX_R34_VBI_START_H 0x34 #define EM28XX_R35_VBI_START_V 0x35 #define EM28XX_R36_VBI_WIDTH 0x36 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 6d261232278c..9451e1ed0ec8 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -807,12 +807,12 @@ static void get_scale(struct em28xx *dev, unsigned int maxh = norm_maxh(dev); *hscale = (((unsigned long)maxw) << 12) / width - 4096L; - if (*hscale >= 0x4000) - *hscale = 0x3fff; + if (*hscale > EM28XX_HVSCALE_MAX) + *hscale = EM28XX_HVSCALE_MAX; *vscale = (((unsigned long)maxh) << 12) / height - 4096L; - if (*vscale >= 0x4000) - *vscale = 0x3fff; + if (*vscale > EM28XX_HVSCALE_MAX) + *vscale = EM28XX_HVSCALE_MAX; } /* ------------------------------------------------------------------ -- cgit v1.2.3 From 6b09a21cbc01521dcc4855484e2c0ffe8aab2a78 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 10 Feb 2013 16:05:12 -0300 Subject: [media] em28xx: rename function get_scale() to size_to_scale() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 9451e1ed0ec8..197823cfd263 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -799,7 +799,7 @@ const struct v4l2_ctrl_ops em28xx_ctrl_ops = { .s_ctrl = em28xx_s_ctrl, }; -static void get_scale(struct em28xx *dev, +static void size_to_scale(struct em28xx *dev, unsigned int width, unsigned int height, unsigned int *hscale, unsigned int *vscale) { @@ -889,7 +889,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, 1, 0); } - get_scale(dev, width, height, &hscale, &vscale); + size_to_scale(dev, width, height, &hscale, &vscale); width = (((unsigned long)maxw) << 12) / (hscale + 4096L); height = (((unsigned long)maxh) << 12) / (vscale + 4096L); @@ -923,7 +923,7 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc, dev->height = height; /* set new image size */ - get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); + size_to_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); em28xx_resolution_set(dev); @@ -986,7 +986,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) /* set new image size */ dev->width = f.fmt.pix.width; dev->height = f.fmt.pix.height; - get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); + size_to_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); em28xx_resolution_set(dev); v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm); -- cgit v1.2.3 From b83741383565f675bd13861fc39cfacdd68d18c1 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 10 Feb 2013 16:05:13 -0300 Subject: [media] em28xx: add function scale_to_size() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 197823cfd263..f745617aeece 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -815,6 +815,17 @@ static void size_to_scale(struct em28xx *dev, *vscale = EM28XX_HVSCALE_MAX; } +static void scale_to_size(struct em28xx *dev, + unsigned int hscale, unsigned int vscale, + unsigned int *width, unsigned int *height) +{ + unsigned int maxw = norm_maxw(dev); + unsigned int maxh = norm_maxh(dev); + + *width = (((unsigned long)maxw) << 12) / (hscale + 4096L); + *height = (((unsigned long)maxh) << 12) / (vscale + 4096L); +} + /* ------------------------------------------------------------------ IOCTL vidioc handling ------------------------------------------------------------------*/ @@ -890,9 +901,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } size_to_scale(dev, width, height, &hscale, &vscale); - - width = (((unsigned long)maxw) << 12) / (hscale + 4096L); - height = (((unsigned long)maxh) << 12) / (vscale + 4096L); + scale_to_size(dev, hscale, hscale, &width, &height); f->fmt.pix.width = width; f->fmt.pix.height = height; -- cgit v1.2.3 From 6c3598e641d447edbaaa05ff0d4cd6da152dc3f4 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 10 Feb 2013 16:05:14 -0300 Subject: [media] em28xx: VIDIOC_ENUM_FRAMESIZES: consider the scaler limits when calculating the minimum frame size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Output resolutions <=20% of the input resolution exceed the capabilities of the scaler. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index f745617aeece..86fd90727f56 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1405,8 +1405,12 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, /* Report a continuous range */ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fsize->stepwise.min_width = 48; - fsize->stepwise.min_height = 32; + scale_to_size(dev, EM28XX_HVSCALE_MAX, EM28XX_HVSCALE_MAX, + &fsize->stepwise.min_width, &fsize->stepwise.min_height); + if (fsize->stepwise.min_width < 48) + fsize->stepwise.min_width = 48; + if (fsize->stepwise.min_height < 38) + fsize->stepwise.min_height = 38; fsize->stepwise.max_width = maxw; fsize->stepwise.max_height = maxh; fsize->stepwise.step_width = 1; -- cgit v1.2.3 From 511ffe920b483340d61bb707ee96e7d6a9e6b13b Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Fri, 15 Feb 2013 14:38:29 -0300 Subject: [media] em28xx: remove unused image quality control functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx.h | 66 --------------------------------------- 1 file changed, 66 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 5f0b2c59e846..6a9e3e1b9929 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -744,72 +744,6 @@ static inline int em28xx_compression_disable(struct em28xx *dev) return em28xx_write_reg(dev, EM28XX_R26_COMPR, 0x00); } -static inline int em28xx_contrast_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R20_YGAIN) & 0x1f; -} - -static inline int em28xx_brightness_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R21_YOFFSET); -} - -static inline int em28xx_saturation_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R22_UVGAIN) & 0x1f; -} - -static inline int em28xx_u_balance_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R23_UOFFSET); -} - -static inline int em28xx_v_balance_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R24_VOFFSET); -} - -static inline int em28xx_gamma_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R14_GAMMA) & 0x3f; -} - -static inline int em28xx_contrast_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R20_YGAIN, &tmp, 1); -} - -static inline int em28xx_brightness_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R21_YOFFSET, &tmp, 1); -} - -static inline int em28xx_saturation_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R22_UVGAIN, &tmp, 1); -} - -static inline int em28xx_u_balance_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R23_UOFFSET, &tmp, 1); -} - -static inline int em28xx_v_balance_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R24_VOFFSET, &tmp, 1); -} - -static inline int em28xx_gamma_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R14_GAMMA, &tmp, 1); -} - /*FIXME: maxw should be dependent of alt mode */ static inline unsigned int norm_maxw(struct em28xx *dev) { -- cgit v1.2.3 From 7960205066632fea0245eda65278039d0f4f791c Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Fri, 15 Feb 2013 14:38:30 -0300 Subject: [media] em28xx: remove unused ac97 v4l2_ctrl_handler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 6a9e3e1b9929..7dc27b58a4d7 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -491,8 +491,6 @@ struct em28xx { struct v4l2_device v4l2_dev; struct v4l2_ctrl_handler ctrl_handler; - /* provides ac97 mute and volume overrides */ - struct v4l2_ctrl_handler ac97_ctrl_handler; struct em28xx_board board; /* Webcam specific fields */ -- cgit v1.2.3 From 43a5e08d0006b99308f0a1c9c14cf5551df35385 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Fri, 15 Feb 2013 14:38:31 -0300 Subject: [media] em28xx: introduce #defines for the image quality default settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The image quality default values will be used in at least two different places and by using #defines we make sure that they are always consistent. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-core.c | 12 ++++++------ drivers/media/usb/em28xx/em28xx-reg.h | 23 +++++++++++++++++------ 2 files changed, 23 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 26d249971a01..b2dcb3d1342d 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -607,12 +607,12 @@ EXPORT_SYMBOL_GPL(em28xx_audio_setup); int em28xx_colorlevels_set_default(struct em28xx *dev) { - em28xx_write_reg(dev, EM28XX_R20_YGAIN, 0x10); /* contrast */ - em28xx_write_reg(dev, EM28XX_R21_YOFFSET, 0x00); /* brightness */ - em28xx_write_reg(dev, EM28XX_R22_UVGAIN, 0x10); /* saturation */ - em28xx_write_reg(dev, EM28XX_R23_UOFFSET, 0x00); - em28xx_write_reg(dev, EM28XX_R24_VOFFSET, 0x00); - em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, 0x00); + em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT); + em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT); + em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT); + em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT); + em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT); + em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT); em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20); em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20); diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index 0a3cb04fbeae..8fd3c7f80201 100644 --- a/drivers/media/usb/em28xx/em28xx-reg.h +++ b/drivers/media/usb/em28xx/em28xx-reg.h @@ -120,12 +120,23 @@ #define EM28XX_R1E_CWIDTH 0x1e #define EM28XX_R1F_CHEIGHT 0x1f -#define EM28XX_R20_YGAIN 0x20 -#define EM28XX_R21_YOFFSET 0x21 -#define EM28XX_R22_UVGAIN 0x22 -#define EM28XX_R23_UOFFSET 0x23 -#define EM28XX_R24_VOFFSET 0x24 -#define EM28XX_R25_SHARPNESS 0x25 +#define EM28XX_R20_YGAIN 0x20 /* contrast [0:4] */ +#define CONTRAST_DEFAULT 0x10 + +#define EM28XX_R21_YOFFSET 0x21 /* brightness */ /* signed */ +#define BRIGHTNESS_DEFAULT 0x00 + +#define EM28XX_R22_UVGAIN 0x22 /* saturation [0:4] */ +#define SATURATION_DEFAULT 0x10 + +#define EM28XX_R23_UOFFSET 0x23 /* blue balance */ /* signed */ +#define BLUE_BALANCE_DEFAULT 0x00 + +#define EM28XX_R24_VOFFSET 0x24 /* red balance */ /* signed */ +#define RED_BALANCE_DEFAULT 0x00 + +#define EM28XX_R25_SHARPNESS 0x25 /* sharpness [0:4] */ +#define SHARPNESS_DEFAULT 0x00 #define EM28XX_R26_COMPR 0x26 #define EM28XX_R27_OUTFMT 0x27 -- cgit v1.2.3 From 8f8b113a030be7456dc5159bec879ff041a5a276 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Fri, 15 Feb 2013 14:38:32 -0300 Subject: [media] em28xx: add image quality bridge controls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the image quality bridge controls contrast, brightness, saturation, blue balance, red balance and sharpness. These controls are enabled only if no subdevice provides them. Tested with the following devices: "Terratec Cinergy 200 USB" "Hauppauge HVR-900" "SilverCrest 1.3MPix webcam" "Hauppauge WinTV USB2" "Speedlink VAD Laplace webcam" Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 7 +--- drivers/media/usb/em28xx/em28xx-video.c | 58 +++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 54a03b20de6e..9332d051bde9 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3091,7 +3091,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, return retval; } - v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_handler_init(hdl, 8); dev->v4l2_dev.ctrl_handler = hdl; /* register i2c bus */ @@ -3160,11 +3160,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, msleep(3); } - v4l2_ctrl_handler_setup(&dev->ctrl_handler); - retval = dev->ctrl_handler.error; - if (retval) - goto fail; - retval = em28xx_register_analog_devices(dev); if (retval < 0) { goto fail; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 86fd90727f56..48b937d1b063 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -782,17 +782,38 @@ void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv) static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl) { struct em28xx *dev = container_of(ctrl->handler, struct em28xx, ctrl_handler); + int ret = -EINVAL; switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: dev->mute = ctrl->val; + ret = em28xx_audio_analog_set(dev); break; case V4L2_CID_AUDIO_VOLUME: dev->volume = ctrl->val; + ret = em28xx_audio_analog_set(dev); + break; + case V4L2_CID_CONTRAST: + ret = em28xx_write_reg(dev, EM28XX_R20_YGAIN, ctrl->val); + break; + case V4L2_CID_BRIGHTNESS: + ret = em28xx_write_reg(dev, EM28XX_R21_YOFFSET, ctrl->val); + break; + case V4L2_CID_SATURATION: + ret = em28xx_write_reg(dev, EM28XX_R22_UVGAIN, ctrl->val); + break; + case V4L2_CID_BLUE_BALANCE: + ret = em28xx_write_reg(dev, EM28XX_R23_UOFFSET, ctrl->val); + break; + case V4L2_CID_RED_BALANCE: + ret = em28xx_write_reg(dev, EM28XX_R24_VOFFSET, ctrl->val); + break; + case V4L2_CID_SHARPNESS: + ret = em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, ctrl->val); break; } - return em28xx_audio_analog_set(dev); + return (ret < 0) ? ret : 0; } const struct v4l2_ctrl_ops em28xx_ctrl_ops = { @@ -1784,9 +1805,42 @@ int em28xx_register_analog_devices(struct em28xx *dev) (EM28XX_XCLK_AUDIO_UNMUTE | val)); em28xx_set_outfmt(dev); - em28xx_colorlevels_set_default(dev); em28xx_compression_disable(dev); + /* Add image controls */ + /* NOTE: at this point, the subdevices are already registered, so bridge + * controls are only added/enabled when no subdevice provides them */ + if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_CONTRAST)) + v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops, + V4L2_CID_CONTRAST, + 0, 0x1f, 1, CONTRAST_DEFAULT); + if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_BRIGHTNESS)) + v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops, + V4L2_CID_BRIGHTNESS, + -0x80, 0x7f, 1, BRIGHTNESS_DEFAULT); + if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_SATURATION)) + v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops, + V4L2_CID_SATURATION, + 0, 0x1f, 1, SATURATION_DEFAULT); + if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_BLUE_BALANCE)) + v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops, + V4L2_CID_BLUE_BALANCE, + -0x30, 0x30, 1, BLUE_BALANCE_DEFAULT); + if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_RED_BALANCE)) + v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops, + V4L2_CID_RED_BALANCE, + -0x30, 0x30, 1, RED_BALANCE_DEFAULT); + if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_SHARPNESS)) + v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops, + V4L2_CID_SHARPNESS, + 0, 0x0f, 1, SHARPNESS_DEFAULT); + + /* Reset image controls */ + em28xx_colorlevels_set_default(dev); + v4l2_ctrl_handler_setup(&dev->ctrl_handler); + if (dev->ctrl_handler.error) + return dev->ctrl_handler.error; + /* allocate and fill video video_device struct */ dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); if (!dev->vdev) { -- cgit v1.2.3 From a062b291af64e94f603f7a231aa55e7d05f0feb9 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Mon, 11 Feb 2013 13:54:01 -0300 Subject: [media] em28xx: remove some obsolete function declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx.h | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 7dc27b58a4d7..a3c08ae7ae8e 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -654,11 +654,6 @@ int em28xx_i2c_register(struct em28xx *dev); int em28xx_i2c_unregister(struct em28xx *dev); /* Provided by em28xx-core.c */ - -u32 em28xx_request_buffers(struct em28xx *dev, u32 count); -void em28xx_queue_unusedframes(struct em28xx *dev); -void em28xx_release_buffers(struct em28xx *dev); - int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, char *buf, int len); int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg); @@ -691,7 +686,6 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, (struct em28xx *dev, struct urb *urb)); void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode); void em28xx_stop_urbs(struct em28xx *dev); -int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev); int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); void em28xx_wake_i2c(struct em28xx *dev); @@ -710,10 +704,8 @@ int em28xx_stop_vbi_streaming(struct vb2_queue *vq); extern const struct v4l2_ctrl_ops em28xx_ctrl_ops; /* Provided by em28xx-cards.c */ -extern int em2800_variant_detect(struct usb_device *udev, int model); extern struct em28xx_board em28xx_boards[]; extern struct usb_device_id em28xx_id_table[]; -extern const unsigned int em28xx_bcount; int em28xx_tuner_callback(void *ptr, int component, int command, int arg); void em28xx_release_resources(struct em28xx *dev); -- cgit v1.2.3 From d5b6a7469127147797638b4c2b0c86d3049ad4ab Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Mon, 11 Feb 2013 14:01:20 -0300 Subject: [media] em28xx: fix spacing and some comments in em28xx.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx.h | 95 +++++++++++++++------------------------ 1 file changed, 37 insertions(+), 58 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index a3c08ae7ae8e..4160a2ae1d84 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -42,28 +42,28 @@ #include "em28xx-reg.h" /* Boards supported by driver */ -#define EM2800_BOARD_UNKNOWN 0 -#define EM2820_BOARD_UNKNOWN 1 -#define EM2820_BOARD_TERRATEC_CINERGY_250 2 -#define EM2820_BOARD_PINNACLE_USB_2 3 -#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4 -#define EM2820_BOARD_MSI_VOX_USB_2 5 -#define EM2800_BOARD_TERRATEC_CINERGY_200 6 -#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7 -#define EM2800_BOARD_KWORLD_USB2800 8 -#define EM2820_BOARD_PINNACLE_DVC_90 9 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10 -#define EM2880_BOARD_TERRATEC_HYBRID_XS 11 -#define EM2820_BOARD_KWORLD_PVRTV2800RF 12 -#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 -#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 -#define EM2800_BOARD_VGEAR_POCKETTV 15 -#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 16 -#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18 -#define EM2860_BOARD_SAA711X_REFERENCE_DESIGN 19 -#define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20 -#define EM2800_BOARD_GRABBEEX_USB2800 21 +#define EM2800_BOARD_UNKNOWN 0 +#define EM2820_BOARD_UNKNOWN 1 +#define EM2820_BOARD_TERRATEC_CINERGY_250 2 +#define EM2820_BOARD_PINNACLE_USB_2 3 +#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4 +#define EM2820_BOARD_MSI_VOX_USB_2 5 +#define EM2800_BOARD_TERRATEC_CINERGY_200 6 +#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7 +#define EM2800_BOARD_KWORLD_USB2800 8 +#define EM2820_BOARD_PINNACLE_DVC_90 9 +#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10 +#define EM2880_BOARD_TERRATEC_HYBRID_XS 11 +#define EM2820_BOARD_KWORLD_PVRTV2800RF 12 +#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 +#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 +#define EM2800_BOARD_VGEAR_POCKETTV 15 +#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 16 +#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17 +#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18 +#define EM2860_BOARD_SAA711X_REFERENCE_DESIGN 19 +#define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20 +#define EM2800_BOARD_GRABBEEX_USB2800 21 #define EM2750_BOARD_UNKNOWN 22 #define EM2750_BOARD_DLCW_130 23 #define EM2820_BOARD_DLINK_USB_TV 24 @@ -99,35 +99,35 @@ #define EM2882_BOARD_KWORLD_VS_DVBT 54 #define EM2882_BOARD_TERRATEC_HYBRID_XS 55 #define EM2882_BOARD_PINNACLE_HYBRID_PRO_330E 56 -#define EM2883_BOARD_KWORLD_HYBRID_330U 57 +#define EM2883_BOARD_KWORLD_HYBRID_330U 57 #define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 #define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60 #define EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2 61 #define EM2820_BOARD_GADMEI_TVR200 62 -#define EM2860_BOARD_KAIOMY_TVNPC_U2 63 -#define EM2860_BOARD_EASYCAP 64 +#define EM2860_BOARD_KAIOMY_TVNPC_U2 63 +#define EM2860_BOARD_EASYCAP 64 #define EM2820_BOARD_IODATA_GVMVP_SZ 65 #define EM2880_BOARD_EMPIRE_DUAL_TV 66 #define EM2860_BOARD_TERRATEC_GRABBY 67 #define EM2860_BOARD_TERRATEC_AV350 68 #define EM2882_BOARD_KWORLD_ATSC_315U 69 #define EM2882_BOARD_EVGA_INDTUBE 70 -#define EM2820_BOARD_SILVERCREST_WEBCAM 71 -#define EM2861_BOARD_GADMEI_UTV330PLUS 72 -#define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73 +#define EM2820_BOARD_SILVERCREST_WEBCAM 71 +#define EM2861_BOARD_GADMEI_UTV330PLUS 72 +#define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73 #define EM2800_BOARD_VC211A 74 #define EM2882_BOARD_DIKOM_DK300 75 #define EM2870_BOARD_KWORLD_A340 76 #define EM2874_BOARD_LEADERSHIP_ISDBT 77 -#define EM28174_BOARD_PCTV_290E 78 +#define EM28174_BOARD_PCTV_290E 78 #define EM2884_BOARD_TERRATEC_H5 79 -#define EM28174_BOARD_PCTV_460E 80 +#define EM28174_BOARD_PCTV_460E 80 #define EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C 81 #define EM2884_BOARD_CINERGY_HTC_STICK 82 -#define EM2860_BOARD_HT_VIDBOX_NW03 83 -#define EM2874_BOARD_MAXMEDIA_UB425_TC 84 -#define EM2884_BOARD_PCTV_510E 85 -#define EM2884_BOARD_PCTV_520E 86 +#define EM2860_BOARD_HT_VIDBOX_NW03 83 +#define EM2874_BOARD_MAXMEDIA_UB425_TC 84 +#define EM2884_BOARD_PCTV_510E 85 +#define EM2884_BOARD_PCTV_520E 86 #define EM2884_BOARD_TERRATEC_HTC_USB_XS 87 /* Limits minimum and default number of buffers */ @@ -172,27 +172,6 @@ #define EM28XX_INTERLACED_DEFAULT 1 -/* -#define (use usbview if you want to get the other alternate number infos) -#define -#define alternate number 2 -#define Endpoint Address: 82 - Direction: in - Attribute: 1 - Type: Isoc - Max Packet Size: 1448 - Interval: 125us - - alternate number 7 - - Endpoint Address: 82 - Direction: in - Attribute: 1 - Type: Isoc - Max Packet Size: 3072 - Interval: 125us -*/ - /* time in msecs to wait for i2c writes to finish */ #define EM2800_I2C_XFER_TIMEOUT 20 @@ -509,8 +488,8 @@ struct em28xx { unsigned int is_audio_only:1; /* Controls audio streaming */ - struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ - atomic_t stream_started; /* stream should be running if true */ + struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ + atomic_t stream_started; /* stream should be running if true */ struct em28xx_fmt *format; @@ -598,7 +577,7 @@ struct em28xx { u8 analog_ep_isoc; /* address of isoc endpoint for analog */ u8 analog_ep_bulk; /* address of bulk endpoint for analog */ u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */ - u8 dvb_ep_bulk; /* address of bulk endpoint for DVC */ + u8 dvb_ep_bulk; /* address of bulk endpoint for DVB */ int alt; /* alternate setting */ int max_pkt_size; /* max packet size of the selected ep at alt */ int packet_multiplier; /* multiplier for wMaxPacketSize, used for -- cgit v1.2.3 From 43a20d791031d5bbc92e143ff077a9bd2a4d438c Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Mon, 11 Feb 2013 14:07:55 -0300 Subject: [media] em28xx: bump driver version to 0.2.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The em28xx driver has changed much, especially since kernel 3.8. So it's time to bump the driver version. Changes since kernel 3.8: - converted the driver to videobuf2 - converted the driver to the v4l2-ctrl framework - added USB bulk transfer support - use USB bulk transfers by default for webcams (allows streaming from multiple devices at the same time) - added image quality bridge controls: contrast, brightness, saturation, blue balance, red balance, sharpness - removed dependency from module ir-kbd-i2c - cleaned up the frame data processing code - removed some unused/obsolete code - made remote controls of devices with external (i2c) receiver/decoder work again - fixed audio over USB for device "Terratec Cinergy 250" - several v4l2 compliance fixes and improvements (including fixes for ioctls enabling/disabling) - lots of further bug fixes and code improvements Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 48b937d1b063..93fc6204df6c 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -52,7 +52,7 @@ #define DRIVER_DESC "Empia em28xx based USB video device driver" -#define EM28XX_VERSION "0.1.3" +#define EM28XX_VERSION "0.2.0" #define em28xx_videodbg(fmt, arg...) do {\ if (video_debug) \ -- cgit v1.2.3 From d7a80eaa9a2adce908ad0707faea4f776199a48a Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 3 Mar 2013 15:37:35 -0300 Subject: [media] em28xx-i2c: get rid of the dprintk2 macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is only a single place where the dprintk2 macro is used, so get rid of it. [mchehab@redhat.com: fix checkpathc.pl complain: ERROR: space prohibited before that close parenthesis ')'] Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 8532c1d4fd46..4ffcafb6ac9a 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -41,14 +41,6 @@ static unsigned int i2c_debug; module_param(i2c_debug, int, 0644); MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); -#define dprintk2(lvl, fmt, args...) \ -do { \ - if (i2c_debug >= lvl) { \ - printk(KERN_DEBUG "%s at %s: " fmt, \ - dev->name, __func__ , ##args); \ - } \ -} while (0) - /* * em2800_i2c_send_bytes() * send up to 4 bytes to the em2800 i2c device @@ -295,9 +287,12 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, return 0; for (i = 0; i < num; i++) { addr = msgs[i].addr << 1; - dprintk2(2, "%s %s addr=%x len=%d:", - (msgs[i].flags & I2C_M_RD) ? "read" : "write", - i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); + if (i2c_debug >= 2) + printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:", + dev->name, __func__ , + (msgs[i].flags & I2C_M_RD) ? "read" : "write", + i == num - 1 ? "stop" : "nonstop", + addr, msgs[i].len); if (!msgs[i].len) { /* no len: check only for device presence */ if (dev->board.is_em2800) rc = em2800_i2c_check_for_device(dev, addr); -- cgit v1.2.3 From 12d7ce185a6d86758c8feecc91f3c029c39730c6 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 3 Mar 2013 15:37:34 -0300 Subject: [media] em28xx-i2c: replace printk() with the corresponding em28xx macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduces the number of characters/lines, unifies the code and improves readability. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 55 +++++++++++++++-------------------- 1 file changed, 24 insertions(+), 31 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 4ffcafb6ac9a..ebe1ec626892 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -394,7 +394,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) /* Check if board has eeprom */ err = i2c_master_recv(&dev->i2c_client, &buf, 0); if (err < 0) { - em28xx_errdev("board has no eeprom\n"); + em28xx_info("board has no eeprom\n"); memset(eedata, 0, len); return -ENODEV; } @@ -403,8 +403,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) err = i2c_master_send(&dev->i2c_client, &buf, 1); if (err != 1) { - printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", - dev->name, err); + em28xx_errdev("failed to read eeprom (err=%d)\n", err); return err; } @@ -421,9 +420,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) if (block != (err = i2c_master_recv(&dev->i2c_client, p, block))) { - printk(KERN_WARNING - "%s: i2c eeprom read error (err=%d)\n", - dev->name, err); + em28xx_errdev("i2c eeprom read error (err=%d)\n", err); return err; } size -= block; @@ -431,7 +428,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) } for (i = 0; i < len; i++) { if (0 == (i % 16)) - printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i); + em28xx_info("i2c eeprom %02x:", i); printk(" %02x", eedata[i]); if (15 == (i % 16)) printk("\n"); @@ -440,55 +437,51 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) if (em_eeprom->id == 0x9567eb1a) dev->hash = em28xx_hash_mem(eedata, len, 32); - printk(KERN_INFO "%s: EEPROM ID= 0x%08x, EEPROM hash = 0x%08lx\n", - dev->name, em_eeprom->id, dev->hash); + em28xx_info("EEPROM ID = 0x%08x, EEPROM hash = 0x%08lx\n", + em_eeprom->id, dev->hash); - printk(KERN_INFO "%s: EEPROM info:\n", dev->name); + em28xx_info("EEPROM info:\n"); switch (em_eeprom->chip_conf >> 4 & 0x3) { case 0: - printk(KERN_INFO "%s:\tNo audio on board.\n", dev->name); + em28xx_info("\tNo audio on board.\n"); break; case 1: - printk(KERN_INFO "%s:\tAC97 audio (5 sample rates)\n", - dev->name); + em28xx_info("\tAC97 audio (5 sample rates)\n"); break; case 2: - printk(KERN_INFO "%s:\tI2S audio, sample rate=32k\n", - dev->name); + em28xx_info("\tI2S audio, sample rate=32k\n"); break; case 3: - printk(KERN_INFO "%s:\tI2S audio, 3 sample rates\n", - dev->name); + em28xx_info("\tI2S audio, 3 sample rates\n"); break; } if (em_eeprom->chip_conf & 1 << 3) - printk(KERN_INFO "%s:\tUSB Remote wakeup capable\n", dev->name); + em28xx_info("\tUSB Remote wakeup capable\n"); if (em_eeprom->chip_conf & 1 << 2) - printk(KERN_INFO "%s:\tUSB Self power capable\n", dev->name); + em28xx_info("\tUSB Self power capable\n"); switch (em_eeprom->chip_conf & 0x3) { case 0: - printk(KERN_INFO "%s:\t500mA max power\n", dev->name); + em28xx_info("\t500mA max power\n"); break; case 1: - printk(KERN_INFO "%s:\t400mA max power\n", dev->name); + em28xx_info("\t400mA max power\n"); break; case 2: - printk(KERN_INFO "%s:\t300mA max power\n", dev->name); + em28xx_info("\t300mA max power\n"); break; case 3: - printk(KERN_INFO "%s:\t200mA max power\n", dev->name); + em28xx_info("\t200mA max power\n"); break; } - printk(KERN_INFO "%s:\tTable at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", - dev->name, - em_eeprom->string_idx_table, - em_eeprom->string1, - em_eeprom->string2, - em_eeprom->string3); + em28xx_info("\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", + em_eeprom->string_idx_table, + em_eeprom->string1, + em_eeprom->string2, + em_eeprom->string3); return 0; } @@ -565,8 +558,8 @@ void em28xx_do_i2c_scan(struct em28xx *dev) if (rc < 0) continue; i2c_devicelist[i] = i; - printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", - dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + em28xx_info("found i2c device @ 0x%x [%s]\n", + i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); } dev->i2c_hash = em28xx_hash_mem(i2c_devicelist, -- cgit v1.2.3 From d90f067713091f010672ddbd023691675a7b33ea Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 3 Mar 2013 15:37:36 -0300 Subject: [media] em28xx-i2c: also print debug messages at debug level 1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current code uses only a single debug level and all debug messages are printed for i2c_debug >= 2 only. So debug level 1 is actually the same as level 0, which is odd. Users expect debugging messages to become enabled for anything else than debug level 0. Fix it and simplify the code a bit by printing the debug messages also at debug level 1; Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index ebe1ec626892..b8e9946f8452 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -287,7 +287,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, return 0; for (i = 0; i < num; i++) { addr = msgs[i].addr << 1; - if (i2c_debug >= 2) + if (i2c_debug) printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:", dev->name, __func__ , (msgs[i].flags & I2C_M_RD) ? "read" : "write", @@ -299,7 +299,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, else rc = em28xx_i2c_check_for_device(dev, addr); if (rc == -ENODEV) { - if (i2c_debug >= 2) + if (i2c_debug) printk(" no device\n"); return rc; } @@ -313,13 +313,13 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, rc = em28xx_i2c_recv_bytes(dev, addr, msgs[i].buf, msgs[i].len); - if (i2c_debug >= 2) { + if (i2c_debug) { for (byte = 0; byte < msgs[i].len; byte++) printk(" %02x", msgs[i].buf[byte]); } } else { /* write bytes */ - if (i2c_debug >= 2) { + if (i2c_debug) { for (byte = 0; byte < msgs[i].len; byte++) printk(" %02x", msgs[i].buf[byte]); } @@ -334,11 +334,11 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, i == num - 1); } if (rc < 0) { - if (i2c_debug >= 2) + if (i2c_debug) printk(" ERROR: %i\n", rc); return rc; } - if (i2c_debug >= 2) + if (i2c_debug) printk("\n"); } -- cgit v1.2.3 From f55eacbe744f696fa5ff48fe4fdc0f00edc08619 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 3 Mar 2013 15:37:37 -0300 Subject: [media] em28xx: do not interpret eeprom content if eeprom key is invalid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the eeprom key isn't valid, either a different (currently unknown) format is used or the eeprom is corrupted. In both cases it doesn't make sense to interpret the data. Also print an error message. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index b8e9946f8452..b8a9bee836fa 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -434,8 +434,12 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) printk("\n"); } - if (em_eeprom->id == 0x9567eb1a) - dev->hash = em28xx_hash_mem(eedata, len, 32); + if (em_eeprom->id != 0x9567eb1a) { + em28xx_errdev("Unknown eeprom type or eeprom corrupted !"); + return -ENODEV; + } + + dev->hash = em28xx_hash_mem(eedata, len, 32); em28xx_info("EEPROM ID = 0x%08x, EEPROM hash = 0x%08lx\n", em_eeprom->id, dev->hash); -- cgit v1.2.3 From 0c28dcc054ecbcd16e197bd9bf9b394cc1f691c5 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 3 Mar 2013 15:37:38 -0300 Subject: [media] em28xx: fix eeprom data endianess MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The data is stored as little endian in the eeprom. Hence the correct data types should be used and the data should be converted to the machine endianess before using it. The eeprom id (key) also isn't a 32 bit value but 4 separate bytes instead. [mchehab@redhat.com: Fix CodingStyle] Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 22 ++++++++++++---------- drivers/media/usb/em28xx/em28xx.h | 12 ++++++------ 2 files changed, 18 insertions(+), 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index b8a9bee836fa..1b90e7536aa5 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -434,19 +434,21 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) printk("\n"); } - if (em_eeprom->id != 0x9567eb1a) { + if (em_eeprom->id[0] != 0x1a || em_eeprom->id[1] != 0xeb || + em_eeprom->id[2] != 0x67 || em_eeprom->id[3] != 0x95) { em28xx_errdev("Unknown eeprom type or eeprom corrupted !"); return -ENODEV; } dev->hash = em28xx_hash_mem(eedata, len, 32); - em28xx_info("EEPROM ID = 0x%08x, EEPROM hash = 0x%08lx\n", - em_eeprom->id, dev->hash); + em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", + em_eeprom->id[0], em_eeprom->id[1], + em_eeprom->id[2], em_eeprom->id[3], dev->hash); em28xx_info("EEPROM info:\n"); - switch (em_eeprom->chip_conf >> 4 & 0x3) { + switch (le16_to_cpu(em_eeprom->chip_conf) >> 4 & 0x3) { case 0: em28xx_info("\tNo audio on board.\n"); break; @@ -461,13 +463,13 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) break; } - if (em_eeprom->chip_conf & 1 << 3) + if (le16_to_cpu(em_eeprom->chip_conf) & 1 << 3) em28xx_info("\tUSB Remote wakeup capable\n"); - if (em_eeprom->chip_conf & 1 << 2) + if (le16_to_cpu(em_eeprom->chip_conf) & 1 << 2) em28xx_info("\tUSB Self power capable\n"); - switch (em_eeprom->chip_conf & 0x3) { + switch (le16_to_cpu(em_eeprom->chip_conf) & 0x3) { case 0: em28xx_info("\t500mA max power\n"); break; @@ -483,9 +485,9 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) } em28xx_info("\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", em_eeprom->string_idx_table, - em_eeprom->string1, - em_eeprom->string2, - em_eeprom->string3); + le16_to_cpu(em_eeprom->string1), + le16_to_cpu(em_eeprom->string2), + le16_to_cpu(em_eeprom->string3)); return 0; } diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 4160a2ae1d84..90266a1e7957 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -405,15 +405,15 @@ struct em28xx_board { }; struct em28xx_eeprom { - u32 id; /* 0x9567eb1a */ - u16 vendor_ID; - u16 product_ID; + u8 id[4]; /* 1a eb 67 95 */ + __le16 vendor_ID; + __le16 product_ID; - u16 chip_conf; + __le16 chip_conf; - u16 board_conf; + __le16 board_conf; - u16 string1, string2, string3; + __le16 string1, string2, string3; u8 string_idx_table; }; -- cgit v1.2.3 From 87b52439cff4a8b745f419b9e99fa68a5533c342 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 3 Mar 2013 15:37:40 -0300 Subject: [media] em28xx: add basic support for eeproms with 16 bit address width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Newer devices (em2874, em2884, em28174, em25xx, em27[6,7,8]x) use eeproms with 16 bit instead of 8 bit address width. The used eeprom type depends on the chip type, which makes sure eeproms can't be damaged. This patch adds basic support for 16 bit eeproms only, which includes - reading the content - calculating the eeprom hash - displaying the content The eeprom content uses a different format, for which support will be added with subsequent patches. Tested with the "Hauppauge HVR-930C" and the "Speedlink VAD Laplace webcam" (with additional experimental patches). Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 4 ++ drivers/media/usb/em28xx/em28xx-i2c.c | 69 +++++++++++++++++++++------------ drivers/media/usb/em28xx/em28xx.h | 1 + 3 files changed, 49 insertions(+), 25 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 9332d051bde9..f371dbede27e 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2183,6 +2183,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = { {0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF}, {0x6b800080, EM2874_BOARD_LEADERSHIP_ISDBT, TUNER_ABSENT}, }; +/* NOTE: introduce a separate hash table for devices with 16 bit eeproms */ /* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */ static unsigned short saa711x_addrs[] = { @@ -3019,11 +3020,13 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, chip_name = "em2874"; dev->reg_gpio_num = EM2874_R80_GPIO; dev->wait_after_write = 0; + dev->eeprom_addrwidth_16bit = 1; break; case CHIP_ID_EM28174: chip_name = "em28174"; dev->reg_gpio_num = EM2874_R80_GPIO; dev->wait_after_write = 0; + dev->eeprom_addrwidth_16bit = 1; break; case CHIP_ID_EM2883: chip_name = "em2882/3"; @@ -3033,6 +3036,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, chip_name = "em2884"; dev->reg_gpio_num = EM2874_R80_GPIO; dev->wait_after_write = 0; + dev->eeprom_addrwidth_16bit = 1; break; default: printk(KERN_INFO DRIVER_NAME diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 1b90e7536aa5..3f0012c9cf25 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -372,46 +372,34 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) { - unsigned char buf, *p = eedata; + unsigned char buf[2], *p = eedata; struct em28xx_eeprom *em_eeprom = (void *)eedata; int i, err, size = len, block, block_max; - if (dev->chip_id == CHIP_ID_EM2874 || - dev->chip_id == CHIP_ID_EM28174 || - dev->chip_id == CHIP_ID_EM2884) { - /* Empia switched to a 16-bit addressable eeprom in newer - devices. While we could certainly write a routine to read - the eeprom, there is nothing of use in there that cannot be - accessed through registers, and there is the risk that we - could corrupt the eeprom (since a 16-bit read call is - interpreted as a write call by 8-bit eeproms). - */ - return 0; - } - dev->i2c_client.addr = 0xa0 >> 1; /* Check if board has eeprom */ - err = i2c_master_recv(&dev->i2c_client, &buf, 0); + err = i2c_master_recv(&dev->i2c_client, buf, 0); if (err < 0) { em28xx_info("board has no eeprom\n"); memset(eedata, 0, len); return -ENODEV; } - buf = 0; - - err = i2c_master_send(&dev->i2c_client, &buf, 1); - if (err != 1) { + /* Select address memory address 0x00(00) */ + buf[0] = 0; + buf[1] = 0; + err = i2c_master_send(&dev->i2c_client, buf, 1 + dev->eeprom_addrwidth_16bit); + if (err != 1 + dev->eeprom_addrwidth_16bit) { em28xx_errdev("failed to read eeprom (err=%d)\n", err); return err; } + /* Read eeprom content */ if (dev->board.is_em2800) block_max = 4; else block_max = 64; - while (size > 0) { if (size > block_max) block = block_max; @@ -426,17 +414,48 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) size -= block; p += block; } + + /* Display eeprom content */ for (i = 0; i < len; i++) { - if (0 == (i % 16)) - em28xx_info("i2c eeprom %02x:", i); + if (0 == (i % 16)) { + if (dev->eeprom_addrwidth_16bit) + em28xx_info("i2c eeprom %04x:", i); + else + em28xx_info("i2c eeprom %02x:", i); + } printk(" %02x", eedata[i]); if (15 == (i % 16)) printk("\n"); } - if (em_eeprom->id[0] != 0x1a || em_eeprom->id[1] != 0xeb || - em_eeprom->id[2] != 0x67 || em_eeprom->id[3] != 0x95) { - em28xx_errdev("Unknown eeprom type or eeprom corrupted !"); + if (dev->eeprom_addrwidth_16bit && + eedata[0] == 0x26 && eedata[3] == 0x00) { + /* new eeprom format; size 4-64kb */ + dev->hash = em28xx_hash_mem(eedata, len, 32); + em28xx_info("EEPROM hash = 0x%08lx\n", dev->hash); + em28xx_info("EEPROM info: boot page address = 0x%02x04, " + "boot configuration = 0x%02x\n", + eedata[1], eedata[2]); + /* boot configuration (address 0x0002): + * [0] microcode download speed: 1 = 400 kHz; 0 = 100 kHz + * [1] always selects 12 kb RAM + * [2] USB device speed: 1 = force Full Speed; 0 = auto detect + * [4] 1 = force fast mode and no suspend for device testing + * [5:7] USB PHY tuning registers; determined by device + * characterization + */ + + /* FIXME: + * - read more than 256 bytes / addresses above 0x00ff + * - find offset for device config dataset and extract it + * - decrypt eeprom data for camera bridges (em25xx, em276x+) + * - use separate/different eeprom hashes (not yet used) + */ + + return 0; + } else if (em_eeprom->id[0] != 0x1a || em_eeprom->id[1] != 0xeb || + em_eeprom->id[2] != 0x67 || em_eeprom->id[3] != 0x95) { + em28xx_info("unknown eeprom format or eeprom corrupted !\n"); return -ENODEV; } diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 90266a1e7957..139dfe54a057 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -510,6 +510,7 @@ struct em28xx { /* i2c i/o */ struct i2c_adapter i2c_adap; struct i2c_client i2c_client; + unsigned char eeprom_addrwidth_16bit:1; /* video for linux */ int users; /* user count for exclusive use */ int streaming_users; /* Number of actively streaming users */ -- cgit v1.2.3 From d832c5b28aff3c9aadfbde3002b640058eee6294 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 3 Mar 2013 15:37:41 -0300 Subject: [media] em28xx: add helper function for reading data blocks from i2c clients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a helper function for reading data blocks from i2c devices with 8 or 16 bit address width and 8 bit register width. This allows us to reduce the size of new code added by the following patches. Works only for devices with activated register auto incrementation. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 74 ++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 28 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 3f0012c9cf25..438cfbcb9bf5 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -370,51 +370,69 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) return (hash >> (32 - bits)) & 0xffffffffUL; } +/* Helper function to read data blocks from i2c clients with 8 or 16 bit + * address width, 8 bit register width and auto incrementation been activated */ +static int em28xx_i2c_read_block(struct em28xx *dev, u16 addr, bool addr_w16, + u16 len, u8 *data) +{ + int remain = len, rsize, rsize_max, ret; + u8 buf[2]; + + /* Sanity check */ + if (addr + remain > (addr_w16 * 0xff00 + 0xff + 1)) + return -EINVAL; + /* Select address */ + buf[0] = addr >> 8; + buf[1] = addr & 0xff; + ret = i2c_master_send(&dev->i2c_client, buf + !addr_w16, 1 + addr_w16); + if (ret < 0) + return ret; + /* Read data */ + if (dev->board.is_em2800) + rsize_max = 4; + else + rsize_max = 64; + while (remain > 0) { + if (remain > rsize_max) + rsize = rsize_max; + else + rsize = remain; + + ret = i2c_master_recv(&dev->i2c_client, data, rsize); + if (ret < 0) + return ret; + + remain -= rsize; + data += rsize; + } + + return len; +} + static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) { - unsigned char buf[2], *p = eedata; + unsigned char buf, *p = eedata; struct em28xx_eeprom *em_eeprom = (void *)eedata; - int i, err, size = len, block, block_max; + int i, err; dev->i2c_client.addr = 0xa0 >> 1; /* Check if board has eeprom */ - err = i2c_master_recv(&dev->i2c_client, buf, 0); + err = i2c_master_recv(&dev->i2c_client, &buf, 0); if (err < 0) { em28xx_info("board has no eeprom\n"); memset(eedata, 0, len); return -ENODEV; } - /* Select address memory address 0x00(00) */ - buf[0] = 0; - buf[1] = 0; - err = i2c_master_send(&dev->i2c_client, buf, 1 + dev->eeprom_addrwidth_16bit); - if (err != 1 + dev->eeprom_addrwidth_16bit) { + /* Read EEPROM content */ + err = em28xx_i2c_read_block(dev, 0x0000, dev->eeprom_addrwidth_16bit, + len, p); + if (err != len) { em28xx_errdev("failed to read eeprom (err=%d)\n", err); return err; } - /* Read eeprom content */ - if (dev->board.is_em2800) - block_max = 4; - else - block_max = 64; - while (size > 0) { - if (size > block_max) - block = block_max; - else - block = size; - - if (block != - (err = i2c_master_recv(&dev->i2c_client, p, block))) { - em28xx_errdev("i2c eeprom read error (err=%d)\n", err); - return err; - } - size -= block; - p += block; - } - /* Display eeprom content */ for (i = 0; i < len; i++) { if (0 == (i % 16)) { -- cgit v1.2.3 From a217968f919b0574ef59054430d8908aebcf0a35 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 3 Mar 2013 15:37:42 -0300 Subject: [media] em28xx: do not store eeprom content permanently MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently reserve an array of 256 bytes for the eeprom content in the device struct. For eeproms with 16 bit address width it might even be necessary to increase the buffer size further. Having such a big chunk of memory reserved even if the device has no eeprom and keeping it after it has already been processed seems to be a waste of memory. Change the code to allocate + free the eeprom memory dynamically. This also makes it possible to handle different dataset sizes depending on what is stored/found in the eeprom. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 9 ++++++++- drivers/media/usb/em28xx/em28xx-i2c.c | 35 +++++++++++++++++++++------------ drivers/media/usb/em28xx/em28xx.h | 2 +- 3 files changed, 31 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index f371dbede27e..331d55034616 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2739,6 +2739,9 @@ static void em28xx_card_setup(struct em28xx *dev) case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: { struct tveeprom tv; + + if (dev->eedata == NULL) + break; #if defined(CONFIG_MODULES) && defined(MODULE) request_module("tveeprom"); #endif @@ -2792,7 +2795,7 @@ static void em28xx_card_setup(struct em28xx *dev) em28xx_set_mode(dev, EM28XX_ANALOG_MODE); break; -/* + /* * The Dikom DK300 is detected as an Kworld VS-DVB-T 323UR. * * This occurs because they share identical USB vendor and @@ -2827,6 +2830,10 @@ static void em28xx_card_setup(struct em28xx *dev) "addresses)\n\n"); } + /* Free eeprom data memory */ + kfree(dev->eedata); + dev->eedata = NULL; + /* Allow override tuner type by a module parameter */ if (tuner >= 0) dev->tuner_type = tuner; diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 438cfbcb9bf5..8d4817747bf2 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -409,27 +409,33 @@ static int em28xx_i2c_read_block(struct em28xx *dev, u16 addr, bool addr_w16, return len; } -static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) +static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char **eedata, int len) { - unsigned char buf, *p = eedata; - struct em28xx_eeprom *em_eeprom = (void *)eedata; + u8 buf, *data; + struct em28xx_eeprom *em_eeprom; int i, err; + *eedata = NULL; + dev->i2c_client.addr = 0xa0 >> 1; /* Check if board has eeprom */ err = i2c_master_recv(&dev->i2c_client, &buf, 0); if (err < 0) { em28xx_info("board has no eeprom\n"); - memset(eedata, 0, len); return -ENODEV; } + data = kzalloc(len, GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + /* Read EEPROM content */ err = em28xx_i2c_read_block(dev, 0x0000, dev->eeprom_addrwidth_16bit, - len, p); + len, data); if (err != len) { em28xx_errdev("failed to read eeprom (err=%d)\n", err); + kfree(data); return err; } @@ -441,19 +447,19 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) else em28xx_info("i2c eeprom %02x:", i); } - printk(" %02x", eedata[i]); + printk(" %02x", data[i]); if (15 == (i % 16)) printk("\n"); } if (dev->eeprom_addrwidth_16bit && - eedata[0] == 0x26 && eedata[3] == 0x00) { + data[0] == 0x26 && data[3] == 0x00) { /* new eeprom format; size 4-64kb */ - dev->hash = em28xx_hash_mem(eedata, len, 32); + dev->hash = em28xx_hash_mem(data, len, 32); em28xx_info("EEPROM hash = 0x%08lx\n", dev->hash); em28xx_info("EEPROM info: boot page address = 0x%02x04, " "boot configuration = 0x%02x\n", - eedata[1], eedata[2]); + data[1], data[2]); /* boot configuration (address 0x0002): * [0] microcode download speed: 1 = 400 kHz; 0 = 100 kHz * [1] always selects 12 kb RAM @@ -471,13 +477,16 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) */ return 0; - } else if (em_eeprom->id[0] != 0x1a || em_eeprom->id[1] != 0xeb || - em_eeprom->id[2] != 0x67 || em_eeprom->id[3] != 0x95) { + } else if (data[0] != 0x1a || data[1] != 0xeb || + data[2] != 0x67 || data[3] != 0x95) { em28xx_info("unknown eeprom format or eeprom corrupted !\n"); return -ENODEV; } - dev->hash = em28xx_hash_mem(eedata, len, 32); + *eedata = data; + em_eeprom = (void *)eedata; + + dev->hash = em28xx_hash_mem(data, len, 32); em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", em_eeprom->id[0], em_eeprom->id[1], @@ -635,7 +644,7 @@ int em28xx_i2c_register(struct em28xx *dev) dev->i2c_client = em28xx_client_template; dev->i2c_client.adapter = &dev->i2c_adap; - retval = em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); + retval = em28xx_i2c_eeprom(dev, &dev->eedata, 256); if ((retval < 0) && (retval != -ENODEV)) { em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n", __func__, retval); diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 139dfe54a057..77f600dc0067 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -562,7 +562,7 @@ struct em28xx { /* resources in use */ unsigned int resources; - unsigned char eedata[256]; + u8 *eedata; /* currently always 256 bytes */ /* Isoc control struct */ struct em28xx_dmaqueue vidq; -- cgit v1.2.3 From 510e884c1abb86b060b895ffaf38ee1aac2e7fe4 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 3 Mar 2013 15:37:43 -0300 Subject: [media] em28xx: extract the device configuration dataset from eeproms with 16 bit address width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new eeproms with 16 address width still have the the device config dataset (the content of the old 8 bit eeproms) embedded. Hauppauge also continues to include the tveeprom data structure inside this dataset in their devices. The start address of the dataset depends on the start address of the microcode and a variable additional offset. It should be mentioned that Camera devices seem to use a different dataset type, which is not yet supported. Tested with devices "Hauppauge HVR-930C". I've also checked the USB-log from the "MSI Digivox ATSC" and it works the same way. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 117 ++++++++++++++++++++++++---------- drivers/media/usb/em28xx/em28xx.h | 4 +- 2 files changed, 85 insertions(+), 36 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 8d4817747bf2..6152423bef76 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -409,13 +409,18 @@ static int em28xx_i2c_read_block(struct em28xx *dev, u16 addr, bool addr_w16, return len; } -static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char **eedata, int len) +static int em28xx_i2c_eeprom(struct em28xx *dev, u8 **eedata, u16 *eedata_len) { - u8 buf, *data; - struct em28xx_eeprom *em_eeprom; + const u16 len = 256; + /* FIXME common length/size for bytes to read, to display, hash + * calculation and returned device dataset. Simplifies the code a lot, + * but we might have to deal with multiple sizes in the future ! */ int i, err; + struct em28xx_eeprom *dev_config; + u8 buf, *data; *eedata = NULL; + *eedata_len = 0; dev->i2c_client.addr = 0xa0 >> 1; @@ -435,8 +440,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char **eedata, int len len, data); if (err != len) { em28xx_errdev("failed to read eeprom (err=%d)\n", err); - kfree(data); - return err; + goto error; } /* Display eeprom content */ @@ -451,15 +455,25 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char **eedata, int len if (15 == (i % 16)) printk("\n"); } + if (dev->eeprom_addrwidth_16bit) + em28xx_info("i2c eeprom %04x: ... (skipped)\n", i); if (dev->eeprom_addrwidth_16bit && data[0] == 0x26 && data[3] == 0x00) { /* new eeprom format; size 4-64kb */ + u16 mc_start; + u16 hwconf_offset; + dev->hash = em28xx_hash_mem(data, len, 32); - em28xx_info("EEPROM hash = 0x%08lx\n", dev->hash); - em28xx_info("EEPROM info: boot page address = 0x%02x04, " + mc_start = (data[1] << 8) + 4; /* usually 0x0004 */ + + em28xx_info("EEPROM ID = %02x %02x %02x %02x, " + "EEPROM hash = 0x%08lx\n", + data[0], data[1], data[2], data[3], dev->hash); + em28xx_info("EEPROM info:\n"); + em28xx_info("\tmicrocode start address = 0x%04x, " "boot configuration = 0x%02x\n", - data[1], data[2]); + mc_start, data[2]); /* boot configuration (address 0x0002): * [0] microcode download speed: 1 = 400 kHz; 0 = 100 kHz * [1] always selects 12 kb RAM @@ -469,32 +483,61 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char **eedata, int len * characterization */ - /* FIXME: - * - read more than 256 bytes / addresses above 0x00ff - * - find offset for device config dataset and extract it - * - decrypt eeprom data for camera bridges (em25xx, em276x+) - * - use separate/different eeprom hashes (not yet used) + /* Read hardware config dataset offset from address + * (microcode start + 46) */ + err = em28xx_i2c_read_block(dev, mc_start + 46, 1, 2, data); + if (err != 2) { + em28xx_errdev("failed to read hardware configuration data from eeprom (err=%d)\n", + err); + goto error; + } + + /* Calculate hardware config dataset start address */ + hwconf_offset = mc_start + data[0] + (data[1] << 8); + + /* Read hardware config dataset */ + /* NOTE: the microcode copy can be multiple pages long, but + * we assume the hardware config dataset is the same as in + * the old eeprom and not longer than 256 bytes. + * tveeprom is currently also limited to 256 bytes. */ + err = em28xx_i2c_read_block(dev, hwconf_offset, 1, len, data); + if (err != len) { + em28xx_errdev("failed to read hardware configuration data from eeprom (err=%d)\n", + err); + goto error; + } - return 0; - } else if (data[0] != 0x1a || data[1] != 0xeb || - data[2] != 0x67 || data[3] != 0x95) { + /* Verify hardware config dataset */ + /* NOTE: not all devices provide this type of dataset */ + if (data[0] != 0x1a || data[1] != 0xeb || + data[2] != 0x67 || data[3] != 0x95) { + em28xx_info("\tno hardware configuration dataset found in eeprom\n"); + kfree(data); + return 0; + } + + /* TODO: decrypt eeprom data for camera bridges (em25xx, em276x+) */ + + } else if (!dev->eeprom_addrwidth_16bit && + data[0] == 0x1a && data[1] == 0xeb && + data[2] == 0x67 && data[3] == 0x95) { + dev->hash = em28xx_hash_mem(data, len, 32); + em28xx_info("EEPROM ID = %02x %02x %02x %02x, " + "EEPROM hash = 0x%08lx\n", + data[0], data[1], data[2], data[3], dev->hash); + em28xx_info("EEPROM info:\n"); + } else { em28xx_info("unknown eeprom format or eeprom corrupted !\n"); - return -ENODEV; + err = -ENODEV; + goto error; } *eedata = data; - em_eeprom = (void *)eedata; + *eedata_len = len; + dev_config = (void *)eedata; - dev->hash = em28xx_hash_mem(data, len, 32); - - em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", - em_eeprom->id[0], em_eeprom->id[1], - em_eeprom->id[2], em_eeprom->id[3], dev->hash); - - em28xx_info("EEPROM info:\n"); - - switch (le16_to_cpu(em_eeprom->chip_conf) >> 4 & 0x3) { + switch (le16_to_cpu(dev_config->chip_conf) >> 4 & 0x3) { case 0: em28xx_info("\tNo audio on board.\n"); break; @@ -509,13 +552,13 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char **eedata, int len break; } - if (le16_to_cpu(em_eeprom->chip_conf) & 1 << 3) + if (le16_to_cpu(dev_config->chip_conf) & 1 << 3) em28xx_info("\tUSB Remote wakeup capable\n"); - if (le16_to_cpu(em_eeprom->chip_conf) & 1 << 2) + if (le16_to_cpu(dev_config->chip_conf) & 1 << 2) em28xx_info("\tUSB Self power capable\n"); - switch (le16_to_cpu(em_eeprom->chip_conf) & 0x3) { + switch (le16_to_cpu(dev_config->chip_conf) & 0x3) { case 0: em28xx_info("\t500mA max power\n"); break; @@ -530,12 +573,16 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char **eedata, int len break; } em28xx_info("\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", - em_eeprom->string_idx_table, - le16_to_cpu(em_eeprom->string1), - le16_to_cpu(em_eeprom->string2), - le16_to_cpu(em_eeprom->string3)); + dev_config->string_idx_table, + le16_to_cpu(dev_config->string1), + le16_to_cpu(dev_config->string2), + le16_to_cpu(dev_config->string3)); return 0; + +error: + kfree(data); + return err; } /* ----------------------------------------------------------- */ @@ -644,7 +691,7 @@ int em28xx_i2c_register(struct em28xx *dev) dev->i2c_client = em28xx_client_template; dev->i2c_client.adapter = &dev->i2c_adap; - retval = em28xx_i2c_eeprom(dev, &dev->eedata, 256); + retval = em28xx_i2c_eeprom(dev, &dev->eedata, &dev->eedata_len); if ((retval < 0) && (retval != -ENODEV)) { em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n", __func__, retval); diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 77f600dc0067..2d6d31ace733 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -562,7 +562,9 @@ struct em28xx { /* resources in use */ unsigned int resources; - u8 *eedata; /* currently always 256 bytes */ + /* eeprom content */ + u8 *eedata; + u16 eedata_len; /* Isoc control struct */ struct em28xx_dmaqueue vidq; -- cgit v1.2.3 From d56e326f7b7f409f0390517b0a29d65b4d60c14c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 2 Mar 2013 09:05:42 -0300 Subject: [media] mb86a20s: don't pollute dmesg with debug messages There are a few debug tests that are shown with dev_err() or dev_info(). Replace them by dev_dbg(). Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index f19cd7367040..44bfb884ba11 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -1095,7 +1095,7 @@ static int mb86a20s_get_blk_error(struct dvb_frontend *fe, if (rc < 0) return rc; *error |= rc; - dev_err(&state->i2c->dev, "%s: block error for layer %c: %d.\n", + dev_dbg(&state->i2c->dev, "%s: block error for layer %c: %d.\n", __func__, 'A' + layer, *error); /* Read Bit Count */ @@ -1386,7 +1386,7 @@ static int mb86a20s_get_main_CNR(struct dvb_frontend *fe) return rc; if (!(rc & 0x40)) { - dev_info(&state->i2c->dev, "%s: CNR is not available yet.\n", + dev_dbg(&state->i2c->dev, "%s: CNR is not available yet.\n", __func__); return -EBUSY; } @@ -1441,7 +1441,7 @@ static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe) /* Check if data is available */ if (!(rc & 0x01)) { - dev_info(&state->i2c->dev, + dev_dbg(&state->i2c->dev, "%s: MER measures aren't available yet.\n", __func__); return -EBUSY; } -- cgit v1.2.3 From 768e6dadd748ecceee852def1f7f71aac4cd35a1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 28 Feb 2013 16:45:39 -0300 Subject: [media] mb86a20s: adjust IF based on what's set on the tuner Instead of hardcoding a fixed IF frequency of 3.3 MHz, use the IF frequency provided by the tuner driver. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 57 +++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 44bfb884ba11..daeee814e491 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -31,6 +31,8 @@ struct mb86a20s_state { struct dvb_frontend frontend; + u32 if_freq; + u32 estimated_rate[3]; bool need_init; @@ -47,7 +49,7 @@ struct regdata { * Initialization sequence: Use whatevere default values that PV SBTVD * does on its initialisation, obtained via USB snoop */ -static struct regdata mb86a20s_init[] = { +static struct regdata mb86a20s_init1[] = { { 0x70, 0x0f }, { 0x70, 0xff }, { 0x08, 0x01 }, @@ -56,7 +58,9 @@ static struct regdata mb86a20s_init[] = { { 0x39, 0x01 }, { 0x71, 0x00 }, { 0x28, 0x2a }, { 0x29, 0x00 }, { 0x2a, 0xff }, { 0x2b, 0x80 }, - { 0x28, 0x20 }, { 0x29, 0x33 }, { 0x2a, 0xdf }, { 0x2b, 0xa9 }, +}; + +static struct regdata mb86a20s_init2[] = { { 0x28, 0x22 }, { 0x29, 0x00 }, { 0x2a, 0x1f }, { 0x2b, 0xf0 }, { 0x3b, 0x21 }, { 0x3c, 0x3a }, @@ -1737,6 +1741,7 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe) static int mb86a20s_initfe(struct dvb_frontend *fe) { struct mb86a20s_state *state = fe->demodulator_priv; + u64 pll; int rc; u8 regD5 = 1; @@ -1746,10 +1751,35 @@ static int mb86a20s_initfe(struct dvb_frontend *fe) fe->ops.i2c_gate_ctrl(fe, 0); /* Initialize the frontend */ - rc = mb86a20s_writeregdata(state, mb86a20s_init); + rc = mb86a20s_writeregdata(state, mb86a20s_init1); if (rc < 0) goto err; + /* Adjust IF frequency to match tuner */ + if (fe->ops.tuner_ops.get_if_frequency) + fe->ops.tuner_ops.get_if_frequency(fe, &state->if_freq); + + if (!state->if_freq) + state->if_freq = 3300000; + + /* pll = freq[Hz] * 2^24/10^6 / 16.285714286 */ + pll = state->if_freq * 1677721600L; + do_div(pll, 1628571429L); + rc = mb86a20s_writereg(state, 0x28, 0x20); + if (rc < 0) + goto err; + rc = mb86a20s_writereg(state, 0x29, (pll >> 16) & 0xff); + if (rc < 0) + goto err; + rc = mb86a20s_writereg(state, 0x2a, (pll >> 8) & 0xff); + if (rc < 0) + goto err; + rc = mb86a20s_writereg(state, 0x2b, pll & 0xff); + if (rc < 0) + goto err; + dev_dbg(&state->i2c->dev, "%s: IF=%d, PLL=0x%06llx\n", + __func__, state->if_freq, (long long)pll); + if (!state->config->is_serial) { regD5 &= ~1; @@ -1761,6 +1791,11 @@ static int mb86a20s_initfe(struct dvb_frontend *fe) goto err; } + rc = mb86a20s_writeregdata(state, mb86a20s_init2); + if (rc < 0) + goto err; + + err: if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -1779,7 +1814,7 @@ err: static int mb86a20s_set_frontend(struct dvb_frontend *fe) { struct mb86a20s_state *state = fe->demodulator_priv; - int rc; + int rc, if_freq; #if 0 /* * FIXME: Properly implement the set frontend properties @@ -1796,6 +1831,18 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe) fe->ops.i2c_gate_ctrl(fe, 1); fe->ops.tuner_ops.set_params(fe); + if (fe->ops.tuner_ops.get_if_frequency) { + fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); + + /* + * If the IF frequency changed, re-initialize the + * frontend. This is needed by some drivers like tda18271, + * that only sets the IF after receiving a set_params() call + */ + if (if_freq != state->if_freq) + state->need_init = true; + } + /* * Make it more reliable: if, for some reason, the initial * device initialization doesn't happen, initialize it when @@ -1805,6 +1852,8 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe) * the agc callback logic is not called during DVB attach time, * causing mb86a20s to not be initialized with Kworld SBTVD. * So, this hack is needed, in order to make Kworld SBTVD to work. + * + * It is also needed to change the IF after the initial init. */ if (state->need_init) mb86a20s_initfe(fe); -- cgit v1.2.3 From 15b1c5a068e710bd4d9c8d76e8ed8c63aa4bff2b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 2 Mar 2013 09:06:17 -0300 Subject: [media] mb86a20s: provide CNR stats before FE_HAS_SYNC State 9 means TS started to be output, and it should be associated with FE_HAS_SYNC. The mb86a20scan get CNR statistics at state 7, when frame sync is obtained. As CNR may help to adjust the antenna, provide it earlier. A latter patch could eventually start outputing MER measures earlier, but that would require a bigger change, and probably won't be better than the current way, as the time between changing from state 8 to 9 is generally lower than the time to get the stats collected. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index daeee814e491..2720b828d89e 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -312,7 +312,7 @@ static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status) dev_dbg(&state->i2c->dev, "%s: Status = 0x%02x (state = %d)\n", __func__, *status, val); - return 0; + return val; } static int mb86a20s_read_signal_strength(struct dvb_frontend *fe) @@ -1564,7 +1564,7 @@ static void mb86a20s_stats_not_ready(struct dvb_frontend *fe) } } -static int mb86a20s_get_stats(struct dvb_frontend *fe) +static int mb86a20s_get_stats(struct dvb_frontend *fe, int status_nr) { struct mb86a20s_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -1584,6 +1584,14 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe) /* Get per-layer stats */ mb86a20s_get_blk_error_layer_CNR(fe); + /* + * At state 7, only CNR is available + * For BER measures, state=9 is required + * FIXME: we may get MER measures with state=8 + */ + if (status_nr < 9) + return 0; + for (i = 0; i < 3; i++) { if (c->isdbt_layer_enabled & (1 << i)) { /* Layer is active and has rc segments */ @@ -1875,7 +1883,7 @@ static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe, { struct mb86a20s_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int rc; + int rc, status_nr; dev_dbg(&state->i2c->dev, "%s called.\n", __func__); @@ -1883,12 +1891,12 @@ static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe, fe->ops.i2c_gate_ctrl(fe, 0); /* Get lock */ - rc = mb86a20s_read_status(fe, status); - if (!(*status & FE_HAS_LOCK)) { + status_nr = mb86a20s_read_status(fe, status); + if (status_nr < 7) { mb86a20s_stats_not_ready(fe); mb86a20s_reset_frontend_cache(fe); } - if (rc < 0) { + if (status_nr < 0) { dev_err(&state->i2c->dev, "%s: Can't read frontend lock status\n", __func__); goto error; @@ -1908,7 +1916,7 @@ static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe, /* Fill signal strength */ c->strength.stat[0].uvalue = rc; - if (*status & FE_HAS_LOCK) { + if (status_nr >= 7) { /* Get TMCC info*/ rc = mb86a20s_get_frontend(fe); if (rc < 0) { @@ -1919,7 +1927,7 @@ static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe, } /* Get statistics */ - rc = mb86a20s_get_stats(fe); + rc = mb86a20s_get_stats(fe, status_nr); if (rc < 0 && rc != -EBUSY) { dev_err(&state->i2c->dev, "%s: Can't get FE statistics.\n", __func__); -- cgit v1.2.3 From dad78c56620d425eede52d74e8ba73ea136703dd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 1 Mar 2013 16:15:16 -0300 Subject: [media] mb86a20s: Fix signal strength calculus A register typo made the calculation to not work. Fix it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 2720b828d89e..0fbfae23d904 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -335,7 +335,7 @@ static int mb86a20s_read_signal_strength(struct dvb_frontend *fe) rc = mb86a20s_writereg(state, 0x04, 0x20); if (rc < 0) return rc; - rc = mb86a20s_writereg(state, 0x04, rf); + rc = mb86a20s_writereg(state, 0x05, rf); if (rc < 0) return rc; -- cgit v1.2.3 From 0921ecfdc2b93ebbe8f2371dac634d91e4fbdf60 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 2 Mar 2013 10:15:30 -0300 Subject: [media] mb86a20s: don't allow updating signal strength too fast Getting signal strength requires some loop poking with I2C. Don't let it happen too fast. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 0fbfae23d904..9948fcbf1596 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -34,6 +34,7 @@ struct mb86a20s_state { u32 if_freq; u32 estimated_rate[3]; + unsigned long get_strength_time; bool need_init; }; @@ -318,9 +319,17 @@ static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status) static int mb86a20s_read_signal_strength(struct dvb_frontend *fe) { struct mb86a20s_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int rc; unsigned rf_max, rf_min, rf; + if (state->get_strength_time && + (!time_after(jiffies, state->get_strength_time))) + return c->strength.stat[0].uvalue; + + /* Reset its value if an error happen */ + c->strength.stat[0].uvalue = 0; + /* Does a binary search to get RF strength */ rf_max = 0xfff; rf_min = 0; @@ -350,15 +359,19 @@ static int mb86a20s_read_signal_strength(struct dvb_frontend *fe) rf = (rf_max + rf_min) / 2; /* Rescale it from 2^12 (4096) to 2^16 */ - rf <<= (16 - 12); + rf = rf << (16 - 12); + if (rf) + rf |= (1 << 12) - 1; + dev_dbg(&state->i2c->dev, "%s: signal strength = %d (%d < RF=%d < %d)\n", __func__, rf, rf_min, rf >> 4, rf_max); - return rf; + c->strength.stat[0].uvalue = rf; + state->get_strength_time = jiffies + + msecs_to_jiffies(1000); + return 0; } } while (1); - - return 0; } static int mb86a20s_get_modulation(struct mb86a20s_state *state, @@ -1882,7 +1895,6 @@ static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe, fe_status_t *status) { struct mb86a20s_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; int rc, status_nr; dev_dbg(&state->i2c->dev, "%s called.\n", __func__); @@ -1913,8 +1925,6 @@ static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe, rc = 0; /* Status is OK */ goto error; } - /* Fill signal strength */ - c->strength.stat[0].uvalue = rc; if (status_nr >= 7) { /* Get TMCC info*/ -- cgit v1.2.3 From 17e67d4c7fb7515ce98d3eb5de00c2575800818b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 1 Mar 2013 15:20:25 -0300 Subject: [media] mb86a20s: change AGC tuning parameters Use the AGC settings present on a newer device. The initial settings were taken from one of the first devices with mb86a20s, and there are several reports that this is not working properly on some places. So, instead of keeping using it, get the parameters taken from a newer device. Tests are welcomed. Tested also with cx231xx PixelView SBTVD Hybrid with no regressions noticed so far. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dmxdev.c | 3 +- drivers/media/dvb-frontends/mb86a20s.c | 86 +++++++++++++++++----------------- 2 files changed, 46 insertions(+), 43 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index d81dbb22aa81..8896993e631f 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -852,7 +852,8 @@ static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter, struct dmx_sct_filter_params *params) { - dprintk("function : %s\n", __func__); + dprintk("function : %s, PID=0x%04x, flags=%02x, timeout=%d\n", + __func__, params->pid, params->flags, params->timeout); dvb_dmxdev_filter_stop(dmxdevfilter); diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 9948fcbf1596..68a88180b631 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -55,7 +55,7 @@ static struct regdata mb86a20s_init1[] = { { 0x70, 0xff }, { 0x08, 0x01 }, { 0x09, 0x3e }, - { 0x50, 0xd1 }, { 0x51, 0x22 }, + { 0x50, 0xd1 }, { 0x51, 0x20 }, { 0x39, 0x01 }, { 0x71, 0x00 }, { 0x28, 0x2a }, { 0x29, 0x00 }, { 0x2a, 0xff }, { 0x2b, 0x80 }, @@ -64,23 +64,23 @@ static struct regdata mb86a20s_init1[] = { static struct regdata mb86a20s_init2[] = { { 0x28, 0x22 }, { 0x29, 0x00 }, { 0x2a, 0x1f }, { 0x2b, 0xf0 }, { 0x3b, 0x21 }, - { 0x3c, 0x3a }, + { 0x3c, 0x38 }, { 0x01, 0x0d }, - { 0x04, 0x08 }, { 0x05, 0x05 }, + { 0x04, 0x08 }, { 0x05, 0x03 }, { 0x04, 0x0e }, { 0x05, 0x00 }, - { 0x04, 0x0f }, { 0x05, 0x14 }, - { 0x04, 0x0b }, { 0x05, 0x8c }, + { 0x04, 0x0f }, { 0x05, 0x37 }, + { 0x04, 0x0b }, { 0x05, 0x78 }, { 0x04, 0x00 }, { 0x05, 0x00 }, - { 0x04, 0x01 }, { 0x05, 0x07 }, - { 0x04, 0x02 }, { 0x05, 0x0f }, - { 0x04, 0x03 }, { 0x05, 0xa0 }, + { 0x04, 0x01 }, { 0x05, 0x1e }, + { 0x04, 0x02 }, { 0x05, 0x07 }, + { 0x04, 0x03 }, { 0x05, 0xd0 }, { 0x04, 0x09 }, { 0x05, 0x00 }, { 0x04, 0x0a }, { 0x05, 0xff }, - { 0x04, 0x27 }, { 0x05, 0x64 }, + { 0x04, 0x27 }, { 0x05, 0x00 }, { 0x04, 0x28 }, { 0x05, 0x00 }, - { 0x04, 0x1e }, { 0x05, 0xff }, - { 0x04, 0x29 }, { 0x05, 0x0a }, - { 0x04, 0x32 }, { 0x05, 0x0a }, + { 0x04, 0x1e }, { 0x05, 0x00 }, + { 0x04, 0x29 }, { 0x05, 0x64 }, + { 0x04, 0x32 }, { 0x05, 0x02 }, { 0x04, 0x14 }, { 0x05, 0x02 }, { 0x04, 0x04 }, { 0x05, 0x00 }, { 0x04, 0x05 }, { 0x05, 0x22 }, @@ -147,39 +147,39 @@ static struct regdata mb86a20s_init2[] = { { 0x50, 0xd5 }, { 0x51, 0x01 }, /* Serial */ { 0x50, 0xd6 }, { 0x51, 0x1f }, { 0x50, 0xd2 }, { 0x51, 0x03 }, - { 0x50, 0xd7 }, { 0x51, 0x3f }, - { 0x28, 0x74 }, { 0x29, 0x00 }, { 0x28, 0x74 }, { 0x29, 0x40 }, - { 0x28, 0x46 }, { 0x29, 0x2c }, { 0x28, 0x46 }, { 0x29, 0x0c }, + { 0x50, 0xd7 }, { 0x51, 0xbf }, + { 0x28, 0x74 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0xff }, + { 0x28, 0x46 }, { 0x29, 0x00 }, { 0x2a, 0x1a }, { 0x2b, 0x0c }, { 0x04, 0x40 }, { 0x05, 0x00 }, - { 0x28, 0x00 }, { 0x29, 0x10 }, - { 0x28, 0x05 }, { 0x29, 0x02 }, + { 0x28, 0x00 }, { 0x2b, 0x08 }, + { 0x28, 0x05 }, { 0x2b, 0x00 }, { 0x1c, 0x01 }, - { 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x03 }, - { 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0d }, - { 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 }, - { 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x01 }, - { 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x21 }, - { 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x29 }, - { 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 }, - { 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x31 }, - { 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0e }, - { 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x4e }, - { 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x46 }, - { 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f }, - { 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x56 }, - { 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x35 }, - { 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbe }, - { 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0x84 }, - { 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x03 }, { 0x2b, 0xee }, - { 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x98 }, - { 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x9f }, - { 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xb2 }, - { 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0xc2 }, - { 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0x4a }, - { 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xbc }, - { 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x04 }, { 0x2b, 0xba }, - { 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x06 }, { 0x2b, 0x14 }, + { 0x28, 0x06 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x1f }, + { 0x28, 0x07 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x18 }, + { 0x28, 0x08 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x12 }, + { 0x28, 0x09 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x30 }, + { 0x28, 0x0a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x37 }, + { 0x28, 0x0b }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x02 }, + { 0x28, 0x0c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x09 }, + { 0x28, 0x0d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x06 }, + { 0x28, 0x0e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x7b }, + { 0x28, 0x0f }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x76 }, + { 0x28, 0x10 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x7d }, + { 0x28, 0x11 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x08 }, + { 0x28, 0x12 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0b }, + { 0x28, 0x13 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 }, + { 0x28, 0x14 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xf2 }, + { 0x28, 0x15 }, { 0x29, 0x00 }, { 0x2a, 0x01 }, { 0x2b, 0xf3 }, + { 0x28, 0x16 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x05 }, + { 0x28, 0x17 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x16 }, + { 0x28, 0x18 }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x0f }, + { 0x28, 0x19 }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xef }, + { 0x28, 0x1a }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xd8 }, + { 0x28, 0x1b }, { 0x29, 0x00 }, { 0x2a, 0x07 }, { 0x2b, 0xf1 }, + { 0x28, 0x1c }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x3d }, + { 0x28, 0x1d }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x94 }, + { 0x28, 0x1e }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0xba }, { 0x50, 0x1e }, { 0x51, 0x5d }, { 0x50, 0x22 }, { 0x51, 0x00 }, { 0x50, 0x23 }, { 0x51, 0xc8 }, @@ -188,6 +188,8 @@ static struct regdata mb86a20s_init2[] = { { 0x50, 0x26 }, { 0x51, 0x00 }, { 0x50, 0x27 }, { 0x51, 0xc3 }, { 0x50, 0x39 }, { 0x51, 0x02 }, + { 0xec, 0x0f }, + { 0xeb, 0x1f }, { 0x28, 0x6a }, { 0x29, 0x00 }, { 0x2a, 0x00 }, { 0x2b, 0x00 }, { 0xd0, 0x00 }, }; -- cgit v1.2.3 From a78b41d5fd9a04037c7b29e59c7319035a54a150 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 2 Mar 2013 13:45:31 -0300 Subject: [media] mb86a20s: Always reset the frontend with set_frontend Always init the frontend when set_frontend is called. The rationale is: it was noticed that, on some devices, it fails to lock with a different channel. It seems that some other registers need to be restored to its initial state, when the channel changes. As it is better to reset everything, even wasting a few more miliseconds than to loose channel lock, let's change the logic to always reset. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 68a88180b631..b6cdc444fb45 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -1854,18 +1854,9 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe) fe->ops.i2c_gate_ctrl(fe, 1); fe->ops.tuner_ops.set_params(fe); - if (fe->ops.tuner_ops.get_if_frequency) { + if (fe->ops.tuner_ops.get_if_frequency) fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); - /* - * If the IF frequency changed, re-initialize the - * frontend. This is needed by some drivers like tda18271, - * that only sets the IF after receiving a set_params() call - */ - if (if_freq != state->if_freq) - state->need_init = true; - } - /* * Make it more reliable: if, for some reason, the initial * device initialization doesn't happen, initialize it when @@ -1877,9 +1868,13 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe) * So, this hack is needed, in order to make Kworld SBTVD to work. * * It is also needed to change the IF after the initial init. + * + * HACK: Always init the frontend when set_frontend is called: + * it was noticed that, on some devices, it fails to lock on a + * different channel. So, it is better to reset everything, even + * wasting some time, than to loose channel lock. */ - if (state->need_init) - mb86a20s_initfe(fe); + mb86a20s_initfe(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); -- cgit v1.2.3 From 8b8e444a271165bce923c98417334f9b989cca20 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 2 Mar 2013 14:54:49 -0300 Subject: [media] mb86a20s: Don't reset strength with the other stats Signal strength is always available. There's no reason to reset it, as it has its own logic to reset it already. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index b6cdc444fb45..746adadfe8d5 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -754,7 +754,6 @@ static int mb86a20s_reset_counters(struct dvb_frontend *fe) /* Reset the counters, if the channel changed */ if (state->last_frequency != c->frequency) { - memset(&c->strength, 0, sizeof(c->strength)); memset(&c->cnr, 0, sizeof(c->cnr)); memset(&c->pre_bit_error, 0, sizeof(c->pre_bit_error)); memset(&c->pre_bit_count, 0, sizeof(c->pre_bit_count)); -- cgit v1.2.3 From 3a2e47519ebbef9b1545cda0525e2fce64c437b7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 2 Mar 2013 15:02:23 -0300 Subject: [media] mb86a20s: cleanup the status at set_frontend() As the device got re-initialized, the stats should vanish until the device gets lock again. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 746adadfe8d5..1c135aa9df44 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -1880,6 +1880,7 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe) rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception); mb86a20s_reset_counters(fe); + mb86a20s_stats_not_ready(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); -- cgit v1.2.3 From 84c09d723c30db7801433e1741b628e23cb3fecd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 3 Mar 2013 07:49:50 -0300 Subject: [media] cx231xx: Improve signal reception for PV SBTVD Instead of using 3.3 MHz IF, use 4MHz. That's the standard value for the demod, and, while it can be adjusted, 3.3 MHz is out of the recommended range. So, let's stick with the default. With regards to the IF voltage level, instead of using 0.5 V(p-p) for IF, use 2V, giving a 12dB gain. The rationale is that, on PixelView SBTVD Hybrid, even 2V(p-p) would be in the nominal range for IF, as the maximum range on this particular device is 3V. A higher gain here should help to improve reception under weak signals. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-dvb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 7c4e360ba9bc..14e26106fd72 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -89,8 +89,8 @@ static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = { }; static struct tda18271_std_map mb86a20s_tda18271_config = { - .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4, - .if_lvl = 7, .rfagc_top = 0x37, }, + .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4, + .if_lvl = 0, .rfagc_top = 0x37, }, }; static struct tda18271_config cnxt_rde253s_tunerconfig = { -- cgit v1.2.3 From 385cd33c8dcac5a166c2d034169427e263bf4608 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 3 Mar 2013 09:34:41 -0300 Subject: [media] em28xx-dvb: Don't put device in suspend mode at feed stop Putting em28xx in suspend mode when a feed stops is just plain wrong. Every time a new PES filter is changed, the DVB demux code will stop the current feed, and then start a new one. If are there any code that switches off the frontend, via some GPIO setting, this would make the DVB fail. This condition was actually trigged with one device, during DVB scan, as, during scan, it is common that userspace apps to change the filter several times, in order to get all tables. Also, this is not needed at all, since the em28xx code already hooks into ops.ts_bus_ctrl(). This warrants that em28xx can check there if DVB frontend is in usage or not. The code there already puts the device on suspend mode, if the DVB frontend is not used (closed). Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-dvb.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index a81ec2e8cc9b..7200dfe59ef9 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -220,8 +220,6 @@ static int em28xx_stop_streaming(struct em28xx_dvb *dvb) em28xx_stop_urbs(dev); - em28xx_set_mode(dev, EM28XX_SUSPEND); - return 0; } -- cgit v1.2.3 From 04fa725e7b1c22c583dd71a8cd85b8d997edfce3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 4 Mar 2013 07:10:06 -0300 Subject: [media] mb86a20s: Implement set_frontend cache logic Up to now, the driver was simply assuming TV mode, 13 segs. Implement the logic to control the ISDB operational mode. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 74 +++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 1c135aa9df44..1859e9ddba6e 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -24,6 +24,18 @@ static int debug = 1; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); +enum mb86a20s_bandwidth { + MB86A20S_13SEG = 0, + MB86A20S_13SEG_PARTIAL = 1, + MB86A20S_1SEG = 2, + MB86A20S_3SEG = 3, +}; + +u8 mb86a20s_subchannel[] = { + 0xb0, 0xc0, 0xd0, 0xe0, + 0xf0, 0x00, 0x10, 0x20, +}; + struct mb86a20s_state { struct i2c_adapter *i2c; const struct mb86a20s_config *config; @@ -32,6 +44,9 @@ struct mb86a20s_state { struct dvb_frontend frontend; u32 if_freq; + enum mb86a20s_bandwidth bw; + bool inversion; + u32 subchannel; u32 estimated_rate[3]; unsigned long get_strength_time; @@ -54,10 +69,7 @@ static struct regdata mb86a20s_init1[] = { { 0x70, 0x0f }, { 0x70, 0xff }, { 0x08, 0x01 }, - { 0x09, 0x3e }, { 0x50, 0xd1 }, { 0x51, 0x20 }, - { 0x39, 0x01 }, - { 0x71, 0x00 }, { 0x28, 0x2a }, { 0x29, 0x00 }, { 0x2a, 0xff }, { 0x2b, 0x80 }, }; @@ -1765,7 +1777,7 @@ static int mb86a20s_initfe(struct dvb_frontend *fe) struct mb86a20s_state *state = fe->demodulator_priv; u64 pll; int rc; - u8 regD5 = 1; + u8 regD5 = 1, reg71, reg09 = 0x3a; dev_dbg(&state->i2c->dev, "%s called.\n", __func__); @@ -1777,6 +1789,27 @@ static int mb86a20s_initfe(struct dvb_frontend *fe) if (rc < 0) goto err; + if (!state->inversion) + reg09 |= 0x04; + rc = mb86a20s_writereg(state, 0x09, reg09); + if (rc < 0) + goto err; + if (!state->bw) + reg71 = 1; + else + reg71 = 0; + rc = mb86a20s_writereg(state, 0x39, reg71); + if (rc < 0) + goto err; + rc = mb86a20s_writereg(state, 0x71, state->bw); + if (rc < 0) + goto err; + if (state->subchannel) { + rc = mb86a20s_writereg(state, 0x44, state->subchannel); + if (rc < 0) + goto err; + } + /* Adjust IF frequency to match tuner */ if (fe->ops.tuner_ops.get_if_frequency) fe->ops.tuner_ops.get_if_frequency(fe, &state->if_freq); @@ -1836,15 +1869,34 @@ err: static int mb86a20s_set_frontend(struct dvb_frontend *fe) { struct mb86a20s_state *state = fe->demodulator_priv; - int rc, if_freq; -#if 0 - /* - * FIXME: Properly implement the set frontend properties - */ struct dtv_frontend_properties *c = &fe->dtv_property_cache; -#endif + int rc, if_freq; dev_dbg(&state->i2c->dev, "%s called.\n", __func__); + if (!c->isdbt_layer_enabled) + c->isdbt_layer_enabled = 7; + + if (c->isdbt_layer_enabled == 1) + state->bw = MB86A20S_1SEG; + else if (c->isdbt_partial_reception) + state->bw = MB86A20S_13SEG_PARTIAL; + else + state->bw = MB86A20S_13SEG; + + if (c->inversion == INVERSION_ON) + state->inversion = true; + else + state->inversion = false; + + if (!c->isdbt_sb_mode) { + state->subchannel = 0; + } else { + if (c->isdbt_sb_subchannel > ARRAY_SIZE(mb86a20s_subchannel)) + c->isdbt_sb_subchannel = 0; + + state->subchannel = mb86a20s_subchannel[c->isdbt_sb_subchannel]; + } + /* * Gate should already be opened, but it doesn't hurt to * double-check @@ -2058,7 +2110,7 @@ static struct dvb_frontend_ops mb86a20s_ops = { /* Use dib8000 values per default */ .info = { .name = "Fujitsu mb86A20s", - .caps = FE_CAN_INVERSION_AUTO | FE_CAN_RECOVER | + .caps = FE_CAN_RECOVER | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | -- cgit v1.2.3 From 0e4bbedd638d6d13b0cfe2c95c75fc3736daec94 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 4 Mar 2013 08:15:49 -0300 Subject: [media] mb86a20s: Don't assume a 32.57142MHz clock Now that some devices initialize register 0x2a with different values, add the calculus formula, instead of hardcoding it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 26 ++++++++++++++++++++++++-- drivers/media/dvb-frontends/mb86a20s.h | 8 ++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 1859e9ddba6e..d04b52e3f4cc 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -70,7 +70,6 @@ static struct regdata mb86a20s_init1[] = { { 0x70, 0xff }, { 0x08, 0x01 }, { 0x50, 0xd1 }, { 0x51, 0x20 }, - { 0x28, 0x2a }, { 0x29, 0x00 }, { 0x2a, 0xff }, { 0x2b, 0x80 }, }; static struct regdata mb86a20s_init2[] = { @@ -1776,6 +1775,7 @@ static int mb86a20s_initfe(struct dvb_frontend *fe) { struct mb86a20s_state *state = fe->demodulator_priv; u64 pll; + u32 fclk; int rc; u8 regD5 = 1, reg71, reg09 = 0x3a; @@ -1810,6 +1810,10 @@ static int mb86a20s_initfe(struct dvb_frontend *fe) goto err; } + fclk = state->config->fclk; + if (!fclk) + fclk = 32571428; + /* Adjust IF frequency to match tuner */ if (fe->ops.tuner_ops.get_if_frequency) fe->ops.tuner_ops.get_if_frequency(fe, &state->if_freq); @@ -1817,6 +1821,24 @@ static int mb86a20s_initfe(struct dvb_frontend *fe) if (!state->if_freq) state->if_freq = 3300000; + pll = (((u64)1) << 34) * state->if_freq; + do_div(pll, 63 * fclk); + pll = (1 << 25) - pll; + rc = mb86a20s_writereg(state, 0x28, 0x2a); + if (rc < 0) + goto err; + rc = mb86a20s_writereg(state, 0x29, (pll >> 16) & 0xff); + if (rc < 0) + goto err; + rc = mb86a20s_writereg(state, 0x2a, (pll >> 8) & 0xff); + if (rc < 0) + goto err; + rc = mb86a20s_writereg(state, 0x2b, pll & 0xff); + if (rc < 0) + goto err; + dev_dbg(&state->i2c->dev, "%s: fclk=%d, IF=%d, clock reg=0x%06llx\n", + __func__, fclk, state->if_freq, (long long)pll); + /* pll = freq[Hz] * 2^24/10^6 / 16.285714286 */ pll = state->if_freq * 1677721600L; do_div(pll, 1628571429L); @@ -1832,7 +1854,7 @@ static int mb86a20s_initfe(struct dvb_frontend *fe) rc = mb86a20s_writereg(state, 0x2b, pll & 0xff); if (rc < 0) goto err; - dev_dbg(&state->i2c->dev, "%s: IF=%d, PLL=0x%06llx\n", + dev_dbg(&state->i2c->dev, "%s: IF=%d, IF reg=0x%06llx\n", __func__, state->if_freq, (long long)pll); if (!state->config->is_serial) { diff --git a/drivers/media/dvb-frontends/mb86a20s.h b/drivers/media/dvb-frontends/mb86a20s.h index bf22e77888b9..1a7dea2b237a 100644 --- a/drivers/media/dvb-frontends/mb86a20s.h +++ b/drivers/media/dvb-frontends/mb86a20s.h @@ -21,12 +21,16 @@ /** * struct mb86a20s_config - Define the per-device attributes of the frontend * + * @fclk: Clock frequency. If zero, assumes the default + * (32.57142 Mhz) * @demod_address: the demodulator's i2c address + * @is_serial: if true, TS is serial. Otherwise, TS is parallel */ struct mb86a20s_config { - u8 demod_address; - bool is_serial; + u32 fclk; + u8 demod_address; + bool is_serial; }; #if defined(CONFIG_DVB_MB86A20S) || (defined(CONFIG_DVB_MB86A20S_MODULE) \ -- cgit v1.2.3 From a61660185b42fabd0b015ff2c26fabbc5e959ff7 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 3 Mar 2013 15:37:44 -0300 Subject: [media] em28xx: enable tveeprom for device Hauppauge HVR-930C MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 331d55034616..4dcef9d6d561 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2737,6 +2737,7 @@ static void em28xx_card_setup(struct em28xx *dev) case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C: { struct tveeprom tv; -- cgit v1.2.3 From 919729237f4f1a37bfe0e94a17e7a4bdfa9f5f8e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 7 Feb 2013 09:31:33 -0300 Subject: [media] tlg2300: use correct device parent Set the correct parent for v4l2_device_register and don't set the name anymore (that's now deduced from the parent). Also remove an unnecessary forward reference and fix two weird looking log messages. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-main.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-main.c b/drivers/media/usb/tlg2300/pd-main.c index 7b1f6ebd0e2c..247d6ac99947 100644 --- a/drivers/media/usb/tlg2300/pd-main.c +++ b/drivers/media/usb/tlg2300/pd-main.c @@ -55,7 +55,6 @@ MODULE_PARM_DESC(debug_mode, "0 = disable, 1 = enable, 2 = verbose"); #define TLG2300_FIRMWARE "tlg2300_firmware.bin" static const char *firmware_name = TLG2300_FIRMWARE; -static struct usb_driver poseidon_driver; static LIST_HEAD(pd_device_list); /* @@ -316,7 +315,7 @@ static int poseidon_suspend(struct usb_interface *intf, pm_message_t msg) if (get_pm_count(pd) <= 0 && !in_hibernation(pd)) { pd->msg.event = PM_EVENT_AUTO_SUSPEND; pd->pm_resume = NULL; /* a good guard */ - printk(KERN_DEBUG "\n\t+ TLG2300 auto suspend +\n\n"); + printk(KERN_DEBUG "TLG2300 auto suspend\n"); } return 0; } @@ -331,7 +330,7 @@ static int poseidon_resume(struct usb_interface *intf) if (!pd) return 0; - printk(KERN_DEBUG "\n\t ++ TLG2300 resume ++\n\n"); + printk(KERN_DEBUG "TLG2300 resume\n"); if (!is_working(pd)) { if (PM_EVENT_AUTO_SUSPEND == pd->msg.event) @@ -431,15 +430,11 @@ static int poseidon_probe(struct usb_interface *interface, usb_set_intfdata(interface, pd); if (new_one) { - struct device *dev = &interface->dev; - logpm(pd); mutex_init(&pd->lock); /* register v4l2 device */ - snprintf(pd->v4l2_dev.name, sizeof(pd->v4l2_dev.name), "%s %s", - dev->driver->name, dev_name(dev)); - ret = v4l2_device_register(NULL, &pd->v4l2_dev); + ret = v4l2_device_register(&interface->dev, &pd->v4l2_dev); /* register devices in directory /dev */ ret = pd_video_init(pd); @@ -530,7 +525,7 @@ module_init(poseidon_init); module_exit(poseidon_exit); MODULE_AUTHOR("Telegent Systems"); -MODULE_DESCRIPTION("For tlg2300-based USB device "); +MODULE_DESCRIPTION("For tlg2300-based USB device"); MODULE_LICENSE("GPL"); MODULE_VERSION("0.0.2"); MODULE_FIRMWARE(TLG2300_FIRMWARE); -- cgit v1.2.3 From 8bdfe557b8fa56cb9d9f6f036c0b2e6cb8abafb4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 12 Jul 2012 12:33:41 -0300 Subject: [media] tlg2300: fix tuner and frequency handling of the radio device This driver now passes the tuner and frequency tests of v4l2-compliance. It's the usual bugs: frequency wasn't clamped to the valid frequency range, incorrect tuner capabilities and tuner fields not filled in, missing test for invalid tuner index, no initial frequency and incorrect error handling. Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-radio.c | 37 ++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 25eeb166aa0b..90dc1d1fcecc 100644 --- a/drivers/media/usb/tlg2300/pd-radio.c +++ b/drivers/media/usb/tlg2300/pd-radio.c @@ -18,8 +18,8 @@ static int set_frequency(struct poseidon *p, __u32 frequency); static int poseidon_fm_close(struct file *filp); static int poseidon_fm_open(struct file *filp); -#define TUNER_FREQ_MIN_FM 76000000 -#define TUNER_FREQ_MAX_FM 108000000 +#define TUNER_FREQ_MIN_FM 76000000U +#define TUNER_FREQ_MAX_FM 108000000U #define MAX_PREEMPHASIS (V4L2_PREEMPHASIS_75_uS + 1) static int preemphasis[MAX_PREEMPHASIS] = { @@ -170,13 +170,14 @@ static int tlg_fm_vidioc_g_tuner(struct file *file, void *priv, return -EINVAL; vt->type = V4L2_TUNER_RADIO; - vt->capability = V4L2_TUNER_CAP_STEREO; - vt->rangelow = TUNER_FREQ_MIN_FM / 62500; - vt->rangehigh = TUNER_FREQ_MAX_FM / 62500; + vt->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW; + vt->rangelow = TUNER_FREQ_MIN_FM * 2 / 125; + vt->rangehigh = TUNER_FREQ_MAX_FM * 2 / 125; vt->rxsubchans = V4L2_TUNER_SUB_STEREO; vt->audmode = V4L2_TUNER_MODE_STEREO; vt->signal = 0; vt->afc = 0; + strlcpy(vt->name, "Radio", sizeof(vt->name)); mutex_lock(&p->lock); ret = send_get_req(p, TUNER_STATUS, TLG_MODE_FM_RADIO, @@ -207,6 +208,8 @@ static int fm_get_freq(struct file *file, void *priv, { struct poseidon *p = file->private_data; + if (argp->tuner) + return -EINVAL; argp->frequency = p->radio_data.fm_freq; return 0; } @@ -221,11 +224,8 @@ static int set_frequency(struct poseidon *p, __u32 frequency) ret = send_set_req(p, TUNER_AUD_ANA_STD, p->radio_data.pre_emphasis, &status); - freq = (frequency * 125) * 500 / 1000;/* kHZ */ - if (freq < TUNER_FREQ_MIN_FM/1000 || freq > TUNER_FREQ_MAX_FM/1000) { - ret = -EINVAL; - goto error; - } + freq = (frequency * 125) / 2; /* Hz */ + freq = clamp(freq, TUNER_FREQ_MIN_FM, TUNER_FREQ_MAX_FM); ret = send_set_req(p, TUNE_FREQ_SELECT, freq, &status); if (ret < 0) @@ -240,7 +240,7 @@ static int set_frequency(struct poseidon *p, __u32 frequency) TLG_TUNE_PLAY_SVC_START, &status); p->radio_data.is_radio_streaming = 1; } - p->radio_data.fm_freq = frequency; + p->radio_data.fm_freq = freq * 2 / 125; error: mutex_unlock(&p->lock); return ret; @@ -251,7 +251,9 @@ static int fm_set_freq(struct file *file, void *priv, { struct poseidon *p = file->private_data; - p->file_for_stream = file; + if (argp->tuner) + return -EINVAL; + p->file_for_stream = file; #ifdef CONFIG_PM p->pm_suspend = pm_fm_suspend; p->pm_resume = pm_fm_resume; @@ -401,16 +403,19 @@ static struct video_device poseidon_fm_template = { int poseidon_fm_init(struct poseidon *p) { struct video_device *fm_dev; + int err; fm_dev = vdev_init(p, &poseidon_fm_template); if (fm_dev == NULL) - return -1; + return -ENOMEM; - if (video_register_device(fm_dev, VFL_TYPE_RADIO, -1) < 0) { + p->radio_data.fm_dev = fm_dev; + set_frequency(p, TUNER_FREQ_MIN_FM); + err = video_register_device(fm_dev, VFL_TYPE_RADIO, -1); + if (err < 0) { video_device_release(fm_dev); - return -1; + return err; } - p->radio_data.fm_dev = fm_dev; return 0; } -- cgit v1.2.3 From 54dd0dde8561a935652f1b0d21e480ff8390d43f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 12 Jul 2012 12:33:41 -0300 Subject: [media] tlg2300: switch to unlocked_ioctl The driver already does locking, so it is safe to switch to unlocked_ioctl. Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-radio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 90dc1d1fcecc..c4feffbebeb6 100644 --- a/drivers/media/usb/tlg2300/pd-radio.c +++ b/drivers/media/usb/tlg2300/pd-radio.c @@ -156,7 +156,7 @@ static const struct v4l2_file_operations poseidon_fm_fops = { .owner = THIS_MODULE, .open = poseidon_fm_open, .release = poseidon_fm_close, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static int tlg_fm_vidioc_g_tuner(struct file *file, void *priv, -- cgit v1.2.3 From 8f0829460507e68c4f41f4beedd6823411504a33 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 31 Jan 2013 06:16:41 -0300 Subject: [media] tlg2300: remove ioctls that are invalid for radio devices The input and audio ioctls are only valid for video/vbi nodes. Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-radio.c | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index c4feffbebeb6..4c76e0894d9e 100644 --- a/drivers/media/usb/tlg2300/pd-radio.c +++ b/drivers/media/usb/tlg2300/pd-radio.c @@ -350,36 +350,9 @@ static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { return vt->index > 0 ? -EINVAL : 0; } -static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *va) -{ - return (va->index != 0) ? -EINVAL : 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - a->index = 0; - a->mode = 0; - a->capability = V4L2_AUDCAP_STEREO; - strcpy(a->name, "Radio"); - return 0; -} - -static int vidioc_s_input(struct file *filp, void *priv, u32 i) -{ - return (i != 0) ? -EINVAL : 0; -} - -static int vidioc_g_input(struct file *filp, void *priv, u32 *i) -{ - return (*i != 0) ? -EINVAL : 0; -} static const struct v4l2_ioctl_ops poseidon_fm_ioctl_ops = { .vidioc_querycap = vidioc_querycap, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, .vidioc_queryctrl = tlg_fm_vidioc_queryctrl, .vidioc_querymenu = tlg_fm_vidioc_querymenu, .vidioc_g_ctrl = tlg_fm_vidioc_g_ctrl, -- cgit v1.2.3 From 6fef490706c327469fe5688ca65d5239b717960d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 12 Jul 2012 12:39:58 -0300 Subject: [media] tlg2300: embed video_device instead of allocating it Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-common.h | 2 +- drivers/media/usb/tlg2300/pd-radio.c | 20 ++++++-------------- 2 files changed, 7 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index 5dd73b7857d1..3a89128c3fc5 100644 --- a/drivers/media/usb/tlg2300/pd-common.h +++ b/drivers/media/usb/tlg2300/pd-common.h @@ -118,7 +118,7 @@ struct radio_data { int users; unsigned int is_radio_streaming; int pre_emphasis; - struct video_device *fm_dev; + struct video_device fm_dev; }; #define DVB_SBUF_NUM 4 diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 4c76e0894d9e..719c3da22193 100644 --- a/drivers/media/usb/tlg2300/pd-radio.c +++ b/drivers/media/usb/tlg2300/pd-radio.c @@ -369,31 +369,23 @@ static struct video_device poseidon_fm_template = { .name = "Telegent-Radio", .fops = &poseidon_fm_fops, .minor = -1, - .release = video_device_release, + .release = video_device_release_empty, .ioctl_ops = &poseidon_fm_ioctl_ops, }; int poseidon_fm_init(struct poseidon *p) { - struct video_device *fm_dev; - int err; + struct video_device *vfd = &p->radio_data.fm_dev; - fm_dev = vdev_init(p, &poseidon_fm_template); - if (fm_dev == NULL) - return -ENOMEM; + *vfd = poseidon_fm_template; + vfd->v4l2_dev = &p->v4l2_dev; + video_set_drvdata(vfd, p); - p->radio_data.fm_dev = fm_dev; set_frequency(p, TUNER_FREQ_MIN_FM); - err = video_register_device(fm_dev, VFL_TYPE_RADIO, -1); - if (err < 0) { - video_device_release(fm_dev); - return err; - } - return 0; + return video_register_device(vfd, VFL_TYPE_RADIO, -1); } int poseidon_fm_exit(struct poseidon *p) { - destroy_video_device(&p->radio_data.fm_dev); return 0; } -- cgit v1.2.3 From 173fdb8aff63a4275fd5f51742b4e13bd7680ab8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 12 Jul 2012 12:56:47 -0300 Subject: [media] tlg2300: add control handler for radio device node Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-common.h | 2 + drivers/media/usb/tlg2300/pd-radio.c | 112 ++++++++-------------------------- 2 files changed, 28 insertions(+), 86 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index 3a89128c3fc5..b26082af1b52 100644 --- a/drivers/media/usb/tlg2300/pd-common.h +++ b/drivers/media/usb/tlg2300/pd-common.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "dvb_frontend.h" #include "dvbdev.h" @@ -119,6 +120,7 @@ struct radio_data { unsigned int is_radio_streaming; int pre_emphasis; struct video_device fm_dev; + struct v4l2_ctrl_handler ctrl_handler; }; #define DVB_SBUF_NUM 4 diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 719c3da22193..45b3d7a769f9 100644 --- a/drivers/media/usb/tlg2300/pd-radio.c +++ b/drivers/media/usb/tlg2300/pd-radio.c @@ -261,104 +261,34 @@ static int fm_set_freq(struct file *file, void *priv, return set_frequency(p, argp->frequency); } -static int tlg_fm_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *arg) +static int tlg_fm_s_ctrl(struct v4l2_ctrl *ctrl) { - return 0; -} - -static int tlg_fm_vidioc_g_exts_ctrl(struct file *file, void *fh, - struct v4l2_ext_controls *ctrls) -{ - struct poseidon *p = file->private_data; - int i; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX) - return -EINVAL; - - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) - continue; - - if (i < MAX_PREEMPHASIS) - ctrl->value = p->radio_data.pre_emphasis; - } - return 0; -} - -static int tlg_fm_vidioc_s_exts_ctrl(struct file *file, void *fh, - struct v4l2_ext_controls *ctrls) -{ - int i; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX) - return -EINVAL; - - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) - continue; - - if (ctrl->value >= 0 && ctrl->value < MAX_PREEMPHASIS) { - struct poseidon *p = file->private_data; - int pre_emphasis = preemphasis[ctrl->value]; - u32 status; - - send_set_req(p, TUNER_AUD_ANA_STD, - pre_emphasis, &status); - p->radio_data.pre_emphasis = pre_emphasis; - } - } - return 0; -} - -static int tlg_fm_vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - return 0; -} - -static int tlg_fm_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *ctrl) -{ - if (!(ctrl->id & V4L2_CTRL_FLAG_NEXT_CTRL)) - return -EINVAL; + struct poseidon *p = container_of(ctrl->handler, struct poseidon, + radio_data.ctrl_handler); + int pre_emphasis; + u32 status; - ctrl->id &= ~V4L2_CTRL_FLAG_NEXT_CTRL; - if (ctrl->id != V4L2_CID_TUNE_PREEMPHASIS) { - /* return the next supported control */ - ctrl->id = V4L2_CID_TUNE_PREEMPHASIS; - v4l2_ctrl_query_fill(ctrl, V4L2_PREEMPHASIS_DISABLED, - V4L2_PREEMPHASIS_75_uS, 1, - V4L2_PREEMPHASIS_50_uS); - ctrl->flags = V4L2_CTRL_FLAG_UPDATE; + switch (ctrl->id) { + case V4L2_CID_TUNE_PREEMPHASIS: + pre_emphasis = preemphasis[ctrl->val]; + send_set_req(p, TUNER_AUD_ANA_STD, pre_emphasis, &status); + p->radio_data.pre_emphasis = pre_emphasis; return 0; } return -EINVAL; } -static int tlg_fm_vidioc_querymenu(struct file *file, void *fh, - struct v4l2_querymenu *qmenu) -{ - return v4l2_ctrl_query_menu(qmenu, NULL, NULL); -} - static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { return vt->index > 0 ? -EINVAL : 0; } +static const struct v4l2_ctrl_ops tlg_fm_ctrl_ops = { + .s_ctrl = tlg_fm_s_ctrl, +}; + static const struct v4l2_ioctl_ops poseidon_fm_ioctl_ops = { .vidioc_querycap = vidioc_querycap, - .vidioc_queryctrl = tlg_fm_vidioc_queryctrl, - .vidioc_querymenu = tlg_fm_vidioc_querymenu, - .vidioc_g_ctrl = tlg_fm_vidioc_g_ctrl, - .vidioc_s_ctrl = tlg_fm_vidioc_s_ctrl, - .vidioc_s_ext_ctrls = tlg_fm_vidioc_s_exts_ctrl, - .vidioc_g_ext_ctrls = tlg_fm_vidioc_g_exts_ctrl, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_tuner = tlg_fm_vidioc_g_tuner, .vidioc_g_frequency = fm_get_freq, @@ -376,16 +306,26 @@ static struct video_device poseidon_fm_template = { int poseidon_fm_init(struct poseidon *p) { struct video_device *vfd = &p->radio_data.fm_dev; + struct v4l2_ctrl_handler *hdl = &p->radio_data.ctrl_handler; *vfd = poseidon_fm_template; - vfd->v4l2_dev = &p->v4l2_dev; - video_set_drvdata(vfd, p); set_frequency(p, TUNER_FREQ_MIN_FM); + v4l2_ctrl_handler_init(hdl, 1); + v4l2_ctrl_new_std_menu(hdl, &tlg_fm_ctrl_ops, V4L2_CID_TUNE_PREEMPHASIS, + V4L2_PREEMPHASIS_75_uS, 0, V4L2_PREEMPHASIS_50_uS); + if (hdl->error) { + v4l2_ctrl_handler_free(hdl); + return hdl->error; + } + vfd->v4l2_dev = &p->v4l2_dev; + vfd->ctrl_handler = hdl; + video_set_drvdata(vfd, p); return video_register_device(vfd, VFL_TYPE_RADIO, -1); } int poseidon_fm_exit(struct poseidon *p) { + v4l2_ctrl_handler_free(&p->radio_data.ctrl_handler); return 0; } -- cgit v1.2.3 From 668cb00ed50688190417ae95cc2d2bf22ec285d2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 16 Jul 2012 07:53:36 -0300 Subject: [media] tlg2300: switch to v4l2_fh This switch to v4l2_fh resolves the last v4l2_compliance issues with respect to control events and priority handling. Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-common.h | 1 - drivers/media/usb/tlg2300/pd-main.c | 3 ++- drivers/media/usb/tlg2300/pd-radio.c | 35 +++++++++++++++++++---------------- 3 files changed, 21 insertions(+), 18 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index b26082af1b52..67ad065d2c3c 100644 --- a/drivers/media/usb/tlg2300/pd-common.h +++ b/drivers/media/usb/tlg2300/pd-common.h @@ -116,7 +116,6 @@ struct poseidon_audio { struct radio_data { __u32 fm_freq; - int users; unsigned int is_radio_streaming; int pre_emphasis; struct video_device fm_dev; diff --git a/drivers/media/usb/tlg2300/pd-main.c b/drivers/media/usb/tlg2300/pd-main.c index 247d6ac99947..e07e4c699cc2 100644 --- a/drivers/media/usb/tlg2300/pd-main.c +++ b/drivers/media/usb/tlg2300/pd-main.c @@ -267,7 +267,8 @@ static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev) static inline int get_autopm_ref(struct poseidon *pd) { return pd->video_data.users + pd->vbi_data.users + pd->audio.users - + atomic_read(&pd->dvb_data.users) + pd->radio_data.users; + + atomic_read(&pd->dvb_data.users) + + !list_empty(&pd->radio_data.fm_dev.fh_list); } /* fixup something for poseidon */ diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 45b3d7a769f9..854ffa007c1f 100644 --- a/drivers/media/usb/tlg2300/pd-radio.c +++ b/drivers/media/usb/tlg2300/pd-radio.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include "pd-common.h" @@ -77,13 +79,9 @@ static int pm_fm_resume(struct poseidon *p) static int poseidon_fm_open(struct file *filp) { - struct video_device *vfd = video_devdata(filp); - struct poseidon *p = video_get_drvdata(vfd); + struct poseidon *p = video_drvdata(filp); int ret = 0; - if (!p) - return -1; - mutex_lock(&p->lock); if (p->state & POSEIDON_STATE_DISCONNECT) { ret = -ENODEV; @@ -94,9 +92,14 @@ static int poseidon_fm_open(struct file *filp) ret = -EBUSY; goto out; } + ret = v4l2_fh_open(filp); + if (ret) + goto out; usb_autopm_get_interface(p->interface); if (0 == p->state) { + struct video_device *vfd = &p->radio_data.fm_dev; + /* default pre-emphasis */ if (p->radio_data.pre_emphasis == 0) p->radio_data.pre_emphasis = TLG_TUNE_ASTD_FM_EUR; @@ -109,9 +112,7 @@ static int poseidon_fm_open(struct file *filp) } p->state |= POSEIDON_STATE_FM; } - p->radio_data.users++; kref_get(&p->kref); - filp->private_data = p; out: mutex_unlock(&p->lock); return ret; @@ -119,13 +120,12 @@ out: static int poseidon_fm_close(struct file *filp) { - struct poseidon *p = filp->private_data; + struct poseidon *p = video_drvdata(filp); struct radio_data *fm = &p->radio_data; uint32_t status; mutex_lock(&p->lock); - fm->users--; - if (0 == fm->users) + if (v4l2_fh_is_singular_file(filp)) p->state &= ~POSEIDON_STATE_FM; if (fm->is_radio_streaming && filp == p->file_for_stream) { @@ -136,14 +136,13 @@ static int poseidon_fm_close(struct file *filp) mutex_unlock(&p->lock); kref_put(&p->kref, poseidon_delete); - filp->private_data = NULL; - return 0; + return v4l2_fh_release(filp); } static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { - struct poseidon *p = file->private_data; + struct poseidon *p = video_drvdata(file); strlcpy(v->driver, "tele-radio", sizeof(v->driver)); strlcpy(v->card, "Telegent Poseidon", sizeof(v->card)); @@ -156,15 +155,16 @@ static const struct v4l2_file_operations poseidon_fm_fops = { .owner = THIS_MODULE, .open = poseidon_fm_open, .release = poseidon_fm_close, + .poll = v4l2_ctrl_poll, .unlocked_ioctl = video_ioctl2, }; static int tlg_fm_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { + struct poseidon *p = video_drvdata(file); struct tuner_fm_sig_stat_s fm_stat = {}; int ret, status, count = 5; - struct poseidon *p = file->private_data; if (vt->index != 0) return -EINVAL; @@ -206,7 +206,7 @@ static int tlg_fm_vidioc_g_tuner(struct file *file, void *priv, static int fm_get_freq(struct file *file, void *priv, struct v4l2_frequency *argp) { - struct poseidon *p = file->private_data; + struct poseidon *p = video_drvdata(file); if (argp->tuner) return -EINVAL; @@ -249,7 +249,7 @@ error: static int fm_set_freq(struct file *file, void *priv, struct v4l2_frequency *argp) { - struct poseidon *p = file->private_data; + struct poseidon *p = video_drvdata(file); if (argp->tuner) return -EINVAL; @@ -293,6 +293,8 @@ static const struct v4l2_ioctl_ops poseidon_fm_ioctl_ops = { .vidioc_g_tuner = tlg_fm_vidioc_g_tuner, .vidioc_g_frequency = fm_get_freq, .vidioc_s_frequency = fm_set_freq, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device poseidon_fm_template = { @@ -320,6 +322,7 @@ int poseidon_fm_init(struct poseidon *p) } vfd->v4l2_dev = &p->v4l2_dev; vfd->ctrl_handler = hdl; + set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); video_set_drvdata(vfd, p); return video_register_device(vfd, VFL_TYPE_RADIO, -1); } -- cgit v1.2.3 From 42e509c6d3090fc890d2b30fc3c0be02300256a3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 31 Jan 2013 06:17:52 -0300 Subject: [media] tlg2300: fix radio querycap Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-radio.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 854ffa007c1f..80307d3857f5 100644 --- a/drivers/media/usb/tlg2300/pd-radio.c +++ b/drivers/media/usb/tlg2300/pd-radio.c @@ -147,7 +147,12 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(v->driver, "tele-radio", sizeof(v->driver)); strlcpy(v->card, "Telegent Poseidon", sizeof(v->card)); usb_make_path(p->udev, v->bus_info, sizeof(v->bus_info)); - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + /* Report all capabilities of the USB device */ + v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_AUDIO | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; return 0; } -- cgit v1.2.3 From 270ecca60e9a2b0e3f8e5a45238d8b9d4c953ebb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 16 Jul 2012 08:17:34 -0300 Subject: [media] tlg2300: add missing video_unregister_device Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-radio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 80307d3857f5..0f958f74dbc4 100644 --- a/drivers/media/usb/tlg2300/pd-radio.c +++ b/drivers/media/usb/tlg2300/pd-radio.c @@ -334,6 +334,7 @@ int poseidon_fm_init(struct poseidon *p) int poseidon_fm_exit(struct poseidon *p) { + video_unregister_device(&p->radio_data.fm_dev); v4l2_ctrl_handler_free(&p->radio_data.ctrl_handler); return 0; } -- cgit v1.2.3 From 1b952f17f3ecb1cf3c38cb0c99dfd794d32259b0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 16 Jul 2012 08:17:58 -0300 Subject: [media] tlg2300: embed video_device Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-common.h | 6 ++-- drivers/media/usb/tlg2300/pd-video.c | 55 +++++++---------------------------- 2 files changed, 13 insertions(+), 48 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index 67ad065d2c3c..052cb0c9530c 100644 --- a/drivers/media/usb/tlg2300/pd-common.h +++ b/drivers/media/usb/tlg2300/pd-common.h @@ -40,7 +40,7 @@ #define TUNER_FREQ_MAX (862000000) struct vbi_data { - struct video_device *v_dev; + struct video_device v_dev; struct video_data *video; struct front_face *front; @@ -63,7 +63,7 @@ struct running_context { struct video_data { /* v4l2 video device */ - struct video_device *v_dev; + struct video_device v_dev; /* the working context */ struct running_context context; @@ -234,7 +234,6 @@ void dvb_stop_streaming(struct pd_dvb_adapter *); /* FM */ int poseidon_fm_init(struct poseidon *); int poseidon_fm_exit(struct poseidon *); -struct video_device *vdev_init(struct poseidon *, struct video_device *); /* vendor command ops */ int send_set_req(struct poseidon*, u8, s32, s32*); @@ -250,7 +249,6 @@ void free_all_urb_generic(struct urb **urb_array, int num); /* misc */ void poseidon_delete(struct kref *kref); -void destroy_video_device(struct video_device **v_dev); extern int debug_mode; void set_debug_mode(struct video_device *vfd, int debug_mode); diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 21723378bb8f..312809a68b23 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -1590,48 +1590,18 @@ static struct video_device pd_video_template = { .name = "Telegent-Video", .fops = &pd_video_fops, .minor = -1, - .release = video_device_release, + .release = video_device_release_empty, .tvnorms = V4L2_STD_ALL, .ioctl_ops = &pd_video_ioctl_ops, }; -struct video_device *vdev_init(struct poseidon *pd, struct video_device *tmp) -{ - struct video_device *vfd; - - vfd = video_device_alloc(); - if (vfd == NULL) - return NULL; - *vfd = *tmp; - vfd->minor = -1; - vfd->v4l2_dev = &pd->v4l2_dev; - /*vfd->parent = &(pd->udev->dev); */ - vfd->release = video_device_release; - video_set_drvdata(vfd, pd); - return vfd; -} - -void destroy_video_device(struct video_device **v_dev) -{ - struct video_device *dev = *v_dev; - - if (dev == NULL) - return; - - if (video_is_registered(dev)) - video_unregister_device(dev); - else - video_device_release(dev); - *v_dev = NULL; -} - void pd_video_exit(struct poseidon *pd) { struct video_data *video = &pd->video_data; struct vbi_data *vbi = &pd->vbi_data; - destroy_video_device(&video->v_dev); - destroy_video_device(&vbi->v_dev); + video_unregister_device(&video->v_dev); + video_unregister_device(&vbi->v_dev); log(); } @@ -1641,21 +1611,19 @@ int pd_video_init(struct poseidon *pd) struct vbi_data *vbi = &pd->vbi_data; int ret = -ENOMEM; - video->v_dev = vdev_init(pd, &pd_video_template); - if (video->v_dev == NULL) - goto out; + video->v_dev = pd_video_template; + video->v_dev.v4l2_dev = &pd->v4l2_dev; + video_set_drvdata(&video->v_dev, pd); - ret = video_register_device(video->v_dev, VFL_TYPE_GRABBER, -1); + ret = video_register_device(&video->v_dev, VFL_TYPE_GRABBER, -1); if (ret != 0) goto out; /* VBI uses the same template as video */ - vbi->v_dev = vdev_init(pd, &pd_video_template); - if (vbi->v_dev == NULL) { - ret = -ENOMEM; - goto out; - } - ret = video_register_device(vbi->v_dev, VFL_TYPE_VBI, -1); + vbi->v_dev = pd_video_template; + vbi->v_dev.v4l2_dev = &pd->v4l2_dev; + video_set_drvdata(&vbi->v_dev, pd); + ret = video_register_device(&vbi->v_dev, VFL_TYPE_VBI, -1); if (ret != 0) goto out; log("register VIDEO/VBI devices"); @@ -1665,4 +1633,3 @@ out: pd_video_exit(pd); return ret; } - -- cgit v1.2.3 From c5d8907faa93757aa440fd2e584e4db4b8edc14a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 31 Jan 2013 06:42:03 -0300 Subject: [media] tlg2300: fix querycap Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-video.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 312809a68b23..8ab28945a347 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -142,17 +142,23 @@ static int get_audio_std(v4l2_std_id v4l2_std) static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { + struct video_device *vdev = video_devdata(file); + struct poseidon *p = video_get_drvdata(vdev); struct front_face *front = fh; - struct poseidon *p = front->pd; logs(front); strcpy(cap->driver, "tele-video"); strcpy(cap->card, "Telegent Poseidon"); usb_make_path(p->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | - V4L2_CAP_AUDIO | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE; + cap->device_caps = V4L2_CAP_TUNER | V4L2_CAP_AUDIO | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (vdev->vfl_type == VFL_TYPE_VBI) + cap->device_caps |= V4L2_CAP_VBI_CAPTURE; + else + cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS | + V4L2_CAP_RADIO | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE; return 0; } -- cgit v1.2.3 From 7556ba9bfb2ef0f2709fba40e77c7cc488645c79 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 31 Jan 2013 06:27:37 -0300 Subject: [media] tlg2300: fix frequency handling The usual set of problems: the frequency isn't clamped to the frequency range, no tuner index check and the frequency isn't initialized properly on module load. Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-common.h | 4 ++-- drivers/media/usb/tlg2300/pd-video.c | 20 ++++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index 052cb0c9530c..55fe66e440e3 100644 --- a/drivers/media/usb/tlg2300/pd-common.h +++ b/drivers/media/usb/tlg2300/pd-common.h @@ -36,8 +36,8 @@ #define V4L_PAL_VBI_FRAMESIZE (V4L_PAL_VBI_LINES * 1440 * 2) #define V4L_NTSC_VBI_FRAMESIZE (V4L_NTSC_VBI_LINES * 1440 * 2) -#define TUNER_FREQ_MIN (45000000) -#define TUNER_FREQ_MAX (862000000) +#define TUNER_FREQ_MIN (45000000U) +#define TUNER_FREQ_MAX (862000000U) struct vbi_data { struct video_device v_dev; diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 8ab28945a347..da7cbd4c4477 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -940,7 +940,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int i) return 0; } -static struct poseidon_control *check_control_id(__u32 id) +static struct poseidon_control *check_control_id(u32 id) { struct poseidon_control *control = &controls[0]; int array_size = ARRAY_SIZE(controls); @@ -1134,21 +1134,21 @@ static int vidioc_g_frequency(struct file *file, void *fh, return 0; } -static int set_frequency(struct poseidon *pd, __u32 frequency) +static int set_frequency(struct poseidon *pd, u32 *frequency) { s32 ret = 0, param, cmd_status; struct running_context *context = &pd->video_data.context; - param = frequency * 62500 / 1000; - if (param < TUNER_FREQ_MIN/1000 || param > TUNER_FREQ_MAX / 1000) - return -EINVAL; + *frequency = clamp(*frequency, + TUNER_FREQ_MIN / 62500, TUNER_FREQ_MAX / 62500); + param = (*frequency) * 62500 / 1000; mutex_lock(&pd->lock); ret = send_set_req(pd, TUNE_FREQ_SELECT, param, &cmd_status); ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status); msleep(250); /* wait for a while until the hardware is ready. */ - context->freq = frequency; + context->freq = *frequency; mutex_unlock(&pd->lock); return ret; } @@ -1159,12 +1159,14 @@ static int vidioc_s_frequency(struct file *file, void *fh, struct front_face *front = fh; struct poseidon *pd = front->pd; + if (freq->tuner) + return -EINVAL; logs(front); #ifdef CONFIG_PM pd->pm_suspend = pm_video_suspend; pd->pm_resume = pm_video_resume; #endif - return set_frequency(pd, freq->frequency); + return set_frequency(pd, &freq->frequency); } static int vidioc_reqbufs(struct file *file, void *fh, @@ -1351,7 +1353,7 @@ static int restore_v4l2_context(struct poseidon *pd, vidioc_s_input(NULL, front, context->sig_index); pd_vidioc_s_tuner(pd, context->audio_idx); pd_vidioc_s_fmt(pd, &context->pix); - set_frequency(pd, context->freq); + set_frequency(pd, &context->freq); return 0; } @@ -1615,8 +1617,10 @@ int pd_video_init(struct poseidon *pd) { struct video_data *video = &pd->video_data; struct vbi_data *vbi = &pd->vbi_data; + u32 freq = TUNER_FREQ_MIN / 62500; int ret = -ENOMEM; + set_frequency(pd, &freq); video->v_dev = pd_video_template; video->v_dev.v4l2_dev = &pd->v4l2_dev; video_set_drvdata(&video->v_dev, pd); -- cgit v1.2.3 From 7cb23987503be7ae4ed17678cdca9ddb025c21b8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 16 Jul 2012 10:03:34 -0300 Subject: [media] tlg2300: fix missing audioset Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index da7cbd4c4477..122f299b7102 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -903,7 +903,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in) * the audio input index mixed with this video input, * Poseidon only have one audio/video, set to "0" */ - in->audioset = 0; + in->audioset = 1; in->tuner = 0; in->std = V4L2_STD_ALL; in->status = 0; -- cgit v1.2.3 From f29056ebd9f78cde41d506f985a9e6dd9a21aa65 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 16 Jul 2012 10:22:48 -0300 Subject: [media] tlg2300: implement the control framework Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-common.h | 1 + drivers/media/usb/tlg2300/pd-video.c | 128 +++++++++++----------------------- 2 files changed, 41 insertions(+), 88 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index 55fe66e440e3..cb5cb0f70062 100644 --- a/drivers/media/usb/tlg2300/pd-common.h +++ b/drivers/media/usb/tlg2300/pd-common.h @@ -64,6 +64,7 @@ struct running_context { struct video_data { /* v4l2 video device */ struct video_device v_dev; + struct v4l2_ctrl_handler ctrl_handler; /* the working context */ struct running_context context; diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 122f299b7102..849c4bb0e79f 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -8,6 +8,7 @@ #include #include +#include #include "pd-common.h" #include "vendorcmds.h" @@ -82,31 +83,6 @@ static const struct pd_input pd_inputs[] = { }; static const unsigned int POSEIDON_INPUTS = ARRAY_SIZE(pd_inputs); -struct poseidon_control { - struct v4l2_queryctrl v4l2_ctrl; - enum cmd_custom_param_id vc_id; -}; - -static struct poseidon_control controls[] = { - { - { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, - "brightness", 0, 10000, 1, 100, 0, }, - CUST_PARM_ID_BRIGHTNESS_CTRL - }, { - { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER, - "contrast", 0, 10000, 1, 100, 0, }, - CUST_PARM_ID_CONTRAST_CTRL, - }, { - { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER, - "hue", 0, 10000, 1, 100, 0, }, - CUST_PARM_ID_HUE_CTRL, - }, { - { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER, - "saturation", 0, 10000, 1, 100, 0, }, - CUST_PARM_ID_SATURATION_CTRL, - }, -}; - struct video_std_to_audio_std { v4l2_std_id video_std; int audio_std; @@ -940,68 +916,28 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int i) return 0; } -static struct poseidon_control *check_control_id(u32 id) -{ - struct poseidon_control *control = &controls[0]; - int array_size = ARRAY_SIZE(controls); - - for (; control < &controls[array_size]; control++) - if (control->v4l2_ctrl.id == id) - return control; - return NULL; -} - -static int vidioc_queryctrl(struct file *file, void *fh, - struct v4l2_queryctrl *a) -{ - struct poseidon_control *control = NULL; - - control = check_control_id(a->id); - if (!control) - return -EINVAL; - - *a = control->v4l2_ctrl; - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl) -{ - struct front_face *front = fh; - struct poseidon *pd = front->pd; - struct poseidon_control *control = NULL; - struct tuner_custom_parameter_s tuner_param; - s32 ret = 0, cmd_status; - - control = check_control_id(ctrl->id); - if (!control) - return -EINVAL; - - mutex_lock(&pd->lock); - ret = send_get_req(pd, TUNER_CUSTOM_PARAMETER, control->vc_id, - &tuner_param, &cmd_status, sizeof(tuner_param)); - mutex_unlock(&pd->lock); - - if (ret || cmd_status) - return -1; - - ctrl->value = tuner_param.param_value; - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a) +static int tlg_s_ctrl(struct v4l2_ctrl *c) { + struct poseidon *pd = container_of(c->handler, struct poseidon, + video_data.ctrl_handler); struct tuner_custom_parameter_s param = {0}; - struct poseidon_control *control = NULL; - struct front_face *front = fh; - struct poseidon *pd = front->pd; s32 ret = 0, cmd_status, params; - control = check_control_id(a->id); - if (!control) - return -EINVAL; - - param.param_value = a->value; - param.param_id = control->vc_id; + switch (c->id) { + case V4L2_CID_BRIGHTNESS: + param.param_id = CUST_PARM_ID_BRIGHTNESS_CTRL; + break; + case V4L2_CID_CONTRAST: + param.param_id = CUST_PARM_ID_CONTRAST_CTRL; + break; + case V4L2_CID_HUE: + param.param_id = CUST_PARM_ID_HUE_CTRL; + break; + case V4L2_CID_SATURATION: + param.param_id = CUST_PARM_ID_SATURATION_CTRL; + break; + } + param.param_value = c->val; params = *(s32 *)¶m; /* temp code */ mutex_lock(&pd->lock); @@ -1587,11 +1523,6 @@ static const struct v4l2_ioctl_ops pd_video_ioctl_ops = { /* Stream on/off */ .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, - - /* Control handling */ - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, }; static struct video_device pd_video_template = { @@ -1603,6 +1534,10 @@ static struct video_device pd_video_template = { .ioctl_ops = &pd_video_ioctl_ops, }; +static const struct v4l2_ctrl_ops tlg_ctrl_ops = { + .s_ctrl = tlg_s_ctrl, +}; + void pd_video_exit(struct poseidon *pd) { struct video_data *video = &pd->video_data; @@ -1610,6 +1545,7 @@ void pd_video_exit(struct poseidon *pd) video_unregister_device(&video->v_dev); video_unregister_device(&vbi->v_dev); + v4l2_ctrl_handler_free(&video->ctrl_handler); log(); } @@ -1617,12 +1553,27 @@ int pd_video_init(struct poseidon *pd) { struct video_data *video = &pd->video_data; struct vbi_data *vbi = &pd->vbi_data; + struct v4l2_ctrl_handler *hdl = &video->ctrl_handler; u32 freq = TUNER_FREQ_MIN / 62500; int ret = -ENOMEM; + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_BRIGHTNESS, + 0, 10000, 1, 100); + v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_CONTRAST, + 0, 10000, 1, 100); + v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_HUE, + 0, 10000, 1, 100); + v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_SATURATION, + 0, 10000, 1, 100); + if (hdl->error) { + v4l2_ctrl_handler_free(hdl); + return hdl->error; + } set_frequency(pd, &freq); video->v_dev = pd_video_template; video->v_dev.v4l2_dev = &pd->v4l2_dev; + video->v_dev.ctrl_handler = hdl; video_set_drvdata(&video->v_dev, pd); ret = video_register_device(&video->v_dev, VFL_TYPE_GRABBER, -1); @@ -1632,6 +1583,7 @@ int pd_video_init(struct poseidon *pd) /* VBI uses the same template as video */ vbi->v_dev = pd_video_template; vbi->v_dev.v4l2_dev = &pd->v4l2_dev; + vbi->v_dev.ctrl_handler = hdl; video_set_drvdata(&vbi->v_dev, pd); ret = video_register_device(&vbi->v_dev, VFL_TYPE_VBI, -1); if (ret != 0) -- cgit v1.2.3 From d4de6e406211028b9186e223b766bcd17579ec97 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 31 Jan 2013 06:33:35 -0300 Subject: [media] tlg2300: remove empty vidioc_try_fmt_vid_cap, add missing g_std Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-video.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 849c4bb0e79f..4c045b3c1456 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -705,12 +705,6 @@ static int vidioc_g_fmt(struct file *file, void *fh, struct v4l2_format *f) return 0; } -static int vidioc_try_fmt(struct file *file, void *fh, - struct v4l2_format *f) -{ - return 0; -} - /* * VLC calls VIDIOC_S_STD before VIDIOC_S_FMT, while * Mplayer calls them in the reverse order. @@ -866,6 +860,14 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *norm) return set_std(front->pd, norm); } +static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) +{ + struct front_face *front = fh; + logs(front); + *norm = front->pd->video_data.context.tvnormid; + return 0; +} + static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in) { struct front_face *front = fh; @@ -1495,7 +1497,6 @@ static const struct v4l2_ioctl_ops pd_video_ioctl_ops = { .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, .vidioc_s_fmt_vid_cap = vidioc_s_fmt, .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi, /* VBI */ - .vidioc_try_fmt_vid_cap = vidioc_try_fmt, /* Input */ .vidioc_g_input = vidioc_g_input, @@ -1510,6 +1511,7 @@ static const struct v4l2_ioctl_ops pd_video_ioctl_ops = { /* Tuner ioctls */ .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_std = vidioc_g_std, .vidioc_s_std = vidioc_s_std, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, -- cgit v1.2.3 From 60c66b6f276ec2a1f76788f0833ad2bf366522b6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 16 Jul 2012 11:52:41 -0300 Subject: [media] tlg2300: allow multiple opens Due to a poor administration of the driver state it wasn't possible to open a video or vbi device multiple times. Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-common.h | 1 - drivers/media/usb/tlg2300/pd-video.c | 40 +++++++++++++---------------------- 2 files changed, 15 insertions(+), 26 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index cb5cb0f70062..3010496787ab 100644 --- a/drivers/media/usb/tlg2300/pd-common.h +++ b/drivers/media/usb/tlg2300/pd-common.h @@ -26,7 +26,6 @@ #define POSEIDON_STATE_ANALOG (0x0001) #define POSEIDON_STATE_FM (0x0002) #define POSEIDON_STATE_DVBT (0x0004) -#define POSEIDON_STATE_VBI (0x0008) #define POSEIDON_STATE_DISCONNECT (0x0080) #define PM_SUSPEND_DELAY 3 diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 4c045b3c1456..834428d90766 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -1352,12 +1352,14 @@ static int pd_video_open(struct file *file) mutex_lock(&pd->lock); usb_autopm_get_interface(pd->interface); - if (vfd->vfl_type == VFL_TYPE_GRABBER - && !(pd->state & POSEIDON_STATE_ANALOG)) { - front = kzalloc(sizeof(struct front_face), GFP_KERNEL); - if (!front) - goto out; - + if (pd->state && !(pd->state & POSEIDON_STATE_ANALOG)) { + ret = -EBUSY; + goto out; + } + front = kzalloc(sizeof(struct front_face), GFP_KERNEL); + if (!front) + goto out; + if (vfd->vfl_type == VFL_TYPE_GRABBER) { pd->cur_transfer_mode = usb_transfer_mode;/* bulk or iso */ init_video_context(&pd->video_data.context); @@ -1368,7 +1370,6 @@ static int pd_video_open(struct file *file) goto out; } - pd->state |= POSEIDON_STATE_ANALOG; front->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; pd->video_data.users++; set_debug_mode(vfd, debug_mode); @@ -1379,13 +1380,7 @@ static int pd_video_open(struct file *file) V4L2_FIELD_INTERLACED,/* video is interlacd */ sizeof(struct videobuf_buffer),/*it's enough*/ front, NULL); - } else if (vfd->vfl_type == VFL_TYPE_VBI - && !(pd->state & POSEIDON_STATE_VBI)) { - front = kzalloc(sizeof(struct front_face), GFP_KERNEL); - if (!front) - goto out; - - pd->state |= POSEIDON_STATE_VBI; + } else { front->type = V4L2_BUF_TYPE_VBI_CAPTURE; pd->vbi_data.front = front; pd->vbi_data.users++; @@ -1396,19 +1391,15 @@ static int pd_video_open(struct file *file) V4L2_FIELD_NONE, /* vbi is NONE mode */ sizeof(struct videobuf_buffer), front, NULL); - } else { - /* maybe add FM support here */ - log("other "); - ret = -EINVAL; - goto out; } - front->pd = pd; - front->curr_frame = NULL; + pd->state |= POSEIDON_STATE_ANALOG; + front->pd = pd; + front->curr_frame = NULL; INIT_LIST_HEAD(&front->active); spin_lock_init(&front->queue_lock); - file->private_data = front; + file->private_data = front; kref_get(&pd->kref); mutex_unlock(&pd->lock); @@ -1429,8 +1420,6 @@ static int pd_video_release(struct file *file) mutex_lock(&pd->lock); if (front->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - pd->state &= ~POSEIDON_STATE_ANALOG; - /* stop the device, and free the URBs */ usb_transfer_stop(&pd->video_data); free_all_urb(&pd->video_data); @@ -1442,10 +1431,11 @@ static int pd_video_release(struct file *file) pd->file_for_stream = NULL; pd->video_data.users--; } else if (front->type == V4L2_BUF_TYPE_VBI_CAPTURE) { - pd->state &= ~POSEIDON_STATE_VBI; pd->vbi_data.front = NULL; pd->vbi_data.users--; } + if (!pd->vbi_data.users && !pd->video_data.users) + pd->state &= ~POSEIDON_STATE_ANALOG; videobuf_stop(&front->q); videobuf_mmap_free(&front->q); -- cgit v1.2.3 From ca1178ed6a6304185d77dd16462de0590d9a7b28 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 31 Jan 2013 06:39:09 -0300 Subject: [media] tlg2300: Remove logs() macro ioctl debugging can now be done through the debug parameter in sysfs. Signed-off-by: Hans Verkuil Acked-by: Huang Shijie Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tlg2300/pd-common.h | 9 --------- drivers/media/usb/tlg2300/pd-video.c | 23 ++--------------------- 2 files changed, 2 insertions(+), 30 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index 3010496787ab..9e23ad32d2fe 100644 --- a/drivers/media/usb/tlg2300/pd-common.h +++ b/drivers/media/usb/tlg2300/pd-common.h @@ -268,13 +268,4 @@ void set_debug_mode(struct video_device *vfd, int debug_mode); log();\ } while (0) -#define logs(f) do { \ - if ((debug_mode & 0x4) && \ - (f)->type == V4L2_BUF_TYPE_VBI_CAPTURE) \ - log("type : VBI");\ - \ - if ((debug_mode & 0x8) && \ - (f)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) \ - log("type : VIDEO");\ - } while (0) #endif diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 834428d90766..dab0ca32d396 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -120,9 +120,6 @@ static int vidioc_querycap(struct file *file, void *fh, { struct video_device *vdev = video_devdata(file); struct poseidon *p = video_get_drvdata(vdev); - struct front_face *front = fh; - - logs(front); strcpy(cap->driver, "tele-video"); strcpy(cap->card, "Telegent Poseidon"); @@ -205,7 +202,6 @@ static void submit_frame(struct front_face *front) */ static void end_field(struct video_data *video) { - /* logs(video->front); */ if (1 == video->field_count) submit_frame(video->front); else @@ -700,7 +696,6 @@ static int vidioc_g_fmt(struct file *file, void *fh, struct v4l2_format *f) struct front_face *front = fh; struct poseidon *pd = front->pd; - logs(front); f->fmt.pix = pd->video_data.context.pix; return 0; } @@ -763,7 +758,6 @@ static int vidioc_s_fmt(struct file *file, void *fh, struct v4l2_format *f) struct front_face *front = fh; struct poseidon *pd = front->pd; - logs(front); /* stop VBI here */ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type) return -EINVAL; @@ -804,7 +798,6 @@ static int vidioc_g_fmt_vbi(struct file *file, void *fh, vbi_fmt->count[1] = V4L_PAL_VBI_LINES; } vbi_fmt->flags = V4L2_VBI_UNSYNC; - logs(front); return 0; } @@ -856,22 +849,20 @@ out: static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *norm) { struct front_face *front = fh; - logs(front); + return set_std(front->pd, norm); } static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) { struct front_face *front = fh; - logs(front); + *norm = front->pd->video_data.context.tvnormid; return 0; } static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in) { - struct front_face *front = fh; - if (in->index >= POSEIDON_INPUTS) return -EINVAL; strcpy(in->name, pd_inputs[in->index].name); @@ -885,7 +876,6 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in) in->tuner = 0; in->std = V4L2_STD_ALL; in->status = 0; - logs(front); return 0; } @@ -895,7 +885,6 @@ static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) struct poseidon *pd = front->pd; struct running_context *context = &pd->video_data.context; - logs(front); *i = context->sig_index; return 0; } @@ -1023,7 +1012,6 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *tuner) tuner->rxsubchans = pd_audio_modes[index].v4l2_audio_sub; tuner->audmode = pd_audio_modes[index].v4l2_audio_mode; tuner->afc = 0; - logs(front); return 0; } @@ -1051,7 +1039,6 @@ static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *a) if (0 != a->index) return -EINVAL; - logs(front); for (index = 0; index < POSEIDON_AUDIOMODS; index++) if (a->audmode == pd_audio_modes[index].v4l2_audio_mode) return pd_vidioc_s_tuner(pd, index); @@ -1099,7 +1086,6 @@ static int vidioc_s_frequency(struct file *file, void *fh, if (freq->tuner) return -EINVAL; - logs(front); #ifdef CONFIG_PM pd->pm_suspend = pm_video_suspend; pd->pm_resume = pm_video_resume; @@ -1111,14 +1097,12 @@ static int vidioc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b) { struct front_face *front = file->private_data; - logs(front); return videobuf_reqbufs(&front->q, b); } static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) { struct front_face *front = file->private_data; - logs(front); return videobuf_querybuf(&front->q, b); } @@ -1207,7 +1191,6 @@ static int vidioc_streamon(struct file *file, void *fh, { struct front_face *front = fh; - logs(front); if (unlikely(type != front->type)) return -EINVAL; return videobuf_streamon(&front->q); @@ -1218,7 +1201,6 @@ static int vidioc_streamoff(struct file *file, void *fh, { struct front_face *front = file->private_data; - logs(front); if (unlikely(type != front->type)) return -EINVAL; return videobuf_streamoff(&front->q); @@ -1416,7 +1398,6 @@ static int pd_video_release(struct file *file) struct poseidon *pd = front->pd; s32 cmd_status = 0; - logs(front); mutex_lock(&pd->lock); if (front->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { -- cgit v1.2.3 From 78dea1aed44a6e3e16973e584b00825359d470bd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 Sep 2012 09:03:29 -0300 Subject: [media] bttv: fix querycap and radio v4l2-compliance issues The querycap ioctl didn't support V4L2_CAP_DEVICE_CAPS and the radio device implemented audio and video inputs and s_std, which are not part of the radio API. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 101 +++++++++------------------------- 1 file changed, 27 insertions(+), 74 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index ccd18e4ee789..cc7f58f94cde 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2630,6 +2630,7 @@ static int bttv_s_fmt_vid_overlay(struct file *file, void *priv, static int bttv_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { + struct video_device *vdev = video_devdata(file); struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; @@ -2642,11 +2643,15 @@ static int bttv_querycap(struct file *file, void *priv, "PCI:%s", pci_name(btv->c.pci)); cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; + V4L2_CAP_STREAMING | + V4L2_CAP_DEVICE_CAPS; if (no_overlay <= 0) cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; + if (btv->vbi_dev) + cap->capabilities |= V4L2_CAP_VBI_CAPTURE; + if (btv->radio_dev) + cap->capabilities |= V4L2_CAP_RADIO; /* * No need to lock here: those vars are initialized during board @@ -2656,6 +2661,25 @@ static int bttv_querycap(struct file *file, void *priv, cap->capabilities |= V4L2_CAP_RDS_CAPTURE; if (btv->tuner_type != TUNER_ABSENT) cap->capabilities |= V4L2_CAP_TUNER; + if (vdev->vfl_type == VFL_TYPE_GRABBER) + cap->device_caps = cap->capabilities & + (V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_TUNER); + else if (vdev->vfl_type == VFL_TYPE_VBI) + cap->device_caps = cap->capabilities & + (V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | + V4L2_CAP_TUNER); + else { + cap->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; + if (btv->has_saa6588) + cap->device_caps |= V4L2_CAP_READWRITE | + V4L2_CAP_RDS_CAPTURE; + } return 0; } @@ -3430,20 +3454,6 @@ static int radio_release(struct file *file) return 0; } -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - strcpy(cap->driver, "bttv"); - strlcpy(cap->card, btv->radio_dev->name, sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(btv->c.pci)); - cap->capabilities = V4L2_CAP_TUNER; - - return 0; -} - static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct bttv_fh *fh = priv; @@ -3464,29 +3474,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return 0; } -static int radio_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - - strcpy(i->name, "Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; -} - -static int radio_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - strcpy(a->name, "Radio"); - - return 0; -} - static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { @@ -3500,28 +3487,6 @@ static int radio_s_tuner(struct file *file, void *priv, return 0; } -static int radio_s_audio(struct file *file, void *priv, - const struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - return 0; -} - -static int radio_s_input(struct file *filp, void *priv, unsigned int i) -{ - if (unlikely(i)) - return -EINVAL; - - return 0; -} - -static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) -{ - return 0; -} - static int radio_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) { @@ -3540,12 +3505,6 @@ static int radio_queryctrl(struct file *file, void *priv, return 0; } -static int radio_g_input(struct file *filp, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - static ssize_t radio_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { @@ -3586,16 +3545,10 @@ static const struct v4l2_file_operations radio_fops = }; static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = radio_querycap, + .vidioc_querycap = bttv_querycap, .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_s_std = radio_s_std, .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_input = radio_g_input, .vidioc_g_ctrl = bttv_g_ctrl, .vidioc_s_ctrl = bttv_s_ctrl, .vidioc_g_frequency = bttv_g_frequency, -- cgit v1.2.3 From 1b9e94dc69959e963fe57ede46259f792641af4d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 Sep 2012 09:23:31 -0300 Subject: [media] bttv: add VIDIOC_DBG_G_CHIP_IDENT VIDIOC_DBG_G_CHIP_IDENT is a prerequisite for the G/S_REGISTER ioctls. In addition, add support to call G/S_REGISTER for supporting i2c devices. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 40 +++++++++++++++++++++++++++++++---- drivers/media/pci/bt8xx/bttv.h | 3 +++ include/media/v4l2-chip-ident.h | 8 +++++++ 3 files changed, 47 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index cc7f58f94cde..b36d67577535 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -49,6 +49,7 @@ #include "bttvp.h" #include #include +#include #include #include @@ -2059,6 +2060,28 @@ static int bttv_log_status(struct file *file, void *f) return 0; } +static int bttv_g_chip_ident(struct file *file, void *f, struct v4l2_dbg_chip_ident *chip) +{ + struct bttv_fh *fh = f; + struct bttv *btv = fh->btv; + + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (chip->match.type == V4L2_CHIP_MATCH_HOST) { + if (v4l2_chip_match_host(&chip->match)) { + chip->ident = btv->id; + if (chip->ident == PCI_DEVICE_ID_FUSION879) + chip->ident = V4L2_IDENT_BT879; + } + return 0; + } + if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && + chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + /* TODO: is this correct? */ + return bttv_call_all_err(btv, core, g_chip_ident, chip); +} + #ifdef CONFIG_VIDEO_ADV_DEBUG static int bttv_g_register(struct file *file, void *f, struct v4l2_dbg_register *reg) @@ -2069,8 +2092,12 @@ static int bttv_g_register(struct file *file, void *f, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; + if (!v4l2_chip_match_host(®->match)) { + /* TODO: subdev errors should not be ignored, this should become a + subdev helper function. */ + bttv_call_all(btv, core, g_register, reg); + return 0; + } /* bt848 has a 12-bit register space */ reg->reg &= 0xfff; @@ -2089,8 +2116,12 @@ static int bttv_s_register(struct file *file, void *f, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; + if (!v4l2_chip_match_host(®->match)) { + /* TODO: subdev errors should not be ignored, this should become a + subdev helper function. */ + bttv_call_all(btv, core, s_register, reg); + return 0; + } /* bt848 has a 12-bit register space */ reg->reg &= 0xfff; @@ -3394,6 +3425,7 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = { .vidioc_s_frequency = bttv_s_frequency, .vidioc_log_status = bttv_log_status, .vidioc_querystd = bttv_querystd, + .vidioc_g_chip_ident = bttv_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = bttv_g_register, .vidioc_s_register = bttv_s_register, diff --git a/drivers/media/pci/bt8xx/bttv.h b/drivers/media/pci/bt8xx/bttv.h index 79a11240a590..6139ce26dc2c 100644 --- a/drivers/media/pci/bt8xx/bttv.h +++ b/drivers/media/pci/bt8xx/bttv.h @@ -359,6 +359,9 @@ void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits); #define bttv_call_all(btv, o, f, args...) \ v4l2_device_call_all(&btv->c.v4l2_dev, 0, o, f, ##args) +#define bttv_call_all_err(btv, o, f, args...) \ + v4l2_device_call_until_err(&btv->c.v4l2_dev, 0, o, f, ##args) + extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for); extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, unsigned char b2, int both); diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 4ee125bae719..b5996f959a31 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -96,12 +96,20 @@ enum { /* module au0828 */ V4L2_IDENT_AU0828 = 828, + /* module bttv: ident 848 + 849 */ + V4L2_IDENT_BT848 = 848, + V4L2_IDENT_BT849 = 849, + /* module bt856: just ident 856 */ V4L2_IDENT_BT856 = 856, /* module bt866: just ident 866 */ V4L2_IDENT_BT866 = 866, + /* module bttv: ident 878 + 879 */ + V4L2_IDENT_BT878 = 878, + V4L2_IDENT_BT879 = 879, + /* module ks0127: reserved range 1120-1129 */ V4L2_IDENT_KS0122S = 1122, V4L2_IDENT_KS0127 = 1127, -- cgit v1.2.3 From f74f89cb1cf2cccdc111bcab7de4fb8c41bb2a07 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 31 Jan 2013 08:45:13 -0300 Subject: [media] bttv: fix ENUM_INPUT and S_INPUT - Fix ENUM_INPUT audioset. - Fix incorrect input check in s_input. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index b36d67577535..6e61dbdd95c3 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1923,7 +1923,7 @@ static int bttv_enum_input(struct file *file, void *priv, } i->type = V4L2_INPUT_TYPE_CAMERA; - i->audioset = 1; + i->audioset = 0; if (btv->tuner_type != TUNER_ABSENT && i->index == 0) { sprintf(i->name, "Television"); @@ -1964,21 +1964,16 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i) { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; - int err; err = v4l2_prio_check(&btv->prio, fh->prio); - if (unlikely(err)) - goto err; + if (err) + return err; - if (i > bttv_tvcards[btv->c.type].video_inputs) { - err = -EINVAL; - goto err; - } + if (i >= bttv_tvcards[btv->c.type].video_inputs) + return -EINVAL; set_input(btv, i, btv->tvnorm); - -err: return 0; } -- cgit v1.2.3 From d9b6707673b6590bb6b984af6c435c807335a459 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Feb 2013 11:43:07 -0300 Subject: [media] bttv: disable g/s_tuner and g/s_freq when no tuner present, fix return codes If no tuner is present, then disable the tuner and frequency ioctls. We can remove a number of checks from those ioctls testing for the presence of a tuner. Also remove some tuner type checks (now done by the core) and fix an error return when the prio check fails. Finally some 'unlikely' statements are removed since those only make sense in tightly often executed loops, otherwise they just clutter up the code. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 44 +++++++++++++---------------------- 1 file changed, 16 insertions(+), 28 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 6e61dbdd95c3..f6f2b009bb6f 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1984,25 +1984,17 @@ static int bttv_s_tuner(struct file *file, void *priv, struct bttv *btv = fh->btv; int err; - if (unlikely(0 != t->index)) + if (t->index) return -EINVAL; - if (unlikely(btv->tuner_type == TUNER_ABSENT)) { - err = -EINVAL; - goto err; - } - err = v4l2_prio_check(&btv->prio, fh->prio); - if (unlikely(err)) - goto err; + if (err) + return err; bttv_call_all(btv, tuner, s_tuner, t); if (btv->audio_mode_gpio) btv->audio_mode_gpio(btv, t, 1); - -err: - return 0; } @@ -2012,9 +2004,10 @@ static int bttv_g_frequency(struct file *file, void *priv, struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; - f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = btv->freq; + if (f->tuner) + return -EINVAL; + f->frequency = btv->freq; return 0; } @@ -2025,24 +2018,17 @@ static int bttv_s_frequency(struct file *file, void *priv, struct bttv *btv = fh->btv; int err; - if (unlikely(f->tuner != 0)) + if (f->tuner) return -EINVAL; err = v4l2_prio_check(&btv->prio, fh->prio); - if (unlikely(err)) - goto err; + if (err) + return err; - if (unlikely(f->type != (btv->radio_user - ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV))) { - err = -EINVAL; - goto err; - } btv->freq = f->frequency; bttv_call_all(btv, tuner, s_frequency, f); if (btv->has_matchbox && btv->radio_user) tea5757_set_freq(btv, btv->freq); -err: - return 0; } @@ -2983,8 +2969,6 @@ static int bttv_g_tuner(struct file *file, void *priv, struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; - if (btv->tuner_type == TUNER_ABSENT) - return -EINVAL; if (0 != t->index) return -EINVAL; @@ -3486,8 +3470,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; - if (btv->tuner_type == TUNER_ABSENT) - return -EINVAL; if (0 != t->index) return -EINVAL; strcpy(t->name, "Radio"); @@ -4131,7 +4113,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) /* ----------------------------------------------------------------------- */ -/* initialitation */ +/* initialization */ static struct video_device *vdev_init(struct bttv *btv, const struct video_device *template, @@ -4150,6 +4132,12 @@ static struct video_device *vdev_init(struct bttv *btv, snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", type_name, bttv_tvcards[btv->c.type].name); + if (btv->tuner_type == TUNER_ABSENT) { + v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER); + v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER); + } return vfd; } -- cgit v1.2.3 From 76ea992a036c4a5d3bc606a79ef775dd32fd3daa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Feb 2013 11:49:14 -0300 Subject: [media] bttv: set initial tv/radio frequencies Set an initial frequencies when the driver is loaded. That way G_FREQUENCY will give a frequency that corresponds with reality. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 34 ++++++++++++++++++++++++++++------ drivers/media/pci/bt8xx/bttvp.h | 3 ++- 2 files changed, 30 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index f6f2b009bb6f..546a9f55b809 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2007,10 +2007,27 @@ static int bttv_g_frequency(struct file *file, void *priv, if (f->tuner) return -EINVAL; - f->frequency = btv->freq; + f->frequency = f->type == V4L2_TUNER_RADIO ? + btv->radio_freq : btv->tv_freq; + return 0; } +static void bttv_set_frequency(struct bttv *btv, struct v4l2_frequency *f) +{ + bttv_call_all(btv, tuner, s_frequency, f); + /* s_frequency may clamp the frequency, so get the actual + frequency before assigning radio/tv_freq. */ + bttv_call_all(btv, tuner, g_frequency, f); + if (f->type == V4L2_TUNER_RADIO) { + btv->radio_freq = f->frequency; + if (btv->has_matchbox) + tea5757_set_freq(btv, btv->radio_freq); + } else { + btv->tv_freq = f->frequency; + } +} + static int bttv_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { @@ -2024,11 +2041,7 @@ static int bttv_s_frequency(struct file *file, void *priv, err = v4l2_prio_check(&btv->prio, fh->prio); if (err) return err; - - btv->freq = f->frequency; - bttv_call_all(btv, tuner, s_frequency, f); - if (btv->has_matchbox && btv->radio_user) - tea5757_set_freq(btv, btv->freq); + bttv_set_frequency(btv, f); return 0; } @@ -4235,6 +4248,11 @@ static void pci_set_command(struct pci_dev *dev) static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) { + struct v4l2_frequency init_freq = { + .tuner = 0, + .type = V4L2_TUNER_ANALOG_TV, + .frequency = 980, + }; int result; unsigned char lat; struct bttv *btv; @@ -4375,6 +4393,10 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) /* some card-specific stuff (needs working i2c) */ bttv_init_card2(btv); bttv_init_tuner(btv); + if (btv->tuner_type != TUNER_ABSENT) { + bttv_set_frequency(btv, &init_freq); + btv->radio_freq = 90500 * 16; /* 90.5Mhz default */ + } init_irqreg(btv); /* register video4linux + input */ diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index 9ec0adba236c..528e03ec19e8 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -418,7 +418,7 @@ struct bttv { unsigned int input; unsigned int audio; unsigned int mute; - unsigned long freq; + unsigned long tv_freq; unsigned int tvnorm; int hue, contrast, bright, saturation; struct v4l2_framebuffer fbuf; @@ -442,6 +442,7 @@ struct bttv { int has_radio; int radio_user; int radio_uses_msp_demodulator; + unsigned long radio_freq; /* miro/pinnacle + Aimslab VHX philips matchbox (tea5757 radio tuner) support */ -- cgit v1.2.3 From a652ef60952dd816bf84c7c52e0caf6e71ea5a49 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 9 Sep 2012 10:27:57 -0300 Subject: [media] bttv: G_PARM: set readbuffers Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 546a9f55b809..fb8ec0a67d14 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2970,6 +2970,9 @@ static int bttv_g_parm(struct file *file, void *f, struct bttv_fh *fh = f; struct bttv *btv = fh->btv; + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + parm->parm.capture.readbuffers = gbuffers; v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id, &parm->parm.capture.timeperframe); -- cgit v1.2.3 From f58648999347ff44194ff948637e465868acc1e6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Feb 2013 11:58:59 -0300 Subject: [media] bttv: fill in colorspace Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index fb8ec0a67d14..dbf1882147c7 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2506,6 +2506,7 @@ static int bttv_g_fmt_vid_cap(struct file *file, void *priv, fh->width, fh->height); f->fmt.pix.field = fh->cap.field; f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } @@ -2577,6 +2578,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv, /* update data for the application */ f->fmt.pix.field = field; pix_format_set_size(&f->fmt.pix, fmt, width, height); + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } -- cgit v1.2.3 From a12fd70e3b32a4de5e5dc6346a0f5bdfd164ed3d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Feb 2013 12:00:03 -0300 Subject: [media] bttv: fill in fb->flags for VIDIOC_G_FBUF Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index dbf1882147c7..cffa8b6683ea 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2769,6 +2769,7 @@ static int bttv_g_fbuf(struct file *file, void *f, *fb = btv->fbuf; fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; + fb->flags = V4L2_FBUF_FLAG_PRIMARY; if (fh->ovfmt) fb->fmt.pixelformat = fh->ovfmt->fourcc; return 0; -- cgit v1.2.3 From ee70e3d8039f16137d2e7e2e1a9cf8374b01be9b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Feb 2013 12:03:30 -0300 Subject: [media] bttv: fix field handling inside TRY_FMT - don't return -EINVAL for invalid field types, handle those as if it was FIELD_ANY. - the handling of FIELD_SEQ_BT/TB was wrong as well: if such field formats aren't supported, then fall back to FIELD_ANY instead of returning an error. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index cffa8b6683ea..73404b7a1396 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2530,6 +2530,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv, struct bttv *btv = fh->btv; enum v4l2_field field; __s32 width, height; + __s32 height2; int rc; fmt = format_by_fourcc(f->fmt.pix.pixelformat); @@ -2538,30 +2539,25 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv, field = f->fmt.pix.field; - if (V4L2_FIELD_ANY == field) { - __s32 height2; - - height2 = btv->crop[!!fh->do_crop].rect.height >> 1; - field = (f->fmt.pix.height > height2) - ? V4L2_FIELD_INTERLACED - : V4L2_FIELD_BOTTOM; - } - - if (V4L2_FIELD_SEQ_BT == field) - field = V4L2_FIELD_SEQ_TB; - switch (field) { case V4L2_FIELD_TOP: case V4L2_FIELD_BOTTOM: case V4L2_FIELD_ALTERNATE: case V4L2_FIELD_INTERLACED: break; + case V4L2_FIELD_SEQ_BT: case V4L2_FIELD_SEQ_TB: - if (fmt->flags & FORMAT_FLAGS_PLANAR) - return -EINVAL; + if (!(fmt->flags & FORMAT_FLAGS_PLANAR)) { + field = V4L2_FIELD_SEQ_TB; + break; + } + /* fall through */ + default: /* FIELD_ANY case */ + height2 = btv->crop[!!fh->do_crop].rect.height >> 1; + field = (f->fmt.pix.height > height2) + ? V4L2_FIELD_INTERLACED + : V4L2_FIELD_BOTTOM; break; - default: - return -EINVAL; } width = f->fmt.pix.width; -- cgit v1.2.3 From 5d478e0de87113b9fa6b4021935e605b71e0ee28 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 5 Feb 2013 12:17:38 -0300 Subject: [media] tda7432: convert to the control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda7432.c | 276 ++++++++++++++++++-------------------------- 1 file changed, 110 insertions(+), 166 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c index f7707e65761e..28b5121881f5 100644 --- a/drivers/media/i2c/tda7432.c +++ b/drivers/media/i2c/tda7432.c @@ -35,6 +35,7 @@ #include #include +#include #include #ifndef VIDEO_AUDIO_BALANCE @@ -60,13 +61,17 @@ MODULE_PARM_DESC(maxvol, "Set maximium volume to +20dB(0) else +0dB(1). Default struct tda7432 { struct v4l2_subdev sd; - int addr; - int input; - int volume; - int muted; - int bass, treble; - int lf, lr, rf, rr; - int loud; + struct v4l2_ctrl_handler hdl; + struct { + /* bass/treble cluster */ + struct v4l2_ctrl *bass; + struct v4l2_ctrl *treble; + }; + struct { + /* mute/balance cluster */ + struct v4l2_ctrl *mute; + struct v4l2_ctrl *balance; + }; }; static inline struct tda7432 *to_state(struct v4l2_subdev *sd) @@ -74,6 +79,11 @@ static inline struct tda7432 *to_state(struct v4l2_subdev *sd) return container_of(sd, struct tda7432, sd); } +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct tda7432, hdl)->sd; +} + /* The TDA7432 is made by STS-Thompson * http://www.st.com * http://us.st.com/stonline/books/pdf/docs/4056.pdf @@ -227,24 +237,22 @@ static int tda7432_write(struct v4l2_subdev *sd, int subaddr, int val) static int tda7432_set(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct tda7432 *t = to_state(sd); unsigned char buf[16]; - v4l2_dbg(1, debug, sd, - "tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n", - t->input, t->volume, t->bass, t->treble, t->lf, t->lr, - t->rf, t->rr, t->loud); buf[0] = TDA7432_IN; - buf[1] = t->input; - buf[2] = t->volume; - buf[3] = t->bass; - buf[4] = t->treble; - buf[5] = t->lf; - buf[6] = t->lr; - buf[7] = t->rf; - buf[8] = t->rr; - buf[9] = t->loud; - if (10 != i2c_master_send(client, buf, 10)) { + buf[1] = TDA7432_STEREO_IN | /* Main (stereo) input */ + TDA7432_BASS_SYM | /* Symmetric bass cut */ + TDA7432_BASS_NORM; /* Normal bass range */ + buf[2] = 0x3b; + if (loudness) /* Turn loudness on? */ + buf[2] |= TDA7432_LD_ON; + buf[3] = TDA7432_TREBLE_0DB | (TDA7432_BASS_0DB << 4); + buf[4] = TDA7432_ATTEN_0DB; + buf[5] = TDA7432_ATTEN_0DB; + buf[6] = TDA7432_ATTEN_0DB; + buf[7] = TDA7432_ATTEN_0DB; + buf[8] = loudness; + if (9 != i2c_master_send(client, buf, 9)) { v4l2_err(sd, "I/O error, trying tda7432_set\n"); return -1; } @@ -252,174 +260,86 @@ static int tda7432_set(struct v4l2_subdev *sd) return 0; } -static void do_tda7432_init(struct v4l2_subdev *sd) -{ - struct tda7432 *t = to_state(sd); - - v4l2_dbg(2, debug, sd, "In tda7432_init\n"); - - t->input = TDA7432_STEREO_IN | /* Main (stereo) input */ - TDA7432_BASS_SYM | /* Symmetric bass cut */ - TDA7432_BASS_NORM; /* Normal bass range */ - t->volume = 0x3b ; /* -27dB Volume */ - if (loudness) /* Turn loudness on? */ - t->volume |= TDA7432_LD_ON; - t->muted = 1; - t->treble = TDA7432_TREBLE_0DB; /* 0dB Treble */ - t->bass = TDA7432_BASS_0DB; /* 0dB Bass */ - t->lf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ - t->lr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ - t->rf = TDA7432_ATTEN_0DB; /* 0dB attenuation */ - t->rr = TDA7432_ATTEN_0DB; /* 0dB attenuation */ - t->loud = loudness; /* insmod parameter */ - - tda7432_set(sd); -} - -static int tda7432_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int tda7432_log_status(struct v4l2_subdev *sd) { - struct tda7432 *t = to_state(sd); + struct tda7432 *state = to_state(sd); - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value=t->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (!maxvol){ /* max +20db */ - ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630; - } else { /* max 0db */ - ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829; - } - return 0; - case V4L2_CID_AUDIO_BALANCE: - { - if ( (t->lf) < (t->rf) ) - /* right is attenuated, balance shifted left */ - ctrl->value = (32768 - 1057*(t->rf)); - else - /* left is attenuated, balance shifted right */ - ctrl->value = (32768 + 1057*(t->lf)); - return 0; - } - case V4L2_CID_AUDIO_BASS: - { - /* Bass/treble 4 bits each */ - int bass=t->bass; - if(bass >= 0x8) - bass = ~(bass - 0x8) & 0xf; - ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass); - return 0; - } - case V4L2_CID_AUDIO_TREBLE: - { - int treble=t->treble; - if(treble >= 0x8) - treble = ~(treble - 0x8) & 0xf; - ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble); - return 0; - } - } - return -EINVAL; + v4l2_ctrl_handler_log_status(&state->hdl, sd->name); + return 0; } -static int tda7432_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int tda7432_s_ctrl(struct v4l2_ctrl *ctrl) { + struct v4l2_subdev *sd = to_sd(ctrl); struct tda7432 *t = to_state(sd); + u8 bass, treble, volume; + u8 lf, lr, rf, rr; switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - t->muted=ctrl->value; - break; - case V4L2_CID_AUDIO_VOLUME: - if(!maxvol){ /* max +20db */ - t->volume = 0x6f - ((ctrl->value)/630); - } else { /* max 0db */ - t->volume = 0x6f - ((ctrl->value)/829); - } - if (loudness) /* Turn on the loudness bit */ - t->volume |= TDA7432_LD_ON; - - tda7432_write(sd, TDA7432_VL, t->volume); - return 0; - case V4L2_CID_AUDIO_BALANCE: - if (ctrl->value < 32768) { + if (t->balance->val < 0) { /* shifted to left, attenuate right */ - t->rr = (32768 - ctrl->value)/1057; - t->rf = t->rr; - t->lr = TDA7432_ATTEN_0DB; - t->lf = TDA7432_ATTEN_0DB; - } else if(ctrl->value > 32769) { + rr = rf = -t->balance->val; + lr = lf = TDA7432_ATTEN_0DB; + } else if (t->balance->val > 0) { /* shifted to right, attenuate left */ - t->lf = (ctrl->value - 32768)/1057; - t->lr = t->lf; - t->rr = TDA7432_ATTEN_0DB; - t->rf = TDA7432_ATTEN_0DB; + rr = rf = TDA7432_ATTEN_0DB; + lr = lf = t->balance->val; } else { /* centered */ - t->rr = TDA7432_ATTEN_0DB; - t->rf = TDA7432_ATTEN_0DB; - t->lf = TDA7432_ATTEN_0DB; - t->lr = TDA7432_ATTEN_0DB; + rr = rf = TDA7432_ATTEN_0DB; + lr = lf = TDA7432_ATTEN_0DB; } - break; - case V4L2_CID_AUDIO_BASS: - t->bass = ctrl->value >> 12; - if(t->bass>= 0x8) - t->bass = (~t->bass & 0xf) + 0x8 ; - - tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble); + if (t->mute->val) { + lf |= TDA7432_MUTE; + lr |= TDA7432_MUTE; + lf |= TDA7432_MUTE; + rr |= TDA7432_MUTE; + } + /* Mute & update balance*/ + tda7432_write(sd, TDA7432_LF, lf); + tda7432_write(sd, TDA7432_LR, lr); + tda7432_write(sd, TDA7432_RF, rf); + tda7432_write(sd, TDA7432_RR, rr); return 0; - case V4L2_CID_AUDIO_TREBLE: - t->treble= ctrl->value >> 12; - if(t->treble>= 0x8) - t->treble = (~t->treble & 0xf) + 0x8 ; + case V4L2_CID_AUDIO_VOLUME: + volume = 0x6f - ctrl->val; + if (loudness) /* Turn on the loudness bit */ + volume |= TDA7432_LD_ON; - tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble); + tda7432_write(sd, TDA7432_VL, volume); return 0; - default: - return -EINVAL; - } - - /* Used for both mute and balance changes */ - if (t->muted) - { - /* Mute & update balance*/ - tda7432_write(sd, TDA7432_LF, t->lf | TDA7432_MUTE); - tda7432_write(sd, TDA7432_LR, t->lr | TDA7432_MUTE); - tda7432_write(sd, TDA7432_RF, t->rf | TDA7432_MUTE); - tda7432_write(sd, TDA7432_RR, t->rr | TDA7432_MUTE); - } else { - tda7432_write(sd, TDA7432_LF, t->lf); - tda7432_write(sd, TDA7432_LR, t->lr); - tda7432_write(sd, TDA7432_RF, t->rf); - tda7432_write(sd, TDA7432_RR, t->rr); - } - return 0; -} - -static int tda7432_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_AUDIO_VOLUME: - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880); - case V4L2_CID_AUDIO_MUTE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); - case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768); + bass = t->bass->val; + treble = t->treble->val; + if (bass >= 0x8) + bass = 14 - (bass - 8); + if (treble >= 0x8) + treble = 14 - (treble - 8); + + tda7432_write(sd, TDA7432_TN, 0x10 | (bass << 4) | treble); + return 0; } return -EINVAL; } /* ----------------------------------------------------------------------- */ -static const struct v4l2_subdev_core_ops tda7432_core_ops = { - .queryctrl = tda7432_queryctrl, - .g_ctrl = tda7432_g_ctrl, +static const struct v4l2_ctrl_ops tda7432_ctrl_ops = { .s_ctrl = tda7432_s_ctrl, }; +static const struct v4l2_subdev_core_ops tda7432_core_ops = { + .log_status = tda7432_log_status, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, +}; + static const struct v4l2_subdev_ops tda7432_ops = { .core = &tda7432_core_ops, }; @@ -444,6 +364,28 @@ static int tda7432_probe(struct i2c_client *client, return -ENOMEM; sd = &t->sd; v4l2_i2c_subdev_init(sd, client, &tda7432_ops); + v4l2_ctrl_handler_init(&t->hdl, 5); + v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, 0, maxvol ? 0x68 : 0x4f, 1, maxvol ? 0x5d : 0x47); + t->mute = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); + t->balance = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, + V4L2_CID_AUDIO_BALANCE, -31, 31, 1, 0); + t->bass = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, + V4L2_CID_AUDIO_BASS, 0, 14, 1, 7); + t->treble = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops, + V4L2_CID_AUDIO_TREBLE, 0, 14, 1, 7); + sd->ctrl_handler = &t->hdl; + if (t->hdl.error) { + int err = t->hdl.error; + + v4l2_ctrl_handler_free(&t->hdl); + kfree(t); + return err; + } + v4l2_ctrl_cluster(2, &t->bass); + v4l2_ctrl_cluster(2, &t->mute); + v4l2_ctrl_handler_setup(&t->hdl); if (loudness < 0 || loudness > 15) { v4l2_warn(sd, "loudness parameter must be between 0 and 15\n"); if (loudness < 0) @@ -452,17 +394,19 @@ static int tda7432_probe(struct i2c_client *client, loudness = 15; } - do_tda7432_init(sd); + tda7432_set(sd); return 0; } static int tda7432_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct tda7432 *t = to_state(sd); - do_tda7432_init(sd); + tda7432_set(sd); v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); + v4l2_ctrl_handler_free(&t->hdl); + kfree(t); return 0; } -- cgit v1.2.3 From 01df530c2791610727e345b3dd97ef75943c7320 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Feb 2013 12:40:28 -0300 Subject: [media] bttv: convert to the control framework Note that the private chroma agc control has been replaced with the standard CHROMA_AGC control. Also fixes a mute/automute problem where closing the file handle would force mute on. That's not what you want since that would make the mute state out of sync with the mute control. Instead check against the user count. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-cards.c | 5 +- drivers/media/pci/bt8xx/bttv-driver.c | 682 +++++++++++++--------------------- drivers/media/pci/bt8xx/bttvp.h | 16 +- include/uapi/linux/v4l2-controls.h | 5 + 4 files changed, 271 insertions(+), 437 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index c4c59175e52c..682ed893d718 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -3554,8 +3554,9 @@ void bttv_init_card2(struct bttv *btv) I2C_CLIENT_END }; - if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tda7432", 0, addrs)) + btv->sd_tda7432 = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tda7432", 0, addrs); + if (btv->sd_tda7432) return; } diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 73404b7a1396..8e0a44d03fc4 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -94,7 +94,7 @@ static unsigned int combfilter; static unsigned int lumafilter; static unsigned int automute = 1; static unsigned int chroma_agc; -static unsigned int adc_crush = 1; +static unsigned int agc_crush = 1; static unsigned int whitecrush_upper = 0xCF; static unsigned int whitecrush_lower = 0x7F; static unsigned int vcr_hack; @@ -126,7 +126,7 @@ module_param(combfilter, int, 0444); module_param(lumafilter, int, 0444); module_param(automute, int, 0444); module_param(chroma_agc, int, 0444); -module_param(adc_crush, int, 0444); +module_param(agc_crush, int, 0444); module_param(whitecrush_upper, int, 0444); module_param(whitecrush_lower, int, 0444); module_param(vcr_hack, int, 0444); @@ -139,27 +139,27 @@ module_param_array(video_nr, int, NULL, 0444); module_param_array(radio_nr, int, NULL, 0444); module_param_array(vbi_nr, int, NULL, 0444); -MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)"); -MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian"); -MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)"); -MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)"); -MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)"); -MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)"); +MODULE_PARM_DESC(radio, "The TV card supports radio, default is 0 (no)"); +MODULE_PARM_DESC(bigendian, "byte order of the framebuffer, default is native endian"); +MODULE_PARM_DESC(bttv_verbose, "verbose startup messages, default is 1 (yes)"); +MODULE_PARM_DESC(bttv_gpio, "log gpio changes, default is 0 (no)"); +MODULE_PARM_DESC(bttv_debug, "debug messages, default is 0 (no)"); +MODULE_PARM_DESC(irq_debug, "irq handler debug messages, default is 0 (no)"); MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); -MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8"); -MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000"); -MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default " +MODULE_PARM_DESC(gbuffers, "number of capture buffers. range 2-32, default 8"); +MODULE_PARM_DESC(gbufsize, "size of the capture buffers, default is 0x208000"); +MODULE_PARM_DESC(reset_crop, "reset cropping parameters at open(), default " "is 1 (yes) for compatibility with older applications"); -MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)"); -MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)"); -MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)"); -MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is 207"); -MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127"); -MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)"); -MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler"); -MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50"); -MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)"); -MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)"); +MODULE_PARM_DESC(automute, "mute audio on bad/missing video signal, default is 1 (yes)"); +MODULE_PARM_DESC(chroma_agc, "enables the AGC of chroma signal, default is 0 (no)"); +MODULE_PARM_DESC(agc_crush, "enables the luminance AGC crush, default is 1 (yes)"); +MODULE_PARM_DESC(whitecrush_upper, "sets the white crush upper value, default is 207"); +MODULE_PARM_DESC(whitecrush_lower, "sets the white crush lower value, default is 127"); +MODULE_PARM_DESC(vcr_hack, "enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)"); +MODULE_PARM_DESC(irq_iswitch, "switch inputs in irq handler"); +MODULE_PARM_DESC(uv_ratio, "ratio between u and v gains, default is 50"); +MODULE_PARM_DESC(full_luma_range, "use the full luma range, default is 0 (no)"); +MODULE_PARM_DESC(coring, "set the luma coring level, default is 0 (no)"); MODULE_PARM_DESC(video_nr, "video device numbers"); MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); MODULE_PARM_DESC(radio_nr, "radio device numbers"); @@ -169,6 +169,17 @@ MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr"); MODULE_LICENSE("GPL"); MODULE_VERSION(BTTV_VERSION); +#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_USER_BTTV_BASE + 0) +#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_USER_BTTV_BASE + 1) +#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_USER_BTTV_BASE + 2) +#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_USER_BTTV_BASE + 3) +#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_USER_BTTV_BASE + 4) +#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_USER_BTTV_BASE + 5) +#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_USER_BTTV_BASE + 6) +#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_USER_BTTV_BASE + 7) +#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_USER_BTTV_BASE + 8) +#define V4L2_CID_PRIVATE_CORING (V4L2_CID_USER_BTTV_BASE + 9) + /* ----------------------------------------------------------------------- */ /* sysfs */ @@ -622,198 +633,6 @@ static const struct bttv_format formats[] = { }; static const unsigned int FORMATS = ARRAY_SIZE(formats); -/* ----------------------------------------------------------------------- */ - -#define V4L2_CID_PRIVATE_CHROMA_AGC (V4L2_CID_PRIVATE_BASE + 0) -#define V4L2_CID_PRIVATE_COMBFILTER (V4L2_CID_PRIVATE_BASE + 1) -#define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 2) -#define V4L2_CID_PRIVATE_LUMAFILTER (V4L2_CID_PRIVATE_BASE + 3) -#define V4L2_CID_PRIVATE_AGC_CRUSH (V4L2_CID_PRIVATE_BASE + 4) -#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5) -#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6) -#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7) -#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8) -#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9) -#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10) -#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11) - -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; -static const struct v4l2_queryctrl bttv_ctls[] = { - /* --- video --- */ - { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0, - .maximum = 65535, - .step = 256, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 65535, - .step = 128, - .default_value = 27648, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 65535, - .step = 128, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_COLOR_KILLER, - .name = "Color killer", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 65535, - .step = 256, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - /* --- audio --- */ - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 65535, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_BALANCE, - .name = "Balance", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_BASS, - .name = "Bass", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_TREBLE, - .name = "Treble", - .minimum = 0, - .maximum = 65535, - .step = 65535/100, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - /* --- private --- */ - { - .id = V4L2_CID_PRIVATE_CHROMA_AGC, - .name = "chroma agc", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_COMBFILTER, - .name = "combfilter", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_AUTOMUTE, - .name = "automute", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_LUMAFILTER, - .name = "luma decimation filter", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_AGC_CRUSH, - .name = "agc crush", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_VCR_HACK, - .name = "vcr hack", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER, - .name = "whitecrush upper", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 0xCF, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER, - .name = "whitecrush lower", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 0x7F, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_PRIVATE_UV_RATIO, - .name = "uv ratio", - .minimum = 0, - .maximum = 100, - .step = 1, - .default_value = 50, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE, - .name = "full luma range", - .minimum = 0, - .maximum = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_PRIVATE_CORING, - .name = "coring", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - } - - - -}; - -static const struct v4l2_queryctrl *ctrl_by_id(int id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(bttv_ctls); i++) - if (bttv_ctls[i].id == id) - return bttv_ctls+i; - - return NULL; -} - /* ----------------------------------------------------------------------- */ /* resource management */ @@ -1173,7 +992,7 @@ static int audio_mux(struct bttv *btv, int input, int mute) { int gpio_val, signal; - struct v4l2_control ctrl; + struct v4l2_ctrl *ctrl; gpio_inout(bttv_tvcards[btv->c.type].gpiomask, bttv_tvcards[btv->c.type].gpiomask); @@ -1183,7 +1002,8 @@ audio_mux(struct bttv *btv, int input, int mute) btv->audio = input; /* automute */ - mute = mute || (btv->opt_automute && !signal && !btv->radio_user); + mute = mute || (btv->opt_automute && (!signal || !btv->users) + && !btv->radio_user); if (mute) gpio_val = bttv_tvcards[btv->c.type].gpiomute; @@ -1205,12 +1025,13 @@ audio_mux(struct bttv *btv, int input, int mute) if (in_interrupt()) return 0; - ctrl.id = V4L2_CID_AUDIO_MUTE; - ctrl.value = btv->mute; - bttv_call_all(btv, core, s_ctrl, &ctrl); if (btv->sd_msp34xx) { u32 in; + ctrl = v4l2_ctrl_find(btv->sd_msp34xx->ctrl_handler, V4L2_CID_AUDIO_MUTE); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, btv->mute); + /* Note: the inputs tuner/radio/extern/intern are translated to msp routings. This assumes common behavior for all msp3400 based TV cards. When this assumption fails, then the @@ -1255,9 +1076,19 @@ audio_mux(struct bttv *btv, int input, int mute) in, MSP_OUTPUT_DEFAULT, 0); } if (btv->sd_tvaudio) { + ctrl = v4l2_ctrl_find(btv->sd_tvaudio->ctrl_handler, V4L2_CID_AUDIO_MUTE); + + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, btv->mute); v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing, input, 0, 0); } + if (btv->sd_tda7432) { + ctrl = v4l2_ctrl_find(btv->sd_tda7432->ctrl_handler, V4L2_CID_AUDIO_MUTE); + + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, btv->mute); + } return 0; } @@ -1395,8 +1226,6 @@ static void init_irqreg(struct bttv *btv) static void init_bt848(struct bttv *btv) { - int val; - if (bttv_tvcards[btv->c.type].no_video) { /* very basic init only */ init_irqreg(btv); @@ -1416,30 +1245,10 @@ static void init_bt848(struct bttv *btv) BT848_GPIO_DMA_CTL_GPINTI, BT848_GPIO_DMA_CTL); - val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; - btwrite(val, BT848_E_SCLOOP); - btwrite(val, BT848_O_SCLOOP); - btwrite(0x20, BT848_E_VSCALE_HI); btwrite(0x20, BT848_O_VSCALE_HI); - btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), - BT848_ADC); - btwrite(whitecrush_upper, BT848_WC_UP); - btwrite(whitecrush_lower, BT848_WC_DOWN); - - if (btv->opt_lumafilter) { - btwrite(0, BT848_E_CONTROL); - btwrite(0, BT848_O_CONTROL); - } else { - btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL); - btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); - } - - bt848_bright(btv, btv->bright); - bt848_hue(btv, btv->hue); - bt848_contrast(btv, btv->contrast); - bt848_sat(btv, btv->saturation); + v4l2_ctrl_handler_setup(&btv->ctrl_handler); /* interrupt */ init_irqreg(btv); @@ -1461,103 +1270,26 @@ static void bttv_reinit_bt848(struct bttv *btv) set_input(btv, btv->input, btv->tvnorm); } -static int bttv_g_ctrl(struct file *file, void *priv, - struct v4l2_control *c) +static int bttv_s_ctrl(struct v4l2_ctrl *c) { - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = btv->bright; - break; - case V4L2_CID_HUE: - c->value = btv->hue; - break; - case V4L2_CID_CONTRAST: - c->value = btv->contrast; - break; - case V4L2_CID_SATURATION: - c->value = btv->saturation; - break; - case V4L2_CID_COLOR_KILLER: - c->value = btv->opt_color_killer; - break; - - case V4L2_CID_AUDIO_MUTE: - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - bttv_call_all(btv, core, g_ctrl, c); - break; - - case V4L2_CID_PRIVATE_CHROMA_AGC: - c->value = btv->opt_chroma_agc; - break; - case V4L2_CID_PRIVATE_COMBFILTER: - c->value = btv->opt_combfilter; - break; - case V4L2_CID_PRIVATE_LUMAFILTER: - c->value = btv->opt_lumafilter; - break; - case V4L2_CID_PRIVATE_AUTOMUTE: - c->value = btv->opt_automute; - break; - case V4L2_CID_PRIVATE_AGC_CRUSH: - c->value = btv->opt_adc_crush; - break; - case V4L2_CID_PRIVATE_VCR_HACK: - c->value = btv->opt_vcr_hack; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: - c->value = btv->opt_whitecrush_upper; - break; - case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: - c->value = btv->opt_whitecrush_lower; - break; - case V4L2_CID_PRIVATE_UV_RATIO: - c->value = btv->opt_uv_ratio; - break; - case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: - c->value = btv->opt_full_luma_range; - break; - case V4L2_CID_PRIVATE_CORING: - c->value = btv->opt_coring; - break; - default: - return -EINVAL; - } - return 0; -} - -static int bttv_s_ctrl(struct file *file, void *f, - struct v4l2_control *c) -{ - int err; - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - err = v4l2_prio_check(&btv->prio, fh->prio); - if (0 != err) - return err; + struct bttv *btv = container_of(c->handler, struct bttv, ctrl_handler); + int val; switch (c->id) { case V4L2_CID_BRIGHTNESS: - bt848_bright(btv, c->value); + bt848_bright(btv, c->val); break; case V4L2_CID_HUE: - bt848_hue(btv, c->value); + bt848_hue(btv, c->val); break; case V4L2_CID_CONTRAST: - bt848_contrast(btv, c->value); + bt848_contrast(btv, c->val); break; case V4L2_CID_SATURATION: - bt848_sat(btv, c->value); + bt848_sat(btv, c->val); break; case V4L2_CID_COLOR_KILLER: - btv->opt_color_killer = c->value; - if (btv->opt_color_killer) { + if (c->val) { btor(BT848_SCLOOP_CKILL, BT848_E_SCLOOP); btor(BT848_SCLOOP_CKILL, BT848_O_SCLOOP); } else { @@ -1566,36 +1298,22 @@ static int bttv_s_ctrl(struct file *file, void *f, } break; case V4L2_CID_AUDIO_MUTE: - audio_mute(btv, c->value); - /* fall through */ - case V4L2_CID_AUDIO_VOLUME: - if (btv->volume_gpio) - btv->volume_gpio(btv, c->value); - - bttv_call_all(btv, core, s_ctrl, c); + audio_mute(btv, c->val); break; - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - bttv_call_all(btv, core, s_ctrl, c); + case V4L2_CID_AUDIO_VOLUME: + btv->volume_gpio(btv, c->val); break; - case V4L2_CID_PRIVATE_CHROMA_AGC: - btv->opt_chroma_agc = c->value; - if (btv->opt_chroma_agc) { - btor(BT848_SCLOOP_CAGC, BT848_E_SCLOOP); - btor(BT848_SCLOOP_CAGC, BT848_O_SCLOOP); - } else { - btand(~BT848_SCLOOP_CAGC, BT848_E_SCLOOP); - btand(~BT848_SCLOOP_CAGC, BT848_O_SCLOOP); - } + case V4L2_CID_CHROMA_AGC: + val = c->val ? BT848_SCLOOP_CAGC : 0; + btwrite(val, BT848_E_SCLOOP); + btwrite(val, BT848_O_SCLOOP); break; case V4L2_CID_PRIVATE_COMBFILTER: - btv->opt_combfilter = c->value; + btv->opt_combfilter = c->val; break; case V4L2_CID_PRIVATE_LUMAFILTER: - btv->opt_lumafilter = c->value; - if (btv->opt_lumafilter) { + if (c->val) { btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL); btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL); } else { @@ -1604,36 +1322,31 @@ static int bttv_s_ctrl(struct file *file, void *f, } break; case V4L2_CID_PRIVATE_AUTOMUTE: - btv->opt_automute = c->value; + btv->opt_automute = c->val; break; case V4L2_CID_PRIVATE_AGC_CRUSH: - btv->opt_adc_crush = c->value; btwrite(BT848_ADC_RESERVED | - (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), + (c->val ? BT848_ADC_CRUSH : 0), BT848_ADC); break; case V4L2_CID_PRIVATE_VCR_HACK: - btv->opt_vcr_hack = c->value; + btv->opt_vcr_hack = c->val; break; case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: - btv->opt_whitecrush_upper = c->value; - btwrite(c->value, BT848_WC_UP); + btwrite(c->val, BT848_WC_UP); break; case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: - btv->opt_whitecrush_lower = c->value; - btwrite(c->value, BT848_WC_DOWN); + btwrite(c->val, BT848_WC_DOWN); break; case V4L2_CID_PRIVATE_UV_RATIO: - btv->opt_uv_ratio = c->value; + btv->opt_uv_ratio = c->val; bt848_sat(btv, btv->saturation); break; case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: - btv->opt_full_luma_range = c->value; - btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM); + btaor((c->val << 7), ~BT848_OFORM_RANGE, BT848_OFORM); break; case V4L2_CID_PRIVATE_CORING: - btv->opt_coring = c->value; - btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM); + btaor((c->val << 5), ~BT848_OFORM_CORE32, BT848_OFORM); break; default: return -EINVAL; @@ -1641,6 +1354,121 @@ static int bttv_s_ctrl(struct file *file, void *f, return 0; } +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_ctrl_ops bttv_ctrl_ops = { + .s_ctrl = bttv_s_ctrl, +}; + +static struct v4l2_ctrl_config bttv_ctrl_combfilter = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_COMBFILTER, + .name = "Comb Filter", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static struct v4l2_ctrl_config bttv_ctrl_automute = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_AUTOMUTE, + .name = "Auto Mute", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static struct v4l2_ctrl_config bttv_ctrl_lumafilter = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_LUMAFILTER, + .name = "Luma Decimation Filter", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static struct v4l2_ctrl_config bttv_ctrl_agc_crush = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_AGC_CRUSH, + .name = "AGC Crush", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static struct v4l2_ctrl_config bttv_ctrl_vcr_hack = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_VCR_HACK, + .name = "VCR Hack", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static struct v4l2_ctrl_config bttv_ctrl_whitecrush_lower = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_WHITECRUSH_LOWER, + .name = "Whitecrush Lower", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 255, + .step = 1, + .def = 0x7f, +}; + +static struct v4l2_ctrl_config bttv_ctrl_whitecrush_upper = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_WHITECRUSH_UPPER, + .name = "Whitecrush Upper", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 255, + .step = 1, + .def = 0xcf, +}; + +static struct v4l2_ctrl_config bttv_ctrl_uv_ratio = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_UV_RATIO, + .name = "UV Ratio", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 100, + .step = 1, + .def = 50, +}; + +static struct v4l2_ctrl_config bttv_ctrl_full_luma = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE, + .name = "Full Luma Range", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, +}; + +static struct v4l2_ctrl_config bttv_ctrl_coring = { + .ops = &bttv_ctrl_ops, + .id = V4L2_CID_PRIVATE_CORING, + .name = "Coring", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 3, + .step = 1, +}; + + /* ----------------------------------------------------------------------- */ void bttv_gpio_tracking(struct bttv *btv, char *comment) @@ -2047,9 +1875,11 @@ static int bttv_s_frequency(struct file *file, void *priv, static int bttv_log_status(struct file *file, void *f) { + struct video_device *vdev = video_devdata(file); struct bttv_fh *fh = f; struct bttv *btv = fh->btv; + v4l2_ctrl_handler_log_status(vdev->ctrl_handler, btv->c.v4l2_dev.name); bttv_call_all(btv, core, log_status); return 0; } @@ -2939,30 +2769,6 @@ static int bttv_streamoff(struct file *file, void *priv, return 0; } -static int bttv_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct bttv_fh *fh = priv; - struct bttv *btv = fh->btv; - const struct v4l2_queryctrl *ctrl; - - if ((c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) && - (c->id < V4L2_CID_PRIVATE_BASE || - c->id >= V4L2_CID_PRIVATE_LASTP1)) - return -EINVAL; - - if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME)) - *c = no_ctl; - else { - ctrl = ctrl_by_id(c->id); - - *c = (NULL != ctrl) ? *ctrl : no_ctl; - } - - return 0; -} - static int bttv_g_parm(struct file *file, void *f, struct v4l2_streamparm *parm) { @@ -3263,6 +3069,7 @@ static int bttv_open(struct file *file) fh = kmalloc(sizeof(*fh), GFP_KERNEL); if (unlikely(!fh)) return -ENOMEM; + btv->users++; file->private_data = fh; *fh = btv->init; @@ -3287,7 +3094,6 @@ static int bttv_open(struct file *file) set_tvnorm(btv,btv->tvnorm); set_input(btv, btv->input, btv->tvnorm); - btv->users++; /* The V4L2 spec requires one global set of cropping parameters which only change on request. These are stored in btv->crop[1]. @@ -3349,7 +3155,7 @@ static int bttv_release(struct file *file) bttv_field_count(btv); if (!btv->users) - audio_mute(btv, 1); + audio_mute(btv, btv->mute); return 0; } @@ -3400,9 +3206,6 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = { .vidioc_enum_input = bttv_enum_input, .vidioc_g_input = bttv_g_input, .vidioc_s_input = bttv_s_input, - .vidioc_queryctrl = bttv_queryctrl, - .vidioc_g_ctrl = bttv_g_ctrl, - .vidioc_s_ctrl = bttv_s_ctrl, .vidioc_streamon = bttv_streamon, .vidioc_streamoff = bttv_streamoff, .vidioc_g_tuner = bttv_g_tuner, @@ -3511,24 +3314,6 @@ static int radio_s_tuner(struct file *file, void *priv, return 0; } -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - const struct v4l2_queryctrl *ctrl; - - if (c->id < V4L2_CID_BASE || - c->id >= V4L2_CID_LASTP1) - return -EINVAL; - - if (c->id == V4L2_CID_AUDIO_MUTE) { - ctrl = ctrl_by_id(c->id); - *c = *ctrl; - } else - *c = no_ctl; - - return 0; -} - static ssize_t radio_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { @@ -3570,11 +3355,9 @@ static const struct v4l2_file_operations radio_fops = static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_querycap = bttv_querycap, + .vidioc_log_status = bttv_log_status, .vidioc_g_tuner = radio_g_tuner, .vidioc_s_tuner = radio_s_tuner, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_ctrl = bttv_g_ctrl, - .vidioc_s_ctrl = bttv_s_ctrl, .vidioc_g_frequency = bttv_g_frequency, .vidioc_s_frequency = bttv_s_frequency, }; @@ -4220,6 +4003,7 @@ static int bttv_register_video(struct bttv *btv) btv->radio_dev = vdev_init(btv, &radio_template, "radio"); if (NULL == btv->radio_dev) goto err; + btv->radio_dev->ctrl_handler = &btv->radio_ctrl_handler; if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO, radio_nr[btv->c.nr]) < 0) goto err; @@ -4258,6 +4042,7 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) int result; unsigned char lat; struct bttv *btv; + struct v4l2_ctrl_handler *hdl; if (bttv_num == BTTV_MAX) return -ENOMEM; @@ -4317,6 +4102,10 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) pr_warn("%d: v4l2_device_register() failed\n", btv->c.nr); goto fail0; } + hdl = &btv->ctrl_handler; + v4l2_ctrl_handler_init(hdl, 20); + btv->c.v4l2_dev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(&btv->radio_ctrl_handler, 6); btv->revision = dev->revision; pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); @@ -4353,16 +4142,19 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) /* init options from insmod args */ btv->opt_combfilter = combfilter; - btv->opt_lumafilter = lumafilter; + bttv_ctrl_combfilter.def = combfilter; + bttv_ctrl_lumafilter.def = lumafilter; btv->opt_automute = automute; - btv->opt_chroma_agc = chroma_agc; - btv->opt_adc_crush = adc_crush; + bttv_ctrl_automute.def = automute; + bttv_ctrl_agc_crush.def = agc_crush; btv->opt_vcr_hack = vcr_hack; - btv->opt_whitecrush_upper = whitecrush_upper; - btv->opt_whitecrush_lower = whitecrush_lower; + bttv_ctrl_vcr_hack.def = vcr_hack; + bttv_ctrl_whitecrush_upper.def = whitecrush_upper; + bttv_ctrl_whitecrush_lower.def = whitecrush_lower; btv->opt_uv_ratio = uv_ratio; - btv->opt_full_luma_range = full_luma_range; - btv->opt_coring = coring; + bttv_ctrl_uv_ratio.def = uv_ratio; + bttv_ctrl_full_luma.def = full_luma_range; + bttv_ctrl_coring.def = coring; /* fill struct bttv with some useful defaults */ btv->init.btv = btv; @@ -4373,6 +4165,34 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) btv->init.height = 240; btv->input = 0; + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 0xff00, 0x100, 32768); + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_CONTRAST, 0, 0xff80, 0x80, 0x6c00); + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_SATURATION, 0, 0xff80, 0x80, 32768); + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_COLOR_KILLER, 0, 1, 1, 0); + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_HUE, 0, 0xff00, 0x100, 32768); + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_CHROMA_AGC, 0, 1, 1, !!chroma_agc); + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); + if (btv->volume_gpio) + v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, 0, 0xff00, 0x100, 0xff00); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_combfilter, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_automute, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_lumafilter, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_agc_crush, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_vcr_hack, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_whitecrush_lower, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_whitecrush_upper, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_uv_ratio, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_full_luma, NULL); + v4l2_ctrl_new_custom(hdl, &bttv_ctrl_coring, NULL); + /* initialize hardware */ if (bttv_gpio) bttv_gpio_tracking(btv,"pre-init"); @@ -4400,20 +4220,26 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) btv->radio_freq = 90500 * 16; /* 90.5Mhz default */ } init_irqreg(btv); + v4l2_ctrl_handler_setup(hdl); + if (hdl->error) { + result = hdl->error; + goto fail2; + } /* register video4linux + input */ if (!bttv_tvcards[btv->c.type].no_video) { - bttv_register_video(btv); - bt848_bright(btv,32768); - bt848_contrast(btv, 27648); - bt848_hue(btv,32768); - bt848_sat(btv,32768); - audio_mute(btv, 1); + v4l2_ctrl_add_handler(&btv->radio_ctrl_handler, hdl, + v4l2_ctrl_radio_filter); + if (btv->radio_ctrl_handler.error) { + result = btv->radio_ctrl_handler.error; + goto fail2; + } set_input(btv, 0, btv->tvnorm); bttv_crop_reset(&btv->crop[0], btv->tvnorm); btv->crop[1] = btv->crop[0]; /* current = default */ disclaim_vbi_lines(btv); disclaim_video_lines(btv); + bttv_register_video(btv); } /* add subdevices and autoload dvb-bt8xx if needed */ @@ -4435,6 +4261,8 @@ fail2: free_irq(btv->c.pci->irq,btv); fail1: + v4l2_ctrl_handler_free(&btv->ctrl_handler); + v4l2_ctrl_handler_free(&btv->radio_ctrl_handler); v4l2_device_unregister(&btv->c.v4l2_dev); fail0: @@ -4476,9 +4304,11 @@ static void bttv_remove(struct pci_dev *pci_dev) bttv_unregister_video(btv); /* free allocated memory */ + v4l2_ctrl_handler_free(&btv->ctrl_handler); + v4l2_ctrl_handler_free(&btv->radio_ctrl_handler); btcx_riscmem_free(btv->c.pci,&btv->main); - /* free ressources */ + /* free resources */ free_irq(btv->c.pci->irq,btv); iounmap(btv->bt848_mmio); release_mem_region(pci_resource_start(btv->c.pci,0), diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index 528e03ec19e8..c3882ef3c529 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -33,9 +33,10 @@ #include #include #include +#include #include #include -#include +#include #include #include #include @@ -393,12 +394,17 @@ struct bttv { wait_queue_head_t i2c_queue; struct v4l2_subdev *sd_msp34xx; struct v4l2_subdev *sd_tvaudio; + struct v4l2_subdev *sd_tda7432; /* video4linux (1) */ struct video_device *video_dev; struct video_device *radio_dev; struct video_device *vbi_dev; + /* controls */ + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl_handler radio_ctrl_handler; + /* infrared remote */ int has_remote; struct bttv_ir *remote; @@ -426,17 +432,9 @@ struct bttv { /* various options */ int opt_combfilter; - int opt_lumafilter; int opt_automute; - int opt_chroma_agc; - int opt_color_killer; - int opt_adc_crush; int opt_vcr_hack; - int opt_whitecrush_upper; - int opt_whitecrush_lower; int opt_uv_ratio; - int opt_full_luma_range; - int opt_coring; /* radio data/state */ int has_radio; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index dcd63745e83a..1d00ca9f0ba3 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -146,6 +146,11 @@ enum v4l2_colorfx { * of controls. We reserve 16 controls for this driver. */ #define V4L2_CID_USER_MEYE_BASE (V4L2_CID_USER_BASE + 0x1000) +/* The base for the bttv driver controls. + * We reserve 32 controls for this driver. */ +#define V4L2_CID_USER_BTTV_BASE (V4L2_CID_USER_BASE + 0x1010) + + /* MPEG-class control IDs */ #define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) -- cgit v1.2.3 From ae50f0f83efce31c8d485b5de131a4fd3f13e24b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Feb 2013 12:42:13 -0300 Subject: [media] bttv: add support for control events Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 48 +++++++++++++++++++++++++---------- drivers/media/pci/bt8xx/bttvp.h | 4 +++ 2 files changed, 39 insertions(+), 13 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 8e0a44d03fc4..d34d271c6100 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -49,6 +49,7 @@ #include "bttvp.h" #include #include +#include #include #include #include @@ -2999,34 +3000,43 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) struct bttv_fh *fh = file->private_data; struct bttv_buffer *buf; enum v4l2_field field; - unsigned int rc = POLLERR; + unsigned int rc = 0; + unsigned long req_events = poll_requested_events(wait); + + if (v4l2_event_pending(&fh->fh)) + rc = POLLPRI; + else if (req_events & POLLPRI) + poll_wait(file, &fh->fh.wait, wait); + + if (!(req_events & (POLLIN | POLLRDNORM))) + return rc; if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI)) - return POLLERR; - return videobuf_poll_stream(file, &fh->vbi, wait); + return rc | POLLERR; + return rc | videobuf_poll_stream(file, &fh->vbi, wait); } if (check_btres(fh,RESOURCE_VIDEO_STREAM)) { /* streaming capture */ if (list_empty(&fh->cap.stream)) - goto err; + return rc | POLLERR; buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream); } else { /* read() capture */ if (NULL == fh->cap.read_buf) { /* need to capture a new frame */ if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) - goto err; + return rc | POLLERR; fh->cap.read_buf = videobuf_sg_alloc(fh->cap.msize); if (NULL == fh->cap.read_buf) - goto err; + return rc | POLLERR; fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR; field = videobuf_next_field(&fh->cap); if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) { kfree (fh->cap.read_buf); fh->cap.read_buf = NULL; - goto err; + return rc | POLLERR; } fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); fh->cap.read_off = 0; @@ -3037,10 +3047,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) poll_wait(file, &buf->vb.done, wait); if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) - rc = POLLIN|POLLRDNORM; - else - rc = 0; -err: + rc = rc | POLLIN|POLLRDNORM; return rc; } @@ -3073,6 +3080,7 @@ static int bttv_open(struct file *file) file->private_data = fh; *fh = btv->init; + v4l2_fh_init(&fh->fh, vdev); fh->type = type; fh->ov.setup_ok = 0; @@ -3112,6 +3120,7 @@ static int bttv_open(struct file *file) bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm); bttv_field_count(btv); + v4l2_fh_add(&fh->fh); return 0; } @@ -3149,7 +3158,6 @@ static int bttv_release(struct file *file) videobuf_mmap_free(&fh->vbi); v4l2_prio_close(&btv->prio, fh->prio); file->private_data = NULL; - kfree(fh); btv->users--; bttv_field_count(btv); @@ -3157,6 +3165,9 @@ static int bttv_release(struct file *file) if (!btv->users) audio_mute(btv, btv->mute); + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); + kfree(fh); return 0; } @@ -3222,6 +3233,8 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = { .vidioc_s_frequency = bttv_s_frequency, .vidioc_log_status = bttv_log_status, .vidioc_querystd = bttv_querystd, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_g_chip_ident = bttv_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = bttv_g_register, @@ -3334,10 +3347,17 @@ static unsigned int radio_poll(struct file *file, poll_table *wait) { struct bttv_fh *fh = file->private_data; struct bttv *btv = fh->btv; + unsigned long req_events = poll_requested_events(wait); struct saa6588_command cmd; + unsigned int res = 0; + + if (v4l2_event_pending(&fh->fh)) + res = POLLPRI; + else if (req_events & POLLPRI) + poll_wait(file, &fh->fh.wait, wait); cmd.instance = file; cmd.event_list = wait; - cmd.result = -ENODEV; + cmd.result = res; bttv_call_all(btv, core, ioctl, SAA6588_CMD_POLL, &cmd); return cmd.result; @@ -3360,6 +3380,8 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_s_tuner = radio_s_tuner, .vidioc_g_frequency = bttv_g_frequency, .vidioc_s_frequency = bttv_s_frequency, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device radio_template = { diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index c3882ef3c529..288cfd8bb560 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -215,6 +216,9 @@ struct bttv_crop { }; struct bttv_fh { + /* This must be the first field in this struct */ + struct v4l2_fh fh; + struct bttv *btv; int resources; #ifdef VIDIOC_G_PRIORITY -- cgit v1.2.3 From 8c14cc1f0ade4e16d4d3384791807abb4f367731 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Feb 2013 12:42:40 -0300 Subject: [media] bttv: fix priority handling Replace the - incorrect - manual priority handling with the core priority implementation. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 61 ++++------------------------------- drivers/media/pci/bt8xx/bttvp.h | 6 ---- 2 files changed, 6 insertions(+), 61 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index d34d271c6100..41de79ba5930 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1706,11 +1706,7 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; unsigned int i; - int err; - - err = v4l2_prio_check(&btv->prio, fh->prio); - if (err) - goto err; + int err = 0; for (i = 0; i < BTTV_TVNORMS; i++) if (*id & bttv_tvnorms[i].v4l2_id) @@ -1793,11 +1789,6 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i) { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; - int err; - - err = v4l2_prio_check(&btv->prio, fh->prio); - if (err) - return err; if (i >= bttv_tvcards[btv->c.type].video_inputs) return -EINVAL; @@ -1811,15 +1802,10 @@ static int bttv_s_tuner(struct file *file, void *priv, { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; - int err; if (t->index) return -EINVAL; - err = v4l2_prio_check(&btv->prio, fh->prio); - if (err) - return err; - bttv_call_all(btv, tuner, s_tuner, t); if (btv->audio_mode_gpio) @@ -1862,14 +1848,10 @@ static int bttv_s_frequency(struct file *file, void *priv, { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; - int err; if (f->tuner) return -EINVAL; - err = v4l2_prio_check(&btv->prio, fh->prio); - if (err) - return err; bttv_set_frequency(btv, f); return 0; } @@ -2808,28 +2790,6 @@ static int bttv_g_tuner(struct file *file, void *priv, return 0; } -static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - - *p = v4l2_prio_max(&btv->prio); - - return 0; -} - -static int bttv_s_priority(struct file *file, void *f, - enum v4l2_priority prio) -{ - struct bttv_fh *fh = f; - struct bttv *btv = fh->btv; - int rc; - - rc = v4l2_prio_change(&btv->prio, &fh->prio, prio); - - return rc; -} - static int bttv_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap) { @@ -2882,11 +2842,6 @@ static int bttv_s_crop(struct file *file, void *f, const struct v4l2_crop *crop) /* Make sure tvnorm, vbi_end and the current cropping parameters remain consistent until we're done. Note read() may change vbi_end in check_alloc_btres_lock(). */ - retval = v4l2_prio_check(&btv->prio, fh->prio); - if (0 != retval) { - return retval; - } - retval = -EBUSY; if (locked_btres(fh->btv, VIDEO_RESOURCES)) { @@ -3085,8 +3040,6 @@ static int bttv_open(struct file *file) fh->type = type; fh->ov.setup_ok = 0; - v4l2_prio_open(&btv->prio, &fh->prio); - videobuf_queue_sg_init(&fh->cap, &bttv_video_qops, &btv->c.pci->dev, &btv->s_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE, @@ -3156,7 +3109,6 @@ static int bttv_release(struct file *file) videobuf_mmap_free(&fh->cap); videobuf_mmap_free(&fh->vbi); - v4l2_prio_close(&btv->prio, fh->prio); file->private_data = NULL; btv->users--; @@ -3226,8 +3178,6 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = { .vidioc_g_fbuf = bttv_g_fbuf, .vidioc_s_fbuf = bttv_s_fbuf, .vidioc_overlay = bttv_overlay, - .vidioc_g_priority = bttv_g_priority, - .vidioc_s_priority = bttv_s_priority, .vidioc_g_parm = bttv_g_parm, .vidioc_g_frequency = bttv_g_frequency, .vidioc_s_frequency = bttv_s_frequency, @@ -3268,13 +3218,13 @@ static int radio_open(struct file *file) return -ENOMEM; file->private_data = fh; *fh = btv->init; - - v4l2_prio_open(&btv->prio, &fh->prio); + v4l2_fh_init(&fh->fh, vdev); btv->radio_user++; bttv_call_all(btv, tuner, s_radio); audio_input(btv,TVAUDIO_INPUT_RADIO); + v4l2_fh_add(&fh->fh); return 0; } @@ -3285,8 +3235,9 @@ static int radio_release(struct file *file) struct bttv *btv = fh->btv; struct saa6588_command cmd; - v4l2_prio_close(&btv->prio, fh->prio); file->private_data = NULL; + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); kfree(fh); btv->radio_user--; @@ -3948,6 +3899,7 @@ static struct video_device *vdev_init(struct bttv *btv, vfd->v4l2_dev = &btv->c.v4l2_dev; vfd->release = video_device_release; vfd->debug = bttv_debug; + set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); video_set_drvdata(vfd, btv); snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", @@ -4086,7 +4038,6 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) INIT_LIST_HEAD(&btv->c.subs); INIT_LIST_HEAD(&btv->capture); INIT_LIST_HEAD(&btv->vcapture); - v4l2_prio_init(&btv->prio); init_timer(&btv->timeout); btv->timeout.function = bttv_irq_timeout; diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index 288cfd8bb560..12cc4ebdc00f 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -221,9 +221,6 @@ struct bttv_fh { struct bttv *btv; int resources; -#ifdef VIDIOC_G_PRIORITY - enum v4l2_priority prio; -#endif enum v4l2_buf_type type; /* video capture */ @@ -420,9 +417,6 @@ struct bttv { spinlock_t s_lock; struct mutex lock; int resources; -#ifdef VIDIOC_G_PRIORITY - struct v4l2_prio_state prio; -#endif /* video state */ unsigned int input; -- cgit v1.2.3 From 6795cc55506606988175c16aa0e17d9f349706ca Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Feb 2013 12:43:07 -0300 Subject: [media] bttv: use centralized std and implement g_std The 'current_norm' field cannot be used if multiple device nodes (video and vbi in this case) set the same std. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 13 ++++++++++++- drivers/media/pci/bt8xx/bttvp.h | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 41de79ba5930..46ead7d65af1 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1716,6 +1716,7 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) goto err; } + btv->std = *id; set_tvnorm(btv, i); err: @@ -1723,6 +1724,15 @@ err: return err; } +static int bttv_g_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct bttv_fh *fh = priv; + struct bttv *btv = fh->btv; + + *id = btv->std; + return 0; +} + static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id) { struct bttv_fh *fh = f; @@ -3166,6 +3176,7 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = { .vidioc_qbuf = bttv_qbuf, .vidioc_dqbuf = bttv_dqbuf, .vidioc_s_std = bttv_s_std, + .vidioc_g_std = bttv_g_std, .vidioc_enum_input = bttv_enum_input, .vidioc_g_input = bttv_g_input, .vidioc_s_input = bttv_s_input, @@ -3196,7 +3207,6 @@ static struct video_device bttv_video_template = { .fops = &bttv_fops, .ioctl_ops = &bttv_ioctl_ops, .tvnorms = BTTV_NORMS, - .current_norm = V4L2_STD_PAL, }; /* ----------------------------------------------------------------------- */ @@ -4192,6 +4202,7 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) bttv_set_frequency(btv, &init_freq); btv->radio_freq = 90500 * 16; /* 90.5Mhz default */ } + btv->std = V4L2_STD_PAL; init_irqreg(btv); v4l2_ctrl_handler_setup(hdl); diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index 12cc4ebdc00f..86d67bb5adec 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -424,6 +424,7 @@ struct bttv { unsigned int mute; unsigned long tv_freq; unsigned int tvnorm; + v4l2_std_id std; int hue, contrast, bright, saturation; struct v4l2_framebuffer fbuf; unsigned int field_count; -- cgit v1.2.3 From fafdc26b8558838988f406abef27d6dcc5b3dd76 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Feb 2013 12:43:37 -0300 Subject: [media] bttv: there may be multiple tvaudio/tda7432 devices Probe for additional tvaudio devices, and allow tvaudio+tda7432 to co-exist. My STB TV PCI FM bttv card has a tda7432, a tda9850 and a tea6420 and with this patch it finally works again (probably for the first time in many years). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-cards.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index 682ed893d718..fa0faaa2a49a 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -3547,6 +3547,16 @@ void bttv_init_card2(struct bttv *btv) if (btv->sd_msp34xx) return; + /* Now see if we can find one of the tvaudio devices. */ + btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs()); + if (btv->sd_tvaudio) { + /* There may be two tvaudio chips on the card, so try to + find another. */ + v4l2_i2c_new_subdev(&btv->c.v4l2_dev, + &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs()); + } + /* it might also be a tda7432. */ if (!bttv_tvcards[btv->c.type].no_tda7432) { static const unsigned short addrs[] = { @@ -3559,10 +3569,6 @@ void bttv_init_card2(struct bttv *btv) if (btv->sd_tda7432) return; } - - /* Now see if we can find one of the tvaudio devices. */ - btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev, - &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs()); if (btv->sd_tvaudio) return; -- cgit v1.2.3 From 3d4b8035050dbca905ab55ecc0a0de16f9ef11bf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Feb 2013 12:44:07 -0300 Subject: [media] bttv: fix g_tuner capabilities override The capability field of v4l2_tuner should be ORed by the various subdevs and by the main driver. In this case the stereo capability was dropped. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvaudio.c | 2 +- drivers/media/pci/bt8xx/bttv-driver.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index e3b33b78dd21..4c91b355b55a 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -1803,7 +1803,7 @@ static int tvaudio_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) vt->audmode = chip->audmode; vt->rxsubchans = desc->getrxsubchans(chip); - vt->capability = V4L2_TUNER_CAP_STEREO | + vt->capability |= V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; return 0; diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 46ead7d65af1..0fdaef225c9e 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2787,9 +2787,9 @@ static int bttv_g_tuner(struct file *file, void *priv, return -EINVAL; t->rxsubchans = V4L2_TUNER_SUB_MONO; + t->capability = V4L2_TUNER_CAP_NORM; bttv_call_all(btv, tuner, g_tuner, t); strcpy(t->name, "Television"); - t->capability = V4L2_TUNER_CAP_NORM; t->type = V4L2_TUNER_ANALOG_TV; if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) t->signal = 0xffff; -- cgit v1.2.3 From c13eb7039f612cc666764d6685a3764f4e6c8821 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 7 Feb 2013 07:56:11 -0300 Subject: [media] bttv: fix try_fmt_vid_overlay and setup initial overlay size try_fmt_vid_overlay should map incorrect sizes and fields to valid values. It also expects that an initial overlay size is defined so g_fmt_vid_overlay returns valid information. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 44 ++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 0fdaef225c9e..b5100da854c0 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2111,22 +2111,33 @@ limit_scaled_size_lock (struct bttv_fh * fh, may also adjust the current cropping parameters to get closer to the desired window size. */ static int -verify_window_lock (struct bttv_fh * fh, - struct v4l2_window * win, - int adjust_size, - int adjust_crop) +verify_window_lock(struct bttv_fh *fh, struct v4l2_window *win, + int adjust_size, int adjust_crop) { enum v4l2_field field; unsigned int width_mask; int rc; - if (win->w.width < 48 || win->w.height < 32) - return -EINVAL; + if (win->w.width < 48) + win->w.width = 48; + if (win->w.height < 32) + win->w.height = 32; if (win->clipcount > 2048) - return -EINVAL; + win->clipcount = 2048; + win->chromakey = 0; + win->global_alpha = 0; field = win->field; + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_INTERLACED: + break; + default: + field = V4L2_FIELD_ANY; + break; + } if (V4L2_FIELD_ANY == field) { __s32 height2; @@ -2135,18 +2146,11 @@ verify_window_lock (struct bttv_fh * fh, ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; } - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } + win->field = field; - /* 4-byte alignment. */ if (NULL == fh->ovfmt) return -EINVAL; + /* 4-byte alignment. */ width_mask = ~0; switch (fh->ovfmt->depth) { case 8: @@ -2171,8 +2175,6 @@ verify_window_lock (struct bttv_fh * fh, adjust_size, adjust_crop); if (0 != rc) return rc; - - win->field = field; return 0; } @@ -2407,9 +2409,10 @@ static int bttv_try_fmt_vid_overlay(struct file *file, void *priv, { struct bttv_fh *fh = priv; - return verify_window_lock(fh, &f->fmt.win, + verify_window_lock(fh, &f->fmt.win, /* adjust_size */ 1, /* adjust_crop */ 0); + return 0; } static int bttv_s_fmt_vid_cap(struct file *file, void *priv, @@ -4146,6 +4149,9 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) btv->init.fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); btv->init.width = 320; btv->init.height = 240; + btv->init.ov.w.width = 320; + btv->init.ov.w.height = 240; + btv->init.ov.field = V4L2_FIELD_INTERLACED; btv->input = 0; v4l2_ctrl_new_std(hdl, &bttv_ctrl_ops, -- cgit v1.2.3 From b8e2a361ce4247118fe81224b43137821cda50f7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 10 Feb 2013 09:24:14 -0300 Subject: [media] bttv: do not switch to the radio tuner unless it is accessed Just opening the radio tuner should not cause a switch to the radio tuner. Only after calling g/s_tuner or g/s_frequency should this happen. This prevents audio being unmuted as soon as the driver is loaded because some process opens /dev/radioX just to see what sort of node it is, which switches on the radio tuner and unmutes audio. This code can be improved further by actually keeping track of who owns the tuner and returning -EBUSY if switching tuner modes will cause problems. But for now just fix the annoying case where on boot the radio turns on automatically. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 23 ++++++++++++++++++++--- drivers/media/pci/bt8xx/bttvp.h | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index b5100da854c0..265263a47a13 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1004,7 +1004,7 @@ audio_mux(struct bttv *btv, int input, int mute) /* automute */ mute = mute || (btv->opt_automute && (!signal || !btv->users) - && !btv->radio_user); + && !btv->has_radio_tuner); if (mute) gpio_val = bttv_tvcards[btv->c.type].gpiomute; @@ -1701,6 +1701,16 @@ static struct videobuf_queue_ops bttv_video_qops = { .buf_release = buffer_release, }; +static void radio_enable(struct bttv *btv) +{ + /* Switch to the radio tuner */ + if (!btv->has_radio_tuner) { + btv->has_radio_tuner = 1; + bttv_call_all(btv, tuner, s_radio); + audio_input(btv, TVAUDIO_INPUT_RADIO); + } +} + static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) { struct bttv_fh *fh = priv; @@ -1832,6 +1842,8 @@ static int bttv_g_frequency(struct file *file, void *priv, if (f->tuner) return -EINVAL; + if (f->type == V4L2_TUNER_RADIO) + radio_enable(btv); f->frequency = f->type == V4L2_TUNER_RADIO ? btv->radio_freq : btv->tv_freq; @@ -1845,6 +1857,7 @@ static void bttv_set_frequency(struct bttv *btv, struct v4l2_frequency *f) frequency before assigning radio/tv_freq. */ bttv_call_all(btv, tuner, g_frequency, f); if (f->type == V4L2_TUNER_RADIO) { + radio_enable(btv); btv->radio_freq = f->frequency; if (btv->has_matchbox) tea5757_set_freq(btv, btv->radio_freq); @@ -3235,8 +3248,6 @@ static int radio_open(struct file *file) btv->radio_user++; - bttv_call_all(btv, tuner, s_radio); - audio_input(btv,TVAUDIO_INPUT_RADIO); v4l2_fh_add(&fh->fh); return 0; @@ -3257,6 +3268,8 @@ static int radio_release(struct file *file) bttv_call_all(btv, core, ioctl, SAA6588_CMD_CLOSE, &cmd); + if (btv->radio_user == 0) + btv->has_radio_tuner = 0; return 0; } @@ -3269,6 +3282,7 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return -EINVAL; strcpy(t->name, "Radio"); t->type = V4L2_TUNER_RADIO; + radio_enable(btv); bttv_call_all(btv, tuner, g_tuner, t); @@ -3287,6 +3301,7 @@ static int radio_s_tuner(struct file *file, void *priv, if (0 != t->index) return -EINVAL; + radio_enable(btv); bttv_call_all(btv, tuner, s_tuner, t); return 0; } @@ -3301,6 +3316,7 @@ static ssize_t radio_read(struct file *file, char __user *data, cmd.buffer = data; cmd.instance = file; cmd.result = -ENODEV; + radio_enable(btv); bttv_call_all(btv, core, ioctl, SAA6588_CMD_READ, &cmd); @@ -3319,6 +3335,7 @@ static unsigned int radio_poll(struct file *file, poll_table *wait) res = POLLPRI; else if (req_events & POLLPRI) poll_wait(file, &fh->fh.wait, wait); + radio_enable(btv); cmd.instance = file; cmd.event_list = wait; cmd.result = res; diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index 86d67bb5adec..eb13be7ae3f4 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -437,6 +437,7 @@ struct bttv { /* radio data/state */ int has_radio; + int has_radio_tuner; int radio_user; int radio_uses_msp_demodulator; unsigned long radio_freq; -- cgit v1.2.3 From e74d7e6d349099574107869463a940d987152215 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 06:56:48 -0300 Subject: [media] bttv: remove g/s_audio since there is only one audio input Note that the current driver does not implement enumaudio (so apps cannot tell that audio inputs are present), it does not set V4L2_CAP_AUDIO, nor does it set audioset when calling ENUM_INPUT. And G_AUDIO doesn't set the stereo flag either. So these g/s_audio ioctls are quite pointless and misleading. Especially since some surveillance boards do not have audio at all. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 19 ------------------- 1 file changed, 19 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 265263a47a13..8610b6a8b8fb 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2925,23 +2925,6 @@ static int bttv_s_crop(struct file *file, void *f, const struct v4l2_crop *crop) return 0; } -static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - strcpy(a->name, "audio"); - return 0; -} - -static int bttv_s_audio(struct file *file, void *priv, const struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - return 0; -} - static ssize_t bttv_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { @@ -3184,8 +3167,6 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = { .vidioc_g_fmt_vbi_cap = bttv_g_fmt_vbi_cap, .vidioc_try_fmt_vbi_cap = bttv_try_fmt_vbi_cap, .vidioc_s_fmt_vbi_cap = bttv_s_fmt_vbi_cap, - .vidioc_g_audio = bttv_g_audio, - .vidioc_s_audio = bttv_s_audio, .vidioc_cropcap = bttv_cropcap, .vidioc_reqbufs = bttv_reqbufs, .vidioc_querybuf = bttv_querybuf, -- cgit v1.2.3 From 4bc837d414c36676499220065143743d720bf40f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 13 Sep 2012 05:29:12 -0300 Subject: [media] cx231xx: add device_caps support to QUERYCAP This fixes a v4l2_compliance failure. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-video.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 06376d904c9f..ffeedcd2448b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1854,6 +1854,7 @@ static int vidioc_streamoff(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { + struct video_device *vdev = video_devdata(file); struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; @@ -1861,17 +1862,20 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->capabilities = V4L2_CAP_VBI_CAPTURE | -#if 0 - V4L2_CAP_SLICED_VBI_CAPTURE | -#endif - V4L2_CAP_VIDEO_CAPTURE | + cap->device_caps = V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + if (vdev->vfl_type == VFL_TYPE_VBI) + cap->device_caps |= V4L2_CAP_VBI_CAPTURE; + else + cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; if (dev->tuner_type != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; + cap->device_caps |= V4L2_CAP_TUNER; + cap->capabilities = cap->device_caps | + V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_DEVICE_CAPS; return 0; } -- cgit v1.2.3 From fddd14c8f6ca2bb9bfdad1874c172002bc537527 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 13 Sep 2012 05:37:11 -0300 Subject: [media] cx231xx: add required VIDIOC_DBG_G_CHIP_IDENT support This fixes a v4l2_compliance failure. [mchehab@redhat.com: CodingStyle fixes] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-video.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index ffeedcd2448b..1b29158bbbe2 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1456,6 +1456,19 @@ static int vidioc_s_frequency(struct file *file, void *priv, return rc; } +static int vidioc_g_chip_ident(struct file *file, void *fh, + struct v4l2_dbg_chip_ident *chip) +{ + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (chip->match.type == V4L2_CHIP_MATCH_HOST) { + if (v4l2_chip_match_host(&chip->match)) + chip->ident = V4L2_IDENT_CX23100; + return 0; + } + return -EINVAL; +} + #ifdef CONFIG_VIDEO_ADV_DEBUG /* @@ -2514,6 +2527,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_g_chip_ident = vidioc_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, -- cgit v1.2.3 From 530e01e782c97076c58b6e474d31cc61caa4a9dd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 29 Jan 2013 12:32:20 -0300 Subject: [media] cx231xx: clean up radio support Radio should not use video or audio inputs. In addition, fix a bug in radio_g_tuner where s_tuner was called in the tuner subdev instead of g_tuner. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-video.c | 79 +++++++------------------------ 1 file changed, 18 insertions(+), 61 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 1b29158bbbe2..2cd31129de86 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1875,20 +1875,24 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - - if (vdev->vfl_type == VFL_TYPE_VBI) - cap->device_caps |= V4L2_CAP_VBI_CAPTURE; - else - cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; + if (vdev->vfl_type == VFL_TYPE_RADIO) + cap->device_caps = V4L2_CAP_RADIO; + else { + cap->device_caps = V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + if (vdev->vfl_type == VFL_TYPE_VBI) + cap->device_caps |= V4L2_CAP_VBI_CAPTURE; + else + cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; + } if (dev->tuner_type != TUNER_ABSENT) cap->device_caps |= V4L2_CAP_TUNER; cap->capabilities = cap->device_caps | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_DEVICE_CAPS; + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; + if (dev->radio_dev) + cap->capabilities |= V4L2_CAP_RADIO; return 0; } @@ -2055,53 +2059,19 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) /* RADIO ESPECIFIC IOCTLS */ /* ----------------------------------------------------------- */ -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev; - - strlcpy(cap->driver, "cx231xx", sizeof(cap->driver)); - strlcpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card)); - usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - - cap->capabilities = V4L2_CAP_TUNER; - return 0; -} - static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev; - if (unlikely(t->index > 0)) + if (t->index) return -EINVAL; strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - - call_all(dev, tuner, s_tuner, t); - - return 0; -} -static int radio_enum_input(struct file *file, void *priv, struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - strcpy(i->name, "Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; -} - -static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; + call_all(dev, tuner, g_tuner, t); - strcpy(a->name, "Radio"); return 0; } - static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev; @@ -2114,16 +2084,6 @@ static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return 0; } -static int radio_s_audio(struct file *file, void *fh, const struct v4l2_audio *a) -{ - return 0; -} - -static int radio_s_input(struct file *file, void *fh, unsigned int i) -{ - return 0; -} - static int radio_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) { @@ -2552,18 +2512,15 @@ static const struct v4l2_file_operations radio_fops = { }; static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = radio_querycap, + .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, .vidioc_queryctrl = radio_queryctrl, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_g_chip_ident = vidioc_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, -- cgit v1.2.3 From 06c46003f7077cce7f87a75d327635e45c6d2b64 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 13 Sep 2012 06:17:47 -0300 Subject: [media] cx231xx: remove broken audio input support from the driver The audio selection code is broken. Audio and video indices were mixed up and s_audio would reject changing the audio input to something else anyway, so what's the point? All the audio input code has been removed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-video.c | 52 +++++-------------------------- 1 file changed, 8 insertions(+), 44 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 2cd31129de86..a31f7daef3dd 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1231,44 +1231,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) return 0; } -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - - switch (a->index) { - case CX231XX_AMUX_VIDEO: - strcpy(a->name, "Television"); - break; - case CX231XX_AMUX_LINE_IN: - strcpy(a->name, "Line In"); - break; - default: - return -EINVAL; - } - - a->index = dev->ctl_ainput; - a->capability = V4L2_AUDCAP_STEREO; - - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int status = 0; - - /* Doesn't allow manual routing */ - if (a->index != dev->ctl_ainput) - return -EINVAL; - - dev->ctl_ainput = INPUT(a->index)->amux; - status = cx231xx_set_audio_input(dev, dev->ctl_ainput); - - return status; -} - static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { @@ -1878,8 +1840,7 @@ static int vidioc_querycap(struct file *file, void *priv, if (vdev->vfl_type == VFL_TYPE_RADIO) cap->device_caps = V4L2_CAP_RADIO; else { - cap->device_caps = V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; if (vdev->vfl_type == VFL_TYPE_VBI) cap->device_caps |= V4L2_CAP_VBI_CAPTURE; else @@ -1887,9 +1848,8 @@ static int vidioc_querycap(struct file *file, void *priv, } if (dev->tuner_type != TUNER_ABSENT) cap->device_caps |= V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | + cap->capabilities = cap->device_caps | V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; if (dev->radio_dev) cap->capabilities |= V4L2_CAP_RADIO; @@ -2464,8 +2424,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, .vidioc_try_fmt_vbi_cap = vidioc_try_fmt_vbi_cap, .vidioc_s_fmt_vbi_cap = vidioc_try_fmt_vbi_cap, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, .vidioc_cropcap = vidioc_cropcap, .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap, .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, @@ -2554,6 +2512,12 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev, snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); video_set_drvdata(vfd, dev); + if (dev->tuner_type == TUNER_ABSENT) { + v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER); + v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER); + } return vfd; } -- cgit v1.2.3 From b251f95767e1b13b9b32b207b53f5be1c491899e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 13 Sep 2012 12:54:36 -0300 Subject: [media] cx231xx: fix tuner compliance issues The g_tuner call wasn't passed on to the subdevices, g_frequency didn't check for invalid tuners and a low-level function that was expected to return 0 or a negative error returned a positive number instead, causing s_frequency to return bogus errors. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-avcore.c | 2 +- drivers/media/usb/cx231xx/cx231xx-video.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index 722207913740..4706ed350293 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c @@ -2133,7 +2133,7 @@ int cx231xx_tuner_post_channel_change(struct cx231xx *dev) status = vid_blk_write_word(dev, DIF_AGC_IF_REF, dwval); - return status; + return status == sizeof(dwval) ? 0 : -EIO; } /****************************************************************************** diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index a31f7daef3dd..2b7b0944b7b4 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1322,6 +1322,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) t->capability = V4L2_TUNER_CAP_NORM; t->rangehigh = 0xffffffffUL; t->signal = 0xffff; /* LOCKED */ + call_all(dev, tuner, g_tuner, t); return 0; } @@ -1350,6 +1351,9 @@ static int vidioc_g_frequency(struct file *file, void *priv, struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; + if (f->tuner) + return -EINVAL; + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = dev->ctl_freq; -- cgit v1.2.3 From 8b735c130717cb0af7793e30bbb6e91709ef10f8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Feb 2013 06:35:02 -0300 Subject: [media] cx231xx: zero priv field and use right width in try_fmt The priv field of v4l2_pix_format must be zeroed. Also fix a bug in try_fmt where the current width was used instead of the width passed to try_fmt. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-video.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 2b7b0944b7b4..9593fd3cdc85 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1005,6 +1005,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.field = V4L2_FIELD_INTERLACED; + f->fmt.pix.priv = 0; return 0; } @@ -1045,10 +1046,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.width = width; f->fmt.pix.height = height; f->fmt.pix.pixelformat = fmt->fourcc; - f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3; + f->fmt.pix.bytesperline = (width * fmt->depth + 7) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.field = V4L2_FIELD_INTERLACED; + f->fmt.pix.priv = 0; return 0; } -- cgit v1.2.3 From 0752d98e1a5619553d46a67590cdd94ee5827ff3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Feb 2013 06:40:33 -0300 Subject: [media] cx231xx: fix frequency clamping Let the tuner clamp the frequency and store that clamped value. This fixes a v4l2_compliance failure. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-video.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 9593fd3cdc85..f3104f008f46 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1356,11 +1356,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, if (f->tuner) return -EINVAL; - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = dev->ctl_freq; - call_all(dev, tuner, g_frequency, f); - return 0; } @@ -1383,16 +1380,12 @@ static int vidioc_s_frequency(struct file *file, void *priv, if (0 != f->tuner) return -EINVAL; - if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) - return -EINVAL; - /* set pre channel change settings in DIF first */ rc = cx231xx_tuner_pre_channel_change(dev); - dev->ctl_freq = f->frequency; call_all(dev, tuner, s_frequency, f); + call_all(dev, tuner, g_frequency, f); + dev->ctl_freq = f->frequency; /* set post channel change settings in DIF first */ rc = cx231xx_tuner_post_channel_change(dev); -- cgit v1.2.3 From 6264722c1212e5455bfdb58cca4377161cf97d23 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Feb 2013 06:41:11 -0300 Subject: [media] cx231xx: fix vbi compliance issues Various v4l2-compliance fixes: remove unused sliced VBI functions, zero the reserved fields of struct v4l2_vbi_format and implement the missing s_fmt_vbi_cap. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-video.c | 67 ++++++++----------------------- 1 file changed, 17 insertions(+), 50 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index f3104f008f46..5389825995e7 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1868,47 +1868,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -/* Sliced VBI ioctls */ -static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - f->fmt.sliced.service_set = 0; - - call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced); - - if (f->fmt.sliced.service_set == 0) - rc = -EINVAL; - - return rc; -} - -static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced); - - if (f->fmt.sliced.service_set == 0) - return -EINVAL; - - return 0; -} - /* RAW VBI ioctls */ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, @@ -1916,6 +1875,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; + f->fmt.vbi.sampling_rate = 6750000 * 4; f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; @@ -1927,6 +1887,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ? PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263; f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; + memset(f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved)); return 0; @@ -1938,12 +1899,6 @@ static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv, struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; - if (dev->vbi_stream_on && !fh->stream_on) { - cx231xx_errdev("%s device in use by another fh\n", __func__); - return -EBUSY; - } - - f->type = V4L2_BUF_TYPE_VBI_CAPTURE; f->fmt.vbi.sampling_rate = 6750000 * 4; f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; @@ -1956,11 +1911,25 @@ static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv, f->fmt.vbi.start[1] = (dev->norm & V4L2_STD_625_50) ? PAL_VBI_START_LINE + 312 : NTSC_VBI_START_LINE + 263; f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; + memset(f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved)); return 0; } +static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx231xx_fh *fh = priv; + struct cx231xx *dev = fh->dev; + + if (dev->vbi_stream_on && !fh->stream_on) { + cx231xx_errdev("%s device in use by another fh\n", __func__); + return -EBUSY; + } + return vidioc_try_fmt_vbi_cap(file, priv, f); +} + static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *rb) { @@ -2422,10 +2391,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, .vidioc_try_fmt_vbi_cap = vidioc_try_fmt_vbi_cap, - .vidioc_s_fmt_vbi_cap = vidioc_try_fmt_vbi_cap, + .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap, .vidioc_cropcap = vidioc_cropcap, - .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap, - .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, -- cgit v1.2.3 From d2370f8eee263a0a0260b9df9798f242d4cb13bf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 17 Sep 2012 07:22:09 -0300 Subject: [media] cx231xx: convert to the control framework This is needed to resolve the v4l2-compliance complaints about the control ioctls. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-audio.c | 4 - drivers/media/usb/cx231xx/cx231xx-cards.c | 2 - drivers/media/usb/cx231xx/cx231xx-video.c | 244 +++--------------------------- drivers/media/usb/cx231xx/cx231xx.h | 13 +- 4 files changed, 27 insertions(+), 236 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index b4c99c7270cf..b40360b8e89e 100644 --- a/drivers/media/usb/cx231xx/cx231xx-audio.c +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c @@ -449,9 +449,6 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream) return -ENODEV; } - /* Sets volume, mute, etc */ - dev->mute = 0; - /* set alternate setting for audio interface */ /* 1 - 48000 samples per sec */ mutex_lock(&dev->lock); @@ -503,7 +500,6 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream) return ret; } - dev->mute = 1; dev->adev.users--; mutex_unlock(&dev->lock); diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 8d529565f163..d6acb1ebff33 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -846,8 +846,6 @@ void cx231xx_card_setup(struct cx231xx *dev) int cx231xx_config(struct cx231xx *dev) { /* TBD need to add cx231xx specific code */ - dev->mute = 1; /* maybe not the right place... */ - dev->volume = 0x1f; return 0; } diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 5389825995e7..7be2e7349ef7 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -100,125 +100,6 @@ static struct cx231xx_fmt format[] = { }, }; -/* supported controls */ -/* Common to all boards */ - -/* ------------------------------------------------------------------- */ - -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; - -static struct cx231xx_ctrl cx231xx_ctls[] = { - /* --- video --- */ - { - .v = { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0x00, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = LUMA_CTRL, - .mask = 0x00ff, - .shift = 0, - }, { - .v = { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = LUMA_CTRL, - .mask = 0xff00, - .shift = 8, - }, { - .v = { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = CHROMA_CTRL, - .mask = 0xff0000, - .shift = 16, - }, { - /* strictly, this only describes only U saturation. - * V saturation is handled specially through code. - */ - .v = { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = CHROMA_CTRL, - .mask = 0x00ff, - .shift = 0, - }, { - /* --- audio --- */ - .v = { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = PATH1_CTL1, - .mask = (0x1f << 24), - .shift = 24, - }, { - .v = { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 0x3f, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .reg = PATH1_VOL_CTL, - .mask = 0xff, - .shift = 0, - } -}; -static const int CX231XX_CTLS = ARRAY_SIZE(cx231xx_ctls); - -static const u32 cx231xx_user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, -#if 0 - V4L2_CID_AUDIO_BALANCE, -#endif - V4L2_CID_AUDIO_MUTE, - 0 -}; - -static const u32 *ctrl_classes[] = { - cx231xx_user_ctrls, - NULL -}; /* ------------------------------------------------------------------ Video buffer and parser functions @@ -1233,78 +1114,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) return 0; } -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int id = qc->id; - int i; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - qc->id = v4l2_ctrl_next(ctrl_classes, qc->id); - if (unlikely(qc->id == 0)) - return -EINVAL; - - memset(qc, 0, sizeof(*qc)); - - qc->id = id; - - if (qc->id < V4L2_CID_BASE || qc->id >= V4L2_CID_LASTP1) - return -EINVAL; - - for (i = 0; i < CX231XX_CTLS; i++) - if (cx231xx_ctls[i].v.id == qc->id) - break; - - if (i == CX231XX_CTLS) { - *qc = no_ctl; - return 0; - } - *qc = cx231xx_ctls[i].v; - - call_all(dev, core, queryctrl, qc); - - if (qc->type) - return 0; - else - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - call_all(dev, core, g_ctrl, ctrl); - return rc; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - call_all(dev, core, s_ctrl, ctrl); - return rc; -} - static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct cx231xx_fh *fh = priv; @@ -2012,26 +1821,6 @@ static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return 0; } -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - int i; - - if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) - return -EINVAL; - if (c->id == V4L2_CID_AUDIO_MUTE) { - for (i = 0; i < CX231XX_CTLS; i++) { - if (cx231xx_ctls[i].v.id == c->id) - break; - } - if (i == CX231XX_CTLS) - return -EINVAL; - *c = cx231xx_ctls[i].v; - } else - *c = no_ctl; - return 0; -} - /* * cx231xx_v4l2_open() * inits the device and starts isoc transfer @@ -2180,6 +1969,8 @@ void cx231xx_release_analog_resources(struct cx231xx *dev) video_device_release(dev->vdev); dev->vdev = NULL; } + v4l2_ctrl_handler_free(&dev->ctrl_handler); + v4l2_ctrl_handler_free(&dev->radio_ctrl_handler); } /* @@ -2402,9 +2193,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_g_tuner = vidioc_g_tuner, @@ -2439,9 +2227,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_s_tuner = radio_s_tuner, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, .vidioc_g_chip_ident = vidioc_g_chip_ident, @@ -2506,9 +2291,21 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) /* Set the initial input */ video_mux(dev, dev->video_input); - /* Audio defaults */ - dev->mute = 1; - dev->volume = 0x1f; + v4l2_ctrl_handler_init(&dev->ctrl_handler, 10); + v4l2_ctrl_handler_init(&dev->radio_ctrl_handler, 5); + + if (dev->sd_cx25840) { + v4l2_ctrl_add_handler(&dev->ctrl_handler, + dev->sd_cx25840->ctrl_handler, NULL); + v4l2_ctrl_add_handler(&dev->radio_ctrl_handler, + dev->sd_cx25840->ctrl_handler, + v4l2_ctrl_radio_filter); + } + + if (dev->ctrl_handler.error) + return dev->ctrl_handler.error; + if (dev->radio_ctrl_handler.error) + return dev->radio_ctrl_handler.error; /* enable vbi capturing */ /* write code here... */ @@ -2520,6 +2317,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) return -ENODEV; } + dev->vdev->ctrl_handler = &dev->ctrl_handler; /* register v4l2 video video_device */ ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]); @@ -2539,6 +2337,11 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) /* Allocate and fill vbi video_device struct */ dev->vbi_dev = cx231xx_vdev_init(dev, &cx231xx_vbi_template, "vbi"); + if (!dev->vbi_dev) { + cx231xx_errdev("cannot allocate video_device.\n"); + return -ENODEV; + } + dev->vbi_dev->ctrl_handler = &dev->ctrl_handler; /* register v4l2 vbi video_device */ ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]); @@ -2557,6 +2360,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) cx231xx_errdev("cannot allocate video_device.\n"); return -ENODEV; } + dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler; ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, radio_nr[dev->devno]); if (ret < 0) { diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 3e11462be0d0..53408ce598d1 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -516,14 +517,6 @@ struct cx231xx_tvnorm { u32 cxoformat; }; -struct cx231xx_ctrl { - struct v4l2_queryctrl v; - u32 off; - u32 reg; - u32 mask; - u32 shift; -}; - enum TRANSFER_TYPE { Raw_Video = 0, Audio, @@ -631,6 +624,8 @@ struct cx231xx { struct v4l2_device v4l2_dev; struct v4l2_subdev *sd_cx25840; struct v4l2_subdev *sd_tuner; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl_handler radio_ctrl_handler; struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ atomic_t stream_started; /* stream should be running if true */ @@ -653,8 +648,6 @@ struct cx231xx { v4l2_std_id norm; /* selected tv norm */ int ctl_freq; /* selected frequency */ unsigned int ctl_ainput; /* selected audio input */ - int mute; - int volume; /* frame properties */ int width; /* current frame width */ -- cgit v1.2.3 From 1d08a4fa75ad165ed06c12b48477c39741ac68e4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 17 Sep 2012 07:31:04 -0300 Subject: [media] cx231xx: add struct v4l2_fh to get prio and event support Required to resolve v4l2-compliance failures. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-video.c | 31 ++++++++++++++++++++++++++----- drivers/media/usb/cx231xx/cx231xx.h | 2 ++ 2 files changed, 28 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 7be2e7349ef7..26d2a4fe74f1 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -1871,6 +1872,7 @@ static int cx231xx_v4l2_open(struct file *filp) fh->radio = radio; fh->type = fh_type; filp->private_data = fh; + v4l2_fh_init(&fh->fh, vdev); if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { dev->width = norm_maxw(dev); @@ -1926,6 +1928,7 @@ static int cx231xx_v4l2_open(struct file *filp) fh, &dev->lock); } mutex_unlock(&dev->lock); + v4l2_fh_add(&fh->fh); return errCode; } @@ -2020,12 +2023,15 @@ static int cx231xx_close(struct file *filp) else cx231xx_set_alt_setting(dev, INDEX_HANC, 0); + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); kfree(fh); dev->users--; wake_up_interruptible_nr(&dev->open, 1); return 0; } + v4l2_fh_del(&fh->fh); dev->users--; if (!dev->users) { videobuf_stop(&fh->vb_vidq); @@ -2052,6 +2058,7 @@ static int cx231xx_close(struct file *filp) /* set alternate 0 */ cx231xx_set_alt_setting(dev, INDEX_VIDEO, 0); } + v4l2_fh_exit(&fh->fh); kfree(fh); wake_up_interruptible_nr(&dev->open, 1); return 0; @@ -2108,29 +2115,37 @@ cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count, */ static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table *wait) { + unsigned long req_events = poll_requested_events(wait); struct cx231xx_fh *fh = filp->private_data; struct cx231xx *dev = fh->dev; + unsigned res = 0; int rc; rc = check_dev(dev); if (rc < 0) - return rc; + return POLLERR; rc = res_get(fh); if (unlikely(rc < 0)) return POLLERR; + if (v4l2_event_pending(&fh->fh)) + res |= POLLPRI; + else + poll_wait(filp, &fh->fh.wait, wait); + + if (!(req_events & (POLLIN | POLLRDNORM))) + return res; + if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == fh->type) || (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)) { - unsigned int res; - mutex_lock(&dev->lock); - res = videobuf_poll_stream(filp, &fh->vb_vidq, wait); + res |= videobuf_poll_stream(filp, &fh->vb_vidq, wait); mutex_unlock(&dev->lock); return res; } - return POLLERR; + return res | POLLERR; } /* @@ -2204,6 +2219,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device cx231xx_vbi_template; @@ -2220,6 +2237,7 @@ static const struct v4l2_file_operations radio_fops = { .owner = THIS_MODULE, .open = cx231xx_v4l2_open, .release = cx231xx_v4l2_close, + .poll = v4l2_ctrl_poll, .ioctl = video_ioctl2, }; @@ -2234,6 +2252,8 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device cx231xx_radio_template = { @@ -2259,6 +2279,7 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev, vfd->release = video_device_release; vfd->debug = video_debug; vfd->lock = &dev->lock; + set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 53408ce598d1..4c83ff54a0ff 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -429,6 +430,7 @@ struct cx231xx_audio { struct cx231xx; struct cx231xx_fh { + struct v4l2_fh fh; struct cx231xx *dev; unsigned int stream_on:1; /* Locks streams */ int radio; -- cgit v1.2.3 From a25a7012ba65ef41fba809c605c4f7d0dc609a23 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 17 Sep 2012 08:30:07 -0300 Subject: [media] cx231xx: remove current_norm usage The use of this field is deprecated since it will not work when multiple device nodes reference the same video input (the video and vbi nodes in this case). The norm field should be a device-global value. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-417.c | 1 - drivers/media/usb/cx231xx/cx231xx-video.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 28688dbcb609..a4091dd75620 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -2115,7 +2115,6 @@ static struct video_device cx231xx_mpeg_template = { .ioctl_ops = &mpeg_ioctl_ops, .minor = -1, .tvnorms = CX231xx_NORMS, - .current_norm = V4L2_STD_NTSC_M, }; void cx231xx_417_unregister(struct cx231xx *dev) diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 26d2a4fe74f1..ae27c8287d21 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -2230,7 +2230,6 @@ static const struct video_device cx231xx_video_template = { .release = video_device_release, .ioctl_ops = &video_ioctl_ops, .tvnorms = V4L2_STD_ALL, - .current_norm = V4L2_STD_PAL, }; static const struct v4l2_file_operations radio_fops = { @@ -2301,7 +2300,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) dev->name, CX231XX_VERSION); /* set default norm */ - /*dev->norm = cx231xx_video_template.current_norm; */ + dev->norm = V4L2_STD_PAL; dev->width = norm_maxw(dev); dev->height = norm_maxh(dev); dev->interlaced = 0; -- cgit v1.2.3 From 1265f080d8f04ffe074bdf948bbec4cb9c420ee0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 17 Sep 2012 09:26:46 -0300 Subject: [media] cx231xx: replace ioctl by unlocked_ioctl There was already a core lock, so why wasn't ioctl already replaced by unlock_ioctl? This patch switches to unlocked_ioctl. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-417.c | 15 ++++++--------- drivers/media/usb/cx231xx/cx231xx-video.c | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index a4091dd75620..15dd334a93d3 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1633,12 +1633,8 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) dprintk(3, "enter vidioc_s_input() i=%d\n", i); - mutex_lock(&dev->lock); - video_mux(dev, i); - mutex_unlock(&dev->lock); - if (i >= 4) return -EINVAL; dev->input = i; @@ -1932,7 +1928,8 @@ static int mpeg_open(struct file *file) if (dev == NULL) return -ENODEV; - mutex_lock(&dev->lock); + if (mutex_lock_interruptible(&dev->lock)) + return -ERESTARTSYS; /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); @@ -1948,14 +1945,14 @@ static int mpeg_open(struct file *file) videobuf_queue_vmalloc_init(&fh->vidq, &cx231xx_qops, NULL, &dev->video_mode.slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, - sizeof(struct cx231xx_buffer), fh, NULL); + sizeof(struct cx231xx_buffer), fh, &dev->lock); /* videobuf_queue_sg_init(&fh->vidq, &cx231xx_qops, &dev->udev->dev, &dev->ts1.slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct cx231xx_buffer), - fh, NULL); + fh, &dev->lock); */ @@ -2069,7 +2066,7 @@ static struct v4l2_file_operations mpeg_fops = { .read = mpeg_read, .poll = mpeg_poll, .mmap = mpeg_mmap, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { @@ -2144,11 +2141,11 @@ static struct video_device *cx231xx_video_dev_alloc( if (NULL == vfd) return NULL; *vfd = *template; - vfd->minor = -1; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, cx231xx_boards[dev->model].name); vfd->v4l2_dev = &dev->v4l2_dev; + vfd->lock = &dev->lock; vfd->release = video_device_release; return vfd; diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index ae27c8287d21..8d4964052036 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -2237,7 +2237,7 @@ static const struct v4l2_file_operations radio_fops = { .open = cx231xx_v4l2_open, .release = cx231xx_v4l2_close, .poll = v4l2_ctrl_poll, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops radio_ioctl_ops = { -- cgit v1.2.3 From 71590765b81bdc22562fb54e1def0f78d9be8909 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 28 Jan 2013 12:57:47 -0300 Subject: [media] cx231xx: get rid of a bunch of unused cx231xx_fh fields Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-video.c | 6 +----- drivers/media/usb/cx231xx/cx231xx.h | 18 +----------------- 2 files changed, 2 insertions(+), 22 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 8d4964052036..b0cd699aeda6 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1621,9 +1621,6 @@ static int vidioc_streamoff(struct file *file, void *priv, if (rc < 0) return rc; - if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; if (type != fh->type) return -EINVAL; @@ -1869,7 +1866,6 @@ static int cx231xx_v4l2_open(struct file *filp) return -ERESTARTSYS; } fh->dev = dev; - fh->radio = radio; fh->type = fh_type; filp->private_data = fh; v4l2_fh_init(&fh->fh, vdev); @@ -1900,7 +1896,7 @@ static int cx231xx_v4l2_open(struct file *filp) dev->video_input = dev->video_input > 2 ? 2 : dev->video_input; } - if (fh->radio) { + if (radio) { cx231xx_videodbg("video_open: setting radio device\n"); /* cx231xx_start_radio(dev); */ diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 4c83ff54a0ff..c17889d64e59 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -433,25 +433,9 @@ struct cx231xx_fh { struct v4l2_fh fh; struct cx231xx *dev; unsigned int stream_on:1; /* Locks streams */ - int radio; - - struct videobuf_queue vb_vidq; - enum v4l2_buf_type type; - - -/*following is copyed from cx23885.h*/ - u32 resources; - - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip *clips; - unsigned int nclips; - - /* video capture */ - struct cx23417_fmt *fmt; - unsigned int width, height; + struct videobuf_queue vb_vidq; /* vbi capture */ struct videobuf_queue vidq; -- cgit v1.2.3 From d61072a4975d0be5f0a858fba8d0304800b43fbf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 29 Jan 2013 10:50:54 -0300 Subject: [media] cx231xx: improve std handling Set the initial standard of subdevices instead of leaving it undefined. Also update the width and height when a new standard is chosen and return -EBUSY when attempting to change the standard while videobuf is busy. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-video.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index b0cd699aeda6..b6cde46131c7 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -992,34 +992,34 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; struct v4l2_mbus_framefmt mbus_fmt; - struct v4l2_format f; int rc; rc = check_dev(dev); if (rc < 0) return rc; - cx231xx_info("vidioc_s_std : 0x%x\n", (unsigned int)*norm); + if (dev->norm == *norm) + return 0; + + if (videobuf_queue_is_busy(&fh->vb_vidq)) + return -EBUSY; dev->norm = *norm; /* Adjusts width/height, if needed */ - f.fmt.pix.width = dev->width; - f.fmt.pix.height = dev->height; - vidioc_try_fmt_vid_cap(file, priv, &f); + dev->width = 720; + dev->height = (dev->norm & V4L2_STD_625_50) ? 576 : 480; call_all(dev, core, s_std, dev->norm); /* We need to reset basic properties in the decoder related to resolution (since a standard change effects things like the number of lines in VACT, etc) */ - v4l2_fill_mbus_format(&mbus_fmt, &f.fmt.pix, V4L2_MBUS_FMT_FIXED); + memset(&mbus_fmt, 0, sizeof(mbus_fmt)); + mbus_fmt.code = V4L2_MBUS_FMT_FIXED; + mbus_fmt.width = dev->width; + mbus_fmt.height = dev->height; call_all(dev, video, s_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f.fmt.pix, &mbus_fmt); - - /* set new image size */ - dev->width = f.fmt.pix.width; - dev->height = f.fmt.pix.height; /* do mode control overrides */ cx231xx_do_mode_ctrl_overrides(dev); @@ -2307,6 +2307,8 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) /* Set the initial input */ video_mux(dev, dev->video_input); + call_all(dev, core, s_std, dev->norm); + v4l2_ctrl_handler_init(&dev->ctrl_handler, 10); v4l2_ctrl_handler_init(&dev->radio_ctrl_handler, 5); -- cgit v1.2.3 From 3f926e326d3c02b73898b7692f2b2306c521e2d3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 29 Jan 2013 12:50:18 -0300 Subject: [media] cx231xx-417: remove empty functions Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-417.c | 68 +-------------------------------- 1 file changed, 1 insertion(+), 67 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 15dd334a93d3..ac15a55fe5d0 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1551,33 +1551,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) dprintk(3, "exit vidioc_s_std() i=0x%x\n", i); return 0; } -static int vidioc_g_audio(struct file *file, void *fh, - struct v4l2_audio *a) -{ - struct v4l2_audio *vin = a; - - int ret = -EINVAL; - if (vin->index > 0) - return ret; - strncpy(vin->name, "VideoGrabber Audio", 14); - vin->capability = V4L2_AUDCAP_STEREO; -return 0; -} -static int vidioc_enumaudio(struct file *file, void *fh, - struct v4l2_audio *a) -{ - struct v4l2_audio *vin = a; - - int ret = -EINVAL; - - if (vin->index > 0) - return ret; - strncpy(vin->name, "VideoGrabber Audio", 14); - vin->capability = V4L2_AUDCAP_STEREO; - - -return 0; -} static const char *iname[] = { [CX231XX_VMUX_COMPOSITE1] = "Composite1", [CX231XX_VMUX_SVIDEO] = "S-Video", @@ -1642,32 +1615,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) return 0; } -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - - - return 0; -} - static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctl) { @@ -1748,13 +1695,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - - return 0; -} - static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) { @@ -2073,20 +2013,14 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_s_std = vidioc_s_std, .vidioc_g_std = vidioc_g_std, .vidioc_enum_input = vidioc_enum_input, - .vidioc_enumaudio = vidioc_enumaudio, - .vidioc_g_audio = vidioc_g_audio, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, -- cgit v1.2.3 From bc08734c825b710ffab93f79ca1ca2d0265dd321 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 29 Jan 2013 12:52:33 -0300 Subject: [media] cx231xx-417: use one querycap for all device nodes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-417.c | 20 +------------------- drivers/media/usb/cx231xx/cx231xx-video.c | 6 +++--- drivers/media/usb/cx231xx/cx231xx.h | 2 ++ 3 files changed, 6 insertions(+), 22 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index ac15a55fe5d0..be8f7481d7f2 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1626,24 +1626,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv, dprintk(3, "exit vidioc_s_ctrl()\n"); return 0; } -static struct v4l2_capability pvr_capability = { - .driver = "cx231xx", - .card = "VideoGrabber", - .bus_info = "usb", - .version = 1, - .capabilities = (V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | - V4L2_CAP_STREAMING | V4L2_CAP_READWRITE), -}; -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - - - - memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability)); - return 0; -} static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) @@ -2016,7 +1998,7 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_querycap = vidioc_querycap, + .vidioc_querycap = cx231xx_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index b6cde46131c7..c199eae6bd3e 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1632,7 +1632,7 @@ static int vidioc_streamoff(struct file *file, void *priv, return 0; } -static int vidioc_querycap(struct file *file, void *priv, +int cx231xx_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct video_device *vdev = video_devdata(file); @@ -2186,7 +2186,7 @@ static const struct v4l2_file_operations cx231xx_v4l_fops = { }; static const struct v4l2_ioctl_ops video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, + .vidioc_querycap = cx231xx_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, @@ -2237,7 +2237,7 @@ static const struct v4l2_file_operations radio_fops = { }; static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, + .vidioc_querycap = cx231xx_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_s_tuner = radio_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index c17889d64e59..efc0d1cafd5d 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -934,6 +934,8 @@ int cx231xx_register_extension(struct cx231xx_ops *dev); void cx231xx_unregister_extension(struct cx231xx_ops *dev); void cx231xx_init_extension(struct cx231xx *dev); void cx231xx_close_extension(struct cx231xx *dev); +int cx231xx_querycap(struct file *file, void *priv, + struct v4l2_capability *cap); /* Provided by cx231xx-cards.c */ extern void cx231xx_pre_card_setup(struct cx231xx *dev); -- cgit v1.2.3 From 5aa95991d7ff15ca965ef5abe91f90afeb262afd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 29 Jan 2013 13:02:15 -0300 Subject: [media] cx231xx-417: fix g/try_fmt compliance problems Colorspace, field and priv were not set, and sizeimage was calculated using the wrong values (dev->ts1.ts_packet_size and dev->ts1.ts_packet_count can be 0 at module load). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-417.c | 34 ++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index be8f7481d7f2..cbdc141fe9b2 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1223,6 +1223,7 @@ static int bb_buf_setup(struct videobuf_queue *q, return 0; } + static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf) { struct cx231xx_fh *fh = vq->priv_data; @@ -1645,17 +1646,18 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, { struct cx231xx_fh *fh = file->private_data; struct cx231xx *dev = fh->dev; + dprintk(3, "enter vidioc_g_fmt_vid_cap()\n"); - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; - f->fmt.pix.colorspace = 0; - f->fmt.pix.width = dev->ts1.width; - f->fmt.pix.height = dev->ts1.height; - f->fmt.pix.field = fh->vidq.field; - dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", - dev->ts1.width, dev->ts1.height, fh->vidq.field); + f->fmt.pix.sizeimage = mpeglines * mpeglinesize; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.width = dev->ts1.width; + f->fmt.pix.height = dev->ts1.height; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + f->fmt.pix.priv = 0; + dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n", + dev->ts1.width, dev->ts1.height); dprintk(3, "exit vidioc_g_fmt_vid_cap()\n"); return 0; } @@ -1665,14 +1667,16 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, { struct cx231xx_fh *fh = file->private_data; struct cx231xx *dev = fh->dev; + dprintk(3, "enter vidioc_try_fmt_vid_cap()\n"); - f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = - dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; - f->fmt.pix.colorspace = 0; - dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", - dev->ts1.width, dev->ts1.height, fh->vidq.field); + f->fmt.pix.sizeimage = mpeglines * mpeglinesize; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.priv = 0; + dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n", + dev->ts1.width, dev->ts1.height); dprintk(3, "exit vidioc_try_fmt_vid_cap()\n"); return 0; } -- cgit v1.2.3 From 5b8acdc5e6d9ea73572478b59b6d3390b044f45a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 29 Jan 2013 12:59:50 -0300 Subject: [media] cx231xx-417: checkpatch cleanups Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-417.c | 732 ++++++++++++++++---------------- 1 file changed, 360 insertions(+), 372 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index cbdc141fe9b2..2c05c8f41527 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -38,7 +38,6 @@ #include #include "cx231xx.h" -/*#include "cx23885-ioctl.h"*/ #define CX231xx_FIRM_IMAGE_SIZE 376836 #define CX231xx_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw" @@ -75,9 +74,11 @@ static unsigned int mpegbufs = 8; module_param(mpegbufs, int, 0644); MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32"); + static unsigned int mpeglines = 128; module_param(mpeglines, int, 0644); MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32"); + static unsigned int mpeglinesize = 512; module_param(mpeglinesize, int, 0644); MODULE_PARM_DESC(mpeglinesize, @@ -86,10 +87,10 @@ MODULE_PARM_DESC(mpeglinesize, static unsigned int v4l_debug = 1; module_param(v4l_debug, int, 0644); MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages"); -struct cx231xx_dmaqueue *dma_qq; + #define dprintk(level, fmt, arg...)\ do { if (v4l_debug >= level) \ - printk(KERN_INFO "%s: " fmt, \ + pr_info("%s: " fmt, \ (dev) ? dev->name : "cx231xx[?]", ## arg); \ } while (0) @@ -131,11 +132,13 @@ static struct cx231xx_tvnorm cx231xx_tvnorms[] = { }; /* ------------------------------------------------------------------ */ + enum cx231xx_capture_type { CX231xx_MPEG_CAPTURE, CX231xx_RAW_CAPTURE, CX231xx_RAW_PASSTHRU_CAPTURE }; + enum cx231xx_capture_bits { CX231xx_RAW_BITS_NONE = 0x00, CX231xx_RAW_BITS_YUV_CAPTURE = 0x01, @@ -144,33 +147,40 @@ enum cx231xx_capture_bits { CX231xx_RAW_BITS_PASSTHRU_CAPTURE = 0x08, CX231xx_RAW_BITS_TO_HOST_CAPTURE = 0x10 }; + enum cx231xx_capture_end { CX231xx_END_AT_GOP, /* stop at the end of gop, generate irq */ CX231xx_END_NOW, /* stop immediately, no irq */ }; + enum cx231xx_framerate { CX231xx_FRAMERATE_NTSC_30, /* NTSC: 30fps */ CX231xx_FRAMERATE_PAL_25 /* PAL: 25fps */ }; + enum cx231xx_stream_port { CX231xx_OUTPUT_PORT_MEMORY, CX231xx_OUTPUT_PORT_STREAMING, CX231xx_OUTPUT_PORT_SERIAL }; + enum cx231xx_data_xfer_status { CX231xx_MORE_BUFFERS_FOLLOW, CX231xx_LAST_BUFFER, }; + enum cx231xx_picture_mask { CX231xx_PICTURE_MASK_NONE, CX231xx_PICTURE_MASK_I_FRAMES, CX231xx_PICTURE_MASK_I_P_FRAMES = 0x3, CX231xx_PICTURE_MASK_ALL_FRAMES = 0x7, }; + enum cx231xx_vbi_mode_bits { CX231xx_VBI_BITS_SLICED, CX231xx_VBI_BITS_RAW, }; + enum cx231xx_vbi_insertion_bits { CX231xx_VBI_BITS_INSERT_IN_XTENSION_USR_DATA, CX231xx_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1, @@ -178,56 +188,69 @@ enum cx231xx_vbi_insertion_bits { CX231xx_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1, CX231xx_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1, }; + enum cx231xx_dma_unit { CX231xx_DMA_BYTES, CX231xx_DMA_FRAMES, }; + enum cx231xx_dma_transfer_status_bits { CX231xx_DMA_TRANSFER_BITS_DONE = 0x01, CX231xx_DMA_TRANSFER_BITS_ERROR = 0x04, CX231xx_DMA_TRANSFER_BITS_LL_ERROR = 0x10, }; + enum cx231xx_pause { CX231xx_PAUSE_ENCODING, CX231xx_RESUME_ENCODING, }; + enum cx231xx_copyright { CX231xx_COPYRIGHT_OFF, CX231xx_COPYRIGHT_ON, }; + enum cx231xx_notification_type { CX231xx_NOTIFICATION_REFRESH, }; + enum cx231xx_notification_status { CX231xx_NOTIFICATION_OFF, CX231xx_NOTIFICATION_ON, }; + enum cx231xx_notification_mailbox { CX231xx_NOTIFICATION_NO_MAILBOX = -1, }; + enum cx231xx_field1_lines { CX231xx_FIELD1_SAA7114 = 0x00EF, /* 239 */ CX231xx_FIELD1_SAA7115 = 0x00F0, /* 240 */ CX231xx_FIELD1_MICRONAS = 0x0105, /* 261 */ }; + enum cx231xx_field2_lines { CX231xx_FIELD2_SAA7114 = 0x00EF, /* 239 */ CX231xx_FIELD2_SAA7115 = 0x00F0, /* 240 */ CX231xx_FIELD2_MICRONAS = 0x0106, /* 262 */ }; + enum cx231xx_custom_data_type { CX231xx_CUSTOM_EXTENSION_USR_DATA, CX231xx_CUSTOM_PRIVATE_PACKET, }; + enum cx231xx_mute { CX231xx_UNMUTE, CX231xx_MUTE, }; + enum cx231xx_mute_video_mask { CX231xx_MUTE_VIDEO_V_MASK = 0x0000FF00, CX231xx_MUTE_VIDEO_U_MASK = 0x00FF0000, CX231xx_MUTE_VIDEO_Y_MASK = 0xFF000000, }; + enum cx231xx_mute_video_shift { CX231xx_MUTE_VIDEO_V_SHIFT = 8, CX231xx_MUTE_VIDEO_U_SHIFT = 16, @@ -296,41 +319,43 @@ enum cx231xx_mute_video_shift { #define CX23417_GPIO_MASK 0xFC0003FF -static int setITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 value) + +static int set_itvc_reg(struct cx231xx *dev, u32 gpio_direction, u32 value) { int status = 0; u32 _gpio_direction = 0; _gpio_direction = _gpio_direction & CX23417_GPIO_MASK; - _gpio_direction = _gpio_direction|gpio_direction; + _gpio_direction = _gpio_direction | gpio_direction; status = cx231xx_send_gpio_cmd(dev, _gpio_direction, (u8 *)&value, 4, 0, 0); return status; } -static int getITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 *pValue) + +static int get_itvc_reg(struct cx231xx *dev, u32 gpio_direction, u32 *val_ptr) { int status = 0; u32 _gpio_direction = 0; _gpio_direction = _gpio_direction & CX23417_GPIO_MASK; - _gpio_direction = _gpio_direction|gpio_direction; + _gpio_direction = _gpio_direction | gpio_direction; status = cx231xx_send_gpio_cmd(dev, _gpio_direction, - (u8 *)pValue, 4, 0, 1); + (u8 *)val_ptr, 4, 0, 1); return status; } -static int waitForMciComplete(struct cx231xx *dev) +static int wait_for_mci_complete(struct cx231xx *dev) { u32 gpio; - u32 gpio_driection = 0; + u32 gpio_direction = 0; u8 count = 0; - getITVCReg(dev, gpio_driection, &gpio); + get_itvc_reg(dev, gpio_direction, &gpio); while (!(gpio&0x020000)) { msleep(10); - getITVCReg(dev, gpio_driection, &gpio); + get_itvc_reg(dev, gpio_direction, &gpio); if (count++ > 100) { dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio); @@ -345,57 +370,57 @@ static int mc417_register_write(struct cx231xx *dev, u16 address, u32 value) u32 temp; int status = 0; - temp = 0x82|MCI_REGISTER_DATA_BYTE0|((value&0x000000FF)<<8); - temp = temp<<10; - status = setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = 0x82 | MCI_REGISTER_DATA_BYTE0 | ((value & 0x000000FF) << 8); + temp = temp << 10; + status = set_itvc_reg(dev, ITVC_WRITE_DIR, temp); if (status < 0) return status; - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*write data byte 1;*/ - temp = 0x82|MCI_REGISTER_DATA_BYTE1|(value&0x0000FF00); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = 0x82 | MCI_REGISTER_DATA_BYTE1 | (value & 0x0000FF00); + temp = temp << 10; + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*write data byte 2;*/ - temp = 0x82|MCI_REGISTER_DATA_BYTE2|((value&0x00FF0000)>>8); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = 0x82 | MCI_REGISTER_DATA_BYTE2 | ((value & 0x00FF0000) >> 8); + temp = temp << 10; + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*write data byte 3;*/ - temp = 0x82|MCI_REGISTER_DATA_BYTE3|((value&0xFF000000)>>16); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = 0x82 | MCI_REGISTER_DATA_BYTE3 | ((value & 0xFF000000) >> 16); + temp = temp << 10; + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*write address byte 0;*/ - temp = 0x82|MCI_REGISTER_ADDRESS_BYTE0|((address&0x000000FF)<<8); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x000000FF) << 8); + temp = temp << 10; + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*write address byte 1;*/ - temp = 0x82|MCI_REGISTER_ADDRESS_BYTE1|(address&0x0000FF00); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0x0000FF00); + temp = temp << 10; + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*Write that the mode is write.*/ temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_WRITE; - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp << 10; + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); - return waitForMciComplete(dev); + return wait_for_mci_complete(dev); } static int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value) @@ -407,70 +432,68 @@ static int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value) temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x00FF) << 8); temp = temp << 10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); temp = temp | ((0x05) << 10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*write address byte 1;*/ temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0xFF00); temp = temp << 10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); temp = temp | ((0x05) << 10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*write that the mode is read;*/ temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_READ; temp = temp << 10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); temp = temp | ((0x05) << 10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*wait for the MIRDY line to be asserted , signalling that the read is done;*/ - ret = waitForMciComplete(dev); + ret = wait_for_mci_complete(dev); /*switch the DATA- GPIO to input mode;*/ /*Read data byte 0;*/ temp = (0x82 | MCI_REGISTER_DATA_BYTE0) << 10; - setITVCReg(dev, ITVC_READ_DIR, temp); + set_itvc_reg(dev, ITVC_READ_DIR, temp); temp = ((0x81 | MCI_REGISTER_DATA_BYTE0) << 10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); + set_itvc_reg(dev, ITVC_READ_DIR, temp); + get_itvc_reg(dev, ITVC_READ_DIR, &temp); return_value |= ((temp & 0x03FC0000) >> 18); - setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10)); + set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10)); /* Read data byte 1;*/ temp = (0x82 | MCI_REGISTER_DATA_BYTE1) << 10; - setITVCReg(dev, ITVC_READ_DIR, temp); + set_itvc_reg(dev, ITVC_READ_DIR, temp); temp = ((0x81 | MCI_REGISTER_DATA_BYTE1) << 10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); + set_itvc_reg(dev, ITVC_READ_DIR, temp); + get_itvc_reg(dev, ITVC_READ_DIR, &temp); return_value |= ((temp & 0x03FC0000) >> 10); - setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10)); + set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10)); /*Read data byte 2;*/ temp = (0x82 | MCI_REGISTER_DATA_BYTE2) << 10; - setITVCReg(dev, ITVC_READ_DIR, temp); + set_itvc_reg(dev, ITVC_READ_DIR, temp); temp = ((0x81 | MCI_REGISTER_DATA_BYTE2) << 10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); + set_itvc_reg(dev, ITVC_READ_DIR, temp); + get_itvc_reg(dev, ITVC_READ_DIR, &temp); return_value |= ((temp & 0x03FC0000) >> 2); - setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10)); + set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10)); /*Read data byte 3;*/ temp = (0x82 | MCI_REGISTER_DATA_BYTE3) << 10; - setITVCReg(dev, ITVC_READ_DIR, temp); + set_itvc_reg(dev, ITVC_READ_DIR, temp); temp = ((0x81 | MCI_REGISTER_DATA_BYTE3) << 10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); + set_itvc_reg(dev, ITVC_READ_DIR, temp); + get_itvc_reg(dev, ITVC_READ_DIR, &temp); return_value |= ((temp & 0x03FC0000) << 6); - setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10)); + set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10)); *value = return_value; - - return ret; } @@ -481,59 +504,59 @@ static int mc417_memory_write(struct cx231xx *dev, u32 address, u32 value) u32 temp; int ret = 0; - temp = 0x82 | MCI_MEMORY_DATA_BYTE0|((value & 0x000000FF) << 8); + temp = 0x82 | MCI_MEMORY_DATA_BYTE0 | ((value & 0x000000FF) << 8); temp = temp << 10; - ret = setITVCReg(dev, ITVC_WRITE_DIR, temp); + ret = set_itvc_reg(dev, ITVC_WRITE_DIR, temp); if (ret < 0) return ret; - temp = temp | ((0x05) << 10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*write data byte 1;*/ temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00); temp = temp << 10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp | ((0x05) << 10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*write data byte 2;*/ - temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = 0x82 | MCI_MEMORY_DATA_BYTE2 | ((value & 0x00FF0000) >> 8); + temp = temp << 10; + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*write data byte 3;*/ - temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = 0x82 | MCI_MEMORY_DATA_BYTE3 | ((value & 0xFF000000) >> 16); + temp = temp << 10; + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /* write address byte 2;*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE | - ((address & 0x003F0000)>>8); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE | + ((address & 0x003F0000) >> 8); + temp = temp << 10; + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /* write address byte 1;*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00); + temp = temp << 10; + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /* write address byte 0;*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8); + temp = temp << 10; + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*wait for MIRDY line;*/ - waitForMciComplete(dev); + wait_for_mci_complete(dev); return 0; } @@ -545,68 +568,68 @@ static int mc417_memory_read(struct cx231xx *dev, u32 address, u32 *value) int ret = 0; /*write address byte 2;*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ | - ((address & 0x003F0000)>>8); - temp = temp<<10; - ret = setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ | + ((address & 0x003F0000) >> 8); + temp = temp << 10; + ret = set_itvc_reg(dev, ITVC_WRITE_DIR, temp); if (ret < 0) return ret; - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*write address byte 1*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00); + temp = temp << 10; + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*write address byte 0*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF)<<8); - temp = temp<<10; - setITVCReg(dev, ITVC_WRITE_DIR, temp); - temp = temp|((0x05)<<10); - setITVCReg(dev, ITVC_WRITE_DIR, temp); + temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8); + temp = temp << 10; + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); + temp = temp | (0x05 << 10); + set_itvc_reg(dev, ITVC_WRITE_DIR, temp); /*Wait for MIRDY line*/ - ret = waitForMciComplete(dev); + ret = wait_for_mci_complete(dev); /*Read data byte 3;*/ - temp = (0x82|MCI_MEMORY_DATA_BYTE3)<<10; - setITVCReg(dev, ITVC_READ_DIR, temp); - temp = ((0x81|MCI_MEMORY_DATA_BYTE3)<<10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); - return_value |= ((temp&0x03FC0000)<<6); - setITVCReg(dev, ITVC_READ_DIR, (0x87<<10)); + temp = (0x82 | MCI_MEMORY_DATA_BYTE3) << 10; + set_itvc_reg(dev, ITVC_READ_DIR, temp); + temp = ((0x81 | MCI_MEMORY_DATA_BYTE3) << 10); + set_itvc_reg(dev, ITVC_READ_DIR, temp); + get_itvc_reg(dev, ITVC_READ_DIR, &temp); + return_value |= ((temp & 0x03FC0000) << 6); + set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10)); /*Read data byte 2;*/ - temp = (0x82|MCI_MEMORY_DATA_BYTE2)<<10; - setITVCReg(dev, ITVC_READ_DIR, temp); - temp = ((0x81|MCI_MEMORY_DATA_BYTE2)<<10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); - return_value |= ((temp&0x03FC0000)>>2); - setITVCReg(dev, ITVC_READ_DIR, (0x87<<10)); + temp = (0x82 | MCI_MEMORY_DATA_BYTE2) << 10; + set_itvc_reg(dev, ITVC_READ_DIR, temp); + temp = ((0x81 | MCI_MEMORY_DATA_BYTE2) << 10); + set_itvc_reg(dev, ITVC_READ_DIR, temp); + get_itvc_reg(dev, ITVC_READ_DIR, &temp); + return_value |= ((temp & 0x03FC0000) >> 2); + set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10)); /* Read data byte 1;*/ - temp = (0x82|MCI_MEMORY_DATA_BYTE1)<<10; - setITVCReg(dev, ITVC_READ_DIR, temp); - temp = ((0x81|MCI_MEMORY_DATA_BYTE1)<<10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); - return_value |= ((temp&0x03FC0000)>>10); - setITVCReg(dev, ITVC_READ_DIR, (0x87<<10)); + temp = (0x82 | MCI_MEMORY_DATA_BYTE1) << 10; + set_itvc_reg(dev, ITVC_READ_DIR, temp); + temp = ((0x81 | MCI_MEMORY_DATA_BYTE1) << 10); + set_itvc_reg(dev, ITVC_READ_DIR, temp); + get_itvc_reg(dev, ITVC_READ_DIR, &temp); + return_value |= ((temp & 0x03FC0000) >> 10); + set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10)); /*Read data byte 0;*/ - temp = (0x82|MCI_MEMORY_DATA_BYTE0)<<10; - setITVCReg(dev, ITVC_READ_DIR, temp); - temp = ((0x81|MCI_MEMORY_DATA_BYTE0)<<10); - setITVCReg(dev, ITVC_READ_DIR, temp); - getITVCReg(dev, ITVC_READ_DIR, &temp); - return_value |= ((temp&0x03FC0000)>>18); - setITVCReg(dev, ITVC_READ_DIR, (0x87<<10)); + temp = (0x82 | MCI_MEMORY_DATA_BYTE0) << 10; + set_itvc_reg(dev, ITVC_READ_DIR, temp); + temp = ((0x81 | MCI_MEMORY_DATA_BYTE0) << 10); + set_itvc_reg(dev, ITVC_READ_DIR, temp); + get_itvc_reg(dev, ITVC_READ_DIR, &temp); + return_value |= ((temp & 0x03FC0000) >> 18); + set_itvc_reg(dev, ITVC_READ_DIR, (0x87 << 10)); *value = return_value; return ret; @@ -619,94 +642,91 @@ static char *cmd_to_str(int cmd) { switch (cmd) { case CX2341X_ENC_PING_FW: - return "PING_FW"; + return "PING_FW"; case CX2341X_ENC_START_CAPTURE: - return "START_CAPTURE"; + return "START_CAPTURE"; case CX2341X_ENC_STOP_CAPTURE: - return "STOP_CAPTURE"; + return "STOP_CAPTURE"; case CX2341X_ENC_SET_AUDIO_ID: - return "SET_AUDIO_ID"; + return "SET_AUDIO_ID"; case CX2341X_ENC_SET_VIDEO_ID: - return "SET_VIDEO_ID"; + return "SET_VIDEO_ID"; case CX2341X_ENC_SET_PCR_ID: - return "SET_PCR_PID"; + return "SET_PCR_PID"; case CX2341X_ENC_SET_FRAME_RATE: - return "SET_FRAME_RATE"; + return "SET_FRAME_RATE"; case CX2341X_ENC_SET_FRAME_SIZE: - return "SET_FRAME_SIZE"; + return "SET_FRAME_SIZE"; case CX2341X_ENC_SET_BIT_RATE: - return "SET_BIT_RATE"; + return "SET_BIT_RATE"; case CX2341X_ENC_SET_GOP_PROPERTIES: - return "SET_GOP_PROPERTIES"; + return "SET_GOP_PROPERTIES"; case CX2341X_ENC_SET_ASPECT_RATIO: - return "SET_ASPECT_RATIO"; + return "SET_ASPECT_RATIO"; case CX2341X_ENC_SET_DNR_FILTER_MODE: - return "SET_DNR_FILTER_PROPS"; + return "SET_DNR_FILTER_PROPS"; case CX2341X_ENC_SET_DNR_FILTER_PROPS: - return "SET_DNR_FILTER_PROPS"; + return "SET_DNR_FILTER_PROPS"; case CX2341X_ENC_SET_CORING_LEVELS: - return "SET_CORING_LEVELS"; + return "SET_CORING_LEVELS"; case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE: - return "SET_SPATIAL_FILTER_TYPE"; + return "SET_SPATIAL_FILTER_TYPE"; case CX2341X_ENC_SET_VBI_LINE: - return "SET_VBI_LINE"; + return "SET_VBI_LINE"; case CX2341X_ENC_SET_STREAM_TYPE: - return "SET_STREAM_TYPE"; + return "SET_STREAM_TYPE"; case CX2341X_ENC_SET_OUTPUT_PORT: - return "SET_OUTPUT_PORT"; + return "SET_OUTPUT_PORT"; case CX2341X_ENC_SET_AUDIO_PROPERTIES: - return "SET_AUDIO_PROPERTIES"; + return "SET_AUDIO_PROPERTIES"; case CX2341X_ENC_HALT_FW: - return "HALT_FW"; + return "HALT_FW"; case CX2341X_ENC_GET_VERSION: - return "GET_VERSION"; + return "GET_VERSION"; case CX2341X_ENC_SET_GOP_CLOSURE: - return "SET_GOP_CLOSURE"; + return "SET_GOP_CLOSURE"; case CX2341X_ENC_GET_SEQ_END: - return "GET_SEQ_END"; + return "GET_SEQ_END"; case CX2341X_ENC_SET_PGM_INDEX_INFO: - return "SET_PGM_INDEX_INFO"; + return "SET_PGM_INDEX_INFO"; case CX2341X_ENC_SET_VBI_CONFIG: - return "SET_VBI_CONFIG"; + return "SET_VBI_CONFIG"; case CX2341X_ENC_SET_DMA_BLOCK_SIZE: - return "SET_DMA_BLOCK_SIZE"; + return "SET_DMA_BLOCK_SIZE"; case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10: - return "GET_PREV_DMA_INFO_MB_10"; + return "GET_PREV_DMA_INFO_MB_10"; case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9: - return "GET_PREV_DMA_INFO_MB_9"; + return "GET_PREV_DMA_INFO_MB_9"; case CX2341X_ENC_SCHED_DMA_TO_HOST: - return "SCHED_DMA_TO_HOST"; + return "SCHED_DMA_TO_HOST"; case CX2341X_ENC_INITIALIZE_INPUT: - return "INITIALIZE_INPUT"; + return "INITIALIZE_INPUT"; case CX2341X_ENC_SET_FRAME_DROP_RATE: - return "SET_FRAME_DROP_RATE"; + return "SET_FRAME_DROP_RATE"; case CX2341X_ENC_PAUSE_ENCODER: - return "PAUSE_ENCODER"; + return "PAUSE_ENCODER"; case CX2341X_ENC_REFRESH_INPUT: - return "REFRESH_INPUT"; + return "REFRESH_INPUT"; case CX2341X_ENC_SET_COPYRIGHT: - return "SET_COPYRIGHT"; + return "SET_COPYRIGHT"; case CX2341X_ENC_SET_EVENT_NOTIFICATION: - return "SET_EVENT_NOTIFICATION"; + return "SET_EVENT_NOTIFICATION"; case CX2341X_ENC_SET_NUM_VSYNC_LINES: - return "SET_NUM_VSYNC_LINES"; + return "SET_NUM_VSYNC_LINES"; case CX2341X_ENC_SET_PLACEHOLDER: - return "SET_PLACEHOLDER"; + return "SET_PLACEHOLDER"; case CX2341X_ENC_MUTE_VIDEO: - return "MUTE_VIDEO"; + return "MUTE_VIDEO"; case CX2341X_ENC_MUTE_AUDIO: - return "MUTE_AUDIO"; + return "MUTE_AUDIO"; case CX2341X_ENC_MISC: - return "MISC"; + return "MISC"; default: return "UNKNOWN"; } } -static int cx231xx_mbox_func(void *priv, - u32 command, - int in, - int out, +static int cx231xx_mbox_func(void *priv, u32 command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) { struct cx231xx *dev = priv; @@ -721,10 +741,8 @@ static int cx231xx_mbox_func(void *priv, without side effects */ mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value); if (value != 0x12345678) { - dprintk(3, - "Firmware and/or mailbox pointer not initialized " - "or corrupted, signature = 0x%x, cmd = %s\n", value, - cmd_to_str(command)); + dprintk(3, "Firmware and/or mailbox pointer not initialized or corrupted, signature = 0x%x, cmd = %s\n", + value, cmd_to_str(command)); return -1; } @@ -733,8 +751,8 @@ static int cx231xx_mbox_func(void *priv, */ mc417_memory_read(dev, dev->cx23417_mailbox, &flag); if (flag) { - dprintk(3, "ERROR: Mailbox appears to be in use " - "(%x), cmd = %s\n", flag, cmd_to_str(command)); + dprintk(3, "ERROR: Mailbox appears to be in use (%x), cmd = %s\n", + flag, cmd_to_str(command)); return -1; } @@ -787,11 +805,8 @@ static int cx231xx_mbox_func(void *priv, /* We don't need to call the API often, so using just one * mailbox will probably suffice */ -static int cx231xx_api_cmd(struct cx231xx *dev, - u32 command, - u32 inputcnt, - u32 outputcnt, - ...) +static int cx231xx_api_cmd(struct cx231xx *dev, u32 command, + u32 inputcnt, u32 outputcnt, ...) { u32 data[CX2341X_MBOX_MAX_DATA]; va_list vargs; @@ -834,81 +849,80 @@ static int cx231xx_find_mailbox(struct cx231xx *dev) else signaturecnt = 0; if (4 == signaturecnt) { - dprintk(1, "Mailbox signature found at 0x%x\n", i+1); - return i+1; + dprintk(1, "Mailbox signature found at 0x%x\n", i + 1); + return i + 1; } } dprintk(3, "Mailbox signature values not found!\n"); return -1; } -static void mciWriteMemoryToGPIO(struct cx231xx *dev, u32 address, u32 value, +static void mci_write_memory_to_gpio(struct cx231xx *dev, u32 address, u32 value, u32 *p_fw_image) { - u32 temp = 0; int i = 0; - temp = 0x82|MCI_MEMORY_DATA_BYTE0|((value&0x000000FF)<<8); - temp = temp<<10; + temp = 0x82 | MCI_MEMORY_DATA_BYTE0 | ((value & 0x000000FF) << 8); + temp = temp << 10; *p_fw_image = temp; p_fw_image++; - temp = temp|((0x05)<<10); + temp = temp | (0x05 << 10); *p_fw_image = temp; p_fw_image++; /*write data byte 1;*/ - temp = 0x82|MCI_MEMORY_DATA_BYTE1|(value&0x0000FF00); - temp = temp<<10; + temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00); + temp = temp << 10; *p_fw_image = temp; p_fw_image++; - temp = temp|((0x05)<<10); + temp = temp | (0x05 << 10); *p_fw_image = temp; p_fw_image++; /*write data byte 2;*/ - temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8); - temp = temp<<10; + temp = 0x82 | MCI_MEMORY_DATA_BYTE2 | ((value & 0x00FF0000) >> 8); + temp = temp << 10; *p_fw_image = temp; p_fw_image++; - temp = temp|((0x05)<<10); + temp = temp | (0x05 << 10); *p_fw_image = temp; p_fw_image++; /*write data byte 3;*/ - temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16); - temp = temp<<10; + temp = 0x82 | MCI_MEMORY_DATA_BYTE3 | ((value & 0xFF000000) >> 16); + temp = temp << 10; *p_fw_image = temp; p_fw_image++; - temp = temp|((0x05)<<10); + temp = temp | (0x05 << 10); *p_fw_image = temp; p_fw_image++; /* write address byte 2;*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE | - ((address & 0x003F0000)>>8); - temp = temp<<10; + temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE | + ((address & 0x003F0000) >> 8); + temp = temp << 10; *p_fw_image = temp; p_fw_image++; - temp = temp|((0x05)<<10); + temp = temp | (0x05 << 10); *p_fw_image = temp; p_fw_image++; /* write address byte 1;*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00); - temp = temp<<10; + temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00); + temp = temp << 10; *p_fw_image = temp; p_fw_image++; - temp = temp|((0x05)<<10); + temp = temp | (0x05 << 10); *p_fw_image = temp; p_fw_image++; /* write address byte 0;*/ - temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8); - temp = temp<<10; + temp = 0x82 | MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF) << 8); + temp = temp << 10; *p_fw_image = temp; p_fw_image++; - temp = temp|((0x05)<<10); + temp = temp | (0x05 << 10); *p_fw_image = temp; p_fw_image++; @@ -971,8 +985,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev) IVTV_REG_APU, 0); if (retval != 0) { - printk(KERN_ERR "%s: Error with mc417_register_write\n", - __func__); + pr_err("%s: Error with mc417_register_write\n", __func__); return -1; } @@ -980,25 +993,21 @@ static int cx231xx_load_firmware(struct cx231xx *dev) &dev->udev->dev); if (retval != 0) { - printk(KERN_ERR - "ERROR: Hotplug firmware request failed (%s).\n", + pr_err("ERROR: Hotplug firmware request failed (%s).\n", CX231xx_FIRM_IMAGE_NAME); - printk(KERN_ERR "Please fix your hotplug setup, the board will " - "not work without firmware loaded!\n"); + pr_err("Please fix your hotplug setup, the board will not work without firmware loaded!\n"); return -1; } if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) { - printk(KERN_ERR "ERROR: Firmware size mismatch " - "(have %zd, expected %d)\n", + pr_err("ERROR: Firmware size mismatch (have %zd, expected %d)\n", firmware->size, CX231xx_FIRM_IMAGE_SIZE); release_firmware(firmware); return -1; } if (0 != memcmp(firmware->data, magic, 8)) { - printk(KERN_ERR - "ERROR: Firmware magic mismatch, wrong file?\n"); + pr_err("ERROR: Firmware magic mismatch, wrong file?\n"); release_firmware(firmware); return -1; } @@ -1013,7 +1022,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev) transfer_size += 4) { fw_data = *p_fw_data; - mciWriteMemoryToGPIO(dev, address, fw_data, p_current_fw); + mci_write_memory_to_gpio(dev, address, fw_data, p_current_fw); address = address + 1; p_current_fw += 20; p_fw_data += 1; @@ -1045,7 +1054,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev) retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); if (retval < 0) { - printk(KERN_ERR "%s: Error with mc417_register_write\n", + pr_err("%s: Error with mc417_register_write\n", __func__); return retval; } @@ -1057,7 +1066,7 @@ static int cx231xx_load_firmware(struct cx231xx *dev) retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8); if (retval < 0) { - printk(KERN_ERR "%s: Error with mc417_register_write\n", + pr_err("%s: Error with mc417_register_write\n", __func__); return retval; } @@ -1105,27 +1114,25 @@ static int cx231xx_initialize_codec(struct cx231xx *dev) dprintk(2, "%s() PING OK\n", __func__); retval = cx231xx_load_firmware(dev); if (retval < 0) { - printk(KERN_ERR "%s() f/w load failed\n", __func__); + pr_err("%s() f/w load failed\n", __func__); return retval; } retval = cx231xx_find_mailbox(dev); if (retval < 0) { - printk(KERN_ERR "%s() mailbox < 0, error\n", + pr_err("%s() mailbox < 0, error\n", __func__); return -1; } dev->cx23417_mailbox = retval; retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); if (retval < 0) { - printk(KERN_ERR - "ERROR: cx23417 firmware ping failed!\n"); + pr_err("ERROR: cx23417 firmware ping failed!\n"); return -1; } retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, &version); if (retval < 0) { - printk(KERN_ERR "ERROR: cx23417 firmware get encoder :" - "version failed!\n"); + pr_err("ERROR: cx23417 firmware get encoder: version failed!\n"); return -1; } dprintk(1, "cx23417 firmware version is 0x%08x\n", version); @@ -1134,7 +1141,7 @@ static int cx231xx_initialize_codec(struct cx231xx *dev) for (i = 0; i < 1; i++) { retval = mc417_register_read(dev, 0x20f8, &val); - dprintk(3, "***before enable656() VIM Capture Lines =%d ***\n", + dprintk(3, "***before enable656() VIM Capture Lines = %d ***\n", val); if (retval < 0) return retval; @@ -1202,7 +1209,7 @@ static int cx231xx_initialize_codec(struct cx231xx *dev) for (i = 0; i < 1; i++) { mc417_register_read(dev, 0x20f8, &val); - dprintk(3, "***VIM Capture Lines =%d ***\n", val); + dprintk(3, "***VIM Capture Lines =%d ***\n", val); } return 0; @@ -1250,91 +1257,85 @@ static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf) static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *urb, struct cx231xx_dmaqueue *dma_q) { - void *vbuf; - struct cx231xx_buffer *buf; - u32 tail_data = 0; - char *p_data; - - if (dma_q->mpeg_buffer_done == 0) { - if (list_empty(&dma_q->active)) - return; - - buf = list_entry(dma_q->active.next, - struct cx231xx_buffer, vb.queue); - dev->video_mode.isoc_ctl.buf = buf; - dma_q->mpeg_buffer_done = 1; - } - /* Fill buffer */ - buf = dev->video_mode.isoc_ctl.buf; - vbuf = videobuf_to_vmalloc(&buf->vb); - - if ((dma_q->mpeg_buffer_completed+len) < - mpeglines*mpeglinesize) { - if (dma_q->add_ps_package_head == - CX231XX_NEED_ADD_PS_PACKAGE_HEAD) { - memcpy(vbuf+dma_q->mpeg_buffer_completed, - dma_q->ps_head, 3); - dma_q->mpeg_buffer_completed = - dma_q->mpeg_buffer_completed + 3; - dma_q->add_ps_package_head = - CX231XX_NONEED_PS_PACKAGE_HEAD; - } - memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len); - dma_q->mpeg_buffer_completed = - dma_q->mpeg_buffer_completed + len; - } else { - dma_q->mpeg_buffer_done = 0; - - tail_data = - mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed; - memcpy(vbuf+dma_q->mpeg_buffer_completed, - data, tail_data); - - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - v4l2_get_timestamp(&buf->vb.ts); - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - dma_q->mpeg_buffer_completed = 0; - - if (len - tail_data > 0) { - p_data = data + tail_data; - dma_q->left_data_count = len - tail_data; - memcpy(dma_q->p_left_data, - p_data, len - tail_data); - } - - } - - return; -} - -static void buffer_filled(char *data, int len, struct urb *urb, - struct cx231xx_dmaqueue *dma_q) -{ - void *vbuf; - struct cx231xx_buffer *buf; + void *vbuf; + struct cx231xx_buffer *buf; + u32 tail_data = 0; + char *p_data; + if (dma_q->mpeg_buffer_done == 0) { if (list_empty(&dma_q->active)) return; - buf = list_entry(dma_q->active.next, - struct cx231xx_buffer, vb.queue); + struct cx231xx_buffer, vb.queue); + dev->video_mode.isoc_ctl.buf = buf; + dma_q->mpeg_buffer_done = 1; + } + /* Fill buffer */ + buf = dev->video_mode.isoc_ctl.buf; + vbuf = videobuf_to_vmalloc(&buf->vb); + + if ((dma_q->mpeg_buffer_completed+len) < + mpeglines*mpeglinesize) { + if (dma_q->add_ps_package_head == + CX231XX_NEED_ADD_PS_PACKAGE_HEAD) { + memcpy(vbuf+dma_q->mpeg_buffer_completed, + dma_q->ps_head, 3); + dma_q->mpeg_buffer_completed = + dma_q->mpeg_buffer_completed + 3; + dma_q->add_ps_package_head = + CX231XX_NONEED_PS_PACKAGE_HEAD; + } + memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len); + dma_q->mpeg_buffer_completed = + dma_q->mpeg_buffer_completed + len; + } else { + dma_q->mpeg_buffer_done = 0; + tail_data = + mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed; + memcpy(vbuf+dma_q->mpeg_buffer_completed, + data, tail_data); - /* Fill buffer */ - vbuf = videobuf_to_vmalloc(&buf->vb); - memcpy(vbuf, data, len); buf->vb.state = VIDEOBUF_DONE; buf->vb.field_count++; v4l2_get_timestamp(&buf->vb.ts); list_del(&buf->vb.queue); wake_up(&buf->vb.done); + dma_q->mpeg_buffer_completed = 0; + + if (len - tail_data > 0) { + p_data = data + tail_data; + dma_q->left_data_count = len - tail_data; + memcpy(dma_q->p_left_data, + p_data, len - tail_data); + } + } +} - return; +static void buffer_filled(char *data, int len, struct urb *urb, + struct cx231xx_dmaqueue *dma_q) +{ + void *vbuf; + struct cx231xx_buffer *buf; + + if (list_empty(&dma_q->active)) + return; + + buf = list_entry(dma_q->active.next, + struct cx231xx_buffer, vb.queue); + + /* Fill buffer */ + vbuf = videobuf_to_vmalloc(&buf->vb); + memcpy(vbuf, data, len); + buf->vb.state = VIDEOBUF_DONE; + buf->vb.field_count++; + v4l2_get_timestamp(&buf->vb.ts); + list_del(&buf->vb.queue); + wake_up(&buf->vb.done); } -static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb) + +static int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb) { struct cx231xx_dmaqueue *dma_q = urb->context; unsigned char *p_buffer; @@ -1359,11 +1360,9 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb) return 0; } -static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb) -{ - /*char *outp;*/ - /*struct cx231xx_buffer *buf;*/ +static int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb) +{ struct cx231xx_dmaqueue *dma_q = urb->context; unsigned char *p_buffer, *buffer; u32 buffer_size = 0; @@ -1394,8 +1393,6 @@ static int bb_buf_prepare(struct videobuf_queue *q, int rc = 0, urb_init = 0; int size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count; - dma_qq = &dev->video_mode.vidq; - if (0 != buf->vb.baddr && buf->vb.bsize < size) return -EINVAL; buf->vb.width = fh->dev->ts1.ts_packet_size; @@ -1521,6 +1518,7 @@ static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm) *norm = dev->encodernorm.id; return 0; } + static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) { struct cx231xx_fh *fh = file->private_data; @@ -1552,7 +1550,8 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) dprintk(3, "exit vidioc_s_std() i=0x%x\n", i); return 0; } -static const char *iname[] = { + +static const char * const iname[] = { [CX231XX_VMUX_COMPOSITE1] = "Composite1", [CX231XX_VMUX_SVIDEO] = "S-Video", [CX231XX_VMUX_TELEVISION] = "Television", @@ -1560,6 +1559,7 @@ static const char *iname[] = { [CX231XX_VMUX_DVB] = "DVB", [CX231XX_VMUX_DEBUG] = "for debug only", }; + static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { @@ -1572,7 +1572,6 @@ static int vidioc_enum_input(struct file *file, void *priv, if (i->index >= 4) return -EINVAL; - input = &cx231xx_boards[dev->model].input[i->index]; if (input->type == 0) @@ -1589,8 +1588,6 @@ static int vidioc_enum_input(struct file *file, void *priv, i->type = V4L2_INPUT_TYPE_TUNER; else i->type = V4L2_INPUT_TYPE_CAMERA; - - return 0; } @@ -1621,6 +1618,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, { struct cx231xx_fh *fh = file->private_data; struct cx231xx *dev = fh->dev; + dprintk(3, "enter vidioc_s_ctrl()\n"); /* Update the A/V core */ call_all(dev, core, s_ctrl, ctl); @@ -1631,7 +1629,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv, static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - if (f->index != 0) return -EINVAL; @@ -1717,22 +1714,22 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; + dprintk(3, "enter vidioc_streamon()\n"); - cx231xx_set_alt_setting(dev, INDEX_TS1, 0); - cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); - if (dev->USE_ISO) - cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS, - CX231XX_NUM_BUFS, - dev->video_mode.max_pkt_size, - cx231xx_isoc_copy); - else { - cx231xx_init_bulk(dev, 320, - 5, - dev->ts1_mode.max_pkt_size, - cx231xx_bulk_copy); - } + cx231xx_set_alt_setting(dev, INDEX_TS1, 0); + cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); + if (dev->USE_ISO) + cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS, + CX231XX_NUM_BUFS, + dev->video_mode.max_pkt_size, + cx231xx_isoc_copy); + else { + cx231xx_init_bulk(dev, 320, + 5, + dev->ts1_mode.max_pkt_size, + cx231xx_bulk_copy); + } dprintk(3, "exit vidioc_streamon()\n"); return videobuf_streamon(&fh->vidq); } @@ -1749,6 +1746,7 @@ static int vidioc_g_ext_ctrls(struct file *file, void *priv, { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; + dprintk(3, "enter vidioc_g_ext_ctrls()\n"); if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; @@ -1763,6 +1761,7 @@ static int vidioc_s_ext_ctrls(struct file *file, void *priv, struct cx231xx *dev = fh->dev; struct cx2341x_mpeg_params p; int err; + dprintk(3, "enter vidioc_s_ext_ctrls()\n"); if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; @@ -1776,9 +1775,6 @@ static int vidioc_s_ext_ctrls(struct file *file, void *priv, } return err; - - -return 0; } static int vidioc_try_ext_ctrls(struct file *file, void *priv, @@ -1788,6 +1784,7 @@ static int vidioc_try_ext_ctrls(struct file *file, void *priv, struct cx231xx *dev = fh->dev; struct cx2341x_mpeg_params p; int err; + dprintk(3, "enter vidioc_try_ext_ctrls()\n"); if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; @@ -1805,14 +1802,8 @@ static int vidioc_log_status(struct file *file, void *priv) char name[32 + 2]; snprintf(name, sizeof(name), "%s/2", dev->name); - dprintk(3, - "%s/2: ============ START LOG STATUS ============\n", - dev->name); call_all(dev, core, log_status); cx2341x_log_status(&dev->mpeg_params, name); - dprintk(3, - "%s/2: ============= END LOG STATUS =============\n", - dev->name); return 0; } @@ -1821,6 +1812,7 @@ static int vidioc_querymenu(struct file *file, void *priv, { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; + dprintk(3, "enter vidioc_querymenu()\n"); dprintk(3, "exit vidioc_querymenu()\n"); return cx231xx_querymenu(dev, a); @@ -1831,6 +1823,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; + dprintk(3, "enter vidioc_queryctrl()\n"); dprintk(3, "exit vidioc_queryctrl()\n"); return cx231xx_queryctrl(dev, c); @@ -1881,7 +1874,6 @@ static int mpeg_open(struct file *file) fh, &dev->lock); */ - cx231xx_set_alt_setting(dev, INDEX_VANC, 1); cx231xx_set_gpio_value(dev, 2, 0); @@ -1909,16 +1901,16 @@ static int mpeg_release(struct file *file) cx231xx_stop_TS1(dev); - /* do this before setting alternate! */ - if (dev->USE_ISO) - cx231xx_uninit_isoc(dev); - else - cx231xx_uninit_bulk(dev); - cx231xx_set_mode(dev, CX231XX_SUSPEND); + /* do this before setting alternate! */ + if (dev->USE_ISO) + cx231xx_uninit_isoc(dev); + else + cx231xx_uninit_bulk(dev); + cx231xx_set_mode(dev, CX231XX_SUSPEND); - cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - CX231xx_END_NOW, CX231xx_MPEG_CAPTURE, - CX231xx_RAW_BITS_NONE); + cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + CX231xx_END_NOW, CX231xx_MPEG_CAPTURE, + CX231xx_RAW_BITS_NONE); /* FIXME: Review this crap */ /* Shut device down on last close */ @@ -1950,7 +1942,6 @@ static ssize_t mpeg_read(struct file *file, char __user *data, struct cx231xx_fh *fh = file->private_data; struct cx231xx *dev = fh->dev; - /* Deal w/ A/V decoder * and mpeg encoder sync issues. */ /* Start mpeg encoder on first read. */ if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { @@ -1968,9 +1959,6 @@ static unsigned int mpeg_poll(struct file *file, struct poll_table_struct *wait) { struct cx231xx_fh *fh = file->private_data; - /*struct cx231xx *dev = fh->dev;*/ - - /*dprintk(2, "%s\n", __func__);*/ return videobuf_poll_stream(file, &fh->vidq, wait); } -- cgit v1.2.3 From b86d15440b683f8634c0cb26fc0861a5bc4913ac Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 29 Jan 2013 13:16:06 -0300 Subject: [media] cx231xx-417: share ioctls with cx231xx-video Share tuner, frequency, debug and input ioctls with cx231xx-video. These are all shared resources, so no need to implement them again. [mchehab@redhat.com: Fix merge conflict and a checkpatch issue] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-417.c | 113 +++++++----------------------- drivers/media/usb/cx231xx/cx231xx-video.c | 54 +++++++------- drivers/media/usb/cx231xx/cx231xx.h | 15 ++++ 3 files changed, 68 insertions(+), 114 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 2c05c8f41527..567d7ab1663d 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "cx231xx.h" @@ -1551,68 +1552,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) return 0; } -static const char * const iname[] = { - [CX231XX_VMUX_COMPOSITE1] = "Composite1", - [CX231XX_VMUX_SVIDEO] = "S-Video", - [CX231XX_VMUX_TELEVISION] = "Television", - [CX231XX_VMUX_CABLE] = "Cable TV", - [CX231XX_VMUX_DVB] = "DVB", - [CX231XX_VMUX_DEBUG] = "for debug only", -}; - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - struct cx231xx_input *input; - int n; - dprintk(3, "enter vidioc_enum_input()i->index=%d\n", i->index); - - if (i->index >= 4) - return -EINVAL; - - input = &cx231xx_boards[dev->model].input[i->index]; - - if (input->type == 0) - return -EINVAL; - - /* FIXME - * strcpy(i->name, input->name); */ - - n = i->index; - strcpy(i->name, iname[INPUT(n)->type]); - - if (input->type == CX231XX_VMUX_TELEVISION || - input->type == CX231XX_VMUX_CABLE) - i->type = V4L2_INPUT_TYPE_TUNER; - else - i->type = V4L2_INPUT_TYPE_CAMERA; - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct cx231xx_fh *fh = file->private_data; - struct cx231xx *dev = fh->dev; - - dprintk(3, "enter vidioc_s_input() i=%d\n", i); - - video_mux(dev, i); - - if (i >= 4) - return -EINVAL; - dev->input = i; - dprintk(3, "exit vidioc_s_input()\n"); - return 0; -} - static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctl) { @@ -1831,22 +1770,12 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int mpeg_open(struct file *file) { - int minor = video_devdata(file)->minor; - struct cx231xx *h, *dev = NULL; - /*struct list_head *list;*/ + struct video_device *vdev = video_devdata(file); + struct cx231xx *dev = video_drvdata(file); struct cx231xx_fh *fh; - /*u32 value = 0;*/ dprintk(2, "%s()\n", __func__); - list_for_each_entry(h, &cx231xx_devlist, devlist) { - if (h->v4l_device->minor == minor) - dev = h; - } - - if (dev == NULL) - return -ENODEV; - if (mutex_lock_interruptible(&dev->lock)) return -ERESTARTSYS; @@ -1858,7 +1787,8 @@ static int mpeg_open(struct file *file) } file->private_data = fh; - fh->dev = dev; + v4l2_fh_init(&fh->fh, vdev); + fh->dev = dev; videobuf_queue_vmalloc_init(&fh->vidq, &cx231xx_qops, @@ -1880,6 +1810,7 @@ static int mpeg_open(struct file *file) cx231xx_initialize_codec(dev); mutex_unlock(&dev->lock); + v4l2_fh_add(&fh->fh); cx231xx_start_TS1(dev); return 0; @@ -1892,11 +1823,6 @@ static int mpeg_release(struct file *file) dprintk(3, "mpeg_release()! dev=0x%p\n", dev); - if (!dev) { - dprintk(3, "abort!!!\n"); - return 0; - } - mutex_lock(&dev->lock); cx231xx_stop_TS1(dev); @@ -1930,7 +1856,8 @@ static int mpeg_release(struct file *file) videobuf_read_stop(&fh->vidq); videobuf_mmap_free(&fh->vidq); - file->private_data = NULL; + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); kfree(fh); mutex_unlock(&dev->lock); return 0; @@ -1986,9 +1913,13 @@ static struct v4l2_file_operations mpeg_fops = { static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_s_std = vidioc_s_std, .vidioc_g_std = vidioc_g_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, + .vidioc_g_tuner = cx231xx_g_tuner, + .vidioc_s_tuner = cx231xx_s_tuner, + .vidioc_g_frequency = cx231xx_g_frequency, + .vidioc_s_frequency = cx231xx_s_frequency, + .vidioc_enum_input = cx231xx_enum_input, + .vidioc_g_input = cx231xx_g_input, + .vidioc_s_input = cx231xx_s_input, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_querycap = cx231xx_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, @@ -2007,10 +1938,10 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_log_status = vidioc_log_status, .vidioc_querymenu = vidioc_querymenu, .vidioc_queryctrl = vidioc_queryctrl, -/* .vidioc_g_chip_ident = cx231xx_g_chip_ident,*/ + .vidioc_g_chip_ident = cx231xx_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG -/* .vidioc_g_register = cx231xx_g_register,*/ -/* .vidioc_s_register = cx231xx_s_register,*/ + .vidioc_g_register = cx231xx_g_register, + .vidioc_s_register = cx231xx_s_register, #endif }; @@ -2055,6 +1986,14 @@ static struct video_device *cx231xx_video_dev_alloc( vfd->v4l2_dev = &dev->v4l2_dev; vfd->lock = &dev->lock; vfd->release = video_device_release; + set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); + video_set_drvdata(vfd, dev); + if (dev->tuner_type == TUNER_ABSENT) { + v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(vfd, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(vfd, VIDIOC_G_TUNER); + v4l2_disable_ioctl(vfd, VIDIOC_S_TUNER); + } return vfd; diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index c199eae6bd3e..bdaa5e01bb47 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1036,7 +1036,7 @@ static const char *iname[] = { [CX231XX_VMUX_DEBUG] = "for debug only", }; -static int vidioc_enum_input(struct file *file, void *priv, +int cx231xx_enum_input(struct file *file, void *priv, struct v4l2_input *i) { struct cx231xx_fh *fh = priv; @@ -1076,7 +1076,7 @@ static int vidioc_enum_input(struct file *file, void *priv, return 0; } -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) +int cx231xx_g_input(struct file *file, void *priv, unsigned int *i) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; @@ -1086,7 +1086,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) return 0; } -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) +int cx231xx_s_input(struct file *file, void *priv, unsigned int i) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; @@ -1115,7 +1115,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) return 0; } -static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; @@ -1139,7 +1139,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return 0; } -static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +int cx231xx_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; @@ -1157,7 +1157,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return 0; } -static int vidioc_g_frequency(struct file *file, void *priv, +int cx231xx_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { struct cx231xx_fh *fh = priv; @@ -1171,7 +1171,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, return 0; } -static int vidioc_s_frequency(struct file *file, void *priv, +int cx231xx_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { struct cx231xx_fh *fh = priv; @@ -1227,8 +1227,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, return rc; } -static int vidioc_g_chip_ident(struct file *file, void *fh, - struct v4l2_dbg_chip_ident *chip) +int vidioc_g_chip_ident(struct file *file, void *fh, + struct v4l2_dbg_chip_ident *chip) { chip->ident = V4L2_IDENT_NONE; chip->revision = 0; @@ -1255,7 +1255,7 @@ static int vidioc_g_chip_ident(struct file *file, void *fh, if type == i2caddr, then is the 7-bit I2C address */ -static int vidioc_g_register(struct file *file, void *priv, +int cx231xx_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { struct cx231xx_fh *fh = priv; @@ -1402,7 +1402,7 @@ static int vidioc_g_register(struct file *file, void *priv, return ret; } -static int vidioc_s_register(struct file *file, void *priv, +int cx231xx_s_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { struct cx231xx_fh *fh = priv; @@ -1811,7 +1811,7 @@ static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev; - if (0 != t->index) + if (t->index) return -EINVAL; call_all(dev, tuner, s_tuner, t); @@ -2201,19 +2201,19 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_dqbuf = vidioc_dqbuf, .vidioc_s_std = vidioc_s_std, .vidioc_g_std = vidioc_g_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, + .vidioc_enum_input = cx231xx_enum_input, + .vidioc_g_input = cx231xx_g_input, + .vidioc_s_input = cx231xx_s_input, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_g_chip_ident = vidioc_g_chip_ident, + .vidioc_g_tuner = cx231xx_g_tuner, + .vidioc_s_tuner = cx231xx_s_tuner, + .vidioc_g_frequency = cx231xx_g_frequency, + .vidioc_s_frequency = cx231xx_s_frequency, + .vidioc_g_chip_ident = cx231xx_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, + .vidioc_g_register = cx231xx_g_register, + .vidioc_s_register = cx231xx_s_register, #endif .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, @@ -2240,12 +2240,12 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_querycap = cx231xx_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_s_tuner = radio_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_g_chip_ident = vidioc_g_chip_ident, + .vidioc_g_frequency = cx231xx_g_frequency, + .vidioc_s_frequency = cx231xx_s_frequency, + .vidioc_g_chip_ident = cx231xx_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, + .vidioc_g_register = cx231xx_g_register, + .vidioc_s_register = cx231xx_s_register, #endif .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index efc0d1cafd5d..6130e4f5924d 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -936,6 +936,21 @@ void cx231xx_init_extension(struct cx231xx *dev); void cx231xx_close_extension(struct cx231xx *dev); int cx231xx_querycap(struct file *file, void *priv, struct v4l2_capability *cap); +int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t); +int cx231xx_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t); +int cx231xx_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f); +int cx231xx_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f); +int cx231xx_enum_input(struct file *file, void *priv, + struct v4l2_input *i); +int cx231xx_g_input(struct file *file, void *priv, unsigned int *i); +int cx231xx_s_input(struct file *file, void *priv, unsigned int i); +int cx231xx_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip); +int cx231xx_g_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg); +int cx231xx_s_register(struct file *file, void *priv, + struct v4l2_dbg_register *reg); /* Provided by cx231xx-cards.c */ extern void cx231xx_pre_card_setup(struct cx231xx *dev); -- cgit v1.2.3 From 88b6ffedd90158173eb74c8f9169208277520cbc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 29 Jan 2013 13:18:09 -0300 Subject: [media] cx231xx-417: convert to the control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-417.c | 213 +++++++++++++------------------- drivers/media/usb/cx231xx/cx231xx.h | 2 +- 2 files changed, 86 insertions(+), 129 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 567d7ab1663d..49c842aa1f70 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -744,7 +745,7 @@ static int cx231xx_mbox_func(void *priv, u32 command, int in, int out, if (value != 0x12345678) { dprintk(3, "Firmware and/or mailbox pointer not initialized or corrupted, signature = 0x%x, cmd = %s\n", value, cmd_to_str(command)); - return -1; + return -EIO; } /* This read looks at 32 bits, but flag is only 8 bits. @@ -754,7 +755,7 @@ static int cx231xx_mbox_func(void *priv, u32 command, int in, int out, if (flag) { dprintk(3, "ERROR: Mailbox appears to be in use (%x), cmd = %s\n", flag, cmd_to_str(command)); - return -1; + return -EBUSY; } flag |= 1; /* tell 'em we're working on it */ @@ -783,7 +784,7 @@ static int cx231xx_mbox_func(void *priv, u32 command, int in, int out, break; if (time_after(jiffies, timeout)) { dprintk(3, "ERROR: API Mailbox timeout\n"); - return -1; + return -EIO; } udelay(10); } @@ -800,7 +801,7 @@ static int cx231xx_mbox_func(void *priv, u32 command, int in, int out, flag = 0; mc417_memory_write(dev, dev->cx23417_mailbox, flag); - return retval; + return 0; } /* We don't need to call the API often, so using just one @@ -829,6 +830,7 @@ static int cx231xx_api_cmd(struct cx231xx *dev, u32 command, return err; } + static int cx231xx_find_mailbox(struct cx231xx *dev) { u32 signature[4] = { @@ -1092,10 +1094,10 @@ static void cx231xx_codec_settings(struct cx231xx *dev) cx231xx_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, dev->ts1.height, dev->ts1.width); - dev->mpeg_params.width = dev->ts1.width; - dev->mpeg_params.height = dev->ts1.height; + dev->mpeg_ctrl_handler.width = dev->ts1.width; + dev->mpeg_ctrl_handler.height = dev->ts1.height; - cx2341x_update(dev, cx231xx_mbox_func, NULL, &dev->mpeg_params); + cx2341x_handler_setup(&dev->mpeg_ctrl_handler); cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1); cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1); @@ -1481,36 +1483,6 @@ static struct videobuf_queue_ops cx231xx_qops = { /* ------------------------------------------------------------------ */ -static const u32 *ctrl_classes[] = { - cx2341x_mpeg_ctrls, - NULL -}; - -static int cx231xx_queryctrl(struct cx231xx *dev, - struct v4l2_queryctrl *qctrl) -{ - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (qctrl->id == 0) - return -EINVAL; - - /* MPEG V4L2 controls */ - if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl)) - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - - return 0; -} - -static int cx231xx_querymenu(struct cx231xx *dev, - struct v4l2_querymenu *qmenu) -{ - struct v4l2_queryctrl qctrl; - - qctrl.id = qmenu->id; - cx231xx_queryctrl(dev, &qctrl); - return v4l2_ctrl_query_menu(qmenu, &qctrl, - cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id)); -} - static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm) { struct cx231xx_fh *fh = file->private_data; @@ -1537,12 +1509,12 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) dprintk(3, "encodernorm set to NTSC\n"); dev->norm = V4L2_STD_NTSC; dev->ts1.height = 480; - dev->mpeg_params.is_50hz = 0; + cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, false); } else { dprintk(3, "encodernorm set to PAL\n"); dev->norm = V4L2_STD_PAL_B; dev->ts1.height = 576; - dev->mpeg_params.is_50hz = 1; + cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, true); } call_all(dev, core, s_std, dev->norm); /* do mode control overrides */ @@ -1680,92 +1652,13 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return videobuf_streamoff(&fh->vidq); } -static int vidioc_g_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - - dprintk(3, "enter vidioc_g_ext_ctrls()\n"); - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - dprintk(3, "exit vidioc_g_ext_ctrls()\n"); - return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS); -} - -static int vidioc_s_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - struct cx2341x_mpeg_params p; - int err; - - dprintk(3, "enter vidioc_s_ext_ctrls()\n"); - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - p = dev->mpeg_params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); - if (err == 0) { - err = cx2341x_update(dev, cx231xx_mbox_func, - &dev->mpeg_params, &p); - dev->mpeg_params = p; - } - - return err; -} - -static int vidioc_try_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - struct cx2341x_mpeg_params p; - int err; - - dprintk(3, "enter vidioc_try_ext_ctrls()\n"); - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - p = dev->mpeg_params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); - dprintk(3, "exit vidioc_try_ext_ctrls() err=%d\n", err); - return err; -} - static int vidioc_log_status(struct file *file, void *priv) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; - char name[32 + 2]; - snprintf(name, sizeof(name), "%s/2", dev->name); call_all(dev, core, log_status); - cx2341x_log_status(&dev->mpeg_params, name); - return 0; -} - -static int vidioc_querymenu(struct file *file, void *priv, - struct v4l2_querymenu *a) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - - dprintk(3, "enter vidioc_querymenu()\n"); - dprintk(3, "exit vidioc_querymenu()\n"); - return cx231xx_querymenu(dev, a); -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct cx231xx_fh *fh = priv; - struct cx231xx *dev = fh->dev; - - dprintk(3, "enter vidioc_queryctrl()\n"); - dprintk(3, "exit vidioc_queryctrl()\n"); - return cx231xx_queryctrl(dev, c); + return v4l2_ctrl_log_status(file, priv); } static int mpeg_open(struct file *file) @@ -1885,9 +1778,23 @@ static ssize_t mpeg_read(struct file *file, char __user *data, static unsigned int mpeg_poll(struct file *file, struct poll_table_struct *wait) { + unsigned long req_events = poll_requested_events(wait); struct cx231xx_fh *fh = file->private_data; + struct cx231xx *dev = fh->dev; + unsigned int res = 0; - return videobuf_poll_stream(file, &fh->vidq, wait); + if (v4l2_event_pending(&fh->fh)) + res |= POLLPRI; + else + poll_wait(file, &fh->fh.wait, wait); + + if (!(req_events & (POLLIN | POLLRDNORM))) + return res; + + mutex_lock(&dev->lock); + res |= videobuf_poll_stream(file, &fh->vidq, wait); + mutex_unlock(&dev->lock); + return res; } static int mpeg_mmap(struct file *file, struct vm_area_struct *vma) @@ -1932,17 +1839,14 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_dqbuf = vidioc_dqbuf, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, - .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, - .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, .vidioc_log_status = vidioc_log_status, - .vidioc_querymenu = vidioc_querymenu, - .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_chip_ident = cx231xx_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = cx231xx_g_register, .vidioc_s_register = cx231xx_s_register, #endif + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device cx231xx_mpeg_template = { @@ -1950,7 +1854,7 @@ static struct video_device cx231xx_mpeg_template = { .fops = &mpeg_fops, .ioctl_ops = &mpeg_ioctl_ops, .minor = -1, - .tvnorms = CX231xx_NORMS, + .tvnorms = V4L2_STD_ALL, }; void cx231xx_417_unregister(struct cx231xx *dev) @@ -1963,10 +1867,44 @@ void cx231xx_417_unregister(struct cx231xx *dev) video_unregister_device(dev->v4l_device); else video_device_release(dev->v4l_device); + v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl); dev->v4l_device = NULL; } } +static int cx231xx_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) +{ + struct cx231xx *dev = container_of(cxhdl, struct cx231xx, mpeg_ctrl_handler); + int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; + struct v4l2_mbus_framefmt fmt; + + /* fix videodecoder resolution */ + fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); + fmt.height = cxhdl->height; + fmt.code = V4L2_MBUS_FMT_FIXED; + v4l2_subdev_call(dev->sd_cx25840, video, s_mbus_fmt, &fmt); + return 0; +} + +static int cx231xx_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx) +{ + static const u32 freqs[3] = { 44100, 48000, 32000 }; + struct cx231xx *dev = container_of(cxhdl, struct cx231xx, mpeg_ctrl_handler); + + /* The audio clock of the digitizer must match the codec sample + rate otherwise you get some very strange effects. */ + if (idx < ARRAY_SIZE(freqs)) + call_all(dev, audio, s_clock_freq, freqs[idx]); + return 0; +} + +static struct cx2341x_handler_ops cx231xx_ops = { + /* needed for the video clock freq */ + .s_audio_sampling_freq = cx231xx_s_audio_sampling_freq, + /* needed for setting up the video resolution */ + .s_video_encoding = cx231xx_s_video_encoding, +}; + static struct video_device *cx231xx_video_dev_alloc( struct cx231xx *dev, struct usb_device *usbdev, @@ -1987,6 +1925,7 @@ static struct video_device *cx231xx_video_dev_alloc( vfd->lock = &dev->lock; vfd->release = video_device_release; set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); + vfd->ctrl_handler = &dev->mpeg_ctrl_handler.hdl; video_set_drvdata(vfd, dev); if (dev->tuner_type == TUNER_ABSENT) { v4l2_disable_ioctl(vfd, VIDIOC_G_FREQUENCY); @@ -2016,10 +1955,27 @@ int cx231xx_417_register(struct cx231xx *dev) tsport->height = 576; tsport->width = 720; - cx2341x_fill_defaults(&dev->mpeg_params); + err = cx2341x_handler_init(&dev->mpeg_ctrl_handler, 50); + if (err) { + dprintk(3, "%s: can't init cx2341x controls\n", dev->name); + return err; + } + dev->mpeg_ctrl_handler.func = cx231xx_mbox_func; + dev->mpeg_ctrl_handler.priv = dev; + dev->mpeg_ctrl_handler.ops = &cx231xx_ops; + if (dev->sd_cx25840) + v4l2_ctrl_add_handler(&dev->mpeg_ctrl_handler.hdl, + dev->sd_cx25840->ctrl_handler, NULL); + if (dev->mpeg_ctrl_handler.hdl.error) { + err = dev->mpeg_ctrl_handler.hdl.error; + dprintk(3, "%s: can't add cx25840 controls\n", dev->name); + v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl); + return err; + } dev->norm = V4L2_STD_NTSC; - dev->mpeg_params.port = CX2341X_PORT_SERIAL; + dev->mpeg_ctrl_handler.port = CX2341X_PORT_SERIAL; + cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, false); /* Allocate and initialize V4L video device */ dev->v4l_device = cx231xx_video_dev_alloc(dev, @@ -2028,6 +1984,7 @@ int cx231xx_417_register(struct cx231xx *dev) VFL_TYPE_GRABBER, -1); if (err < 0) { dprintk(3, "%s: can't register mpeg device\n", dev->name); + v4l2_ctrl_handler_free(&dev->mpeg_ctrl_handler.hdl); return err; } diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 6130e4f5924d..0f92fd1ea794 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -612,6 +612,7 @@ struct cx231xx { struct v4l2_subdev *sd_tuner; struct v4l2_ctrl_handler ctrl_handler; struct v4l2_ctrl_handler radio_ctrl_handler; + struct cx2341x_handler mpeg_ctrl_handler; struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */ atomic_t stream_started; /* stream should be running if true */ @@ -715,7 +716,6 @@ struct cx231xx { u8 USE_ISO; struct cx231xx_tvnorm encodernorm; struct cx231xx_tsport ts1, ts2; - struct cx2341x_mpeg_params mpeg_params; struct video_device *v4l_device; atomic_t v4l_reader_count; u32 freq; -- cgit v1.2.3 From 4485ea917b06c63087f369a7139c39b27ad14d10 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 7 Feb 2013 11:07:40 -0300 Subject: [media] cx231xx: remove bogus driver prefix in log messages The prefix is generated automatically, so no need to provide it again. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-vbi.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index 46e3892557c2..1340ff268817 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -70,10 +70,10 @@ static inline void print_err_status(struct cx231xx *dev, int packet, int status) break; } if (packet < 0) { - cx231xx_err(DRIVER_NAME "URB status %d [%s].\n", status, + cx231xx_err("URB status %d [%s].\n", status, errmsg); } else { - cx231xx_err(DRIVER_NAME "URB packet %d, status %d [%s].\n", + cx231xx_err("URB packet %d, status %d [%s].\n", packet, status, errmsg); } } @@ -317,7 +317,7 @@ static void cx231xx_irq_vbi_callback(struct urb *urb) case -ESHUTDOWN: return; default: /* error */ - cx231xx_err(DRIVER_NAME "urb completition error %d.\n", + cx231xx_err("urb completition error %d.\n", urb->status); break; } @@ -332,7 +332,7 @@ static void cx231xx_irq_vbi_callback(struct urb *urb) urb->status = usb_submit_urb(urb, GFP_ATOMIC); if (urb->status) { - cx231xx_err(DRIVER_NAME "urb resubmit failed (error=%i)\n", + cx231xx_err("urb resubmit failed (error=%i)\n", urb->status); } } @@ -345,7 +345,7 @@ void cx231xx_uninit_vbi_isoc(struct cx231xx *dev) struct urb *urb; int i; - cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_uninit_vbi_isoc\n"); + cx231xx_info("called cx231xx_uninit_vbi_isoc\n"); dev->vbi_mode.bulk_ctl.nfields = -1; for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) { @@ -394,7 +394,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, struct urb *urb; int rc; - cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_prepare_isoc\n"); + cx231xx_info("called cx231xx_vbi_isoc\n"); /* De-allocates all pending stuff */ cx231xx_uninit_vbi_isoc(dev); @@ -442,8 +442,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { - cx231xx_err(DRIVER_NAME - ": cannot alloc bulk_ctl.urb %i\n", i); + cx231xx_err("cannot alloc bulk_ctl.urb %i\n", i); cx231xx_uninit_vbi_isoc(dev); return -ENOMEM; } @@ -453,8 +452,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, dev->vbi_mode.bulk_ctl.transfer_buffer[i] = kzalloc(sb_size, GFP_KERNEL); if (!dev->vbi_mode.bulk_ctl.transfer_buffer[i]) { - cx231xx_err(DRIVER_NAME - ": unable to allocate %i bytes for transfer" + cx231xx_err("unable to allocate %i bytes for transfer" " buffer %i%s\n", sb_size, i, in_interrupt() ? " while in int" : ""); cx231xx_uninit_vbi_isoc(dev); @@ -473,8 +471,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets, for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) { rc = usb_submit_urb(dev->vbi_mode.bulk_ctl.urb[i], GFP_ATOMIC); if (rc) { - cx231xx_err(DRIVER_NAME - ": submit of urb %i failed (error=%i)\n", i, + cx231xx_err("submit of urb %i failed (error=%i)\n", i, rc); cx231xx_uninit_vbi_isoc(dev); return rc; @@ -526,7 +523,7 @@ static inline void vbi_buffer_filled(struct cx231xx *dev, struct cx231xx_buffer *buf) { /* Advice that buffer was filled */ - /* cx231xx_info(DRIVER_NAME "[%p/%d] wakeup\n", buf, buf->vb.i); */ + /* cx231xx_info("[%p/%d] wakeup\n", buf, buf->vb.i); */ buf->vb.state = VIDEOBUF_DONE; buf->vb.field_count++; @@ -618,7 +615,7 @@ static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q, char *outp; if (list_empty(&dma_q->active)) { - cx231xx_err(DRIVER_NAME ": No active queue to serve\n"); + cx231xx_err("No active queue to serve\n"); dev->vbi_mode.bulk_ctl.buf = NULL; *buf = NULL; return; -- cgit v1.2.3 From b31077a88a1242541b1c9b191c238ac313609d9f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 7 Feb 2013 13:22:06 -0300 Subject: [media] cx231xx: disable 417 support from the Conexant video grabber The 417 support doesn't work. Until someone can dig into this driver to figure out why it isn't working the 417 support is disabled. Sometimes you can actually stream a bit, but very soon the whole machine crashes, so something is seriously wrong. For the record, this was not introduced by my recent changes to this driver, it was broken before that. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-cards.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index d6acb1ebff33..70944516125a 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -263,7 +263,10 @@ struct cx231xx_board cx231xx_boards[] = { .norm = V4L2_STD_PAL, .no_alt_vanc = 1, .external_av = 1, - .has_417 = 1, + /* Actually, it has a 417, but it isn't working correctly. + * So set to 0 for now until someone can manage to get this + * to work reliably. */ + .has_417 = 0, .input = {{ .type = CX231XX_VMUX_COMPOSITE1, -- cgit v1.2.3 From 720b3dfad42af96e3c937df8e167aac6c2901295 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 8 Feb 2013 11:48:41 -0300 Subject: [media] cx231xx: don't reset width/height on first open The last set width/height must be preserved as per the spec. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-video.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index bdaa5e01bb47..41c5c996ed2c 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1871,9 +1871,6 @@ static int cx231xx_v4l2_open(struct file *filp) v4l2_fh_init(&fh->fh, vdev); if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { - dev->width = norm_maxw(dev); - dev->height = norm_maxh(dev); - /* Power up in Analog TV mode */ if (dev->board.external_av) cx231xx_set_power_mode(dev, -- cgit v1.2.3 From fff9e818fb523804084cf8456f48ffbc56b70fbe Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 8 Feb 2013 12:43:25 -0300 Subject: [media] cx231xx: don't use port 3 on the Conexant video grabber It's not working reliably if port 3 is enabled. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-cards.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 70944516125a..62d104b98390 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -263,6 +263,7 @@ struct cx231xx_board cx231xx_boards[] = { .norm = V4L2_STD_PAL, .no_alt_vanc = 1, .external_av = 1, + .dont_use_port_3 = 1, /* Actually, it has a 417, but it isn't working correctly. * So set to 0 for now until someone can manage to get this * to work reliably. */ -- cgit v1.2.3 From 69a11a32643bda3e7f76af397cb6cd7b32c640f9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 7 Feb 2013 15:28:53 -0300 Subject: [media] cx231xx: fix big-endian problems Tested on my big-endian ppc-based test machine. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-audio.c | 4 ++-- drivers/media/usb/cx231xx/cx231xx-avcore.c | 8 ++++---- drivers/media/usb/cx231xx/cx231xx-cards.c | 16 ++++++++-------- drivers/media/usb/cx231xx/cx231xx-core.c | 2 +- drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c | 2 +- 5 files changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index b40360b8e89e..81a1d971d797 100644 --- a/drivers/media/usb/cx231xx/cx231xx-audio.c +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c @@ -704,8 +704,8 @@ static int cx231xx_audio_init(struct cx231xx *dev) audio_index + 1]; adev->end_point_addr = - le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc. - bEndpointAddress); + uif->altsetting[0].endpoint[isoc_pipe].desc. + bEndpointAddress; adev->num_alt = uif->num_altsetting; cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index 4706ed350293..3f26f64d7bf4 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c @@ -2221,7 +2221,7 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode) if (status < 0) return status; - tmp = *((u32 *) value); + tmp = le32_to_cpu(*((u32 *) value)); switch (mode) { case POLARIS_AVMODE_ENXTERNAL_AV: @@ -2442,7 +2442,7 @@ int cx231xx_power_suspend(struct cx231xx *dev) if (status > 0) return status; - tmp = *((u32 *) value); + tmp = le32_to_cpu(*((u32 *) value)); tmp &= (~PWR_MODE_MASK); value[0] = (u8) tmp; @@ -2470,7 +2470,7 @@ int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask) if (status < 0) return status; - tmp = *((u32 *) value); + tmp = le32_to_cpu(*((u32 *) value)); tmp |= ep_mask; value[0] = (u8) tmp; value[1] = (u8) (tmp >> 8); @@ -2495,7 +2495,7 @@ int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask) if (status < 0) return status; - tmp = *((u32 *) value); + tmp = le32_to_cpu(*((u32 *) value)); tmp &= (~ep_mask); value[0] = (u8) tmp; value[1] = (u8) (tmp >> 8); diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 62d104b98390..b7b1acd7e7b0 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -1189,8 +1189,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface, uif = udev->actconfig->interface[dev->current_pcb_config. hs_config_info[0].interface_info.video_index + 1]; - dev->video_mode.end_point_addr = le16_to_cpu(uif->altsetting[0]. - endpoint[isoc_pipe].desc.bEndpointAddress); + dev->video_mode.end_point_addr = uif->altsetting[0]. + endpoint[isoc_pipe].desc.bEndpointAddress; dev->video_mode.num_alt = uif->num_altsetting; cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", @@ -1223,8 +1223,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface, vanc_index + 1]; dev->vbi_mode.end_point_addr = - le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc. - bEndpointAddress); + uif->altsetting[0].endpoint[isoc_pipe].desc. + bEndpointAddress; dev->vbi_mode.num_alt = uif->num_altsetting; cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", @@ -1258,8 +1258,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface, hanc_index + 1]; dev->sliced_cc_mode.end_point_addr = - le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe].desc. - bEndpointAddress); + uif->altsetting[0].endpoint[isoc_pipe].desc. + bEndpointAddress; dev->sliced_cc_mode.num_alt = uif->num_altsetting; cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", @@ -1294,8 +1294,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface, ts1_index + 1]; dev->ts1_mode.end_point_addr = - le16_to_cpu(uif->altsetting[0].endpoint[isoc_pipe]. - desc.bEndpointAddress); + uif->altsetting[0].endpoint[isoc_pipe]. + desc.bEndpointAddress; dev->ts1_mode.num_alt = uif->num_altsetting; cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n", diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 05358d486135..4ba3ce09b713 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -1488,7 +1488,7 @@ int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode) if (status < 0) return status; - tmp = *((u32 *) value); + tmp = le32_to_cpu(*((u32 *) value)); tmp |= mode; value[0] = (u8) tmp; diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c index 7473c33e823e..d7308ab7a90f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c +++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c @@ -672,7 +672,7 @@ u32 initialize_cx231xx(struct cx231xx *dev) pcb config it is related to */ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT, data, 4); - config_info = *((u32 *) data); + config_info = le32_to_cpu(*((u32 *) data)); usb_speed = (u8) (config_info & 0x1); /* Verify this device belongs to Bus power or Self power device */ -- cgit v1.2.3 From 6b236a375d4764a6b7f7b83fb49bccacb7db4969 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 8 Feb 2013 13:13:12 -0300 Subject: [media] cx231xx: fix gpio big-endian problems Tested on my big-endian ppc-based test machine. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-avcore.c | 73 ++++++++++++++++-------------- drivers/media/usb/cx231xx/cx231xx.h | 2 - 2 files changed, 38 insertions(+), 37 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index 3f26f64d7bf4..2e51fb9fd21c 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c @@ -2638,20 +2638,23 @@ EXPORT_SYMBOL_GPL(cx231xx_capture_start); /***************************************************************************** * G P I O B I T control functions * ******************************************************************************/ -int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val) +static int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 gpio_val) { int status = 0; - status = cx231xx_send_gpio_cmd(dev, gpio_bit, gpio_val, 4, 0, 0); + gpio_val = cpu_to_le32(gpio_val); + status = cx231xx_send_gpio_cmd(dev, gpio_bit, (u8 *)&gpio_val, 4, 0, 0); return status; } -int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val) +static int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u32 *gpio_val) { + u32 tmp; int status = 0; - status = cx231xx_send_gpio_cmd(dev, gpio_bit, gpio_val, 4, 0, 1); + status = cx231xx_send_gpio_cmd(dev, gpio_bit, (u8 *)&tmp, 4, 0, 1); + *gpio_val = le32_to_cpu(tmp); return status; } @@ -2683,7 +2686,7 @@ int cx231xx_set_gpio_direction(struct cx231xx *dev, else value = dev->gpio_dir | (1 << pin_number); - status = cx231xx_set_gpio_bit(dev, value, (u8 *) &dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, value, dev->gpio_val); /* cache the value for future */ dev->gpio_dir = value; @@ -2717,7 +2720,7 @@ int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value) value = dev->gpio_dir | (1 << pin_number); dev->gpio_dir = value; status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *) &dev->gpio_val); + dev->gpio_val); value = 0; } @@ -2730,7 +2733,7 @@ int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value) dev->gpio_val = value; /* toggle bit0 of GP_IO */ - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); return status; } @@ -2748,7 +2751,7 @@ int cx231xx_gpio_i2c_start(struct cx231xx *dev) dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; dev->gpio_val |= 1 << dev->board.tuner_sda_gpio; - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); if (status < 0) return -EINVAL; @@ -2756,7 +2759,7 @@ int cx231xx_gpio_i2c_start(struct cx231xx *dev) dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); if (status < 0) return -EINVAL; @@ -2764,7 +2767,7 @@ int cx231xx_gpio_i2c_start(struct cx231xx *dev) dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); if (status < 0) return -EINVAL; @@ -2782,7 +2785,7 @@ int cx231xx_gpio_i2c_end(struct cx231xx *dev) dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); if (status < 0) return -EINVAL; @@ -2790,7 +2793,7 @@ int cx231xx_gpio_i2c_end(struct cx231xx *dev) dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); if (status < 0) return -EINVAL; @@ -2800,7 +2803,7 @@ int cx231xx_gpio_i2c_end(struct cx231xx *dev) dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio); status = - cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); if (status < 0) return -EINVAL; @@ -2822,33 +2825,33 @@ int cx231xx_gpio_i2c_write_byte(struct cx231xx *dev, u8 data) dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); + dev->gpio_val); /* set SCL to output 1; set SDA to output 0 */ dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); + dev->gpio_val); /* set SCL to output 0; set SDA to output 0 */ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); + dev->gpio_val); } else { /* set SCL to output 0; set SDA to output 1 */ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); dev->gpio_val |= 1 << dev->board.tuner_sda_gpio; status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); + dev->gpio_val); /* set SCL to output 1; set SDA to output 1 */ dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); + dev->gpio_val); /* set SCL to output 0; set SDA to output 1 */ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); + dev->gpio_val); } } return status; @@ -2867,17 +2870,17 @@ int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf) /* set SCL to output 0; set SDA to input */ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); + dev->gpio_val); /* set SCL to output 1; set SDA to input */ dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); + dev->gpio_val); /* get SDA data bit */ gpio_logic_value = dev->gpio_val; status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); + &dev->gpio_val); if ((dev->gpio_val & (1 << dev->board.tuner_sda_gpio)) != 0) value |= (1 << (8 - i - 1)); @@ -2888,7 +2891,7 @@ int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf) !!!set SDA to input, never to modify SDA direction at the same times */ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); /* store the value */ *buf = value & 0xff; @@ -2909,12 +2912,12 @@ int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev) dev->gpio_dir &= ~(1 << dev->board.tuner_scl_gpio); gpio_logic_value = dev->gpio_val; - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); do { msleep(2); status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, - (u8 *)&dev->gpio_val); + &dev->gpio_val); nCnt--; } while (((dev->gpio_val & (1 << dev->board.tuner_scl_gpio)) == 0) && @@ -2929,7 +2932,7 @@ int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev) * through clock stretch, slave has given a SCL signal, * so the SDA data can be directly read. */ - status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_get_gpio_bit(dev, dev->gpio_dir, &dev->gpio_val); if ((dev->gpio_val & 1 << dev->board.tuner_sda_gpio) == 0) { dev->gpio_val = gpio_logic_value; @@ -2945,7 +2948,7 @@ int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev) dev->gpio_val = gpio_logic_value; dev->gpio_dir |= (1 << dev->board.tuner_scl_gpio); dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); return status; } @@ -2956,24 +2959,24 @@ int cx231xx_gpio_i2c_write_ack(struct cx231xx *dev) /* set SDA to ouput */ dev->gpio_dir |= 1 << dev->board.tuner_sda_gpio; - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); /* set SCL = 0 (output); set SDA = 0 (output) */ dev->gpio_val &= ~(1 << dev->board.tuner_sda_gpio); dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); /* set SCL = 1 (output); set SDA = 0 (output) */ dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); /* set SCL = 0 (output); set SDA = 0 (output) */ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); /* set SDA to input,and then the slave will read data from SDA. */ dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); return status; } @@ -2985,15 +2988,15 @@ int cx231xx_gpio_i2c_write_nak(struct cx231xx *dev) /* set scl to output ; set sda to input */ dev->gpio_dir |= 1 << dev->board.tuner_scl_gpio; dev->gpio_dir &= ~(1 << dev->board.tuner_sda_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); /* set scl to output 0; set sda to input */ dev->gpio_val &= ~(1 << dev->board.tuner_scl_gpio); - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); /* set scl to output 1; set sda to input */ dev->gpio_val |= 1 << dev->board.tuner_scl_gpio; - status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, (u8 *)&dev->gpio_val); + status = cx231xx_set_gpio_bit(dev, dev->gpio_dir, dev->gpio_val); return status; } diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 0f92fd1ea794..a8e50d2d491c 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -845,8 +845,6 @@ int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus, /* Gpio related functions */ int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val, u8 len, u8 request, u8 direction); -int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val); -int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val); int cx231xx_set_gpio_value(struct cx231xx *dev, int pin_number, int pin_value); int cx231xx_set_gpio_direction(struct cx231xx *dev, int pin_number, int pin_value); -- cgit v1.2.3 From 2aeb73e19dc3d17beebc1b9a678f4c60e1072e25 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 12 Feb 2013 05:25:38 -0300 Subject: [media] stk-webcam: add ASUS F3JC to upside-down list And add an extensive comment relating the history of the upside-down handling in this driver. Signed-off-by: Hans Verkuil Tested-by: Arvydas Sidorenko Thanks-to: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-webcam.c | 40 +++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 4cbab085e348..b2a5ee453a6a 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -63,7 +63,39 @@ static struct usb_device_id stkwebcam_table[] = { }; MODULE_DEVICE_TABLE(usb, stkwebcam_table); -/* The stk webcam laptop module is mounted upside down in some laptops :( */ +/* + * The stk webcam laptop module is mounted upside down in some laptops :( + * + * Some background information (thanks to Hans de Goede for providing this): + * + * 1) Once upon a time the stkwebcam driver was written + * + * 2) The webcam in question was used mostly in Asus laptop models, including + * the laptop of the original author of the driver, and in these models, in + * typical Asus fashion (see the long long list for uvc cams inside v4l-utils), + * they mounted the webcam-module the wrong way up. So the hflip and vflip + * module options were given a default value of 1 (the correct value for + * upside down mounted models) + * + * 3) Years later I got a bug report from a user with a laptop with stkwebcam, + * where the module was actually mounted the right way up, and thus showed + * upside down under Linux. So now I was facing the choice of 2 options: + * + * a) Add a not-upside-down list to stkwebcam, which overrules the default. + * + * b) Do it like all the other drivers do, and make the default right for + * cams mounted the proper way and add an upside-down model list, with + * models where we need to flip-by-default. + * + * Despite knowing that going b) would cause a period of pain where we were + * building the table I opted to go for option b), since a) is just too ugly, + * and worse different from how every other driver does it leading to + * confusion in the long run. This change was made in kernel 3.6. + * + * So for any user report about upside-down images since kernel 3.6 ask them + * to provide the output of 'sudo dmidecode' so the laptop can be added in + * the table below. + */ static const struct dmi_system_id stk_upside_down_dmi_table[] = { { .ident = "ASUS G1", @@ -71,6 +103,12 @@ static const struct dmi_system_id stk_upside_down_dmi_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "G1") } + }, { + .ident = "ASUS F3JC", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "F3JC") + } }, {} }; -- cgit v1.2.3 From e144760a33e3f09ccf6f3abb186920753f27a998 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Feb 2013 09:30:49 -0300 Subject: [media] stk-webcam: remove bogus STD support It's a webcam, the STD API is not applicable to webcams. Signed-off-by: Hans Verkuil Tested-by: Arvydas Sidorenko Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-webcam.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index b2a5ee453a6a..e9dbe23122c3 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -806,12 +806,6 @@ static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i) return 0; } -/* from vivi.c */ -static int stk_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a) -{ - return 0; -} - /* List of all V4Lv2 controls supported by the driver */ static struct v4l2_queryctrl stk_controls[] = { { @@ -1263,7 +1257,6 @@ static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = { .vidioc_enum_input = stk_vidioc_enum_input, .vidioc_s_input = stk_vidioc_s_input, .vidioc_g_input = stk_vidioc_g_input, - .vidioc_s_std = stk_vidioc_s_std, .vidioc_reqbufs = stk_vidioc_reqbufs, .vidioc_querybuf = stk_vidioc_querybuf, .vidioc_qbuf = stk_vidioc_qbuf, @@ -1289,8 +1282,6 @@ static void stk_v4l_dev_release(struct video_device *vd) static struct video_device stk_v4l_data = { .name = "stkwebcam", - .tvnorms = V4L2_STD_UNKNOWN, - .current_norm = V4L2_STD_UNKNOWN, .fops = &v4l_stk_fops, .ioctl_ops = &v4l_stk_ioctl_ops, .release = stk_v4l_dev_release, -- cgit v1.2.3 From 968c60f60376a573460b6ef4991435d09528d48c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Feb 2013 08:17:42 -0300 Subject: [media] stk-webcam: add support for struct v4l2_device Signed-off-by: Hans Verkuil Tested-by: Arvydas Sidorenko Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-webcam.c | 10 +++++++++- drivers/media/usb/stkwebcam/stk-webcam.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index e9dbe23122c3..eaf152c51ae2 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -1294,7 +1294,7 @@ static int stk_register_video_device(struct stk_camera *dev) dev->vdev = stk_v4l_data; dev->vdev.debug = debug; - dev->vdev.parent = &dev->interface->dev; + dev->vdev.v4l2_dev = &dev->v4l2_dev; err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); if (err) STK_ERROR("v4l registration failed\n"); @@ -1323,6 +1323,12 @@ static int stk_camera_probe(struct usb_interface *interface, STK_ERROR("Out of memory !\n"); return -ENOMEM; } + err = v4l2_device_register(&interface->dev, &dev->v4l2_dev); + if (err < 0) { + dev_err(&udev->dev, "couldn't register v4l2_device\n"); + kfree(dev); + return err; + } spin_lock_init(&dev->spinlock); init_waitqueue_head(&dev->wait_frame); @@ -1383,6 +1389,7 @@ static int stk_camera_probe(struct usb_interface *interface, return 0; error: + v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); return err; } @@ -1400,6 +1407,7 @@ static void stk_camera_disconnect(struct usb_interface *interface) video_device_node_name(&dev->vdev)); video_unregister_device(&dev->vdev); + v4l2_device_unregister(&dev->v4l2_dev); } #ifdef CONFIG_PM diff --git a/drivers/media/usb/stkwebcam/stk-webcam.h b/drivers/media/usb/stkwebcam/stk-webcam.h index 9f6736637571..49ebe855cba6 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.h +++ b/drivers/media/usb/stkwebcam/stk-webcam.h @@ -23,6 +23,7 @@ #define STKWEBCAM_H #include +#include #include #define DRIVER_VERSION "v0.0.1" @@ -91,6 +92,7 @@ struct regval { }; struct stk_camera { + struct v4l2_device v4l2_dev; struct video_device vdev; struct usb_device *udev; struct usb_interface *interface; -- cgit v1.2.3 From dc0fb28675e7ef7ac12a5532500b2f89e41f2174 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Feb 2013 08:53:11 -0300 Subject: [media] stk-webcam: convert to the control framework Signed-off-by: Hans Verkuil Tested-by: Arvydas Sidorenko Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-webcam.c | 119 ++++++++----------------------- drivers/media/usb/stkwebcam/stk-webcam.h | 3 +- 2 files changed, 33 insertions(+), 89 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index eaf152c51ae2..f1cf9060ce71 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -806,99 +806,25 @@ static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i) return 0; } -/* List of all V4Lv2 controls supported by the driver */ -static struct v4l2_queryctrl stk_controls[] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 0xffff, - .step = 0x0100, - .default_value = 0x6000, - }, - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Horizontal Flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vertical Flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, -}; - -static int stk_vidioc_queryctrl(struct file *filp, - void *priv, struct v4l2_queryctrl *c) +static int stk_s_ctrl(struct v4l2_ctrl *ctrl) { - int i; - int nbr; - nbr = ARRAY_SIZE(stk_controls); - - for (i = 0; i < nbr; i++) { - if (stk_controls[i].id == c->id) { - memcpy(c, &stk_controls[i], - sizeof(struct v4l2_queryctrl)); - return 0; - } - } - return -EINVAL; -} - -static int stk_vidioc_g_ctrl(struct file *filp, - void *priv, struct v4l2_control *c) -{ - struct stk_camera *dev = priv; - switch (c->id) { - case V4L2_CID_BRIGHTNESS: - c->value = dev->vsettings.brightness; - break; - case V4L2_CID_HFLIP: - if (dmi_check_system(stk_upside_down_dmi_table)) - c->value = !dev->vsettings.hflip; - else - c->value = dev->vsettings.hflip; - break; - case V4L2_CID_VFLIP: - if (dmi_check_system(stk_upside_down_dmi_table)) - c->value = !dev->vsettings.vflip; - else - c->value = dev->vsettings.vflip; - break; - default: - return -EINVAL; - } - return 0; -} + struct stk_camera *dev = + container_of(ctrl->handler, struct stk_camera, hdl); -static int stk_vidioc_s_ctrl(struct file *filp, - void *priv, struct v4l2_control *c) -{ - struct stk_camera *dev = priv; - switch (c->id) { + switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - dev->vsettings.brightness = c->value; - return stk_sensor_set_brightness(dev, c->value >> 8); + return stk_sensor_set_brightness(dev, ctrl->val); case V4L2_CID_HFLIP: if (dmi_check_system(stk_upside_down_dmi_table)) - dev->vsettings.hflip = !c->value; + dev->vsettings.hflip = !ctrl->val; else - dev->vsettings.hflip = c->value; + dev->vsettings.hflip = ctrl->val; return 0; case V4L2_CID_VFLIP: if (dmi_check_system(stk_upside_down_dmi_table)) - dev->vsettings.vflip = !c->value; + dev->vsettings.vflip = !ctrl->val; else - dev->vsettings.vflip = c->value; + dev->vsettings.vflip = ctrl->val; return 0; default: return -EINVAL; @@ -1238,6 +1164,10 @@ static int stk_vidioc_enum_framesizes(struct file *filp, } } +static const struct v4l2_ctrl_ops stk_ctrl_ops = { + .s_ctrl = stk_s_ctrl, +}; + static struct v4l2_file_operations v4l_stk_fops = { .owner = THIS_MODULE, .open = v4l_stk_open, @@ -1263,9 +1193,6 @@ static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = { .vidioc_dqbuf = stk_vidioc_dqbuf, .vidioc_streamon = stk_vidioc_streamon, .vidioc_streamoff = stk_vidioc_streamoff, - .vidioc_queryctrl = stk_vidioc_queryctrl, - .vidioc_g_ctrl = stk_vidioc_g_ctrl, - .vidioc_s_ctrl = stk_vidioc_s_ctrl, .vidioc_g_parm = stk_vidioc_g_parm, .vidioc_enum_framesizes = stk_vidioc_enum_framesizes, }; @@ -1310,8 +1237,9 @@ static int stk_register_video_device(struct stk_camera *dev) static int stk_camera_probe(struct usb_interface *interface, const struct usb_device_id *id) { - int i; + struct v4l2_ctrl_handler *hdl; int err = 0; + int i; struct stk_camera *dev = NULL; struct usb_device *udev = interface_to_usbdev(interface); @@ -1329,6 +1257,20 @@ static int stk_camera_probe(struct usb_interface *interface, kfree(dev); return err; } + hdl = &dev->hdl; + v4l2_ctrl_handler_init(hdl, 3); + v4l2_ctrl_new_std(hdl, &stk_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 0xff, 0x1, 0x60); + v4l2_ctrl_new_std(hdl, &stk_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 1); + v4l2_ctrl_new_std(hdl, &stk_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 1); + if (hdl->error) { + err = hdl->error; + dev_err(&udev->dev, "couldn't register control\n"); + goto error; + } + dev->v4l2_dev.ctrl_handler = hdl; spin_lock_init(&dev->spinlock); init_waitqueue_head(&dev->wait_frame); @@ -1372,7 +1314,6 @@ static int stk_camera_probe(struct usb_interface *interface, err = -ENODEV; goto error; } - dev->vsettings.brightness = 0x7fff; dev->vsettings.palette = V4L2_PIX_FMT_RGB565; dev->vsettings.mode = MODE_VGA; dev->frame_size = 640 * 480 * 2; @@ -1389,6 +1330,7 @@ static int stk_camera_probe(struct usb_interface *interface, return 0; error: + v4l2_ctrl_handler_free(hdl); v4l2_device_unregister(&dev->v4l2_dev); kfree(dev); return err; @@ -1407,6 +1349,7 @@ static void stk_camera_disconnect(struct usb_interface *interface) video_device_node_name(&dev->vdev)); video_unregister_device(&dev->vdev); + v4l2_ctrl_handler_free(&dev->hdl); v4l2_device_unregister(&dev->v4l2_dev); } diff --git a/drivers/media/usb/stkwebcam/stk-webcam.h b/drivers/media/usb/stkwebcam/stk-webcam.h index 49ebe855cba6..901f0df21bc7 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.h +++ b/drivers/media/usb/stkwebcam/stk-webcam.h @@ -24,6 +24,7 @@ #include #include +#include #include #define DRIVER_VERSION "v0.0.1" @@ -60,7 +61,6 @@ enum stk_mode {MODE_VGA, MODE_SXGA, MODE_CIF, MODE_QVGA, MODE_QCIF}; struct stk_video { enum stk_mode mode; - int brightness; __u32 palette; int hflip; int vflip; @@ -93,6 +93,7 @@ struct regval { struct stk_camera { struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler hdl; struct video_device vdev; struct usb_device *udev; struct usb_interface *interface; -- cgit v1.2.3 From 10351adc6ac9251863ec6d90436e3ad277d178e0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Feb 2013 09:00:48 -0300 Subject: [media] stk-webcam: don't use private_data, use video_drvdata file->private_data is needed to store the pointer to struct v4l2_fh. So use video_drvdata to get hold of the stk_camera struct. Signed-off-by: Hans Verkuil Tested-by: Arvydas Sidorenko Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-webcam.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index f1cf9060ce71..49a4dfd22bf2 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -604,11 +604,7 @@ static void stk_free_buffers(struct stk_camera *dev) static int v4l_stk_open(struct file *fp) { static int first_init = 1; /* webcam LED management */ - struct stk_camera *dev; - struct video_device *vdev; - - vdev = video_devdata(fp); - dev = vdev_to_camera(vdev); + struct stk_camera *dev = video_drvdata(fp); if (dev == NULL || !is_present(dev)) return -ENXIO; @@ -618,7 +614,6 @@ static int v4l_stk_open(struct file *fp) else first_init = 0; - fp->private_data = dev; usb_autopm_get_interface(dev->interface); return 0; @@ -626,7 +621,7 @@ static int v4l_stk_open(struct file *fp) static int v4l_stk_release(struct file *fp) { - struct stk_camera *dev = fp->private_data; + struct stk_camera *dev = video_drvdata(fp); if (dev->owner == fp) { stk_stop_stream(dev); @@ -649,7 +644,7 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf, int ret; unsigned long flags; struct stk_sio_buffer *sbuf; - struct stk_camera *dev = fp->private_data; + struct stk_camera *dev = video_drvdata(fp); if (!is_present(dev)) return -EIO; @@ -705,7 +700,7 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf, static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait) { - struct stk_camera *dev = fp->private_data; + struct stk_camera *dev = video_drvdata(fp); poll_wait(fp, &dev->wait_frame, wait); @@ -741,7 +736,7 @@ static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma) unsigned int i; int ret; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - struct stk_camera *dev = fp->private_data; + struct stk_camera *dev = video_drvdata(fp); struct stk_sio_buffer *sbuf = NULL; if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) @@ -879,7 +874,7 @@ static int stk_vidioc_g_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *f) { struct v4l2_pix_format *pix_format = &f->fmt.pix; - struct stk_camera *dev = priv; + struct stk_camera *dev = video_drvdata(filp); int i; for (i = 0; i < ARRAY_SIZE(stk_sizes) && @@ -984,7 +979,7 @@ static int stk_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmtd) { int ret; - struct stk_camera *dev = priv; + struct stk_camera *dev = video_drvdata(filp); if (dev == NULL) return -ENODEV; @@ -1011,7 +1006,7 @@ static int stk_vidioc_s_fmt_vid_cap(struct file *filp, static int stk_vidioc_reqbufs(struct file *filp, void *priv, struct v4l2_requestbuffers *rb) { - struct stk_camera *dev = priv; + struct stk_camera *dev = video_drvdata(filp); if (dev == NULL) return -ENODEV; @@ -1037,7 +1032,7 @@ static int stk_vidioc_reqbufs(struct file *filp, static int stk_vidioc_querybuf(struct file *filp, void *priv, struct v4l2_buffer *buf) { - struct stk_camera *dev = priv; + struct stk_camera *dev = video_drvdata(filp); struct stk_sio_buffer *sbuf; if (buf->index >= dev->n_sbufs) @@ -1050,7 +1045,7 @@ static int stk_vidioc_querybuf(struct file *filp, static int stk_vidioc_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf) { - struct stk_camera *dev = priv; + struct stk_camera *dev = video_drvdata(filp); struct stk_sio_buffer *sbuf; unsigned long flags; @@ -1074,7 +1069,7 @@ static int stk_vidioc_qbuf(struct file *filp, static int stk_vidioc_dqbuf(struct file *filp, void *priv, struct v4l2_buffer *buf) { - struct stk_camera *dev = priv; + struct stk_camera *dev = video_drvdata(filp); struct stk_sio_buffer *sbuf; unsigned long flags; int ret; @@ -1107,7 +1102,7 @@ static int stk_vidioc_dqbuf(struct file *filp, static int stk_vidioc_streamon(struct file *filp, void *priv, enum v4l2_buf_type type) { - struct stk_camera *dev = priv; + struct stk_camera *dev = video_drvdata(filp); if (is_streaming(dev)) return 0; if (dev->sio_bufs == NULL) @@ -1119,7 +1114,7 @@ static int stk_vidioc_streamon(struct file *filp, static int stk_vidioc_streamoff(struct file *filp, void *priv, enum v4l2_buf_type type) { - struct stk_camera *dev = priv; + struct stk_camera *dev = video_drvdata(filp); unsigned long flags; int i; stk_stop_stream(dev); @@ -1222,6 +1217,7 @@ static int stk_register_video_device(struct stk_camera *dev) dev->vdev = stk_v4l_data; dev->vdev.debug = debug; dev->vdev.v4l2_dev = &dev->v4l2_dev; + video_set_drvdata(&dev->vdev, dev); err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); if (err) STK_ERROR("v4l registration failed\n"); -- cgit v1.2.3 From 89ea47069cc536f6ae6f428c89bcb960fea3eaff Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Feb 2013 09:08:41 -0300 Subject: [media] stk-webcam: add support for control events and prio handling Also correct the first_init static: this should be part of the stk_camera struct. Signed-off-by: Hans Verkuil Tested-by: Arvydas Sidorenko Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-webcam.c | 27 +++++++++++++++++---------- drivers/media/usb/stkwebcam/stk-webcam.h | 1 + 2 files changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 49a4dfd22bf2..c07366619227 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "stk-webcam.h" @@ -603,20 +604,21 @@ static void stk_free_buffers(struct stk_camera *dev) static int v4l_stk_open(struct file *fp) { - static int first_init = 1; /* webcam LED management */ struct stk_camera *dev = video_drvdata(fp); + int err; if (dev == NULL || !is_present(dev)) return -ENXIO; - if (!first_init) + if (!dev->first_init) stk_camera_write_reg(dev, 0x0, 0x24); else - first_init = 0; - - usb_autopm_get_interface(dev->interface); + dev->first_init = 0; - return 0; + err = v4l2_fh_open(fp); + if (!err) + usb_autopm_get_interface(dev->interface); + return err; } static int v4l_stk_release(struct file *fp) @@ -633,8 +635,7 @@ static int v4l_stk_release(struct file *fp) if (is_present(dev)) usb_autopm_put_interface(dev->interface); - - return 0; + return v4l2_fh_release(fp); } static ssize_t v4l_stk_read(struct file *fp, char __user *buf, @@ -701,6 +702,7 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf, static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait) { struct stk_camera *dev = video_drvdata(fp); + unsigned res = v4l2_ctrl_poll(fp, wait); poll_wait(fp, &dev->wait_frame, wait); @@ -708,9 +710,9 @@ static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait) return POLLERR; if (!list_empty(&dev->sio_full)) - return POLLIN | POLLRDNORM; + return res | POLLIN | POLLRDNORM; - return 0; + return res; } @@ -1190,6 +1192,9 @@ static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = { .vidioc_streamoff = stk_vidioc_streamoff, .vidioc_g_parm = stk_vidioc_g_parm, .vidioc_enum_framesizes = stk_vidioc_enum_framesizes, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static void stk_v4l_dev_release(struct video_device *vd) @@ -1217,6 +1222,7 @@ static int stk_register_video_device(struct stk_camera *dev) dev->vdev = stk_v4l_data; dev->vdev.debug = debug; dev->vdev.v4l2_dev = &dev->v4l2_dev; + set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags); video_set_drvdata(&dev->vdev, dev); err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); if (err) @@ -1270,6 +1276,7 @@ static int stk_camera_probe(struct usb_interface *interface, spin_lock_init(&dev->spinlock); init_waitqueue_head(&dev->wait_frame); + dev->first_init = 1; /* webcam LED management */ dev->udev = udev; dev->interface = interface; diff --git a/drivers/media/usb/stkwebcam/stk-webcam.h b/drivers/media/usb/stkwebcam/stk-webcam.h index 901f0df21bc7..2156320487d8 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.h +++ b/drivers/media/usb/stkwebcam/stk-webcam.h @@ -99,6 +99,7 @@ struct stk_camera { struct usb_interface *interface; int webcam_model; struct file *owner; + int first_init; u8 isoc_ep; -- cgit v1.2.3 From b27763f0faad374e215a474389ff5949e0b40764 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 10 Feb 2013 14:32:52 -0300 Subject: [media] stk-webcam: fix querycap and simplify s_input Add device_caps support to querycap, fill in bus_info correctly and do not set the version field (let the core handle that). Also simplify the s_input ioctl. Signed-off-by: Hans Verkuil Tested-by: Arvydas Sidorenko Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-webcam.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index c07366619227..a00edf3de6bd 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -768,12 +768,15 @@ static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma) static int stk_vidioc_querycap(struct file *filp, void *priv, struct v4l2_capability *cap) { + struct stk_camera *dev = video_drvdata(filp); + strcpy(cap->driver, "stk"); strcpy(cap->card, "stk"); - cap->version = DRIVER_VERSION_NUM; + usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -797,10 +800,7 @@ static int stk_vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; - else - return 0; + return i ? -EINVAL : 0; } static int stk_s_ctrl(struct v4l2_ctrl *ctrl) -- cgit v1.2.3 From 8407653f5e2b9805958e0a392c0411ce027a3934 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Feb 2013 09:18:14 -0300 Subject: [media] stk-webcam: zero the priv field of v4l2_pix_format The priv field should be set to 0. In this case the driver abused the priv field for internal housekeeping. Modify the code so priv is no longer used for that purpose. Signed-off-by: Hans Verkuil Tested-by: Arvydas Sidorenko Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-webcam.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index a00edf3de6bd..bb524574c838 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -897,11 +897,12 @@ static int stk_vidioc_g_fmt_vid_cap(struct file *filp, pix_format->bytesperline = 2 * pix_format->width; pix_format->sizeimage = pix_format->bytesperline * pix_format->height; + pix_format->priv = 0; return 0; } -static int stk_vidioc_try_fmt_vid_cap(struct file *filp, - void *priv, struct v4l2_format *fmtd) +static int stk_try_fmt_vid_cap(struct file *filp, + struct v4l2_format *fmtd, int *idx) { int i; switch (fmtd->fmt.pix.pixelformat) { @@ -923,11 +924,13 @@ static int stk_vidioc_try_fmt_vid_cap(struct file *filp, < abs(fmtd->fmt.pix.width - stk_sizes[i].w))) { fmtd->fmt.pix.height = stk_sizes[i-1].h; fmtd->fmt.pix.width = stk_sizes[i-1].w; - fmtd->fmt.pix.priv = i - 1; + if (idx) + *idx = i - 1; } else { fmtd->fmt.pix.height = stk_sizes[i].h; fmtd->fmt.pix.width = stk_sizes[i].w; - fmtd->fmt.pix.priv = i; + if (idx) + *idx = i; } fmtd->fmt.pix.field = V4L2_FIELD_NONE; @@ -938,9 +941,16 @@ static int stk_vidioc_try_fmt_vid_cap(struct file *filp, fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width; fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline * fmtd->fmt.pix.height; + fmtd->fmt.pix.priv = 0; return 0; } +static int stk_vidioc_try_fmt_vid_cap(struct file *filp, + void *priv, struct v4l2_format *fmtd) +{ + return stk_try_fmt_vid_cap(filp, fmtd, NULL); +} + static int stk_setup_format(struct stk_camera *dev) { int i = 0; @@ -981,6 +991,7 @@ static int stk_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, struct v4l2_format *fmtd) { int ret; + int idx; struct stk_camera *dev = video_drvdata(filp); if (dev == NULL) @@ -991,7 +1002,7 @@ static int stk_vidioc_s_fmt_vid_cap(struct file *filp, return -EBUSY; if (dev->owner && dev->owner != filp) return -EBUSY; - ret = stk_vidioc_try_fmt_vid_cap(filp, priv, fmtd); + ret = stk_try_fmt_vid_cap(filp, fmtd, &idx); if (ret) return ret; dev->owner = filp; @@ -999,7 +1010,7 @@ static int stk_vidioc_s_fmt_vid_cap(struct file *filp, dev->vsettings.palette = fmtd->fmt.pix.pixelformat; stk_free_buffers(dev); dev->frame_size = fmtd->fmt.pix.sizeimage; - dev->vsettings.mode = stk_sizes[fmtd->fmt.pix.priv].m; + dev->vsettings.mode = stk_sizes[idx].m; stk_initialise(dev); return stk_setup_format(dev); -- cgit v1.2.3 From f80daa2d7d7725559908909254d240c433cafc93 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Feb 2013 09:27:32 -0300 Subject: [media] stk-webcam: enable core-locking This makes it possible to switch to unlocked_ioctl. Signed-off-by: Hans Verkuil Tested-by: Arvydas Sidorenko Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-webcam.c | 24 ++++++++++++++++++++++-- drivers/media/usb/stkwebcam/stk-webcam.h | 1 + 2 files changed, 23 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index bb524574c838..2f1a09db1135 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -610,6 +610,8 @@ static int v4l_stk_open(struct file *fp) if (dev == NULL || !is_present(dev)) return -ENXIO; + if (mutex_lock_interruptible(&dev->lock)) + return -ERESTARTSYS; if (!dev->first_init) stk_camera_write_reg(dev, 0x0, 0x24); else @@ -618,6 +620,7 @@ static int v4l_stk_open(struct file *fp) err = v4l2_fh_open(fp); if (!err) usb_autopm_get_interface(dev->interface); + mutex_unlock(&dev->lock); return err; } @@ -625,6 +628,7 @@ static int v4l_stk_release(struct file *fp) { struct stk_camera *dev = video_drvdata(fp); + mutex_lock(&dev->lock); if (dev->owner == fp) { stk_stop_stream(dev); stk_free_buffers(dev); @@ -635,10 +639,11 @@ static int v4l_stk_release(struct file *fp) if (is_present(dev)) usb_autopm_put_interface(dev->interface); + mutex_unlock(&dev->lock); return v4l2_fh_release(fp); } -static ssize_t v4l_stk_read(struct file *fp, char __user *buf, +static ssize_t stk_read(struct file *fp, char __user *buf, size_t count, loff_t *f_pos) { int i; @@ -699,6 +704,19 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf, return count; } +static ssize_t v4l_stk_read(struct file *fp, char __user *buf, + size_t count, loff_t *f_pos) +{ + struct stk_camera *dev = video_drvdata(fp); + int ret; + + if (mutex_lock_interruptible(&dev->lock)) + return -ERESTARTSYS; + ret = stk_read(fp, buf, count, f_pos); + mutex_unlock(&dev->lock); + return ret; +} + static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait) { struct stk_camera *dev = video_drvdata(fp); @@ -1183,7 +1201,7 @@ static struct v4l2_file_operations v4l_stk_fops = { .read = v4l_stk_read, .poll = v4l_stk_poll, .mmap = v4l_stk_mmap, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = { @@ -1231,6 +1249,7 @@ static int stk_register_video_device(struct stk_camera *dev) int err; dev->vdev = stk_v4l_data; + dev->vdev.lock = &dev->lock; dev->vdev.debug = debug; dev->vdev.v4l2_dev = &dev->v4l2_dev; set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags); @@ -1286,6 +1305,7 @@ static int stk_camera_probe(struct usb_interface *interface, dev->v4l2_dev.ctrl_handler = hdl; spin_lock_init(&dev->spinlock); + mutex_init(&dev->lock); init_waitqueue_head(&dev->wait_frame); dev->first_init = 1; /* webcam LED management */ diff --git a/drivers/media/usb/stkwebcam/stk-webcam.h b/drivers/media/usb/stkwebcam/stk-webcam.h index 2156320487d8..03550cf60dcd 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.h +++ b/drivers/media/usb/stkwebcam/stk-webcam.h @@ -99,6 +99,7 @@ struct stk_camera { struct usb_interface *interface; int webcam_model; struct file *owner; + struct mutex lock; int first_init; u8 isoc_ep; -- cgit v1.2.3 From 1b499fe506257369fd6059422989e36c71b99897 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Feb 2013 04:23:01 -0300 Subject: [media] stk-webcam: fix read() handling when reqbufs was already called Signed-off-by: Hans Verkuil Tested-by: Arvydas Sidorenko Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-webcam.c | 3 ++- drivers/media/usb/stkwebcam/stk-webcam.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 2f1a09db1135..a8fdbaf34720 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -654,7 +654,7 @@ static ssize_t stk_read(struct file *fp, char __user *buf, if (!is_present(dev)) return -EIO; - if (dev->owner && dev->owner != fp) + if (dev->owner && (!dev->reading || dev->owner != fp)) return -EBUSY; dev->owner = fp; if (!is_streaming(dev)) { @@ -662,6 +662,7 @@ static ssize_t stk_read(struct file *fp, char __user *buf, || stk_allocate_buffers(dev, 3) || stk_start_stream(dev)) return -ENOMEM; + dev->reading = 1; spin_lock_irqsave(&dev->spinlock, flags); for (i = 0; i < dev->n_sbufs; i++) { list_add_tail(&dev->sio_bufs[i].list, &dev->sio_avail); diff --git a/drivers/media/usb/stkwebcam/stk-webcam.h b/drivers/media/usb/stkwebcam/stk-webcam.h index 03550cf60dcd..9bbfa3d9bfdd 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.h +++ b/drivers/media/usb/stkwebcam/stk-webcam.h @@ -118,6 +118,7 @@ struct stk_camera { int frame_size; /* Streaming buffers */ + int reading; unsigned int n_sbufs; struct stk_sio_buffer *sio_bufs; struct list_head sio_avail; -- cgit v1.2.3 From f81e372a5d11694b86fc35ded379a441c209b920 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 10 Feb 2013 14:36:41 -0300 Subject: [media] stk-webcam: s_fmt shouldn't grab ownership Signed-off-by: Hans Verkuil Tested-by: Arvydas Sidorenko Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-webcam.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index a8fdbaf34720..45d73e2f3e57 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -1019,12 +1019,11 @@ static int stk_vidioc_s_fmt_vid_cap(struct file *filp, return -ENODEV; if (is_streaming(dev)) return -EBUSY; - if (dev->owner && dev->owner != filp) + if (dev->owner) return -EBUSY; ret = stk_try_fmt_vid_cap(filp, fmtd, &idx); if (ret) return ret; - dev->owner = filp; dev->vsettings.palette = fmtd->fmt.pix.pixelformat; stk_free_buffers(dev); -- cgit v1.2.3 From 9776e17189d33b0ac9235597460d6a22cf1bc6a7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 10 Feb 2013 14:37:58 -0300 Subject: [media] stk-webcam: implement support for count == 0 when calling REQBUFS The spec specifies that setting count to 0 in v4l2_requestbuffers should result in releasing any streaming resources and the stream ownership. Implement this. Signed-off-by: Hans Verkuil Tested-by: Arvydas Sidorenko Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-webcam.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 45d73e2f3e57..c43c8d32be40 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -1046,6 +1046,13 @@ static int stk_vidioc_reqbufs(struct file *filp, if (is_streaming(dev) || (dev->owner && dev->owner != filp)) return -EBUSY; + stk_free_buffers(dev); + if (rb->count == 0) { + stk_camera_write_reg(dev, 0x0, 0x49); /* turn off the LED */ + unset_initialised(dev); + dev->owner = NULL; + return 0; + } dev->owner = filp; /*FIXME If they ask for zero, we must stop streaming and free */ -- cgit v1.2.3 From 6aa69f99b2ecc7f9b387fcf22d30e6601b58819f Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Fri, 25 Jan 2013 06:29:57 -0300 Subject: [media] vb2: Add support for non monotonic timestamps Not all drivers use monotonic timestamps. This patch adds a way to set the timestamp type per every queue. In addition, set proper timestamp type in drivers that I am sure that use either MONOTONIC or COPY timestamps. Other drivers will correctly report UNKNOWN timestamp type instead of assuming that all drivers use monotonic timestamps. Signed-off-by: Kamil Debski Signed-off-by: Kyungmin Park Reviewed-by: Sylwester Nawrocki Acked-by: Hans Verkuil Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/blackfin/bfin_capture.c | 1 + drivers/media/platform/davinci/vpbe_display.c | 1 + drivers/media/platform/davinci/vpif_capture.c | 1 + drivers/media/platform/davinci/vpif_display.c | 1 + drivers/media/platform/s3c-camif/camif-capture.c | 1 + drivers/media/platform/s5p-fimc/fimc-capture.c | 1 + drivers/media/platform/s5p-fimc/fimc-lite.c | 1 + drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 ++ drivers/media/platform/soc_camera/atmel-isi.c | 1 + drivers/media/platform/soc_camera/mx2_camera.c | 1 + drivers/media/platform/soc_camera/mx3_camera.c | 1 + drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c | 1 + drivers/media/platform/vivi.c | 1 + drivers/media/usb/pwc/pwc-if.c | 1 + drivers/media/usb/stk1160/stk1160-v4l.c | 1 + drivers/media/usb/uvc/uvc_queue.c | 1 + drivers/media/v4l2-core/videobuf2-core.c | 8 ++++++-- include/media/videobuf2-core.h | 1 + 18 files changed, 24 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 5f209d5810dc..8ffe42aabd85 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -1029,6 +1029,7 @@ static int bcap_probe(struct platform_device *pdev) q->buf_struct_size = sizeof(struct bcap_buffer); q->ops = &bcap_video_qops; q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; vb2_queue_init(q); diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 5e6b0cab514b..9f9f2c1a073f 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -1404,6 +1404,7 @@ static int vpbe_display_reqbufs(struct file *file, void *priv, q->ops = &video_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpbe_disp_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) { diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 5892d2bc8eee..1943e41f3866 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1035,6 +1035,7 @@ static int vpif_reqbufs(struct file *file, void *priv, q->ops = &video_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpif_cap_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) { diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index dd249c96126d..5477c2cb8653 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1001,6 +1001,7 @@ static int vpif_reqbufs(struct file *file, void *priv, q->ops = &video_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct vpif_disp_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) { diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index a55793c3d811..e91f350929eb 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -1153,6 +1153,7 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx) q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct camif_buffer); q->drv_priv = vp; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index f553cc2a8ee8..87b68420f771 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c @@ -1797,6 +1797,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, q->ops = &fimc_capture_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct fimc_vid_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index bfc4206935c8..47fbf7bcf608 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite.c @@ -1325,6 +1325,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct flite_buffer); q->drv_priv = fimc; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret < 0) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index e84703c314ce..92c6bf11af74 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -804,6 +804,7 @@ static int s5p_mfc_open(struct file *file) goto err_queue_init; } q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(q); if (ret) { mfc_err("Failed to initialize videobuf2 queue(capture)\n"); @@ -825,6 +826,7 @@ static int s5p_mfc_open(struct file *file) goto err_queue_init; } q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(q); if (ret) { mfc_err("Failed to initialize videobuf2 queue(output)\n"); diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 82dbf99d347c..c314ff9b98dc 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -514,6 +514,7 @@ static int isi_camera_init_videobuf(struct vb2_queue *q, q->buf_struct_size = sizeof(struct frame_buffer); q->ops = &isi_video_qops; q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; return vb2_queue_init(q); } diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index ffba7d91f413..048c26a27c34 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -797,6 +797,7 @@ static int mx2_camera_init_videobuf(struct vb2_queue *q, q->ops = &mx2_videobuf_ops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct mx2_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; return vb2_queue_init(q); } diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index f5cbb92db545..2c3bd69fb38c 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -455,6 +455,7 @@ static int mx3_camera_init_videobuf(struct vb2_queue *q, q->ops = &mx3_videobuf_ops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct mx3_camera_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; return vb2_queue_init(q); } diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index bb08a46432f4..973e72b24fa8 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -2026,6 +2026,7 @@ static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q, q->ops = &sh_mobile_ceu_videobuf_ops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct sh_mobile_ceu_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; return vb2_queue_init(q); } diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c index 8a33a712f480..c46d2e8677a5 100644 --- a/drivers/media/platform/vivi.c +++ b/drivers/media/platform/vivi.c @@ -1429,6 +1429,7 @@ static int __init vivi_create_instance(int inst) q->buf_struct_size = sizeof(struct vivi_buffer); q->ops = &vivi_video_qops; q->mem_ops = &vb2_vmalloc_memops; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(q); if (ret) diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 5ec15cb1ed26..77bbf7889659 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -1001,6 +1001,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf); pdev->vb_queue.ops = &pwc_vb_queue_ops; pdev->vb_queue.mem_ops = &vb2_vmalloc_memops; + pdev->vb_queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; rc = vb2_queue_init(&pdev->vb_queue); if (rc < 0) { PWC_ERROR("Oops, could not initialize vb2 queue.\n"); diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 6694f9e2ca57..5307a63e378f 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -687,6 +687,7 @@ int stk1160_vb2_setup(struct stk1160 *dev) q->buf_struct_size = sizeof(struct stk1160_buffer); q->ops = &stk1160_video_qops; q->mem_ops = &vb2_vmalloc_memops; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; rc = vb2_queue_init(q); if (rc < 0) diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 6c233a54ce40..cd962be860ca 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -149,6 +149,7 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.ops = &uvc_queue_qops; queue->queue.mem_ops = &vb2_vmalloc_memops; + queue->queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; ret = vb2_queue_init(&queue->queue); if (ret) return ret; diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index db1235dcb328..be0448161c60 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -403,7 +403,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) * Clear any buffer state related flags. */ b->flags &= ~V4L2_BUFFER_MASK_FLAGS; - b->flags |= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + b->flags |= q->timestamp_type; switch (vb->state) { case VB2_BUF_STATE_QUEUED: @@ -2039,9 +2039,13 @@ int vb2_queue_init(struct vb2_queue *q) WARN_ON(!q->type) || WARN_ON(!q->io_modes) || WARN_ON(!q->ops->queue_setup) || - WARN_ON(!q->ops->buf_queue)) + WARN_ON(!q->ops->buf_queue) || + WARN_ON(q->timestamp_type & ~V4L2_BUF_FLAG_TIMESTAMP_MASK)) return -EINVAL; + /* Warn that the driver should choose an appropriate timestamp type */ + WARN_ON(q->timestamp_type == V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN); + INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); spin_lock_init(&q->done_lock); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 9cfd4ee9e56f..a2d427450780 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -326,6 +326,7 @@ struct vb2_queue { const struct vb2_mem_ops *mem_ops; void *drv_priv; unsigned int buf_struct_size; + u32 timestamp_type; /* private: internal use only */ enum v4l2_memory memory; -- cgit v1.2.3 From 69b95a3a80b44ebb71bf153e79bcb8580e1d3de5 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 7 Feb 2013 18:36:12 -0300 Subject: [media] s3c-camif: Fail on insufficient number of allocated buffers Ensure the driver gets always at least its minimum required number of buffers allocated by checking actual number of allocated buffers in vb2_reqbufs(). And free any partially allocated buffer queue with signaling an error to user space. Without this patch applications may wait forever to dequeue a filled buffer, because the hardware didn't even start after VIDIOC_STREAMON, VIDIOC_QBUF calls, due to insufficient number of empty buffers. Reported-by: Alexander Nestorov Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s3c-camif/camif-capture.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index e91f350929eb..70438a0f62ae 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -934,12 +934,19 @@ static int s3c_camif_reqbufs(struct file *file, void *priv, vp->owner = NULL; ret = vb2_reqbufs(&vp->vb_queue, rb); - if (!ret) { - vp->reqbufs_count = rb->count; - if (vp->owner == NULL && rb->count > 0) - vp->owner = priv; + if (ret < 0) + return ret; + + if (rb->count && rb->count < CAMIF_REQ_BUFS_MIN) { + rb->count = 0; + vb2_reqbufs(&vp->vb_queue, rb); + ret = -ENOMEM; } + vp->reqbufs_count = rb->count; + if (vp->owner == NULL && rb->count > 0) + vp->owner = priv; + return ret; } -- cgit v1.2.3 From 5ce60d790a246c4c32043ac9b142615466479728 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 6 Feb 2013 01:29:43 -0300 Subject: [media] s5p-g2d: Add DT based discovery support This patch adds device tree based discovery support to the G2D driver. Signed-off-by: Sachin Kamat Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-g2d/g2d.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index aaaf276a5a6c..14d663dacdbd 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -695,11 +696,14 @@ static struct v4l2_m2m_ops g2d_m2m_ops = { .unlock = g2d_unlock, }; +static const struct of_device_id exynos_g2d_match[]; + static int g2d_probe(struct platform_device *pdev) { struct g2d_dev *dev; struct video_device *vfd; struct resource *res; + const struct of_device_id *of_id; int ret = 0; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); @@ -794,7 +798,17 @@ static int g2d_probe(struct platform_device *pdev) } def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; - dev->variant = g2d_get_drv_data(pdev); + + if (!pdev->dev.of_node) { + dev->variant = g2d_get_drv_data(pdev); + } else { + of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node); + if (!of_id) { + ret = -ENODEV; + goto unreg_video_dev; + } + dev->variant = (struct g2d_variant *)of_id->data; + } return 0; @@ -835,13 +849,25 @@ static int g2d_remove(struct platform_device *pdev) } static struct g2d_variant g2d_drvdata_v3x = { - .hw_rev = TYPE_G2D_3X, + .hw_rev = TYPE_G2D_3X, /* Revision 3.0 for S5PV210 and Exynos4210 */ }; static struct g2d_variant g2d_drvdata_v4x = { .hw_rev = TYPE_G2D_4X, /* Revision 4.1 for Exynos4X12 and Exynos5 */ }; +static const struct of_device_id exynos_g2d_match[] = { + { + .compatible = "samsung,s5pv210-g2d", + .data = &g2d_drvdata_v3x, + }, { + .compatible = "samsung,exynos4212-g2d", + .data = &g2d_drvdata_v4x, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos_g2d_match); + static struct platform_device_id g2d_driver_ids[] = { { .name = "s5p-g2d", @@ -861,6 +887,7 @@ static struct platform_driver g2d_pdrv = { .driver = { .name = G2D_NAME, .owner = THIS_MODULE, + .of_match_table = exynos_g2d_match, }, }; -- cgit v1.2.3 From c1f07ab2b3e7a1a0ec8152dc30ab5fec346bf367 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Feb 2013 06:31:12 -0300 Subject: [media] gspca_sonixj: Convert to the control framework Signed-off-by: Hans Verkuil Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/sonixj.c | 545 ++++++++++++--------------------------- 1 file changed, 164 insertions(+), 381 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c index 671d0c6dece3..8246e1dc3e9d 100644 --- a/drivers/media/usb/gspca/sonixj.c +++ b/drivers/media/usb/gspca/sonixj.c @@ -31,32 +31,26 @@ MODULE_AUTHOR("Jean-François Moine "); MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver"); MODULE_LICENSE("GPL"); -/* controls */ -enum e_ctrl { - BRIGHTNESS, - CONTRAST, - COLORS, - BLUE, - RED, - GAMMA, - EXPOSURE, - AUTOGAIN, - GAIN, - HFLIP, - VFLIP, - SHARPNESS, - ILLUM, - FREQ, - NCTRLS /* number of controls */ -}; - /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - struct gspca_ctrl ctrls[NCTRLS]; - atomic_t avg_lum; + struct v4l2_ctrl *brightness; + struct v4l2_ctrl *contrast; + struct v4l2_ctrl *saturation; + struct { /* red/blue balance control cluster */ + struct v4l2_ctrl *red_bal; + struct v4l2_ctrl *blue_bal; + }; + struct { /* hflip/vflip control cluster */ + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *hflip; + }; + struct v4l2_ctrl *gamma; + struct v4l2_ctrl *illum; + struct v4l2_ctrl *sharpness; + struct v4l2_ctrl *freq; u32 exposure; struct work_struct work; @@ -127,283 +121,6 @@ static void qual_upd(struct work_struct *work); #define SEN_CLK_EN 0x20 /* enable sensor clock */ #define DEF_EN 0x80 /* defect pixel by 0: soft, 1: hard */ -/* V4L2 controls supported by the driver */ -static void setbrightness(struct gspca_dev *gspca_dev); -static void setcontrast(struct gspca_dev *gspca_dev); -static void setcolors(struct gspca_dev *gspca_dev); -static void setredblue(struct gspca_dev *gspca_dev); -static void setgamma(struct gspca_dev *gspca_dev); -static void setexposure(struct gspca_dev *gspca_dev); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static void setgain(struct gspca_dev *gspca_dev); -static void sethvflip(struct gspca_dev *gspca_dev); -static void setsharpness(struct gspca_dev *gspca_dev); -static void setillum(struct gspca_dev *gspca_dev); -static void setfreq(struct gspca_dev *gspca_dev); - -static const struct ctrl sd_ctrls[NCTRLS] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x80, - }, - .set_control = setbrightness - }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, -#define CONTRAST_MAX 127 - .maximum = CONTRAST_MAX, - .step = 1, - .default_value = 20, - }, - .set_control = setcontrast - }, -[COLORS] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 40, - .step = 1, -#define COLORS_DEF 25 - .default_value = COLORS_DEF, - }, - .set_control = setcolors - }, -[BLUE] = { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = 24, - .maximum = 40, - .step = 1, - .default_value = 32, - }, - .set_control = setredblue - }, -[RED] = { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = 24, - .maximum = 40, - .step = 1, - .default_value = 32, - }, - .set_control = setredblue - }, -[GAMMA] = { - { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 0, - .maximum = 40, - .step = 1, -#define GAMMA_DEF 20 - .default_value = GAMMA_DEF, - }, - .set_control = setgamma - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 500, - .maximum = 1500, - .step = 1, - .default_value = 1024 - }, - .set_control = setexposure - }, -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = sd_setautogain, - }, -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 4, - .maximum = 49, - .step = 1, - .default_value = 15 - }, - .set_control = setgain - }, -[HFLIP] = { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = sethvflip - }, -[VFLIP] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vflip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = sethvflip - }, -[SHARPNESS] = { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 90, - }, - .set_control = setsharpness - }, -[ILLUM] = { - { - .id = V4L2_CID_ILLUMINATORS_1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Illuminator / infrared", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = setillum - }, -/* ov7630/ov7648/ov7660 only */ -[FREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ - .step = 1, - .default_value = 1, - }, - .set_control = setfreq - }, -}; - -/* table of the disabled controls */ -static const __u32 ctrl_dis[] = { -[SENSOR_ADCM1700] = (1 << EXPOSURE) | - (1 << AUTOGAIN) | - (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_GC0307] = (1 << EXPOSURE) | - (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_HV7131R] = (1 << EXPOSURE) | - (1 << GAIN) | - (1 << HFLIP) | - (1 << FREQ), - -[SENSOR_MI0360] = (1 << EXPOSURE) | - (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_MI0360B] = (1 << EXPOSURE) | - (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_MO4000] = (1 << EXPOSURE) | - (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_MT9V111] = (1 << EXPOSURE) | - (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_OM6802] = (1 << EXPOSURE) | - (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_OV7630] = (1 << EXPOSURE) | - (1 << GAIN) | - (1 << HFLIP), - -[SENSOR_OV7648] = (1 << EXPOSURE) | - (1 << GAIN) | - (1 << HFLIP), - -[SENSOR_OV7660] = (1 << EXPOSURE) | - (1 << AUTOGAIN) | - (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP), - -[SENSOR_PO1030] = (1 << EXPOSURE) | - (1 << AUTOGAIN) | - (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_PO2030N] = (1 << FREQ), - -[SENSOR_SOI768] = (1 << EXPOSURE) | - (1 << AUTOGAIN) | - (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), - -[SENSOR_SP80708] = (1 << EXPOSURE) | - (1 << AUTOGAIN) | - (1 << GAIN) | - (1 << HFLIP) | - (1 << VFLIP) | - (1 << FREQ), -}; - static const struct v4l2_pix_format cif_mode[] = { {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 352, @@ -1822,7 +1539,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->nmodes = ARRAY_SIZE(vga_mode); } cam->npkt = 24; /* 24 packets per ISOC message */ - cam->ctrls = sd->ctrls; sd->ag_cnt = -1; sd->quality = QUALITY_DEF; @@ -1888,9 +1604,6 @@ static int sd_init(struct gspca_dev *gspca_dev) break; } - if (sd->sensor == SENSOR_OM6802) - sd->ctrls[SHARPNESS].def = 0x10; - /* Note we do not disable the sensor clock here (power saving mode), as that also disables the button on the cam. */ reg_w1(gspca_dev, 0xf1, 0x00); @@ -1899,13 +1612,92 @@ static int sd_init(struct gspca_dev *gspca_dev) sn9c1xx = sn_tb[sd->sensor]; sd->i2c_addr = sn9c1xx[9]; - gspca_dev->ctrl_dis = ctrl_dis[sd->sensor]; - if (!(sd->flags & F_ILLUM)) - gspca_dev->ctrl_dis |= (1 << ILLUM); - return gspca_dev->usb_err; } +static int sd_s_ctrl(struct v4l2_ctrl *ctrl); + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +/* this function is called at probe time */ +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 14); + + sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); +#define CONTRAST_MAX 127 + sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, CONTRAST_MAX, 1, 20); +#define COLORS_DEF 25 + sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 40, 1, COLORS_DEF); + sd->red_bal = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_RED_BALANCE, 24, 40, 1, 32); + sd->blue_bal = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 24, 40, 1, 32); +#define GAMMA_DEF 20 + sd->gamma = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAMMA, 0, 40, 1, GAMMA_DEF); + + if (sd->sensor == SENSOR_OM6802) + sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 255, 1, 16); + else + sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 255, 1, 90); + + if (sd->flags & F_ILLUM) + sd->illum = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0); + + if (sd->sensor == SENSOR_PO2030N) { + gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 500, 1500, 1, 1024); + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 4, 49, 1, 15); + sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + } + + if (sd->sensor != SENSOR_ADCM1700 && sd->sensor != SENSOR_OV7660 && + sd->sensor != SENSOR_PO1030 && sd->sensor != SENSOR_SOI768 && + sd->sensor != SENSOR_SP80708) + gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + + if (sd->sensor == SENSOR_HV7131R || sd->sensor == SENSOR_OV7630 || + sd->sensor == SENSOR_OV7648 || sd->sensor == SENSOR_PO2030N) + sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + if (sd->sensor == SENSOR_OV7630 || sd->sensor == SENSOR_OV7648 || + sd->sensor == SENSOR_OV7660) + sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, + V4L2_CID_POWER_LINE_FREQUENCY_50HZ); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + + v4l2_ctrl_cluster(2, &sd->red_bal); + if (sd->sensor == SENSOR_PO2030N) { + v4l2_ctrl_cluster(2, &sd->vflip); + v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false); + } + + return 0; +} + static u32 expo_adjust(struct gspca_dev *gspca_dev, u32 expo) { @@ -2014,10 +1806,9 @@ static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; unsigned int expo; - int brightness; + int brightness = sd->brightness->val; u8 k2; - brightness = sd->ctrls[BRIGHTNESS].val; k2 = (brightness - 0x80) >> 2; switch (sd->sensor) { case SENSOR_ADCM1700: @@ -2064,7 +1855,7 @@ static void setcontrast(struct gspca_dev *gspca_dev) u8 k2; u8 contrast[6]; - k2 = sd->ctrls[CONTRAST].val * 37 / (CONTRAST_MAX + 1) + k2 = sd->contrast->val * 37 / (CONTRAST_MAX + 1) + 37; /* 37..73 */ contrast[0] = (k2 + 1) / 2; /* red */ contrast[1] = 0; @@ -2090,7 +1881,7 @@ static void setcolors(struct gspca_dev *gspca_dev) 60, -51, -9 /* VR VG VB */ }; - colors = sd->ctrls[COLORS].val; + colors = sd->saturation->val; if (sd->sensor == SENSOR_MI0360B) uv = uv_mi0360b; else @@ -2112,14 +1903,14 @@ static void setredblue(struct gspca_dev *gspca_dev) {0xc1, 0x6e, 0x16, 0x00, 0x40, 0x00, 0x00, 0x10}; /* 0x40 = normal value = gain x 1 */ - rg1b[3] = sd->ctrls[RED].val * 2; - rg1b[5] = sd->ctrls[BLUE].val * 2; + rg1b[3] = sd->red_bal->val * 2; + rg1b[5] = sd->blue_bal->val * 2; i2c_w8(gspca_dev, rg1b); return; } - reg_w1(gspca_dev, 0x05, sd->ctrls[RED].val); + reg_w1(gspca_dev, 0x05, sd->red_bal->val); /* reg_w1(gspca_dev, 0x07, 32); */ - reg_w1(gspca_dev, 0x06, sd->ctrls[BLUE].val); + reg_w1(gspca_dev, 0x06, sd->blue_bal->val); } static void setgamma(struct gspca_dev *gspca_dev) @@ -2153,7 +1944,7 @@ static void setgamma(struct gspca_dev *gspca_dev) break; } - val = sd->ctrls[GAMMA].val; + val = sd->gamma->val; for (i = 0; i < sizeof gamma; i++) gamma[i] = gamma_base[i] + delta[i] * (val - GAMMA_DEF) / 32; @@ -2168,11 +1959,11 @@ static void setexposure(struct gspca_dev *gspca_dev) u8 rexpo[] = /* 1a: expo H, 1b: expo M */ {0xa1, 0x6e, 0x1a, 0x00, 0x40, 0x00, 0x00, 0x10}; - rexpo[3] = sd->ctrls[EXPOSURE].val >> 8; + rexpo[3] = gspca_dev->exposure->val >> 8; i2c_w8(gspca_dev, rexpo); msleep(6); rexpo[2] = 0x1b; - rexpo[3] = sd->ctrls[EXPOSURE].val; + rexpo[3] = gspca_dev->exposure->val; i2c_w8(gspca_dev, rexpo); } } @@ -2181,8 +1972,6 @@ static void setautogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - if (gspca_dev->ctrl_dis & (1 << AUTOGAIN)) - return; switch (sd->sensor) { case SENSOR_OV7630: case SENSOR_OV7648: { @@ -2192,13 +1981,13 @@ static void setautogain(struct gspca_dev *gspca_dev) comb = 0xc0; else comb = 0xa0; - if (sd->ctrls[AUTOGAIN].val) + if (gspca_dev->autogain->val) comb |= 0x03; i2c_w1(&sd->gspca_dev, 0x13, comb); return; } } - if (sd->ctrls[AUTOGAIN].val) + if (gspca_dev->autogain->val) sd->ag_cnt = AG_CNT_START; else sd->ag_cnt = -1; @@ -2212,7 +2001,7 @@ static void setgain(struct gspca_dev *gspca_dev) u8 rgain[] = /* 15: gain */ {0xa1, 0x6e, 0x15, 0x00, 0x40, 0x00, 0x00, 0x15}; - rgain[3] = sd->ctrls[GAIN].val; + rgain[3] = gspca_dev->gain->val; i2c_w8(gspca_dev, rgain); } } @@ -2225,19 +2014,19 @@ static void sethvflip(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_HV7131R: comn = 0x18; /* clkdiv = 1, ablcen = 1 */ - if (sd->ctrls[VFLIP].val) + if (sd->vflip->val) comn |= 0x01; i2c_w1(gspca_dev, 0x01, comn); /* sctra */ break; case SENSOR_OV7630: comn = 0x02; - if (!sd->ctrls[VFLIP].val) + if (!sd->vflip->val) comn |= 0x80; i2c_w1(gspca_dev, 0x75, comn); break; case SENSOR_OV7648: comn = 0x06; - if (sd->ctrls[VFLIP].val) + if (sd->vflip->val) comn |= 0x80; i2c_w1(gspca_dev, 0x75, comn); break; @@ -2251,9 +2040,9 @@ static void sethvflip(struct gspca_dev *gspca_dev) * bit3-0: X */ comn = 0x0a; - if (sd->ctrls[HFLIP].val) + if (sd->hflip->val) comn |= 0x80; - if (sd->ctrls[VFLIP].val) + if (sd->vflip->val) comn |= 0x40; i2c_w1(&sd->gspca_dev, 0x1e, comn); break; @@ -2264,23 +2053,21 @@ static void setsharpness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - reg_w1(gspca_dev, 0x99, sd->ctrls[SHARPNESS].val); + reg_w1(gspca_dev, 0x99, sd->sharpness->val); } static void setillum(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - if (gspca_dev->ctrl_dis & (1 << ILLUM)) - return; switch (sd->sensor) { case SENSOR_ADCM1700: reg_w1(gspca_dev, 0x02, /* gpio */ - sd->ctrls[ILLUM].val ? 0x64 : 0x60); + sd->illum->val ? 0x64 : 0x60); break; case SENSOR_MT9V111: reg_w1(gspca_dev, 0x02, - sd->ctrls[ILLUM].val ? 0x77 : 0x74); + sd->illum->val ? 0x77 : 0x74); /* should have been: */ /* 0x55 : 0x54); * 370i */ /* 0x66 : 0x64); * Clip */ @@ -2292,13 +2079,11 @@ static void setfreq(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - if (gspca_dev->ctrl_dis & (1 << FREQ)) - return; if (sd->sensor == SENSOR_OV7660) { u8 com8; com8 = 0xdf; /* auto gain/wb/expo */ - switch (sd->ctrls[FREQ].val) { + switch (sd->freq->val) { case 0: /* Banding filter disabled */ i2c_w1(gspca_dev, 0x13, com8 | 0x20); break; @@ -2326,7 +2111,7 @@ static void setfreq(struct gspca_dev *gspca_dev) break; } - switch (sd->ctrls[FREQ].val) { + switch (sd->freq->val) { case 0: /* Banding filter disabled */ break; case 1: /* 50 hz (filter on and framerate adj) */ @@ -2698,17 +2483,6 @@ static int sd_start(struct gspca_dev *gspca_dev) sd->reg01 = reg01; sd->reg17 = reg17; - sethvflip(gspca_dev); - setbrightness(gspca_dev); - setcontrast(gspca_dev); - setcolors(gspca_dev); - setautogain(gspca_dev); - if (!(gspca_dev->ctrl_inac & ((1 << EXPOSURE) | (1 << GAIN)))) { - setexposure(gspca_dev); - setgain(gspca_dev); - } - setfreq(gspca_dev); - sd->pktsz = sd->npkt = 0; sd->nchg = sd->short_mark = 0; sd->work_thread = create_singlethread_workqueue(MODULE_NAME); @@ -2803,9 +2577,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev) } } -#define WANT_REGULAR_AUTOGAIN -#include "autogain_functions.h" - static void do_autogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -2825,7 +2596,7 @@ static void do_autogain(struct gspca_dev *gspca_dev) PDEBUG(D_FRAM, "mean lum %d", delta); if (sd->sensor == SENSOR_PO2030N) { - auto_gain_n_exposure(gspca_dev, delta, luma_mean, luma_delta, + gspca_expo_autogain(gspca_dev, delta, luma_mean, luma_delta, 15, 1024); return; } @@ -3042,39 +2813,53 @@ marker_found: } } -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); - sd->ctrls[AUTOGAIN].val = val; - if (val) - gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN); - else - gspca_dev->ctrl_inac &= ~(1 << EXPOSURE) & ~(1 << GAIN); - if (gspca_dev->streaming) - setautogain(gspca_dev); - return gspca_dev->usb_err; -} + gspca_dev->usb_err = 0; -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - switch (menu->id) { + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev); + break; + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev); + break; + case V4L2_CID_SATURATION: + setcolors(gspca_dev); + break; + case V4L2_CID_RED_BALANCE: + setredblue(gspca_dev); + break; + case V4L2_CID_GAMMA: + setgamma(gspca_dev); + break; + case V4L2_CID_AUTOGAIN: + setautogain(gspca_dev); + setexposure(gspca_dev); + setgain(gspca_dev); + break; + case V4L2_CID_VFLIP: + sethvflip(gspca_dev); + break; + case V4L2_CID_SHARPNESS: + setsharpness(gspca_dev); + break; + case V4L2_CID_ILLUMINATORS_1: + setillum(gspca_dev); + break; case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "NoFliker"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } + setfreq(gspca_dev); break; + default: + return -EINVAL; } - return -EINVAL; + return gspca_dev->usb_err; } #if IS_ENABLED(CONFIG_INPUT) @@ -3099,16 +2884,14 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = NCTRLS, .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, .dq_callback = do_autogain, - .querymenu = sd_querymenu, #if IS_ENABLED(CONFIG_INPUT) .int_pkt_scan = sd_int_pkt_scan, #endif -- cgit v1.2.3 From 676fdd856b22fa384b09bdad3c81d8117feadbe6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 19 Feb 2013 07:19:17 -0300 Subject: [media] gscpa_gl860: Convert to the control framework Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/gl860/gl860.c | 222 ++++++++++++++++++---------------- 1 file changed, 119 insertions(+), 103 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/gspca/gl860/gl860.c b/drivers/media/usb/gspca/gl860/gl860.c index ced3b71f14e5..96d9c28a748c 100644 --- a/drivers/media/usb/gspca/gl860/gl860.c +++ b/drivers/media/usb/gspca/gl860/gl860.c @@ -58,115 +58,135 @@ MODULE_PARM_DESC(sensor, /*============================ webcam controls =============================*/ -/* Functions to get and set a control value */ -#define SD_SETGET(thename) \ -static int sd_set_##thename(struct gspca_dev *gspca_dev, s32 val)\ -{\ - struct sd *sd = (struct sd *) gspca_dev;\ -\ - sd->vcur.thename = val;\ - if (gspca_dev->streaming)\ - sd->waitSet = 1;\ - return 0;\ -} \ -static int sd_get_##thename(struct gspca_dev *gspca_dev, s32 *val)\ -{\ - struct sd *sd = (struct sd *) gspca_dev;\ -\ - *val = sd->vcur.thename;\ - return 0;\ -} +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *) gspca_dev; -SD_SETGET(mirror) -SD_SETGET(flip) -SD_SETGET(AC50Hz) -SD_SETGET(backlight) -SD_SETGET(brightness) -SD_SETGET(gamma) -SD_SETGET(hue) -SD_SETGET(saturation) -SD_SETGET(sharpness) -SD_SETGET(whitebal) -SD_SETGET(contrast) - -#define GL860_NCTRLS 11 - -/* control table */ -static struct ctrl sd_ctrls_mi1320[GL860_NCTRLS]; -static struct ctrl sd_ctrls_mi2020[GL860_NCTRLS]; -static struct ctrl sd_ctrls_ov2640[GL860_NCTRLS]; -static struct ctrl sd_ctrls_ov9655[GL860_NCTRLS]; - -#define SET_MY_CTRL(theid, \ - thetype, thelabel, thename) \ - if (sd->vmax.thename != 0) {\ - sd_ctrls[nCtrls].qctrl.id = theid;\ - sd_ctrls[nCtrls].qctrl.type = thetype;\ - strcpy(sd_ctrls[nCtrls].qctrl.name, thelabel);\ - sd_ctrls[nCtrls].qctrl.minimum = 0;\ - sd_ctrls[nCtrls].qctrl.maximum = sd->vmax.thename;\ - sd_ctrls[nCtrls].qctrl.default_value = sd->vcur.thename;\ - sd_ctrls[nCtrls].qctrl.step = \ - (sd->vmax.thename < 16) ? 1 : sd->vmax.thename/16;\ - sd_ctrls[nCtrls].set = sd_set_##thename;\ - sd_ctrls[nCtrls].get = sd_get_##thename;\ - nCtrls++;\ + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + sd->vcur.brightness = ctrl->val; + break; + case V4L2_CID_CONTRAST: + sd->vcur.contrast = ctrl->val; + break; + case V4L2_CID_SATURATION: + sd->vcur.saturation = ctrl->val; + break; + case V4L2_CID_HUE: + sd->vcur.hue = ctrl->val; + break; + case V4L2_CID_GAMMA: + sd->vcur.gamma = ctrl->val; + break; + case V4L2_CID_HFLIP: + sd->vcur.mirror = ctrl->val; + break; + case V4L2_CID_VFLIP: + sd->vcur.flip = ctrl->val; + break; + case V4L2_CID_POWER_LINE_FREQUENCY: + sd->vcur.AC50Hz = ctrl->val; + break; + case V4L2_CID_WHITE_BALANCE_TEMPERATURE: + sd->vcur.whitebal = ctrl->val; + break; + case V4L2_CID_SHARPNESS: + sd->vcur.sharpness = ctrl->val; + break; + case V4L2_CID_BACKLIGHT_COMPENSATION: + sd->vcur.backlight = ctrl->val; + break; + default: + return -EINVAL; } -static int gl860_build_control_table(struct gspca_dev *gspca_dev) + if (gspca_dev->streaming) + sd->waitSet = 1; + + return 0; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +static int sd_init_controls(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct ctrl *sd_ctrls; - int nCtrls = 0; - - if (_MI1320_) - sd_ctrls = sd_ctrls_mi1320; - else if (_MI2020_) - sd_ctrls = sd_ctrls_mi2020; - else if (_OV2640_) - sd_ctrls = sd_ctrls_ov2640; - else if (_OV9655_) - sd_ctrls = sd_ctrls_ov9655; - else - return 0; - - memset(sd_ctrls, 0, GL860_NCTRLS * sizeof(struct ctrl)); - - SET_MY_CTRL(V4L2_CID_BRIGHTNESS, - V4L2_CTRL_TYPE_INTEGER, "Brightness", brightness) - SET_MY_CTRL(V4L2_CID_SHARPNESS, - V4L2_CTRL_TYPE_INTEGER, "Sharpness", sharpness) - SET_MY_CTRL(V4L2_CID_CONTRAST, - V4L2_CTRL_TYPE_INTEGER, "Contrast", contrast) - SET_MY_CTRL(V4L2_CID_GAMMA, - V4L2_CTRL_TYPE_INTEGER, "Gamma", gamma) - SET_MY_CTRL(V4L2_CID_HUE, - V4L2_CTRL_TYPE_INTEGER, "Palette", hue) - SET_MY_CTRL(V4L2_CID_SATURATION, - V4L2_CTRL_TYPE_INTEGER, "Saturation", saturation) - SET_MY_CTRL(V4L2_CID_WHITE_BALANCE_TEMPERATURE, - V4L2_CTRL_TYPE_INTEGER, "White Bal.", whitebal) - SET_MY_CTRL(V4L2_CID_BACKLIGHT_COMPENSATION, - V4L2_CTRL_TYPE_INTEGER, "Backlight" , backlight) - - SET_MY_CTRL(V4L2_CID_HFLIP, - V4L2_CTRL_TYPE_BOOLEAN, "Mirror", mirror) - SET_MY_CTRL(V4L2_CID_VFLIP, - V4L2_CTRL_TYPE_BOOLEAN, "Flip", flip) - SET_MY_CTRL(V4L2_CID_POWER_LINE_FREQUENCY, - V4L2_CTRL_TYPE_BOOLEAN, "AC power 50Hz", AC50Hz) - - return nCtrls; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 11); + + if (sd->vmax.brightness) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_BRIGHTNESS, + 0, sd->vmax.brightness, 1, + sd->vcur.brightness); + + if (sd->vmax.contrast) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_CONTRAST, + 0, sd->vmax.contrast, 1, + sd->vcur.contrast); + + if (sd->vmax.saturation) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_SATURATION, + 0, sd->vmax.saturation, 1, + sd->vcur.saturation); + + if (sd->vmax.hue) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_HUE, + 0, sd->vmax.hue, 1, sd->vcur.hue); + + if (sd->vmax.gamma) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_GAMMA, + 0, sd->vmax.gamma, 1, sd->vcur.gamma); + + if (sd->vmax.mirror) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_HFLIP, + 0, sd->vmax.mirror, 1, sd->vcur.mirror); + + if (sd->vmax.flip) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_VFLIP, + 0, sd->vmax.flip, 1, sd->vcur.flip); + + if (sd->vmax.AC50Hz) + v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + sd->vmax.AC50Hz, 0, sd->vcur.AC50Hz); + + if (sd->vmax.whitebal) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_WHITE_BALANCE_TEMPERATURE, + 0, sd->vmax.whitebal, 1, sd->vcur.whitebal); + + if (sd->vmax.sharpness) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_SHARPNESS, + 0, sd->vmax.sharpness, 1, + sd->vcur.sharpness); + + if (sd->vmax.backlight) + v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BACKLIGHT_COMPENSATION, + 0, sd->vmax.backlight, 1, + sd->vcur.backlight); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + + return 0; } /*==================== sud-driver structure initialisation =================*/ static const struct sd_desc sd_desc_mi1320 = { .name = MODULE_NAME, - .ctrls = sd_ctrls_mi1320, - .nctrls = GL860_NCTRLS, .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .isoc_init = sd_isoc_init, .start = sd_start, .stop0 = sd_stop0, @@ -176,10 +196,9 @@ static const struct sd_desc sd_desc_mi1320 = { static const struct sd_desc sd_desc_mi2020 = { .name = MODULE_NAME, - .ctrls = sd_ctrls_mi2020, - .nctrls = GL860_NCTRLS, .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .isoc_init = sd_isoc_init, .start = sd_start, .stop0 = sd_stop0, @@ -189,10 +208,9 @@ static const struct sd_desc sd_desc_mi2020 = { static const struct sd_desc sd_desc_ov2640 = { .name = MODULE_NAME, - .ctrls = sd_ctrls_ov2640, - .nctrls = GL860_NCTRLS, .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .isoc_init = sd_isoc_init, .start = sd_start, .stop0 = sd_stop0, @@ -202,10 +220,9 @@ static const struct sd_desc sd_desc_ov2640 = { static const struct sd_desc sd_desc_ov9655 = { .name = MODULE_NAME, - .ctrls = sd_ctrls_ov9655, - .nctrls = GL860_NCTRLS, .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .isoc_init = sd_isoc_init, .start = sd_start, .stop0 = sd_stop0, @@ -371,7 +388,6 @@ static int sd_config(struct gspca_dev *gspca_dev, dev_init_settings(gspca_dev); if (AC50Hz != 0xff) ((struct sd *) gspca_dev)->vcur.AC50Hz = AC50Hz; - gl860_build_control_table(gspca_dev); return 0; } -- cgit v1.2.3 From c84e412f6f3be6ba262b1b9691ce57593b576c90 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 19 Feb 2013 14:57:03 -0300 Subject: [media] gscpa_m5602: Convert to the control framework Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/m5602/m5602_bridge.h | 27 +- drivers/media/usb/gspca/m5602/m5602_core.c | 16 +- drivers/media/usb/gspca/m5602/m5602_mt9m111.c | 388 ++++++---------------- drivers/media/usb/gspca/m5602/m5602_mt9m111.h | 2 + drivers/media/usb/gspca/m5602/m5602_ov7660.c | 300 ++++------------- drivers/media/usb/gspca/m5602/m5602_ov7660.h | 3 + drivers/media/usb/gspca/m5602/m5602_ov9650.c | 445 ++++++------------------- drivers/media/usb/gspca/m5602/m5602_ov9650.h | 2 + drivers/media/usb/gspca/m5602/m5602_po1030.c | 452 ++++++-------------------- drivers/media/usb/gspca/m5602/m5602_po1030.h | 2 + drivers/media/usb/gspca/m5602/m5602_s5k4aa.c | 338 +++++-------------- drivers/media/usb/gspca/m5602/m5602_s5k4aa.h | 2 + drivers/media/usb/gspca/m5602/m5602_s5k83a.c | 290 ++++------------- drivers/media/usb/gspca/m5602/m5602_s5k83a.h | 9 +- drivers/media/usb/gspca/m5602/m5602_sensor.h | 3 + 15 files changed, 569 insertions(+), 1710 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/gspca/m5602/m5602_bridge.h b/drivers/media/usb/gspca/m5602/m5602_bridge.h index 51af3ee3ab85..19eb1a64f9d6 100644 --- a/drivers/media/usb/gspca/m5602/m5602_bridge.h +++ b/drivers/media/usb/gspca/m5602/m5602_bridge.h @@ -136,16 +136,33 @@ struct sd { /* A pointer to the currently connected sensor */ const struct m5602_sensor *sensor; - struct sd_desc *desc; - - /* Sensor private data */ - void *sensor_priv; - /* The current frame's id, used to detect frame boundaries */ u8 frame_id; /* The current frame count */ u32 frame_count; + + /* Camera rotation polling thread for "flipable" cams */ + struct task_struct *rotation_thread; + + struct { /* auto-white-bal + green/red/blue balance control cluster */ + struct v4l2_ctrl *auto_white_bal; + struct v4l2_ctrl *red_bal; + struct v4l2_ctrl *blue_bal; + struct v4l2_ctrl *green_bal; + }; + struct { /* autoexpo / expo cluster */ + struct v4l2_ctrl *autoexpo; + struct v4l2_ctrl *expo; + }; + struct { /* autogain / gain cluster */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *gain; + }; + struct { /* hflip/vflip cluster */ + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + }; }; int m5602_read_bridge( diff --git a/drivers/media/usb/gspca/m5602/m5602_core.c b/drivers/media/usb/gspca/m5602/m5602_core.c index ed22638978ce..907a968f474d 100644 --- a/drivers/media/usb/gspca/m5602/m5602_core.c +++ b/drivers/media/usb/gspca/m5602/m5602_core.c @@ -252,6 +252,16 @@ static int m5602_init(struct gspca_dev *gspca_dev) return err; } +static int m5602_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (!sd->sensor->init_controls) + return 0; + + return sd->sensor->init_controls(sd); +} + static int m5602_start_transfer(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -336,11 +346,12 @@ static void m5602_stop_transfer(struct gspca_dev *gspca_dev) sd->sensor->stop(sd); } -/* sub-driver description, the ctrl and nctrl is filled at probe time */ -static struct sd_desc sd_desc = { +/* sub-driver description */ +static const struct sd_desc sd_desc = { .name = MODULE_NAME, .config = m5602_configure, .init = m5602_init, + .init_controls = m5602_init_controls, .start = m5602_start_transfer, .stopN = m5602_stop_transfer, .pkt_scan = m5602_urb_complete @@ -355,7 +366,6 @@ static int m5602_configure(struct gspca_dev *gspca_dev, int err; cam = &gspca_dev->cam; - sd->desc = &sd_desc; if (dump_bridge) m5602_dump_bridge(sd); diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c index 6268aa24ec5d..b5f66921b3eb 100644 --- a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c +++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c @@ -20,22 +20,8 @@ #include "m5602_mt9m111.h" -static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 val); -static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val); -static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val); -static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); -static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); +static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl); +static void mt9m111_dump_registers(struct sd *sd); static struct v4l2_pix_format mt9m111_modes[] = { { @@ -50,118 +36,26 @@ static struct v4l2_pix_format mt9m111_modes[] = { } }; -static const struct ctrl mt9m111_ctrls[] = { -#define VFLIP_IDX 0 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = mt9m111_set_vflip, - .get = mt9m111_get_vflip - }, -#define HFLIP_IDX 1 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = mt9m111_set_hflip, - .get = mt9m111_get_hflip - }, -#define GAIN_IDX 2 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0, - .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2, - .step = 1, - .default_value = MT9M111_DEFAULT_GAIN, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = mt9m111_set_gain, - .get = mt9m111_get_gain - }, -#define AUTO_WHITE_BALANCE_IDX 3 - { - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto white balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set = mt9m111_set_auto_white_balance, - .get = mt9m111_get_auto_white_balance - }, -#define GREEN_BALANCE_IDX 4 - { - { - .id = M5602_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0x7ff, - .step = 0x1, - .default_value = MT9M111_GREEN_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = mt9m111_set_green_balance, - .get = mt9m111_get_green_balance - }, -#define BLUE_BALANCE_IDX 5 - { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0x7ff, - .step = 0x1, - .default_value = MT9M111_BLUE_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = mt9m111_set_blue_balance, - .get = mt9m111_get_blue_balance - }, -#define RED_BALANCE_IDX 5 - { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0x7ff, - .step = 0x1, - .default_value = MT9M111_RED_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = mt9m111_set_red_balance, - .get = mt9m111_get_red_balance - }, +static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = { + .s_ctrl = mt9m111_s_ctrl, }; -static void mt9m111_dump_registers(struct sd *sd); +static const struct v4l2_ctrl_config mt9m111_greenbal_cfg = { + .ops = &mt9m111_ctrl_ops, + .id = M5602_V4L2_CID_GREEN_BALANCE, + .name = "Green Balance", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 0x7ff, + .step = 1, + .def = MT9M111_GREEN_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER, +}; int mt9m111_probe(struct sd *sd) { u8 data[2] = {0x00, 0x00}; int i; - s32 *sensor_settings; if (force_sensor) { if (force_sensor == MT9M111_SENSOR) { @@ -200,19 +94,8 @@ int mt9m111_probe(struct sd *sd) return -ENODEV; sensor_found: - sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32), - GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - sd->gspca_dev.cam.cam_mode = mt9m111_modes; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes); - sd->desc->ctrls = mt9m111_ctrls; - sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls); - - for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++) - sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value; - sd->sensor_priv = sensor_settings; return 0; } @@ -220,7 +103,6 @@ sensor_found: int mt9m111_init(struct sd *sd) { int i, err = 0; - s32 *sensor_settings = sd->sensor_priv; /* Init the sensor */ for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) { @@ -241,30 +123,45 @@ int mt9m111_init(struct sd *sd) if (dump_sensor) mt9m111_dump_registers(sd); - err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); - if (err < 0) - return err; - - err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); - if (err < 0) - return err; - - err = mt9m111_set_green_balance(&sd->gspca_dev, - sensor_settings[GREEN_BALANCE_IDX]); - if (err < 0) - return err; + return 0; +} - err = mt9m111_set_blue_balance(&sd->gspca_dev, - sensor_settings[BLUE_BALANCE_IDX]); - if (err < 0) - return err; +int mt9m111_init_controls(struct sd *sd) +{ + struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; + + sd->gspca_dev.vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 7); + + sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, + 0, 1, 1, 0); + sd->green_bal = v4l2_ctrl_new_custom(hdl, &mt9m111_greenbal_cfg, NULL); + sd->red_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 0x7ff, 1, + MT9M111_RED_GAIN_DEFAULT); + sd->blue_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 0, 0x7ff, 1, + MT9M111_BLUE_GAIN_DEFAULT); + + v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_GAIN, 0, + (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2, 1, + MT9M111_DEFAULT_GAIN); + + sd->hflip = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_HFLIP, + 0, 1, 1, 0); + sd->vflip = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_VFLIP, + 0, 1, 1, 0); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } - err = mt9m111_set_red_balance(&sd->gspca_dev, - sensor_settings[RED_BALANCE_IDX]); - if (err < 0) - return err; + v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false); + v4l2_ctrl_cluster(2, &sd->hflip); - return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); + return 0; } int mt9m111_start(struct sd *sd) @@ -272,7 +169,6 @@ int mt9m111_start(struct sd *sd) int i, err = 0; u8 data[2]; struct cam *cam = &sd->gspca_dev.cam; - s32 *sensor_settings = sd->sensor_priv; int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1; int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; @@ -334,25 +230,10 @@ int mt9m111_start(struct sd *sd) switch (width) { case 640: PDEBUG(D_V4L2, "Configuring camera for VGA mode"); - data[0] = MT9M111_RMB_OVER_SIZED; - data[1] = MT9M111_RMB_ROW_SKIP_2X | - MT9M111_RMB_COLUMN_SKIP_2X | - (sensor_settings[VFLIP_IDX] << 0) | - (sensor_settings[HFLIP_IDX] << 1); - - err = m5602_write_sensor(sd, - MT9M111_SC_R_MODE_CONTEXT_B, data, 2); break; case 320: PDEBUG(D_V4L2, "Configuring camera for QVGA mode"); - data[0] = MT9M111_RMB_OVER_SIZED; - data[1] = MT9M111_RMB_ROW_SKIP_4X | - MT9M111_RMB_COLUMN_SKIP_4X | - (sensor_settings[VFLIP_IDX] << 0) | - (sensor_settings[HFLIP_IDX] << 1); - err = m5602_write_sensor(sd, - MT9M111_SC_R_MODE_CONTEXT_B, data, 2); break; } return err; @@ -361,105 +242,46 @@ int mt9m111_start(struct sd *sd) void mt9m111_disconnect(struct sd *sd) { sd->sensor = NULL; - kfree(sd->sensor_priv); -} - -static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[VFLIP_IDX]; - PDEBUG(D_V4L2, "Read vertical flip %d", *val); - - return 0; -} - -static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 data[2] = {0x00, 0x00}; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set vertical flip to %d", val); - - sensor_settings[VFLIP_IDX] = val; - - /* The mt9m111 is flipped by default */ - val = !val; - - /* Set the correct page map */ - err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); - if (err < 0) - return err; - - data[1] = (data[1] & 0xfe) | val; - err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, - data, 2); - return err; -} - -static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[HFLIP_IDX]; - PDEBUG(D_V4L2, "Read horizontal flip %d", *val); - - return 0; } -static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +static int mt9m111_set_hvflip(struct gspca_dev *gspca_dev) { int err; u8 data[2] = {0x00, 0x00}; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; + int hflip; + int vflip; - PDEBUG(D_V4L2, "Set horizontal flip to %d", val); - - sensor_settings[HFLIP_IDX] = val; + PDEBUG(D_V4L2, "Set hvflip to %d %d", sd->hflip->val, sd->vflip->val); /* The mt9m111 is flipped by default */ - val = !val; + hflip = !sd->hflip->val; + vflip = !sd->vflip->val; /* Set the correct page map */ err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); if (err < 0) return err; - err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); - if (err < 0) - return err; - - data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02); + data[0] = MT9M111_RMB_OVER_SIZED; + if (gspca_dev->width == 640) { + data[1] = MT9M111_RMB_ROW_SKIP_2X | + MT9M111_RMB_COLUMN_SKIP_2X | + (hflip << 1) | vflip; + } else { + data[1] = MT9M111_RMB_ROW_SKIP_4X | + MT9M111_RMB_COLUMN_SKIP_4X | + (hflip << 1) | vflip; + } err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); return err; } -static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GAIN_IDX]; - PDEBUG(D_V4L2, "Read gain %d", *val); - - return 0; -} - static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; int err; u8 data[2]; @@ -467,7 +289,6 @@ static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, if (err < 0) return err; - sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01; data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1)); err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); @@ -476,24 +297,11 @@ static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, return err; } -static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val) { - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read auto white balance %d", *val); - return 0; -} - static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) { int err, tmp; u8 data[2] = {0x00, 0x00}; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - sensor_settings[GAIN_IDX] = val; /* Set the correct page map */ err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); @@ -532,9 +340,7 @@ static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) int err; u8 data[2]; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - sensor_settings[GREEN_BALANCE_IDX] = val; data[1] = (val & 0xff); data[0] = (val & 0xff00) >> 8; @@ -548,23 +354,11 @@ static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) data, 2); } -static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GREEN_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read green balance %d", *val); - return 0; -} - static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) { u8 data[2]; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - sensor_settings[BLUE_BALANCE_IDX] = val; data[1] = (val & 0xff); data[0] = (val & 0xff00) >> 8; @@ -574,23 +368,11 @@ static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) data, 2); } -static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[BLUE_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read blue balance %d", *val); - return 0; -} - static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) { u8 data[2]; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - sensor_settings[RED_BALANCE_IDX] = val; data[1] = (val & 0xff); data[0] = (val & 0xff00) >> 8; @@ -600,14 +382,40 @@ static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) data, 2); } -static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) +static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl) { + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; + int err; - *val = sensor_settings[RED_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read red balance %d", *val); - return 0; + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_AUTO_WHITE_BALANCE: + err = mt9m111_set_auto_white_balance(gspca_dev, ctrl->val); + if (err || ctrl->val) + return err; + err = mt9m111_set_green_balance(gspca_dev, sd->green_bal->val); + if (err) + return err; + err = mt9m111_set_red_balance(gspca_dev, sd->red_bal->val); + if (err) + return err; + err = mt9m111_set_blue_balance(gspca_dev, sd->blue_bal->val); + break; + case V4L2_CID_GAIN: + err = mt9m111_set_gain(gspca_dev, ctrl->val); + break; + case V4L2_CID_HFLIP: + err = mt9m111_set_hvflip(gspca_dev); + break; + default: + return -EINVAL; + } + + return err; } static void mt9m111_dump_registers(struct sd *sd) diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.h b/drivers/media/usb/gspca/m5602/m5602_mt9m111.h index 8c672b5c8c6a..07448d35e3cd 100644 --- a/drivers/media/usb/gspca/m5602/m5602_mt9m111.h +++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.h @@ -110,6 +110,7 @@ extern bool dump_sensor; int mt9m111_probe(struct sd *sd); int mt9m111_init(struct sd *sd); +int mt9m111_init_controls(struct sd *sd); int mt9m111_start(struct sd *sd); void mt9m111_disconnect(struct sd *sd); @@ -121,6 +122,7 @@ static const struct m5602_sensor mt9m111 = { .probe = mt9m111_probe, .init = mt9m111_init, + .init_controls = mt9m111_init_controls, .disconnect = mt9m111_disconnect, .start = mt9m111_start, }; diff --git a/drivers/media/usb/gspca/m5602/m5602_ov7660.c b/drivers/media/usb/gspca/m5602/m5602_ov7660.c index 9a14835c128f..3bbe3ad5d4a9 100644 --- a/drivers/media/usb/gspca/m5602/m5602_ov7660.c +++ b/drivers/media/usb/gspca/m5602/m5602_ov7660.c @@ -20,111 +20,8 @@ #include "m5602_ov7660.h" -static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val); -static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 val); -static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val); -static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val); -static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val); - -static const struct ctrl ov7660_ctrls[] = { -#define GAIN_IDX 1 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = OV7660_DEFAULT_GAIN, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = ov7660_set_gain, - .get = ov7660_get_gain - }, -#define BLUE_BALANCE_IDX 2 -#define RED_BALANCE_IDX 3 -#define AUTO_WHITE_BALANCE_IDX 4 - { - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto white balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = ov7660_set_auto_white_balance, - .get = ov7660_get_auto_white_balance - }, -#define AUTO_GAIN_CTRL_IDX 5 - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto gain control", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = ov7660_set_auto_gain, - .get = ov7660_get_auto_gain - }, -#define AUTO_EXPOSURE_IDX 6 - { - { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = ov7660_set_auto_exposure, - .get = ov7660_get_auto_exposure - }, -#define HFLIP_IDX 7 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = ov7660_set_hflip, - .get = ov7660_get_hflip - }, -#define VFLIP_IDX 8 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = ov7660_set_vflip, - .get = ov7660_get_vflip - }, - -}; +static int ov7660_s_ctrl(struct v4l2_ctrl *ctrl); +static void ov7660_dump_registers(struct sd *sd); static struct v4l2_pix_format ov7660_modes[] = { { @@ -140,15 +37,15 @@ static struct v4l2_pix_format ov7660_modes[] = { } }; -static void ov7660_dump_registers(struct sd *sd); +static const struct v4l2_ctrl_ops ov7660_ctrl_ops = { + .s_ctrl = ov7660_s_ctrl, +}; int ov7660_probe(struct sd *sd) { int err = 0, i; u8 prod_id = 0, ver_id = 0; - s32 *sensor_settings; - if (force_sensor) { if (force_sensor == OV7660_SENSOR) { pr_info("Forcing an %s sensor\n", ov7660.name); @@ -191,19 +88,8 @@ int ov7660_probe(struct sd *sd) return -ENODEV; sensor_found: - sensor_settings = kmalloc( - ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - sd->gspca_dev.cam.cam_mode = ov7660_modes; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes); - sd->desc->ctrls = ov7660_ctrls; - sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls); - - for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++) - sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value; - sd->sensor_priv = sensor_settings; return 0; } @@ -211,7 +97,6 @@ sensor_found: int ov7660_init(struct sd *sd) { int i, err = 0; - s32 *sensor_settings = sd->sensor_priv; /* Init the sensor */ for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) { @@ -231,33 +116,40 @@ int ov7660_init(struct sd *sd) if (dump_sensor) ov7660_dump_registers(sd); - err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); - if (err < 0) - return err; + return 0; +} - err = ov7660_set_auto_white_balance(&sd->gspca_dev, - sensor_settings[AUTO_WHITE_BALANCE_IDX]); - if (err < 0) - return err; +int ov7660_init_controls(struct sd *sd) +{ + struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; - err = ov7660_set_auto_gain(&sd->gspca_dev, - sensor_settings[AUTO_GAIN_CTRL_IDX]); - if (err < 0) - return err; + sd->gspca_dev.vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 6); - err = ov7660_set_auto_exposure(&sd->gspca_dev, - sensor_settings[AUTO_EXPOSURE_IDX]); - if (err < 0) - return err; - err = ov7660_set_hflip(&sd->gspca_dev, - sensor_settings[HFLIP_IDX]); - if (err < 0) - return err; + v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE, + 0, 1, 1, 1); + v4l2_ctrl_new_std_menu(hdl, &ov7660_ctrl_ops, + V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO); - err = ov7660_set_vflip(&sd->gspca_dev, - sensor_settings[VFLIP_IDX]); + sd->autogain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + sd->gain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_GAIN, 0, + 255, 1, OV7660_DEFAULT_GAIN); - return err; + sd->hflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_HFLIP, + 0, 1, 1, 0); + sd->vflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_VFLIP, + 0, 1, 1, 0); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + + v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false); + v4l2_ctrl_cluster(2, &sd->hflip); + + return 0; } int ov7660_start(struct sd *sd) @@ -275,56 +167,29 @@ void ov7660_disconnect(struct sd *sd) ov7660_stop(sd); sd->sensor = NULL; - kfree(sd->sensor_priv); -} - -static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GAIN_IDX]; - PDEBUG(D_V4L2, "Read gain %d", *val); - return 0; } static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val) { int err; - u8 i2c_data; + u8 i2c_data = val; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; PDEBUG(D_V4L2, "Setting gain to %d", val); - sensor_settings[GAIN_IDX] = val; - err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1); return err; } - -static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; - return 0; -} - static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; PDEBUG(D_V4L2, "Set auto white balance to %d", val); - sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); if (err < 0) return err; @@ -335,26 +200,14 @@ static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, return err; } -static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_GAIN_CTRL_IDX]; - PDEBUG(D_V4L2, "Read auto gain control %d", *val); - return 0; -} - static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; PDEBUG(D_V4L2, "Set auto gain control to %d", val); - sensor_settings[AUTO_GAIN_CTRL_IDX] = val; err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); if (err < 0) return err; @@ -364,94 +217,69 @@ static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); } -static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_EXPOSURE_IDX]; - PDEBUG(D_V4L2, "Read auto exposure control %d", *val); - return 0; -} - static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; PDEBUG(D_V4L2, "Set auto exposure control to %d", val); - sensor_settings[AUTO_EXPOSURE_IDX] = val; err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); if (err < 0) return err; + val = (val == V4L2_EXPOSURE_AUTO); i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0)); return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); } -static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[HFLIP_IDX]; - PDEBUG(D_V4L2, "Read horizontal flip %d", *val); - return 0; -} - -static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +static int ov7660_set_hvflip(struct gspca_dev *gspca_dev) { int err; u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - PDEBUG(D_V4L2, "Set horizontal flip to %d", val); + PDEBUG(D_V4L2, "Set hvflip to %d, %d", sd->hflip->val, sd->vflip->val); - sensor_settings[HFLIP_IDX] = val; - - i2c_data = ((val & 0x01) << 5) | - (sensor_settings[VFLIP_IDX] << 4); + i2c_data = (sd->hflip->val << 5) | (sd->vflip->val << 4); err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1); return err; } -static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +static int ov7660_s_ctrl(struct v4l2_ctrl *ctrl) { + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[VFLIP_IDX]; - PDEBUG(D_V4L2, "Read vertical flip %d", *val); - - return 0; -} - -static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val) -{ int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set vertical flip to %d", val); - sensor_settings[VFLIP_IDX] = val; - i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5); - err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1); - if (err < 0) - return err; - - /* When vflip is toggled we need to readjust the bridge hsync/vsync */ - if (gspca_dev->streaming) - err = ov7660_start(sd); + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_AUTO_WHITE_BALANCE: + err = ov7660_set_auto_white_balance(gspca_dev, ctrl->val); + break; + case V4L2_CID_EXPOSURE_AUTO: + err = ov7660_set_auto_exposure(gspca_dev, ctrl->val); + break; + case V4L2_CID_AUTOGAIN: + err = ov7660_set_auto_gain(gspca_dev, ctrl->val); + if (err || ctrl->val) + return err; + err = ov7660_set_gain(gspca_dev, sd->gain->val); + break; + case V4L2_CID_HFLIP: + err = ov7660_set_hvflip(gspca_dev); + break; + default: + return -EINVAL; + } return err; } diff --git a/drivers/media/usb/gspca/m5602/m5602_ov7660.h b/drivers/media/usb/gspca/m5602/m5602_ov7660.h index 2b6a13b508f7..6fece1ce1232 100644 --- a/drivers/media/usb/gspca/m5602/m5602_ov7660.h +++ b/drivers/media/usb/gspca/m5602/m5602_ov7660.h @@ -90,6 +90,8 @@ extern bool dump_sensor; int ov7660_probe(struct sd *sd); int ov7660_init(struct sd *sd); +int ov7660_init(struct sd *sd); +int ov7660_init_controls(struct sd *sd); int ov7660_start(struct sd *sd); int ov7660_stop(struct sd *sd); void ov7660_disconnect(struct sd *sd); @@ -100,6 +102,7 @@ static const struct m5602_sensor ov7660 = { .i2c_regW = 1, .probe = ov7660_probe, .init = ov7660_init, + .init_controls = ov7660_init_controls, .start = ov7660_start, .stop = ov7660_stop, .disconnect = ov7660_disconnect, diff --git a/drivers/media/usb/gspca/m5602/m5602_ov9650.c b/drivers/media/usb/gspca/m5602/m5602_ov9650.c index 2114a8b90ec9..e2fe2f942fe6 100644 --- a/drivers/media/usb/gspca/m5602/m5602_ov9650.c +++ b/drivers/media/usb/gspca/m5602/m5602_ov9650.c @@ -20,26 +20,8 @@ #include "m5602_ov9650.h" -static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); -static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); -static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val); -static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 val); -static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val); -static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val); +static int ov9650_s_ctrl(struct v4l2_ctrl *ctrl); +static void ov9650_dump_registers(struct sd *sd); /* Vertically and horizontally flips the image if matched, needed for machines where the sensor is mounted upside down */ @@ -113,140 +95,6 @@ static {} }; -static const struct ctrl ov9650_ctrls[] = { -#define EXPOSURE_IDX 0 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x1ff, - .step = 0x4, - .default_value = EXPOSURE_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = ov9650_set_exposure, - .get = ov9650_get_exposure - }, -#define GAIN_IDX 1 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0x00, - .maximum = 0x3ff, - .step = 0x1, - .default_value = GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = ov9650_set_gain, - .get = ov9650_get_gain - }, -#define RED_BALANCE_IDX 2 - { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = RED_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = ov9650_set_red_balance, - .get = ov9650_get_red_balance - }, -#define BLUE_BALANCE_IDX 3 - { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = BLUE_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = ov9650_set_blue_balance, - .get = ov9650_get_blue_balance - }, -#define HFLIP_IDX 4 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = ov9650_set_hflip, - .get = ov9650_get_hflip - }, -#define VFLIP_IDX 5 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = ov9650_set_vflip, - .get = ov9650_get_vflip - }, -#define AUTO_WHITE_BALANCE_IDX 6 - { - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto white balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = ov9650_set_auto_white_balance, - .get = ov9650_get_auto_white_balance - }, -#define AUTO_GAIN_CTRL_IDX 7 - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto gain control", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = ov9650_set_auto_gain, - .get = ov9650_get_auto_gain - }, -#define AUTO_EXPOSURE_IDX 8 - { - { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = ov9650_set_auto_exposure, - .get = ov9650_get_auto_exposure - } - -}; - static struct v4l2_pix_format ov9650_modes[] = { { 176, @@ -291,13 +139,14 @@ static struct v4l2_pix_format ov9650_modes[] = { } }; -static void ov9650_dump_registers(struct sd *sd); +static const struct v4l2_ctrl_ops ov9650_ctrl_ops = { + .s_ctrl = ov9650_s_ctrl, +}; int ov9650_probe(struct sd *sd) { int err = 0; u8 prod_id = 0, ver_id = 0, i; - s32 *sensor_settings; if (force_sensor) { if (force_sensor == OV9650_SENSOR) { @@ -338,19 +187,9 @@ int ov9650_probe(struct sd *sd) return -ENODEV; sensor_found: - sensor_settings = kmalloc( - ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - sd->gspca_dev.cam.cam_mode = ov9650_modes; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes); - sd->desc->ctrls = ov9650_ctrls; - sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls); - for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++) - sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value; - sd->sensor_priv = sensor_settings; return 0; } @@ -358,7 +197,6 @@ int ov9650_init(struct sd *sd) { int i, err = 0; u8 data; - s32 *sensor_settings = sd->sensor_priv; if (dump_sensor) ov9650_dump_registers(sd); @@ -372,46 +210,52 @@ int ov9650_init(struct sd *sd) err = m5602_write_bridge(sd, init_ov9650[i][1], data); } - err = ov9650_set_exposure(&sd->gspca_dev, - sensor_settings[EXPOSURE_IDX]); - if (err < 0) - return err; - - err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); - if (err < 0) - return err; - - err = ov9650_set_red_balance(&sd->gspca_dev, - sensor_settings[RED_BALANCE_IDX]); - if (err < 0) - return err; - - err = ov9650_set_blue_balance(&sd->gspca_dev, - sensor_settings[BLUE_BALANCE_IDX]); - if (err < 0) - return err; - - err = ov9650_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); - if (err < 0) - return err; - - err = ov9650_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); - if (err < 0) - return err; + return 0; +} - err = ov9650_set_auto_exposure(&sd->gspca_dev, - sensor_settings[AUTO_EXPOSURE_IDX]); - if (err < 0) - return err; +int ov9650_init_controls(struct sd *sd) +{ + struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; + + sd->gspca_dev.vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 9); + + sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, + 0, 1, 1, 1); + sd->red_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 255, 1, + RED_GAIN_DEFAULT); + sd->blue_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 0, 255, 1, + BLUE_GAIN_DEFAULT); + + sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &ov9650_ctrl_ops, + V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO); + sd->expo = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_EXPOSURE, + 0, 0x1ff, 4, EXPOSURE_DEFAULT); + + sd->autogain = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + sd->gain = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_GAIN, 0, + 0x3ff, 1, GAIN_DEFAULT); + + sd->hflip = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_HFLIP, + 0, 1, 1, 0); + sd->vflip = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_VFLIP, + 0, 1, 1, 0); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } - err = ov9650_set_auto_white_balance(&sd->gspca_dev, - sensor_settings[AUTO_WHITE_BALANCE_IDX]); - if (err < 0) - return err; + v4l2_ctrl_auto_cluster(3, &sd->auto_white_bal, 0, false); + v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false); + v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false); + v4l2_ctrl_cluster(2, &sd->hflip); - err = ov9650_set_auto_gain(&sd->gspca_dev, - sensor_settings[AUTO_GAIN_CTRL_IDX]); - return err; + return 0; } int ov9650_start(struct sd *sd) @@ -419,7 +263,6 @@ int ov9650_start(struct sd *sd) u8 data; int i, err = 0; struct cam *cam = &sd->gspca_dev.cam; - s32 *sensor_settings = sd->sensor_priv; int width = cam->cam_mode[sd->gspca_dev.curr_mode].width; int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; @@ -427,9 +270,9 @@ int ov9650_start(struct sd *sd) int hor_offs = OV9650_LEFT_OFFSET; if ((!dmi_check_system(ov9650_flip_dmi_table) && - sensor_settings[VFLIP_IDX]) || + sd->vflip->val) || (dmi_check_system(ov9650_flip_dmi_table) && - !sensor_settings[VFLIP_IDX])) + !sd->vflip->val)) ver_offs--; if (width <= 320) @@ -553,29 +396,16 @@ void ov9650_disconnect(struct sd *sd) ov9650_stop(sd); sd->sensor = NULL; - kfree(sd->sensor_priv); -} - -static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[EXPOSURE_IDX]; - PDEBUG(D_V4L2, "Read exposure %d", *val); - return 0; } static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; PDEBUG(D_V4L2, "Set exposure to %d", val); - sensor_settings[EXPOSURE_IDX] = val; /* The 6 MSBs */ i2c_data = (val >> 10) & 0x3f; err = m5602_write_sensor(sd, OV9650_AECHM, @@ -596,27 +426,14 @@ static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) return err; } -static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GAIN_IDX]; - PDEBUG(D_V4L2, "Read gain %d", *val); - return 0; -} - static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; PDEBUG(D_V4L2, "Setting gain to %d", val); - sensor_settings[GAIN_IDX] = val; - /* The 2 MSB */ /* Read the OV9650_VREF register first to avoid corrupting the VREF high and low bits */ @@ -637,117 +454,46 @@ static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) return err; } -static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[RED_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read red gain %d", *val); - return 0; -} - static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; PDEBUG(D_V4L2, "Set red gain to %d", val); - sensor_settings[RED_BALANCE_IDX] = val; - i2c_data = val & 0xff; err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1); return err; } -static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[BLUE_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read blue gain %d", *val); - - return 0; -} - static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; PDEBUG(D_V4L2, "Set blue gain to %d", val); - sensor_settings[BLUE_BALANCE_IDX] = val; - i2c_data = val & 0xff; err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1); return err; } -static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[HFLIP_IDX]; - PDEBUG(D_V4L2, "Read horizontal flip %d", *val); - return 0; -} - -static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +static int ov9650_set_hvflip(struct gspca_dev *gspca_dev) { int err; u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; + int hflip = sd->hflip->val; + int vflip = sd->vflip->val; - PDEBUG(D_V4L2, "Set horizontal flip to %d", val); - - sensor_settings[HFLIP_IDX] = val; - - if (!dmi_check_system(ov9650_flip_dmi_table)) - i2c_data = ((val & 0x01) << 5) | - (sensor_settings[VFLIP_IDX] << 4); - else - i2c_data = ((val & 0x01) << 5) | - (!sensor_settings[VFLIP_IDX] << 4); - - err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); - - return err; -} - -static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[VFLIP_IDX]; - PDEBUG(D_V4L2, "Read vertical flip %d", *val); - - return 0; -} - -static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) -{ - int err; - u8 i2c_data; - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - PDEBUG(D_V4L2, "Set vertical flip to %d", val); - sensor_settings[VFLIP_IDX] = val; + PDEBUG(D_V4L2, "Set hvflip to %d %d", hflip, vflip); if (dmi_check_system(ov9650_flip_dmi_table)) - val = !val; + vflip = !vflip; - i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5); + i2c_data = (hflip << 5) | (vflip << 4); err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); if (err < 0) return err; @@ -759,57 +505,34 @@ static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) return err; } -static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_EXPOSURE_IDX]; - PDEBUG(D_V4L2, "Read auto exposure control %d", *val); - return 0; -} - static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; PDEBUG(D_V4L2, "Set auto exposure control to %d", val); - sensor_settings[AUTO_EXPOSURE_IDX] = val; err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); if (err < 0) return err; + val = (val == V4L2_EXPOSURE_AUTO); i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0)); return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); } -static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; - return 0; -} - static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; PDEBUG(D_V4L2, "Set auto white balance to %d", val); - sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); if (err < 0) return err; @@ -820,26 +543,14 @@ static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, return err; } -static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_GAIN_CTRL_IDX]; - PDEBUG(D_V4L2, "Read auto gain control %d", *val); - return 0; -} - static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; PDEBUG(D_V4L2, "Set auto gain control to %d", val); - sensor_settings[AUTO_GAIN_CTRL_IDX] = val; err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); if (err < 0) return err; @@ -849,6 +560,48 @@ static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); } +static int ov9650_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *) gspca_dev; + int err; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_AUTO_WHITE_BALANCE: + err = ov9650_set_auto_white_balance(gspca_dev, ctrl->val); + if (err || ctrl->val) + return err; + err = ov9650_set_red_balance(gspca_dev, sd->red_bal->val); + if (err) + return err; + err = ov9650_set_blue_balance(gspca_dev, sd->blue_bal->val); + break; + case V4L2_CID_EXPOSURE_AUTO: + err = ov9650_set_auto_exposure(gspca_dev, ctrl->val); + if (err || ctrl->val == V4L2_EXPOSURE_AUTO) + return err; + err = ov9650_set_exposure(gspca_dev, sd->expo->val); + break; + case V4L2_CID_AUTOGAIN: + err = ov9650_set_auto_gain(gspca_dev, ctrl->val); + if (err || ctrl->val) + return err; + err = ov9650_set_gain(gspca_dev, sd->gain->val); + break; + case V4L2_CID_HFLIP: + err = ov9650_set_hvflip(gspca_dev); + break; + default: + return -EINVAL; + } + + return err; +} + static void ov9650_dump_registers(struct sd *sd) { int address; diff --git a/drivers/media/usb/gspca/m5602/m5602_ov9650.h b/drivers/media/usb/gspca/m5602/m5602_ov9650.h index f7aa5bf68983..f9f5870da60f 100644 --- a/drivers/media/usb/gspca/m5602/m5602_ov9650.h +++ b/drivers/media/usb/gspca/m5602/m5602_ov9650.h @@ -139,6 +139,7 @@ extern bool dump_sensor; int ov9650_probe(struct sd *sd); int ov9650_init(struct sd *sd); +int ov9650_init_controls(struct sd *sd); int ov9650_start(struct sd *sd); int ov9650_stop(struct sd *sd); void ov9650_disconnect(struct sd *sd); @@ -149,6 +150,7 @@ static const struct m5602_sensor ov9650 = { .i2c_regW = 1, .probe = ov9650_probe, .init = ov9650_init, + .init_controls = ov9650_init_controls, .start = ov9650_start, .stop = ov9650_stop, .disconnect = ov9650_disconnect, diff --git a/drivers/media/usb/gspca/m5602/m5602_po1030.c b/drivers/media/usb/gspca/m5602/m5602_po1030.c index b8771698cbcb..189086291303 100644 --- a/drivers/media/usb/gspca/m5602/m5602_po1030.c +++ b/drivers/media/usb/gspca/m5602/m5602_po1030.c @@ -20,28 +20,8 @@ #include "m5602_po1030.h" -static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 val); -static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val); -static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, - __s32 val); -static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev, - __s32 *val); +static int po1030_s_ctrl(struct v4l2_ctrl *ctrl); +static void po1030_dump_registers(struct sd *sd); static struct v4l2_pix_format po1030_modes[] = { { @@ -56,146 +36,25 @@ static struct v4l2_pix_format po1030_modes[] = { } }; -static const struct ctrl po1030_ctrls[] = { -#define GAIN_IDX 0 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0x00, - .maximum = 0x4f, - .step = 0x1, - .default_value = PO1030_GLOBAL_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = po1030_set_gain, - .get = po1030_get_gain - }, -#define EXPOSURE_IDX 1 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0x02ff, - .step = 0x1, - .default_value = PO1030_EXPOSURE_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = po1030_set_exposure, - .get = po1030_get_exposure - }, -#define RED_BALANCE_IDX 2 - { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "red balance", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = PO1030_RED_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = po1030_set_red_balance, - .get = po1030_get_red_balance - }, -#define BLUE_BALANCE_IDX 3 - { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "blue balance", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = PO1030_BLUE_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = po1030_set_blue_balance, - .get = po1030_get_blue_balance - }, -#define HFLIP_IDX 4 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set = po1030_set_hflip, - .get = po1030_get_hflip - }, -#define VFLIP_IDX 5 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set = po1030_set_vflip, - .get = po1030_get_vflip - }, -#define AUTO_WHITE_BALANCE_IDX 6 - { - { - .id = V4L2_CID_AUTO_WHITE_BALANCE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto white balance", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set = po1030_set_auto_white_balance, - .get = po1030_get_auto_white_balance - }, -#define AUTO_EXPOSURE_IDX 7 - { - { - .id = V4L2_CID_EXPOSURE_AUTO, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "auto exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set = po1030_set_auto_exposure, - .get = po1030_get_auto_exposure - }, -#define GREEN_BALANCE_IDX 8 - { - { - .id = M5602_V4L2_CID_GREEN_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "green balance", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = PO1030_GREEN_GAIN_DEFAULT, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = po1030_set_green_balance, - .get = po1030_get_green_balance - }, +static const struct v4l2_ctrl_ops po1030_ctrl_ops = { + .s_ctrl = po1030_s_ctrl, }; -static void po1030_dump_registers(struct sd *sd); +static const struct v4l2_ctrl_config po1030_greenbal_cfg = { + .ops = &po1030_ctrl_ops, + .id = M5602_V4L2_CID_GREEN_BALANCE, + .name = "Green Balance", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 255, + .step = 1, + .def = PO1030_GREEN_GAIN_DEFAULT, + .flags = V4L2_CTRL_FLAG_SLIDER, +}; int po1030_probe(struct sd *sd) { u8 dev_id_h = 0, i; - s32 *sensor_settings; if (force_sensor) { if (force_sensor == PO1030_SENSOR) { @@ -229,26 +88,14 @@ int po1030_probe(struct sd *sd) return -ENODEV; sensor_found: - sensor_settings = kmalloc( - ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - sd->gspca_dev.cam.cam_mode = po1030_modes; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes); - sd->desc->ctrls = po1030_ctrls; - sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls); - - for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++) - sensor_settings[i] = po1030_ctrls[i].qctrl.default_value; - sd->sensor_priv = sensor_settings; return 0; } int po1030_init(struct sd *sd) { - s32 *sensor_settings = sd->sensor_priv; int i, err = 0; /* Init the sensor */ @@ -279,46 +126,50 @@ int po1030_init(struct sd *sd) if (dump_sensor) po1030_dump_registers(sd); - err = po1030_set_exposure(&sd->gspca_dev, - sensor_settings[EXPOSURE_IDX]); - if (err < 0) - return err; - - err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); - if (err < 0) - return err; - - err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); - if (err < 0) - return err; - - err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); - if (err < 0) - return err; - - err = po1030_set_red_balance(&sd->gspca_dev, - sensor_settings[RED_BALANCE_IDX]); - if (err < 0) - return err; - - err = po1030_set_blue_balance(&sd->gspca_dev, - sensor_settings[BLUE_BALANCE_IDX]); - if (err < 0) - return err; + return 0; +} - err = po1030_set_green_balance(&sd->gspca_dev, - sensor_settings[GREEN_BALANCE_IDX]); - if (err < 0) - return err; +int po1030_init_controls(struct sd *sd) +{ + struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; + + sd->gspca_dev.vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 9); + + sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, + 0, 1, 1, 0); + sd->green_bal = v4l2_ctrl_new_custom(hdl, &po1030_greenbal_cfg, NULL); + sd->red_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 255, 1, + PO1030_RED_GAIN_DEFAULT); + sd->blue_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 0, 255, 1, + PO1030_BLUE_GAIN_DEFAULT); + + sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &po1030_ctrl_ops, + V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_MANUAL); + sd->expo = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_EXPOSURE, + 0, 0x2ff, 1, PO1030_EXPOSURE_DEFAULT); + + sd->gain = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_GAIN, 0, + 0x4f, 1, PO1030_GLOBAL_GAIN_DEFAULT); + + sd->hflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_HFLIP, + 0, 1, 1, 0); + sd->vflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_VFLIP, + 0, 1, 1, 0); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } - err = po1030_set_auto_white_balance(&sd->gspca_dev, - sensor_settings[AUTO_WHITE_BALANCE_IDX]); - if (err < 0) - return err; + v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false); + v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false); + v4l2_ctrl_cluster(2, &sd->hflip); - err = po1030_set_auto_exposure(&sd->gspca_dev, - sensor_settings[AUTO_EXPOSURE_IDX]); - return err; + return 0; } int po1030_start(struct sd *sd) @@ -448,24 +299,12 @@ int po1030_start(struct sd *sd) return err; } -static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[EXPOSURE_IDX]; - PDEBUG(D_V4L2, "Exposure read as %d", *val); - return 0; -} - static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; - sensor_settings[EXPOSURE_IDX] = val; PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff); i2c_data = ((val & 0xff00) >> 8); @@ -486,25 +325,12 @@ static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) return err; } -static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GAIN_IDX]; - PDEBUG(D_V4L2, "Read global gain %d", *val); - return 0; -} - static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; - sensor_settings[GAIN_IDX] = val; - i2c_data = val & 0xff; PDEBUG(D_V4L2, "Set global gain to %d", i2c_data); err = m5602_write_sensor(sd, PO1030_GLOBALGAIN, @@ -512,65 +338,19 @@ static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val) return err; } -static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[HFLIP_IDX]; - PDEBUG(D_V4L2, "Read hflip %d", *val); - - return 0; -} - -static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 i2c_data; - int err; - - sensor_settings[HFLIP_IDX] = val; - - PDEBUG(D_V4L2, "Set hflip %d", val); - err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); - if (err < 0) - return err; - - i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7); - - err = m5602_write_sensor(sd, PO1030_CONTROL2, - &i2c_data, 1); - - return err; -} - -static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +static int po1030_set_hvflip(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[VFLIP_IDX]; - PDEBUG(D_V4L2, "Read vflip %d", *val); - - return 0; -} - -static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; - sensor_settings[VFLIP_IDX] = val; - - PDEBUG(D_V4L2, "Set vflip %d", val); + PDEBUG(D_V4L2, "Set hvflip %d %d", sd->hflip->val, sd->vflip->val); err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); if (err < 0) return err; - i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6); + i2c_data = (0x3f & i2c_data) | (sd->hflip->val << 7) | + (sd->vflip->val << 6); err = m5602_write_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); @@ -578,25 +358,12 @@ static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val) return err; } -static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[RED_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read red gain %d", *val); - return 0; -} - static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; - sensor_settings[RED_BALANCE_IDX] = val; - i2c_data = val & 0xff; PDEBUG(D_V4L2, "Set red gain to %d", i2c_data); err = m5602_write_sensor(sd, PO1030_RED_GAIN, @@ -604,26 +371,12 @@ static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) return err; } -static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[BLUE_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read blue gain %d", *val); - - return 0; -} - static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; - sensor_settings[BLUE_BALANCE_IDX] = val; - i2c_data = val & 0xff; PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data); err = m5602_write_sensor(sd, PO1030_BLUE_GAIN, @@ -632,25 +385,12 @@ static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) return err; } -static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GREEN_BALANCE_IDX]; - PDEBUG(D_V4L2, "Read green gain %d", *val); - - return 0; -} - static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; - sensor_settings[GREEN_BALANCE_IDX] = val; i2c_data = val & 0xff; PDEBUG(D_V4L2, "Set green gain to %d", i2c_data); @@ -663,28 +403,13 @@ static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) &i2c_data, 1); } -static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev, - __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; - PDEBUG(D_V4L2, "Auto white balancing is %d", *val); - - return 0; -} - static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; - sensor_settings[AUTO_WHITE_BALANCE_IDX] = val; - err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); if (err < 0) return err; @@ -695,31 +420,19 @@ static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, return err; } -static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev, - __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTO_EXPOSURE_IDX]; - PDEBUG(D_V4L2, "Auto exposure is %d", *val); - return 0; -} - static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; u8 i2c_data; int err; - sensor_settings[AUTO_EXPOSURE_IDX] = val; err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); if (err < 0) return err; PDEBUG(D_V4L2, "Set auto exposure to %d", val); + val = (val == V4L2_EXPOSURE_AUTO); i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1); return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); } @@ -727,7 +440,48 @@ static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, void po1030_disconnect(struct sd *sd) { sd->sensor = NULL; - kfree(sd->sensor_priv); +} + +static int po1030_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *) gspca_dev; + int err; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_AUTO_WHITE_BALANCE: + err = po1030_set_auto_white_balance(gspca_dev, ctrl->val); + if (err || ctrl->val) + return err; + err = po1030_set_green_balance(gspca_dev, sd->green_bal->val); + if (err) + return err; + err = po1030_set_red_balance(gspca_dev, sd->red_bal->val); + if (err) + return err; + err = po1030_set_blue_balance(gspca_dev, sd->blue_bal->val); + break; + case V4L2_CID_EXPOSURE_AUTO: + err = po1030_set_auto_exposure(gspca_dev, ctrl->val); + if (err || ctrl->val == V4L2_EXPOSURE_AUTO) + return err; + err = po1030_set_exposure(gspca_dev, sd->expo->val); + break; + case V4L2_CID_GAIN: + err = po1030_set_gain(gspca_dev, ctrl->val); + break; + case V4L2_CID_HFLIP: + err = po1030_set_hvflip(gspca_dev); + break; + default: + return -EINVAL; + } + + return err; } static void po1030_dump_registers(struct sd *sd) diff --git a/drivers/media/usb/gspca/m5602/m5602_po1030.h b/drivers/media/usb/gspca/m5602/m5602_po1030.h index 81a2bcb88fe3..a6ab76149bd0 100644 --- a/drivers/media/usb/gspca/m5602/m5602_po1030.h +++ b/drivers/media/usb/gspca/m5602/m5602_po1030.h @@ -151,6 +151,7 @@ extern bool dump_sensor; int po1030_probe(struct sd *sd); int po1030_init(struct sd *sd); +int po1030_init_controls(struct sd *sd); int po1030_start(struct sd *sd); void po1030_disconnect(struct sd *sd); @@ -162,6 +163,7 @@ static const struct m5602_sensor po1030 = { .probe = po1030_probe, .init = po1030_init, + .init_controls = po1030_init_controls, .start = po1030_start, .disconnect = po1030_disconnect, }; diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c index c8e1572eb502..42ffaf04771c 100644 --- a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c +++ b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c @@ -20,18 +20,12 @@ #include "m5602_s5k4aa.h" -static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val); -static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val); +static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl); +static void s5k4aa_dump_registers(struct sd *sd); + +static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = { + .s_ctrl = s5k4aa_s_ctrl, +}; static const @@ -147,104 +141,11 @@ static struct v4l2_pix_format s5k4aa_modes[] = { } }; -static const struct ctrl s5k4aa_ctrls[] = { -#define VFLIP_IDX 0 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = s5k4aa_set_vflip, - .get = s5k4aa_get_vflip - }, -#define HFLIP_IDX 1 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = s5k4aa_set_hflip, - .get = s5k4aa_get_hflip - }, -#define GAIN_IDX 2 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = S5K4AA_DEFAULT_GAIN, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = s5k4aa_set_gain, - .get = s5k4aa_get_gain - }, -#define EXPOSURE_IDX 3 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 13, - .maximum = 0xfff, - .step = 1, - .default_value = 0x100, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = s5k4aa_set_exposure, - .get = s5k4aa_get_exposure - }, -#define NOISE_SUPP_IDX 4 - { - { - .id = V4L2_CID_PRIVATE_BASE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Noise suppression (smoothing)", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - .set = s5k4aa_set_noise, - .get = s5k4aa_get_noise - }, -#define BRIGHTNESS_IDX 5 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 0x1f, - .step = 1, - .default_value = S5K4AA_DEFAULT_BRIGHTNESS, - }, - .set = s5k4aa_set_brightness, - .get = s5k4aa_get_brightness - }, - -}; - -static void s5k4aa_dump_registers(struct sd *sd); - int s5k4aa_probe(struct sd *sd) { u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75}; int i, err = 0; - s32 *sensor_settings; if (force_sensor) { if (force_sensor == S5K4AA_SENSOR) { @@ -303,19 +204,8 @@ int s5k4aa_probe(struct sd *sd) pr_info("Detected a s5k4aa sensor\n"); sensor_found: - sensor_settings = kmalloc( - ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - sd->gspca_dev.cam.cam_mode = s5k4aa_modes; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes); - sd->desc->ctrls = s5k4aa_ctrls; - sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls); - - for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++) - sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value; - sd->sensor_priv = sensor_settings; return 0; } @@ -325,7 +215,6 @@ int s5k4aa_start(struct sd *sd) int i, err = 0; u8 data[2]; struct cam *cam = &sd->gspca_dev.cam; - s32 *sensor_settings = sd->sensor_priv; switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) { case 1280: @@ -359,9 +248,6 @@ int s5k4aa_start(struct sd *sd) return -EINVAL; } } - err = s5k4aa_set_noise(&sd->gspca_dev, 0); - if (err < 0) - return err; break; case 640: @@ -395,37 +281,12 @@ int s5k4aa_start(struct sd *sd) return -EINVAL; } } - err = s5k4aa_set_noise(&sd->gspca_dev, 1); - if (err < 0) - return err; break; } if (err < 0) return err; - err = s5k4aa_set_exposure(&sd->gspca_dev, - sensor_settings[EXPOSURE_IDX]); - if (err < 0) - return err; - - err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); - if (err < 0) - return err; - - err = s5k4aa_set_brightness(&sd->gspca_dev, - sensor_settings[BRIGHTNESS_IDX]); - if (err < 0) - return err; - - err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]); - if (err < 0) - return err; - - err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); - if (err < 0) - return err; - - return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); + return 0; } int s5k4aa_init(struct sd *sd) @@ -466,13 +327,36 @@ int s5k4aa_init(struct sd *sd) return err; } -static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) +int s5k4aa_init_controls(struct sd *sd) { - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; + struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; + + sd->gspca_dev.vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 6); - *val = sensor_settings[EXPOSURE_IDX]; - PDEBUG(D_V4L2, "Read exposure %d", *val); + v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_BRIGHTNESS, + 0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS); + + v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_EXPOSURE, + 13, 0xfff, 1, 0x100); + + v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_GAIN, + 0, 127, 1, S5K4AA_DEFAULT_GAIN); + + v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_SHARPNESS, + 0, 1, 1, 1); + + sd->hflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_HFLIP, + 0, 1, 1, 0); + sd->vflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_VFLIP, + 0, 1, 1, 0); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + + v4l2_ctrl_cluster(2, &sd->hflip); return 0; } @@ -480,11 +364,9 @@ static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; u8 data = S5K4AA_PAGE_MAP_2; int err; - sensor_settings[EXPOSURE_IDX] = val; PDEBUG(D_V4L2, "Set exposure to %d", val); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) @@ -499,27 +381,15 @@ static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) return err; } -static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +static int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[VFLIP_IDX]; - PDEBUG(D_V4L2, "Read vertical flip %d", *val); - - return 0; -} - -static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; u8 data = S5K4AA_PAGE_MAP_2; int err; + int hflip = sd->hflip->val; + int vflip = sd->vflip->val; - sensor_settings[VFLIP_IDX] = val; - - PDEBUG(D_V4L2, "Set vertical flip to %d", val); + PDEBUG(D_V4L2, "Set hvflip %d %d", hflip, vflip); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) return err; @@ -528,92 +398,47 @@ static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val) if (err < 0) return err; - if (dmi_check_system(s5k4aa_vflip_dmi_table)) - val = !val; + if (dmi_check_system(s5k4aa_vflip_dmi_table)) { + hflip = !hflip; + vflip = !vflip; + } - data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7)); + data = (data & 0x7f) | (vflip << 7) | (hflip << 6); err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); if (err < 0) return err; - err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); if (err < 0) return err; - if (val) + if (hflip) data &= 0xfe; else data |= 0x01; - err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); - return err; -} - -static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[HFLIP_IDX]; - PDEBUG(D_V4L2, "Read horizontal flip %d", *val); - - return 0; -} - -static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - u8 data = S5K4AA_PAGE_MAP_2; - int err; - - sensor_settings[HFLIP_IDX] = val; - - PDEBUG(D_V4L2, "Set horizontal flip to %d", val); - err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - if (err < 0) - return err; - - err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); - if (err < 0) - return err; - - if (dmi_check_system(s5k4aa_vflip_dmi_table)) - val = !val; - - data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6)); - err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); if (err < 0) return err; - err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); if (err < 0) return err; - if (val) + if (vflip) data &= 0xfe; else data |= 0x01; - err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); - return err; -} - -static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; + err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + if (err < 0) + return err; - *val = sensor_settings[GAIN_IDX]; - PDEBUG(D_V4L2, "Read gain %d", *val); return 0; } static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; u8 data = S5K4AA_PAGE_MAP_2; int err; - sensor_settings[GAIN_IDX] = val; - PDEBUG(D_V4L2, "Set gain to %d", val); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) @@ -625,25 +450,12 @@ static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) return err; } -static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[BRIGHTNESS_IDX]; - PDEBUG(D_V4L2, "Read brightness %d", *val); - return 0; -} - static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; u8 data = S5K4AA_PAGE_MAP_2; int err; - sensor_settings[BRIGHTNESS_IDX] = val; - PDEBUG(D_V4L2, "Set brightness to %d", val); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) @@ -653,25 +465,12 @@ static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val) return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1); } -static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[NOISE_SUPP_IDX]; - PDEBUG(D_V4L2, "Read noise %d", *val); - return 0; -} - static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; u8 data = S5K4AA_PAGE_MAP_2; int err; - sensor_settings[NOISE_SUPP_IDX] = val; - PDEBUG(D_V4L2, "Set noise to %d", val); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) @@ -681,10 +480,41 @@ static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val) return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1); } +static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + int err; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + err = s5k4aa_set_brightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_EXPOSURE: + err = s5k4aa_set_exposure(gspca_dev, ctrl->val); + break; + case V4L2_CID_GAIN: + err = s5k4aa_set_gain(gspca_dev, ctrl->val); + break; + case V4L2_CID_SHARPNESS: + err = s5k4aa_set_noise(gspca_dev, ctrl->val); + break; + case V4L2_CID_HFLIP: + err = s5k4aa_set_hvflip(gspca_dev); + break; + default: + return -EINVAL; + } + + return err; +} + void s5k4aa_disconnect(struct sd *sd) { sd->sensor = NULL; - kfree(sd->sensor_priv); } static void s5k4aa_dump_registers(struct sd *sd) diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h index 8e0035e731c7..9953e9766954 100644 --- a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h +++ b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.h @@ -69,6 +69,7 @@ extern bool dump_sensor; int s5k4aa_probe(struct sd *sd); int s5k4aa_init(struct sd *sd); +int s5k4aa_init_controls(struct sd *sd); int s5k4aa_start(struct sd *sd); void s5k4aa_disconnect(struct sd *sd); @@ -79,6 +80,7 @@ static const struct m5602_sensor s5k4aa = { .probe = s5k4aa_probe, .init = s5k4aa_init, + .init_controls = s5k4aa_init_controls, .start = s5k4aa_start, .disconnect = s5k4aa_disconnect, }; diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c index 1de743a02b02..69ee6e26b8ea 100644 --- a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c +++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c @@ -21,16 +21,11 @@ #include #include "m5602_s5k83a.h" -static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val); -static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); -static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val); +static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl); + +static const struct v4l2_ctrl_ops s5k83a_ctrl_ops = { + .s_ctrl = s5k83a_s_ctrl, +}; static struct v4l2_pix_format s5k83a_modes[] = { { @@ -46,83 +41,6 @@ static struct v4l2_pix_format s5k83a_modes[] = { } }; -static const struct ctrl s5k83a_ctrls[] = { -#define GAIN_IDX 0 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = S5K83A_DEFAULT_GAIN, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = s5k83a_set_gain, - .get = s5k83a_get_gain - - }, -#define BRIGHTNESS_IDX 1 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "brightness", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x01, - .default_value = S5K83A_DEFAULT_BRIGHTNESS, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = s5k83a_set_brightness, - .get = s5k83a_get_brightness, - }, -#define EXPOSURE_IDX 2 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = S5K83A_MAXIMUM_EXPOSURE, - .step = 0x01, - .default_value = S5K83A_DEFAULT_EXPOSURE, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = s5k83a_set_exposure, - .get = s5k83a_get_exposure - }, -#define HFLIP_IDX 3 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = s5k83a_set_hflip, - .get = s5k83a_get_hflip - }, -#define VFLIP_IDX 4 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = s5k83a_set_vflip, - .get = s5k83a_get_vflip - } -}; - static void s5k83a_dump_registers(struct sd *sd); static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data); static int s5k83a_set_led_indication(struct sd *sd, u8 val); @@ -131,7 +49,6 @@ static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, int s5k83a_probe(struct sd *sd) { - struct s5k83a_priv *sens_priv; u8 prod_id = 0, ver_id = 0; int i, err = 0; @@ -173,38 +90,18 @@ int s5k83a_probe(struct sd *sd) pr_info("Detected a s5k83a sensor\n"); sensor_found: - sens_priv = kmalloc( - sizeof(struct s5k83a_priv), GFP_KERNEL); - if (!sens_priv) - return -ENOMEM; - - sens_priv->settings = - kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL); - if (!sens_priv->settings) { - kfree(sens_priv); - return -ENOMEM; - } - sd->gspca_dev.cam.cam_mode = s5k83a_modes; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes); - sd->desc->ctrls = s5k83a_ctrls; - sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls); /* null the pointer! thread is't running now */ - sens_priv->rotation_thread = NULL; - - for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++) - sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value; + sd->rotation_thread = NULL; - sd->sensor_priv = sens_priv; return 0; } int s5k83a_init(struct sd *sd) { int i, err = 0; - s32 *sensor_settings = - ((struct s5k83a_priv *) sd->sensor_priv)->settings; for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) { u8 data[2] = {0x00, 0x00}; @@ -237,33 +134,44 @@ int s5k83a_init(struct sd *sd) if (dump_sensor) s5k83a_dump_registers(sd); - err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); - if (err < 0) - return err; + return err; +} - err = s5k83a_set_brightness(&sd->gspca_dev, - sensor_settings[BRIGHTNESS_IDX]); - if (err < 0) - return err; +int s5k83a_init_controls(struct sd *sd) +{ + struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; - err = s5k83a_set_exposure(&sd->gspca_dev, - sensor_settings[EXPOSURE_IDX]); - if (err < 0) - return err; + sd->gspca_dev.vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 6); - err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); - if (err < 0) - return err; + v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_BRIGHTNESS, + 0, 255, 1, S5K83A_DEFAULT_BRIGHTNESS); - err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); + v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_EXPOSURE, + 0, S5K83A_MAXIMUM_EXPOSURE, 1, + S5K83A_DEFAULT_EXPOSURE); - return err; + v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_GAIN, + 0, 255, 1, S5K83A_DEFAULT_GAIN); + + sd->hflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_HFLIP, + 0, 1, 1, 0); + sd->vflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_VFLIP, + 0, 1, 1, 0); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + + v4l2_ctrl_cluster(2, &sd->hflip); + + return 0; } static int rotation_thread_function(void *data) { struct sd *sd = (struct sd *) data; - struct s5k83a_priv *sens_priv = sd->sensor_priv; u8 reg, previous_rotation = 0; __s32 vflip, hflip; @@ -277,8 +185,8 @@ static int rotation_thread_function(void *data) previous_rotation = reg; pr_info("Camera was flipped\n"); - s5k83a_get_vflip((struct gspca_dev *) sd, &vflip); - s5k83a_get_hflip((struct gspca_dev *) sd, &hflip); + hflip = sd->hflip->val; + vflip = sd->vflip->val; if (reg) { vflip = !vflip; @@ -294,26 +202,25 @@ static int rotation_thread_function(void *data) /* return to "front" flip */ if (previous_rotation) { - s5k83a_get_vflip((struct gspca_dev *) sd, &vflip); - s5k83a_get_hflip((struct gspca_dev *) sd, &hflip); + hflip = sd->hflip->val; + vflip = sd->vflip->val; s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip); } - sens_priv->rotation_thread = NULL; + sd->rotation_thread = NULL; return 0; } int s5k83a_start(struct sd *sd) { int i, err = 0; - struct s5k83a_priv *sens_priv = sd->sensor_priv; /* Create another thread, polling the GPIO ports of the camera to check if it got rotated. This is how the windows driver does it so we have to assume that there is no better way of accomplishing this */ - sens_priv->rotation_thread = kthread_create(rotation_thread_function, - sd, "rotation thread"); - wake_up_process(sens_priv->rotation_thread); + sd->rotation_thread = kthread_create(rotation_thread_function, + sd, "rotation thread"); + wake_up_process(sd->rotation_thread); /* Preinit the sensor */ for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) { @@ -333,32 +240,17 @@ int s5k83a_start(struct sd *sd) int s5k83a_stop(struct sd *sd) { - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - if (sens_priv->rotation_thread) - kthread_stop(sens_priv->rotation_thread); + if (sd->rotation_thread) + kthread_stop(sd->rotation_thread); return s5k83a_set_led_indication(sd, 0); } void s5k83a_disconnect(struct sd *sd) { - struct s5k83a_priv *sens_priv = sd->sensor_priv; - s5k83a_stop(sd); sd->sensor = NULL; - kfree(sens_priv->settings); - kfree(sens_priv); -} - -static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - *val = sens_priv->settings[GAIN_IDX]; - return 0; } static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val) @@ -366,9 +258,6 @@ static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val) int err; u8 data[2]; struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - sens_priv->settings[GAIN_IDX] = val; data[0] = 0x00; data[1] = 0x20; @@ -391,60 +280,29 @@ static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val) return err; } -static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - *val = sens_priv->settings[BRIGHTNESS_IDX]; - return 0; -} - static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 data[1]; struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - sens_priv->settings[BRIGHTNESS_IDX] = val; data[0] = val; err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1); return err; } -static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - *val = sens_priv->settings[EXPOSURE_IDX]; - return 0; -} - static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val) { int err; u8 data[2]; struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - sens_priv->settings[EXPOSURE_IDX] = val; data[0] = 0; data[1] = val; err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2); return err; } -static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - *val = sens_priv->settings[VFLIP_IDX]; - return 0; -} - static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, __s32 vflip, __s32 hflip) { @@ -476,60 +334,52 @@ static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, return err; } -static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val) +static int s5k83a_set_hvflip(struct gspca_dev *gspca_dev) { int err; u8 reg; - __s32 hflip; struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - sens_priv->settings[VFLIP_IDX] = val; - - s5k83a_get_hflip(gspca_dev, &hflip); + int hflip = sd->hflip->val; + int vflip = sd->vflip->val; err = s5k83a_get_rotation(sd, ®); if (err < 0) return err; if (reg) { - val = !val; hflip = !hflip; + vflip = !vflip; } - err = s5k83a_set_flip_real(gspca_dev, val, hflip); + err = s5k83a_set_flip_real(gspca_dev, vflip, hflip); return err; } -static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - *val = sens_priv->settings[HFLIP_IDX]; - return 0; -} - -static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val) +static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl) { + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); int err; - u8 reg; - __s32 vflip; - struct sd *sd = (struct sd *) gspca_dev; - struct s5k83a_priv *sens_priv = sd->sensor_priv; - - sens_priv->settings[HFLIP_IDX] = val; - s5k83a_get_vflip(gspca_dev, &vflip); - - err = s5k83a_get_rotation(sd, ®); - if (err < 0) - return err; - if (reg) { - val = !val; - vflip = !vflip; + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + err = s5k83a_set_brightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_EXPOSURE: + err = s5k83a_set_exposure(gspca_dev, ctrl->val); + break; + case V4L2_CID_GAIN: + err = s5k83a_set_gain(gspca_dev, ctrl->val); + break; + case V4L2_CID_HFLIP: + err = s5k83a_set_hvflip(gspca_dev); + break; + default: + return -EINVAL; } - err = s5k83a_set_flip_real(gspca_dev, vflip, val); return err; } diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k83a.h b/drivers/media/usb/gspca/m5602/m5602_s5k83a.h index 79952247b534..d61b918228df 100644 --- a/drivers/media/usb/gspca/m5602/m5602_s5k83a.h +++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.h @@ -45,6 +45,7 @@ extern bool dump_sensor; int s5k83a_probe(struct sd *sd); int s5k83a_init(struct sd *sd); +int s5k83a_init_controls(struct sd *sd); int s5k83a_start(struct sd *sd); int s5k83a_stop(struct sd *sd); void s5k83a_disconnect(struct sd *sd); @@ -53,6 +54,7 @@ static const struct m5602_sensor s5k83a = { .name = "S5K83A", .probe = s5k83a_probe, .init = s5k83a_init, + .init_controls = s5k83a_init_controls, .start = s5k83a_start, .stop = s5k83a_stop, .disconnect = s5k83a_disconnect, @@ -60,13 +62,6 @@ static const struct m5602_sensor s5k83a = { .i2c_regW = 2, }; -struct s5k83a_priv { - /* We use another thread periodically - probing the orientation of the camera */ - struct task_struct *rotation_thread; - s32 *settings; -}; - static const unsigned char preinit_s5k83a[][4] = { {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, diff --git a/drivers/media/usb/gspca/m5602/m5602_sensor.h b/drivers/media/usb/gspca/m5602/m5602_sensor.h index edff4f1f586f..48341b4d607b 100644 --- a/drivers/media/usb/gspca/m5602/m5602_sensor.h +++ b/drivers/media/usb/gspca/m5602/m5602_sensor.h @@ -57,6 +57,9 @@ struct m5602_sensor { /* Performs a initialization sequence */ int (*init)(struct sd *sd); + /* Controls initialization, maybe NULL */ + int (*init_controls)(struct sd *sd); + /* Executed when the camera starts to send data */ int (*start)(struct sd *sd); -- cgit v1.2.3 From 9f8c734735f97fa36a1b4ce89a5f4126b321ff3b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Feb 2013 06:31:55 -0300 Subject: [media] gspca_sonixb: Remove querymenu function (dead code) We forgot to remove that when sonixb was converted to the control framework. Signed-off-by: Hans Verkuil Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/sonixb.c | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c index 104ae25275b4..3fe207e038c7 100644 --- a/drivers/media/usb/gspca/sonixb.c +++ b/drivers/media/usb/gspca/sonixb.c @@ -1379,27 +1379,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } } -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "NoFliker"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } - break; - } - return -EINVAL; -} - #if IS_ENABLED(CONFIG_INPUT) static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, /* interrupt packet data */ @@ -1428,7 +1407,6 @@ static const struct sd_desc sd_desc = { .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, .dq_callback = do_autogain, #if IS_ENABLED(CONFIG_INPUT) .int_pkt_scan = sd_int_pkt_scan, -- cgit v1.2.3 From 2effe6de386212fe721aae132ee4735cd37a9b13 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 17 Feb 2013 17:11:25 -0300 Subject: [media] gscpa: Remove autogain_functions.h Now that sonixj.c has been converted to the control framework it is no longer used. Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/autogain_functions.h | 183 --------------------------- 1 file changed, 183 deletions(-) delete mode 100644 drivers/media/usb/gspca/autogain_functions.h (limited to 'drivers/media') diff --git a/drivers/media/usb/gspca/autogain_functions.h b/drivers/media/usb/gspca/autogain_functions.h deleted file mode 100644 index d625eafe63eb..000000000000 --- a/drivers/media/usb/gspca/autogain_functions.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Functions for auto gain. - * - * Copyright (C) 2010-2011 Hans de Goede - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifdef WANT_REGULAR_AUTOGAIN -/* auto gain and exposure algorithm based on the knee algorithm described here: - http://ytse.tricolour.net/docs/LowLightOptimization.html - - Returns 0 if no changes were made, 1 if the gain and or exposure settings - where changed. */ -static inline int auto_gain_n_exposure( - struct gspca_dev *gspca_dev, - int avg_lum, - int desired_avg_lum, - int deadzone, - int gain_knee, - int exposure_knee) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i, steps, gain, orig_gain, exposure, orig_exposure; - int retval = 0; - - orig_gain = gain = sd->ctrls[GAIN].val; - orig_exposure = exposure = sd->ctrls[EXPOSURE].val; - - /* If we are of a multiple of deadzone, do multiple steps to reach the - desired lumination fast (with the risc of a slight overshoot) */ - steps = abs(desired_avg_lum - avg_lum) / deadzone; - - PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", - avg_lum, desired_avg_lum, steps); - - for (i = 0; i < steps; i++) { - if (avg_lum > desired_avg_lum) { - if (gain > gain_knee) - gain--; - else if (exposure > exposure_knee) - exposure--; - else if (gain > sd->ctrls[GAIN].def) - gain--; - else if (exposure > sd->ctrls[EXPOSURE].min) - exposure--; - else if (gain > sd->ctrls[GAIN].min) - gain--; - else - break; - } else { - if (gain < sd->ctrls[GAIN].def) - gain++; - else if (exposure < exposure_knee) - exposure++; - else if (gain < gain_knee) - gain++; - else if (exposure < sd->ctrls[EXPOSURE].max) - exposure++; - else if (gain < sd->ctrls[GAIN].max) - gain++; - else - break; - } - } - - if (gain != orig_gain) { - sd->ctrls[GAIN].val = gain; - setgain(gspca_dev); - retval = 1; - } - if (exposure != orig_exposure) { - sd->ctrls[EXPOSURE].val = exposure; - setexposure(gspca_dev); - retval = 1; - } - - if (retval) - PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d", - gain, exposure); - return retval; -} -#endif - -#ifdef WANT_COARSE_EXPO_AUTOGAIN -/* Autogain + exposure algorithm for cameras with a coarse exposure control - (usually this means we can only control the clockdiv to change exposure) - As changing the clockdiv so that the fps drops from 30 to 15 fps for - example, will lead to a huge exposure change (it effectively doubles), - this algorithm normally tries to only adjust the gain (between 40 and - 80 %) and if that does not help, only then changes exposure. This leads - to a much more stable image then using the knee algorithm which at - certain points of the knee graph will only try to adjust exposure, - which leads to oscilating as one exposure step is huge. - - Note this assumes that the sd struct for the cam in question has - exp_too_low_cnt and exp_too_high_cnt int members for use by this function. - - Returns 0 if no changes were made, 1 if the gain and or exposure settings - where changed. */ -static inline int coarse_grained_expo_autogain( - struct gspca_dev *gspca_dev, - int avg_lum, - int desired_avg_lum, - int deadzone) -{ - struct sd *sd = (struct sd *) gspca_dev; - int steps, gain, orig_gain, exposure, orig_exposure; - int gain_low, gain_high; - int retval = 0; - - orig_gain = gain = sd->ctrls[GAIN].val; - orig_exposure = exposure = sd->ctrls[EXPOSURE].val; - - gain_low = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 2; - gain_low += sd->ctrls[GAIN].min; - gain_high = (sd->ctrls[GAIN].max - sd->ctrls[GAIN].min) / 5 * 4; - gain_high += sd->ctrls[GAIN].min; - - /* If we are of a multiple of deadzone, do multiple steps to reach the - desired lumination fast (with the risc of a slight overshoot) */ - steps = (desired_avg_lum - avg_lum) / deadzone; - - PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", - avg_lum, desired_avg_lum, steps); - - if ((gain + steps) > gain_high && - exposure < sd->ctrls[EXPOSURE].max) { - gain = gain_high; - sd->exp_too_low_cnt++; - sd->exp_too_high_cnt = 0; - } else if ((gain + steps) < gain_low && - exposure > sd->ctrls[EXPOSURE].min) { - gain = gain_low; - sd->exp_too_high_cnt++; - sd->exp_too_low_cnt = 0; - } else { - gain += steps; - if (gain > sd->ctrls[GAIN].max) - gain = sd->ctrls[GAIN].max; - else if (gain < sd->ctrls[GAIN].min) - gain = sd->ctrls[GAIN].min; - sd->exp_too_high_cnt = 0; - sd->exp_too_low_cnt = 0; - } - - if (sd->exp_too_high_cnt > 3) { - exposure--; - sd->exp_too_high_cnt = 0; - } else if (sd->exp_too_low_cnt > 3) { - exposure++; - sd->exp_too_low_cnt = 0; - } - - if (gain != orig_gain) { - sd->ctrls[GAIN].val = gain; - setgain(gspca_dev); - retval = 1; - } - if (exposure != orig_exposure) { - sd->ctrls[EXPOSURE].val = exposure; - setexposure(gspca_dev); - retval = 1; - } - - if (retval) - PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d", - gain, exposure); - return retval; -} -#endif -- cgit v1.2.3 From 70c8ecf54bf735f300f86bde562420af90bf9db4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 16 Feb 2013 14:42:59 -0300 Subject: [media] gspca: Remove old control code now that all drivers are converted Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/gspca.c | 160 ---------------------------------------- drivers/media/usb/gspca/gspca.h | 24 ------ 2 files changed, 184 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 3564bdbb2ea3..5784ff4e1b2f 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -984,7 +984,6 @@ out: static void gspca_set_default_mode(struct gspca_dev *gspca_dev) { - struct gspca_ctrl *ctrl; int i; i = gspca_dev->cam.nmodes - 1; /* take the highest mode */ @@ -993,17 +992,8 @@ static void gspca_set_default_mode(struct gspca_dev *gspca_dev) gspca_dev->height = gspca_dev->cam.cam_mode[i].height; gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat; - /* set the current control values to their default values - * which may have changed in sd_init() */ /* does nothing if ctrl_handler == NULL */ v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler); - ctrl = gspca_dev->cam.ctrls; - if (ctrl != NULL) { - for (i = 0; - i < gspca_dev->sd_desc->nctrls; - i++, ctrl++) - ctrl->val = ctrl->def; - } } static int wxh_to_mode(struct gspca_dev *gspca_dev, @@ -1357,134 +1347,6 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int get_ctrl(struct gspca_dev *gspca_dev, - int id) -{ - const struct ctrl *ctrls; - int i; - - for (i = 0, ctrls = gspca_dev->sd_desc->ctrls; - i < gspca_dev->sd_desc->nctrls; - i++, ctrls++) { - if (gspca_dev->ctrl_dis & (1 << i)) - continue; - if (id == ctrls->qctrl.id) - return i; - } - return -1; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *q_ctrl) -{ - struct gspca_dev *gspca_dev = video_drvdata(file); - const struct ctrl *ctrls; - struct gspca_ctrl *gspca_ctrl; - int i, idx; - u32 id; - - id = q_ctrl->id; - if (id & V4L2_CTRL_FLAG_NEXT_CTRL) { - id &= V4L2_CTRL_ID_MASK; - id++; - idx = -1; - for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { - if (gspca_dev->ctrl_dis & (1 << i)) - continue; - if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id) - continue; - if (idx >= 0 - && gspca_dev->sd_desc->ctrls[i].qctrl.id - > gspca_dev->sd_desc->ctrls[idx].qctrl.id) - continue; - idx = i; - } - } else { - idx = get_ctrl(gspca_dev, id); - } - if (idx < 0) - return -EINVAL; - ctrls = &gspca_dev->sd_desc->ctrls[idx]; - memcpy(q_ctrl, &ctrls->qctrl, sizeof *q_ctrl); - if (gspca_dev->cam.ctrls != NULL) { - gspca_ctrl = &gspca_dev->cam.ctrls[idx]; - q_ctrl->default_value = gspca_ctrl->def; - q_ctrl->minimum = gspca_ctrl->min; - q_ctrl->maximum = gspca_ctrl->max; - } - if (gspca_dev->ctrl_inac & (1 << idx)) - q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct gspca_dev *gspca_dev = video_drvdata(file); - const struct ctrl *ctrls; - struct gspca_ctrl *gspca_ctrl; - int idx; - - idx = get_ctrl(gspca_dev, ctrl->id); - if (idx < 0) - return -EINVAL; - if (gspca_dev->ctrl_inac & (1 << idx)) - return -EINVAL; - ctrls = &gspca_dev->sd_desc->ctrls[idx]; - if (gspca_dev->cam.ctrls != NULL) { - gspca_ctrl = &gspca_dev->cam.ctrls[idx]; - if (ctrl->value < gspca_ctrl->min - || ctrl->value > gspca_ctrl->max) - return -ERANGE; - } else { - gspca_ctrl = NULL; - if (ctrl->value < ctrls->qctrl.minimum - || ctrl->value > ctrls->qctrl.maximum) - return -ERANGE; - } - PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value); - gspca_dev->usb_err = 0; - if (ctrls->set != NULL) - return ctrls->set(gspca_dev, ctrl->value); - if (gspca_ctrl != NULL) { - gspca_ctrl->val = ctrl->value; - if (ctrls->set_control != NULL - && gspca_dev->streaming) - ctrls->set_control(gspca_dev); - } - return gspca_dev->usb_err; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct gspca_dev *gspca_dev = video_drvdata(file); - const struct ctrl *ctrls; - int idx; - - idx = get_ctrl(gspca_dev, ctrl->id); - if (idx < 0) - return -EINVAL; - ctrls = &gspca_dev->sd_desc->ctrls[idx]; - - gspca_dev->usb_err = 0; - if (ctrls->get != NULL) - return ctrls->get(gspca_dev, &ctrl->value); - if (gspca_dev->cam.ctrls != NULL) - ctrl->value = gspca_dev->cam.ctrls[idx].val; - return 0; -} - -static int vidioc_querymenu(struct file *file, void *priv, - struct v4l2_querymenu *qmenu) -{ - struct gspca_dev *gspca_dev = video_drvdata(file); - - if (!gspca_dev->sd_desc->querymenu) - return -ENOTTY; - return gspca_dev->sd_desc->querymenu(gspca_dev, qmenu); -} - static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *input) { @@ -2125,10 +1987,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = { .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_streamon = vidioc_streamon, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_querymenu = vidioc_querymenu, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, @@ -2157,22 +2015,6 @@ static const struct video_device gspca_template = { .release = video_device_release_empty, /* We use v4l2_dev.release */ }; -/* initialize the controls */ -static void ctrls_init(struct gspca_dev *gspca_dev) -{ - struct gspca_ctrl *ctrl; - int i; - - for (i = 0, ctrl = gspca_dev->cam.ctrls; - i < gspca_dev->sd_desc->nctrls; - i++, ctrl++) { - ctrl->def = gspca_dev->sd_desc->ctrls[i].qctrl.default_value; - ctrl->val = ctrl->def; - ctrl->min = gspca_dev->sd_desc->ctrls[i].qctrl.minimum; - ctrl->max = gspca_dev->sd_desc->ctrls[i].qctrl.maximum; - } -} - /* * probe and create a new gspca device * @@ -2249,8 +2091,6 @@ int gspca_dev_probe2(struct usb_interface *intf, ret = sd_desc->config(gspca_dev, id); if (ret < 0) goto out; - if (gspca_dev->cam.ctrls != NULL) - ctrls_init(gspca_dev); ret = sd_desc->init(gspca_dev); if (ret < 0) goto out; diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h index 5559932bf2f5..ac62cd3b590e 100644 --- a/drivers/media/usb/gspca/gspca.h +++ b/drivers/media/usb/gspca/gspca.h @@ -46,20 +46,11 @@ struct framerates { int nrates; }; -/* control definition */ -struct gspca_ctrl { - s16 val; /* current value */ - s16 def; /* default value */ - s16 min, max; /* minimum and maximum values */ -}; - /* device information - set at probe time */ struct cam { const struct v4l2_pix_format *cam_mode; /* size nmodes */ const struct framerates *mode_framerates; /* must have size nmodes, * just like cam_mode */ - struct gspca_ctrl *ctrls; /* control table - size nctrls */ - /* may be NULL */ u32 bulk_size; /* buffer size when image transfer by bulk */ u32 input_flags; /* value for ENUM_INPUT status flags */ u8 nmodes; /* size of cam_mode */ @@ -93,8 +84,6 @@ typedef int (*cam_ident_op) (struct gspca_dev *, struct v4l2_dbg_chip_ident *); typedef void (*cam_streamparm_op) (struct gspca_dev *, struct v4l2_streamparm *); -typedef int (*cam_qmnu_op) (struct gspca_dev *, - struct v4l2_querymenu *); typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev, u8 *data, int len); @@ -102,20 +91,10 @@ typedef int (*cam_int_pkt_op) (struct gspca_dev *gspca_dev, u8 *data, int len); -struct ctrl { - struct v4l2_queryctrl qctrl; - int (*set)(struct gspca_dev *, __s32); - int (*get)(struct gspca_dev *, __s32 *); - cam_v_op set_control; -}; - /* subdriver description */ struct sd_desc { /* information */ const char *name; /* sub-driver name */ -/* controls */ - const struct ctrl *ctrls; /* static control definition */ - int nctrls; /* mandatory operations */ cam_cf_op config; /* called on probe */ cam_op init; /* called on probe and resume */ @@ -130,7 +109,6 @@ struct sd_desc { cam_v_op dq_callback; /* called when a frame has been dequeued */ cam_get_jpg_op get_jcomp; cam_set_jpg_op set_jcomp; - cam_qmnu_op querymenu; cam_streamparm_op get_streamparm; cam_streamparm_op set_streamparm; #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -174,8 +152,6 @@ struct gspca_dev { struct cam cam; /* device information */ const struct sd_desc *sd_desc; /* subdriver description */ - unsigned ctrl_dis; /* disabled controls (bit map) */ - unsigned ctrl_inac; /* inactive controls (bit map) */ struct v4l2_ctrl_handler ctrl_handler; /* autogain and exposure or gain control cluster, these are global as -- cgit v1.2.3 From c93396e13576928a073154b5715761ff8a998368 Mon Sep 17 00:00:00 2001 From: Theodore Kilgore Date: Mon, 4 Feb 2013 13:17:55 -0300 Subject: [media] gspca: Remove gspca-specific debug magic Instead use v4l2_dbg and v4l2_err. Note that the PDEBUG macro is kept to make this patch-set less invasive, but it is simply a wrapper around v4l2_dbg now. Most of the other changes are there to make the dev parameter for the v4l2_xxx macros available everywhere we do logging. Signed-off-by: Theodore Kilgore Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/benq.c | 2 +- drivers/media/usb/gspca/conex.c | 12 ++-- drivers/media/usb/gspca/cpia1.c | 33 +++++----- drivers/media/usb/gspca/etoms.c | 10 ++- drivers/media/usb/gspca/gl860/gl860.c | 2 +- drivers/media/usb/gspca/gspca.c | 69 ++++++-------------- drivers/media/usb/gspca/gspca.h | 40 ++++++------ drivers/media/usb/gspca/jeilinj.c | 2 +- drivers/media/usb/gspca/konica.c | 28 ++++---- drivers/media/usb/gspca/m5602/m5602_core.c | 6 +- drivers/media/usb/gspca/m5602/m5602_mt9m111.c | 18 +++--- drivers/media/usb/gspca/m5602/m5602_ov7660.c | 10 +-- drivers/media/usb/gspca/m5602/m5602_ov9650.c | 26 ++++---- drivers/media/usb/gspca/m5602/m5602_po1030.c | 21 +++--- drivers/media/usb/gspca/m5602/m5602_s5k4aa.c | 16 +++-- drivers/media/usb/gspca/m5602/m5602_s5k83a.c | 1 + drivers/media/usb/gspca/mr97310a.c | 8 +-- drivers/media/usb/gspca/ov519.c | 81 ++++++++++++++++-------- drivers/media/usb/gspca/ov534.c | 2 +- drivers/media/usb/gspca/pac207.c | 2 +- drivers/media/usb/gspca/pac7302.c | 7 +- drivers/media/usb/gspca/pac7311.c | 5 +- drivers/media/usb/gspca/pac_common.h | 2 +- drivers/media/usb/gspca/sn9c2028.c | 4 +- drivers/media/usb/gspca/sonixj.c | 11 ++-- drivers/media/usb/gspca/spca1528.c | 4 +- drivers/media/usb/gspca/spca500.c | 36 +++++------ drivers/media/usb/gspca/spca501.c | 44 ++++++------- drivers/media/usb/gspca/spca505.c | 42 ++++++------ drivers/media/usb/gspca/spca508.c | 41 ++++++------ drivers/media/usb/gspca/spca561.c | 70 ++++++++++---------- drivers/media/usb/gspca/sq905.c | 2 +- drivers/media/usb/gspca/sq905c.c | 6 +- drivers/media/usb/gspca/sq930x.c | 4 +- drivers/media/usb/gspca/stv0680.c | 14 ++-- drivers/media/usb/gspca/stv06xx/stv06xx.c | 17 +++-- drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c | 8 ++- drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c | 14 ++-- drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c | 2 + drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c | 10 +-- drivers/media/usb/gspca/sunplus.c | 27 +++----- drivers/media/usb/gspca/vc032x.c | 9 +-- drivers/media/usb/gspca/w996Xcf.c | 5 +- drivers/media/usb/gspca/zc3xx.c | 3 +- 44 files changed, 373 insertions(+), 403 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/gspca/benq.c b/drivers/media/usb/gspca/benq.c index 352f32190e68..05f406deae13 100644 --- a/drivers/media/usb/gspca/benq.c +++ b/drivers/media/usb/gspca/benq.c @@ -186,7 +186,7 @@ static void sd_isoc_irq(struct urb *urb) /* check the packet status and length */ if (urb0->iso_frame_desc[i].actual_length != SD_PKT_SZ || urb->iso_frame_desc[i].actual_length != SD_PKT_SZ) { - PDEBUG(D_ERR, "ISOC bad lengths %d / %d", + PERR("ISOC bad lengths %d / %d", urb0->iso_frame_desc[i].actual_length, urb->iso_frame_desc[i].actual_length); gspca_dev->last_packet_type = DISCARD_PACKET; diff --git a/drivers/media/usb/gspca/conex.c b/drivers/media/usb/gspca/conex.c index c9052f20435e..38714df31ac4 100644 --- a/drivers/media/usb/gspca/conex.c +++ b/drivers/media/usb/gspca/conex.c @@ -73,12 +73,11 @@ static void reg_r(struct gspca_dev *gspca_dev, { struct usb_device *dev = gspca_dev->dev; -#ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - pr_err("reg_r: buffer overflow\n"); + PERR("reg_r: buffer overflow\n"); return; } -#endif + usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0, @@ -113,13 +112,12 @@ static void reg_w(struct gspca_dev *gspca_dev, { struct usb_device *dev = gspca_dev->dev; -#ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - pr_err("reg_w: buffer overflow\n"); + PERR("reg_w: buffer overflow\n"); return; } PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer); -#endif + memcpy(gspca_dev->usb_buf, buffer, len); usb_control_msg(dev, usb_sndctrlpipe(dev, 0), @@ -689,7 +687,7 @@ static void cx11646_jpeg(struct gspca_dev*gspca_dev) reg_w_val(gspca_dev, 0x0053, 0x00); } while (--retry); if (retry == 0) - PDEBUG(D_ERR, "Damned Errors sending jpeg Table"); + PERR("Damned Errors sending jpeg Table"); /* send the qtable now */ reg_r(gspca_dev, 0x0001, 1); /* -> 0x18 */ length = 8; diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c index 1dcdd9f95f1c..064b53043b15 100644 --- a/drivers/media/usb/gspca/cpia1.c +++ b/drivers/media/usb/gspca/cpia1.c @@ -421,8 +421,7 @@ static int cpia_usb_transferCmd(struct gspca_dev *gspca_dev, u8 *command) pipe = usb_sndctrlpipe(gspca_dev->dev, 0); requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE; } else { - PDEBUG(D_ERR, "Unexpected first byte of command: %x", - command[0]); + PERR("Unexpected first byte of command: %x", command[0]); return -EINVAL; } @@ -701,7 +700,7 @@ static void reset_camera_params(struct gspca_dev *gspca_dev) params->qx3.cradled = 0; } -static void printstatus(struct cam_params *params) +static void printstatus(struct gspca_dev *gspca_dev, struct cam_params *params) { PDEBUG(D_PROBE, "status: %02x %02x %02x %02x %02x %02x %02x %02x", params->status.systemState, params->status.grabState, @@ -725,10 +724,9 @@ static int goto_low_power(struct gspca_dev *gspca_dev) if (sd->params.status.systemState != LO_POWER_STATE) { if (sd->params.status.systemState != WARM_BOOT_STATE) { - PDEBUG(D_ERR, - "unexpected state after lo power cmd: %02x", - sd->params.status.systemState); - printstatus(&sd->params); + PERR("unexpected state after lo power cmd: %02x", + sd->params.status.systemState); + printstatus(gspca_dev, &sd->params); } return -EIO; } @@ -756,9 +754,9 @@ static int goto_high_power(struct gspca_dev *gspca_dev) return ret; if (sd->params.status.systemState != HI_POWER_STATE) { - PDEBUG(D_ERR, "unexpected state after hi power cmd: %02x", - sd->params.status.systemState); - printstatus(&sd->params); + PERR("unexpected state after hi power cmd: %02x", + sd->params.status.systemState); + printstatus(gspca_dev, &sd->params); return -EIO; } @@ -1449,8 +1447,8 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->params.version.firmwareVersion = 0; get_version_information(gspca_dev); if (sd->params.version.firmwareVersion != 1) { - PDEBUG(D_ERR, "only firmware version 1 is supported (got: %d)", - sd->params.version.firmwareVersion); + PERR("only firmware version 1 is supported (got: %d)", + sd->params.version.firmwareVersion); return -ENODEV; } @@ -1475,9 +1473,9 @@ static int sd_start(struct gspca_dev *gspca_dev) /* Start the camera in low power mode */ if (goto_low_power(gspca_dev)) { if (sd->params.status.systemState != WARM_BOOT_STATE) { - PDEBUG(D_ERR, "unexpected systemstate: %02x", - sd->params.status.systemState); - printstatus(&sd->params); + PERR("unexpected systemstate: %02x", + sd->params.status.systemState); + printstatus(gspca_dev, &sd->params); return -ENODEV; } @@ -1523,9 +1521,8 @@ static int sd_start(struct gspca_dev *gspca_dev) return ret; if (sd->params.status.fatalError) { - PDEBUG(D_ERR, "fatal_error: %04x, vp_status: %04x", - sd->params.status.fatalError, - sd->params.status.vpStatus); + PERR("fatal_error: %04x, vp_status: %04x", + sd->params.status.fatalError, sd->params.status.vpStatus); return -EIO; } diff --git a/drivers/media/usb/gspca/etoms.c b/drivers/media/usb/gspca/etoms.c index 38f68e11c3a2..948a6357573d 100644 --- a/drivers/media/usb/gspca/etoms.c +++ b/drivers/media/usb/gspca/etoms.c @@ -163,12 +163,11 @@ static void reg_r(struct gspca_dev *gspca_dev, { struct usb_device *dev = gspca_dev->dev; -#ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - pr_err("reg_r: buffer overflow\n"); + PERR("reg_r: buffer overflow\n"); return; } -#endif + usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0, @@ -201,13 +200,12 @@ static void reg_w(struct gspca_dev *gspca_dev, { struct usb_device *dev = gspca_dev->dev; -#ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { pr_err("reg_w: buffer overflow\n"); return; } PDEBUG(D_USBO, "reg write [%02x] = %02x..", index, *buffer); -#endif + memcpy(gspca_dev->usb_buf, buffer, len); usb_control_msg(dev, usb_sndctrlpipe(dev, 0), @@ -274,7 +272,7 @@ static int et_video(struct gspca_dev *gspca_dev, : 0); /* stopvideo */ ret = Et_WaitStatus(gspca_dev); if (ret != 0) - PDEBUG(D_ERR, "timeout video on/off"); + PERR("timeout video on/off"); return ret; } diff --git a/drivers/media/usb/gspca/gl860/gl860.c b/drivers/media/usb/gspca/gl860/gl860.c index 96d9c28a748c..cb1e64ca59c9 100644 --- a/drivers/media/usb/gspca/gl860/gl860.c +++ b/drivers/media/usb/gspca/gl860/gl860.c @@ -582,7 +582,7 @@ int gl860_RTx(struct gspca_dev *gspca_dev, pr_err("ctrl transfer failed %4d [p%02x r%d v%04x i%04x len%d]\n", r, pref, req, val, index, len); else if (len > 1 && r < len) - PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len); + PERR("short ctrl transfer %d/%d", r, len); msleep(1); diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 5784ff4e1b2f..5800d65f9144 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -60,14 +60,14 @@ MODULE_DESCRIPTION("GSPCA USB Camera Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(GSPCA_VERSION); -#ifdef GSPCA_DEBUG -int gspca_debug = D_ERR | D_PROBE; +int gspca_debug; EXPORT_SYMBOL(gspca_debug); -static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h) +static void PDEBUG_MODE(struct gspca_dev *gspca_dev, int debug, char *txt, + __u32 pixfmt, int w, int h) { if ((pixfmt >> 24) >= '0' && (pixfmt >> 24) <= 'z') { - PDEBUG(D_CONF|D_STREAM, "%s %c%c%c%c %dx%d", + PDEBUG(debug, "%s %c%c%c%c %dx%d", txt, pixfmt & 0xff, (pixfmt >> 8) & 0xff, @@ -75,15 +75,12 @@ static void PDEBUG_MODE(char *txt, __u32 pixfmt, int w, int h) pixfmt >> 24, w, h); } else { - PDEBUG(D_CONF|D_STREAM, "%s 0x%08x %dx%d", + PDEBUG(debug, "%s 0x%08x %dx%d", txt, pixfmt, w, h); } } -#else -#define PDEBUG_MODE(txt, pixfmt, w, h) -#endif /* specific memory types - !! should be different from V4L2_MEMORY_xxx */ #define GSPCA_MEMORY_NO 0 /* V4L2_MEMORY_xxx starts from 1 */ @@ -129,7 +126,7 @@ static void int_irq(struct urb *urb) case 0: if (gspca_dev->sd_desc->int_pkt_scan(gspca_dev, urb->transfer_buffer, urb->actual_length) < 0) { - PDEBUG(D_ERR, "Unknown packet received"); + PERR("Unknown packet received"); } break; @@ -143,7 +140,7 @@ static void int_irq(struct urb *urb) break; default: - PDEBUG(D_ERR, "URB error %i, resubmitting", urb->status); + PERR("URB error %i, resubmitting", urb->status); urb->status = 0; ret = 0; } @@ -229,7 +226,7 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev, urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; ret = usb_submit_urb(urb, GFP_KERNEL); if (ret < 0) { - PDEBUG(D_ERR, "submit int URB failed with error %i", ret); + PERR("submit int URB failed with error %i", ret); goto error_submit; } gspca_dev->int_urb = urb; @@ -315,7 +312,7 @@ static void fill_frame(struct gspca_dev *gspca_dev, if (gspca_dev->frozen) return; #endif - PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); + PERR("urb status: %d", urb->status); urb->status = 0; goto resubmit; } @@ -388,7 +385,7 @@ static void bulk_irq(struct urb *urb) if (gspca_dev->frozen) return; #endif - PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); + PERR("urb status: %d", urb->status); urb->status = 0; goto resubmit; } @@ -460,7 +457,7 @@ void gspca_frame_add(struct gspca_dev *gspca_dev, /* append the packet to the frame buffer */ if (len > 0) { if (gspca_dev->image_len + len > gspca_dev->frsz) { - PDEBUG(D_ERR|D_PACK, "frame overflow %d > %d", + PERR("frame overflow %d > %d", gspca_dev->image_len + len, gspca_dev->frsz); packet_type = DISCARD_PACKET; @@ -960,9 +957,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) /* the bandwidth is not wide enough * negotiate or try a lower alternate setting */ retry: - PDEBUG(D_ERR|D_STREAM, - "alt %d - bandwidth not wide enough - trying again", - alt); + PERR("alt %d - bandwidth not wide enough, trying again", alt); msleep(20); /* wait for kill complete */ if (gspca_dev->sd_desc->isoc_nego) { ret = gspca_dev->sd_desc->isoc_nego(gspca_dev); @@ -1127,10 +1122,9 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, w = fmt->fmt.pix.width; h = fmt->fmt.pix.height; -#ifdef GSPCA_DEBUG - if (gspca_debug & D_CONF) - PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h); -#endif + PDEBUG_MODE(gspca_dev, D_CONF, "try fmt cap", + fmt->fmt.pix.pixelformat, w, h); + /* search the closest mode for width and height */ mode = wxh_to_mode(gspca_dev, w, h); @@ -1143,8 +1137,6 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, fmt->fmt.pix.pixelformat); if (mode2 >= 0) mode = mode2; -/* else - ; * no chance, return this mode */ } fmt->fmt.pix = gspca_dev->cam.cam_mode[mode]; /* some drivers use priv internally, zero it before giving it to @@ -1280,15 +1272,6 @@ static int dev_open(struct file *file) if (!try_module_get(gspca_dev->module)) return -ENODEV; -#ifdef GSPCA_DEBUG - /* activate the v4l2 debug */ - if (gspca_debug & D_V4L2) - gspca_dev->vdev.debug |= V4L2_DEBUG_IOCTL - | V4L2_DEBUG_IOCTL_ARG; - else - gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL - | V4L2_DEBUG_IOCTL_ARG); -#endif return v4l2_fh_open(file); } @@ -1483,14 +1466,8 @@ static int vidioc_streamon(struct file *file, void *priv, if (ret < 0) goto out; } -#ifdef GSPCA_DEBUG - if (gspca_debug & D_STREAM) { - PDEBUG_MODE("stream on OK", - gspca_dev->pixfmt, - gspca_dev->width, - gspca_dev->height); - } -#endif + PDEBUG_MODE(gspca_dev, D_STREAM, "stream on OK", gspca_dev->pixfmt, + gspca_dev->width, gspca_dev->height); ret = 0; out: mutex_unlock(&gspca_dev->queue_lock); @@ -1741,8 +1718,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr, frame->data, frame->v4l2_buf.bytesused)) { - PDEBUG(D_ERR|D_STREAM, - "dqbuf cp to user failed"); + PERR("dqbuf cp to user failed"); ret = -EFAULT; } } @@ -1954,8 +1930,7 @@ static ssize_t dev_read(struct file *file, char __user *data, count = frame->v4l2_buf.bytesused; ret = copy_to_user(data, frame->data, count); if (ret != 0) { - PDEBUG(D_ERR|D_STREAM, - "read cp to user lack %d / %zd", ret, count); + PERR("read cp to user lack %d / %zd", ret, count); ret = -EFAULT; goto out; } @@ -2290,10 +2265,6 @@ static void __exit gspca_exit(void) module_init(gspca_init); module_exit(gspca_exit); -#ifdef GSPCA_DEBUG module_param_named(debug, gspca_debug, int, 0644); MODULE_PARM_DESC(debug, - "Debug (bit) 0x01:error 0x02:probe 0x04:config" - " 0x08:stream 0x10:frame 0x20:packet" - " 0x0100: v4l2"); -#endif + "1:probe 2:config 3:stream 4:frame 5:packet 6:usbi 7:usbo"); diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h index ac62cd3b590e..c3af3212d51e 100644 --- a/drivers/media/usb/gspca/gspca.h +++ b/drivers/media/usb/gspca/gspca.h @@ -10,30 +10,26 @@ #include #include -/* compilation option */ -/*#define GSPCA_DEBUG 1*/ -#ifdef GSPCA_DEBUG -/* GSPCA our debug messages */ + +/* GSPCA debug codes */ + +#define D_PROBE 1 +#define D_CONF 2 +#define D_STREAM 3 +#define D_FRAM 4 +#define D_PACK 5 +#define D_USBI 6 +#define D_USBO 7 + extern int gspca_debug; -#define PDEBUG(level, fmt, ...) \ -do { \ - if (gspca_debug & (level)) \ - pr_info(fmt, ##__VA_ARGS__); \ -} while (0) - -#define D_ERR 0x01 -#define D_PROBE 0x02 -#define D_CONF 0x04 -#define D_STREAM 0x08 -#define D_FRAM 0x10 -#define D_PACK 0x20 -#define D_USBI 0x00 -#define D_USBO 0x00 -#define D_V4L2 0x0100 -#else -#define PDEBUG(level, fmt, ...) do {} while(0) -#endif + + +#define PDEBUG(level, fmt, ...) \ + v4l2_dbg(level, gspca_debug, &gspca_dev->v4l2_dev, fmt, ##__VA_ARGS__) + +#define PERR(fmt, ...) \ + v4l2_err(&gspca_dev->v4l2_dev, fmt, ##__VA_ARGS__) #define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */ /* image transfers */ diff --git a/drivers/media/usb/gspca/jeilinj.c b/drivers/media/usb/gspca/jeilinj.c index 1ba29fe7fada..8da3dde38385 100644 --- a/drivers/media/usb/gspca/jeilinj.c +++ b/drivers/media/usb/gspca/jeilinj.c @@ -266,7 +266,7 @@ static int jlj_start(struct gspca_dev *gspca_dev) msleep(2); setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq)); if (gspca_dev->usb_err < 0) - PDEBUG(D_ERR, "Start streaming command failed"); + PERR("Start streaming command failed"); return gspca_dev->usb_err; } diff --git a/drivers/media/usb/gspca/konica.c b/drivers/media/usb/gspca/konica.c index 61e25dbf2447..39c96bb4c985 100644 --- a/drivers/media/usb/gspca/konica.c +++ b/drivers/media/usb/gspca/konica.c @@ -277,7 +277,7 @@ static void sd_isoc_irq(struct urb *urb) if (gspca_dev->frozen) return; #endif - PDEBUG(D_ERR, "urb status: %d", urb->status); + PERR("urb status: %d", urb->status); st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) pr_err("resubmit urb error %d\n", st); @@ -295,33 +295,30 @@ static void sd_isoc_irq(struct urb *urb) sd->last_data_urb = NULL; if (!data_urb || data_urb->start_frame != status_urb->start_frame) { - PDEBUG(D_ERR|D_PACK, "lost sync on frames"); + PERR("lost sync on frames"); goto resubmit; } if (data_urb->number_of_packets != status_urb->number_of_packets) { - PDEBUG(D_ERR|D_PACK, - "no packets does not match, data: %d, status: %d", - data_urb->number_of_packets, - status_urb->number_of_packets); + PERR("no packets does not match, data: %d, status: %d", + data_urb->number_of_packets, + status_urb->number_of_packets); goto resubmit; } for (i = 0; i < status_urb->number_of_packets; i++) { if (data_urb->iso_frame_desc[i].status || status_urb->iso_frame_desc[i].status) { - PDEBUG(D_ERR|D_PACK, - "pkt %d data-status %d, status-status %d", i, - data_urb->iso_frame_desc[i].status, - status_urb->iso_frame_desc[i].status); + PERR("pkt %d data-status %d, status-status %d", i, + data_urb->iso_frame_desc[i].status, + status_urb->iso_frame_desc[i].status); gspca_dev->last_packet_type = DISCARD_PACKET; continue; } if (status_urb->iso_frame_desc[i].actual_length != 1) { - PDEBUG(D_ERR|D_PACK, - "bad status packet length %d", - status_urb->iso_frame_desc[i].actual_length); + PERR("bad status packet length %d", + status_urb->iso_frame_desc[i].actual_length); gspca_dev->last_packet_type = DISCARD_PACKET; continue; } @@ -366,12 +363,11 @@ resubmit: if (data_urb) { st = usb_submit_urb(data_urb, GFP_ATOMIC); if (st < 0) - PDEBUG(D_ERR|D_PACK, - "usb_submit_urb(data_urb) ret %d", st); + PERR("usb_submit_urb(data_urb) ret %d", st); } st = usb_submit_urb(status_urb, GFP_ATOMIC); if (st < 0) - pr_err("usb_submit_urb(status_urb) ret %d\n", st); + PERR("usb_submit_urb(status_urb) ret %d\n", st); } static int sd_s_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/usb/gspca/m5602/m5602_core.c b/drivers/media/usb/gspca/m5602/m5602_core.c index 907a968f474d..d926e62cb80b 100644 --- a/drivers/media/usb/gspca/m5602/m5602_core.c +++ b/drivers/media/usb/gspca/m5602/m5602_core.c @@ -41,6 +41,7 @@ MODULE_DEVICE_TABLE(usb, m5602_table); int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data) { int err; + struct gspca_dev *gspca_dev = (struct gspca_dev *) sd; struct usb_device *udev = sd->gspca_dev.dev; __u8 *buf = sd->gspca_dev.usb_buf; @@ -62,6 +63,7 @@ int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data) int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data) { int err; + struct gspca_dev *gspca_dev = (struct gspca_dev *) sd; struct usb_device *udev = sd->gspca_dev.dev; __u8 *buf = sd->gspca_dev.usb_buf; @@ -98,6 +100,7 @@ int m5602_read_sensor(struct sd *sd, const u8 address, u8 *i2c_data, const u8 len) { int err, i; + struct gspca_dev *gspca_dev = (struct gspca_dev *) sd; if (!len || len > sd->sensor->i2c_regW) return -EINVAL; @@ -147,6 +150,7 @@ int m5602_write_sensor(struct sd *sd, const u8 address, { int err, i; u8 *p; + struct gspca_dev *gspca_dev = (struct gspca_dev *) sd; struct usb_device *udev = sd->gspca_dev.dev; __u8 *buf = sd->gspca_dev.usb_buf; @@ -378,7 +382,7 @@ static int m5602_configure(struct gspca_dev *gspca_dev, return 0; fail: - PDEBUG(D_ERR, "ALi m5602 webcam failed"); + PERR("ALi m5602 webcam failed"); cam->cam_mode = NULL; cam->nmodes = 0; diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c index b5f66921b3eb..cfa4663f8934 100644 --- a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c +++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c @@ -56,6 +56,7 @@ int mt9m111_probe(struct sd *sd) { u8 data[2] = {0x00, 0x00}; int i; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; if (force_sensor) { if (force_sensor == MT9M111_SENSOR) { @@ -169,6 +170,7 @@ int mt9m111_start(struct sd *sd) int i, err = 0; u8 data[2]; struct cam *cam = &sd->gspca_dev.cam; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1; int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; @@ -229,11 +231,11 @@ int mt9m111_start(struct sd *sd) switch (width) { case 640: - PDEBUG(D_V4L2, "Configuring camera for VGA mode"); + PDEBUG(D_CONF, "Configuring camera for VGA mode"); break; case 320: - PDEBUG(D_V4L2, "Configuring camera for QVGA mode"); + PDEBUG(D_CONF, "Configuring camera for QVGA mode"); break; } return err; @@ -252,7 +254,7 @@ static int mt9m111_set_hvflip(struct gspca_dev *gspca_dev) int hflip; int vflip; - PDEBUG(D_V4L2, "Set hvflip to %d %d", sd->hflip->val, sd->vflip->val); + PDEBUG(D_CONF, "Set hvflip to %d %d", sd->hflip->val, sd->vflip->val); /* The mt9m111 is flipped by default */ hflip = !sd->hflip->val; @@ -293,7 +295,7 @@ static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); - PDEBUG(D_V4L2, "Set auto white balance %d", val); + PDEBUG(D_CONF, "Set auto white balance %d", val); return err; } @@ -326,7 +328,7 @@ static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) data[1] = (tmp & 0xff); data[0] = (tmp & 0xff00) >> 8; - PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp, + PDEBUG(D_CONF, "tmp=%d, data[1]=%d, data[0]=%d", tmp, data[1], data[0]); err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN, @@ -344,7 +346,7 @@ static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) data[1] = (val & 0xff); data[0] = (val & 0xff00) >> 8; - PDEBUG(D_V4L2, "Set green balance %d", val); + PDEBUG(D_CONF, "Set green balance %d", val); err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN, data, 2); if (err < 0) @@ -362,7 +364,7 @@ static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) data[1] = (val & 0xff); data[0] = (val & 0xff00) >> 8; - PDEBUG(D_V4L2, "Set blue balance %d", val); + PDEBUG(D_CONF, "Set blue balance %d", val); return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN, data, 2); @@ -376,7 +378,7 @@ static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) data[1] = (val & 0xff); data[0] = (val & 0xff00) >> 8; - PDEBUG(D_V4L2, "Set red balance %d", val); + PDEBUG(D_CONF, "Set red balance %d", val); return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN, data, 2); diff --git a/drivers/media/usb/gspca/m5602/m5602_ov7660.c b/drivers/media/usb/gspca/m5602/m5602_ov7660.c index 3bbe3ad5d4a9..4ac78893cc5f 100644 --- a/drivers/media/usb/gspca/m5602/m5602_ov7660.c +++ b/drivers/media/usb/gspca/m5602/m5602_ov7660.c @@ -175,7 +175,7 @@ static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val) u8 i2c_data = val; struct sd *sd = (struct sd *) gspca_dev; - PDEBUG(D_V4L2, "Setting gain to %d", val); + PDEBUG(D_CONF, "Setting gain to %d", val); err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1); return err; @@ -188,7 +188,7 @@ static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - PDEBUG(D_V4L2, "Set auto white balance to %d", val); + PDEBUG(D_CONF, "Set auto white balance to %d", val); err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); if (err < 0) @@ -206,7 +206,7 @@ static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - PDEBUG(D_V4L2, "Set auto gain control to %d", val); + PDEBUG(D_CONF, "Set auto gain control to %d", val); err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); if (err < 0) @@ -224,7 +224,7 @@ static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - PDEBUG(D_V4L2, "Set auto exposure control to %d", val); + PDEBUG(D_CONF, "Set auto exposure control to %d", val); err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); if (err < 0) @@ -242,7 +242,7 @@ static int ov7660_set_hvflip(struct gspca_dev *gspca_dev) u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - PDEBUG(D_V4L2, "Set hvflip to %d, %d", sd->hflip->val, sd->vflip->val); + PDEBUG(D_CONF, "Set hvflip to %d, %d", sd->hflip->val, sd->vflip->val); i2c_data = (sd->hflip->val << 5) | (sd->vflip->val << 4); diff --git a/drivers/media/usb/gspca/m5602/m5602_ov9650.c b/drivers/media/usb/gspca/m5602/m5602_ov9650.c index e2fe2f942fe6..59bc62bfae26 100644 --- a/drivers/media/usb/gspca/m5602/m5602_ov9650.c +++ b/drivers/media/usb/gspca/m5602/m5602_ov9650.c @@ -147,6 +147,7 @@ int ov9650_probe(struct sd *sd) { int err = 0; u8 prod_id = 0, ver_id = 0, i; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; if (force_sensor) { if (force_sensor == OV9650_SENSOR) { @@ -268,6 +269,7 @@ int ov9650_start(struct sd *sd) int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv; int hor_offs = OV9650_LEFT_OFFSET; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; if ((!dmi_check_system(ov9650_flip_dmi_table) && sd->vflip->val) || @@ -351,7 +353,7 @@ int ov9650_start(struct sd *sd) switch (width) { case 640: - PDEBUG(D_V4L2, "Configuring camera for VGA mode"); + PDEBUG(D_CONF, "Configuring camera for VGA mode"); data = OV9650_VGA_SELECT | OV9650_RGB_SELECT | OV9650_RAW_RGB_SELECT; @@ -359,7 +361,7 @@ int ov9650_start(struct sd *sd) break; case 352: - PDEBUG(D_V4L2, "Configuring camera for CIF mode"); + PDEBUG(D_CONF, "Configuring camera for CIF mode"); data = OV9650_CIF_SELECT | OV9650_RGB_SELECT | OV9650_RAW_RGB_SELECT; @@ -367,7 +369,7 @@ int ov9650_start(struct sd *sd) break; case 320: - PDEBUG(D_V4L2, "Configuring camera for QVGA mode"); + PDEBUG(D_CONF, "Configuring camera for QVGA mode"); data = OV9650_QVGA_SELECT | OV9650_RGB_SELECT | OV9650_RAW_RGB_SELECT; @@ -375,7 +377,7 @@ int ov9650_start(struct sd *sd) break; case 176: - PDEBUG(D_V4L2, "Configuring camera for QCIF mode"); + PDEBUG(D_CONF, "Configuring camera for QCIF mode"); data = OV9650_QCIF_SELECT | OV9650_RGB_SELECT | OV9650_RAW_RGB_SELECT; @@ -404,7 +406,7 @@ static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) u8 i2c_data; int err; - PDEBUG(D_V4L2, "Set exposure to %d", val); + PDEBUG(D_CONF, "Set exposure to %d", val); /* The 6 MSBs */ i2c_data = (val >> 10) & 0x3f; @@ -432,7 +434,7 @@ static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - PDEBUG(D_V4L2, "Setting gain to %d", val); + PDEBUG(D_CONF, "Setting gain to %d", val); /* The 2 MSB */ /* Read the OV9650_VREF register first to avoid @@ -460,7 +462,7 @@ static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - PDEBUG(D_V4L2, "Set red gain to %d", val); + PDEBUG(D_CONF, "Set red gain to %d", val); i2c_data = val & 0xff; err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1); @@ -473,7 +475,7 @@ static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - PDEBUG(D_V4L2, "Set blue gain to %d", val); + PDEBUG(D_CONF, "Set blue gain to %d", val); i2c_data = val & 0xff; err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1); @@ -488,7 +490,7 @@ static int ov9650_set_hvflip(struct gspca_dev *gspca_dev) int hflip = sd->hflip->val; int vflip = sd->vflip->val; - PDEBUG(D_V4L2, "Set hvflip to %d %d", hflip, vflip); + PDEBUG(D_CONF, "Set hvflip to %d %d", hflip, vflip); if (dmi_check_system(ov9650_flip_dmi_table)) vflip = !vflip; @@ -512,7 +514,7 @@ static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - PDEBUG(D_V4L2, "Set auto exposure control to %d", val); + PDEBUG(D_CONF, "Set auto exposure control to %d", val); err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); if (err < 0) @@ -531,7 +533,7 @@ static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - PDEBUG(D_V4L2, "Set auto white balance to %d", val); + PDEBUG(D_CONF, "Set auto white balance to %d", val); err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); if (err < 0) @@ -549,7 +551,7 @@ static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - PDEBUG(D_V4L2, "Set auto gain control to %d", val); + PDEBUG(D_CONF, "Set auto gain control to %d", val); err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); if (err < 0) diff --git a/drivers/media/usb/gspca/m5602/m5602_po1030.c b/drivers/media/usb/gspca/m5602/m5602_po1030.c index 189086291303..4bf5c43424b7 100644 --- a/drivers/media/usb/gspca/m5602/m5602_po1030.c +++ b/drivers/media/usb/gspca/m5602/m5602_po1030.c @@ -55,6 +55,7 @@ static const struct v4l2_ctrl_config po1030_greenbal_cfg = { int po1030_probe(struct sd *sd) { u8 dev_id_h = 0, i; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; if (force_sensor) { if (force_sensor == PO1030_SENSOR) { @@ -305,10 +306,10 @@ static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) u8 i2c_data; int err; - PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff); + PDEBUG(D_CONF, "Set exposure to %d", val & 0xffff); i2c_data = ((val & 0xff00) >> 8); - PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x", + PDEBUG(D_CONF, "Set exposure to high byte to 0x%x", i2c_data); err = m5602_write_sensor(sd, PO1030_INTEGLINES_H, @@ -317,7 +318,7 @@ static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) return err; i2c_data = (val & 0xff); - PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x", + PDEBUG(D_CONF, "Set exposure to low byte to 0x%x", i2c_data); err = m5602_write_sensor(sd, PO1030_INTEGLINES_M, &i2c_data, 1); @@ -332,7 +333,7 @@ static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val) int err; i2c_data = val & 0xff; - PDEBUG(D_V4L2, "Set global gain to %d", i2c_data); + PDEBUG(D_CONF, "Set global gain to %d", i2c_data); err = m5602_write_sensor(sd, PO1030_GLOBALGAIN, &i2c_data, 1); return err; @@ -344,7 +345,7 @@ static int po1030_set_hvflip(struct gspca_dev *gspca_dev) u8 i2c_data; int err; - PDEBUG(D_V4L2, "Set hvflip %d %d", sd->hflip->val, sd->vflip->val); + PDEBUG(D_CONF, "Set hvflip %d %d", sd->hflip->val, sd->vflip->val); err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); if (err < 0) return err; @@ -365,7 +366,7 @@ static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) int err; i2c_data = val & 0xff; - PDEBUG(D_V4L2, "Set red gain to %d", i2c_data); + PDEBUG(D_CONF, "Set red gain to %d", i2c_data); err = m5602_write_sensor(sd, PO1030_RED_GAIN, &i2c_data, 1); return err; @@ -378,7 +379,7 @@ static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) int err; i2c_data = val & 0xff; - PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data); + PDEBUG(D_CONF, "Set blue gain to %d", i2c_data); err = m5602_write_sensor(sd, PO1030_BLUE_GAIN, &i2c_data, 1); @@ -392,7 +393,7 @@ static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) int err; i2c_data = val & 0xff; - PDEBUG(D_V4L2, "Set green gain to %d", i2c_data); + PDEBUG(D_CONF, "Set green gain to %d", i2c_data); err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN, &i2c_data, 1); @@ -414,7 +415,7 @@ static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, if (err < 0) return err; - PDEBUG(D_V4L2, "Set auto white balance to %d", val); + PDEBUG(D_CONF, "Set auto white balance to %d", val); i2c_data = (i2c_data & 0xfe) | (val & 0x01); err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); return err; @@ -431,7 +432,7 @@ static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, if (err < 0) return err; - PDEBUG(D_V4L2, "Set auto exposure to %d", val); + PDEBUG(D_CONF, "Set auto exposure to %d", val); val = (val == V4L2_EXPOSURE_AUTO); i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1); return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c index 42ffaf04771c..7d12599458e2 100644 --- a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c +++ b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c @@ -145,6 +145,7 @@ int s5k4aa_probe(struct sd *sd) { u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75}; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int i, err = 0; if (force_sensor) { @@ -215,10 +216,11 @@ int s5k4aa_start(struct sd *sd) int i, err = 0; u8 data[2]; struct cam *cam = &sd->gspca_dev.cam; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) { case 1280: - PDEBUG(D_V4L2, "Configuring camera for SXGA mode"); + PDEBUG(D_CONF, "Configuring camera for SXGA mode"); for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) { switch (SXGA_s5k4aa[i][0]) { @@ -251,7 +253,7 @@ int s5k4aa_start(struct sd *sd) break; case 640: - PDEBUG(D_V4L2, "Configuring camera for VGA mode"); + PDEBUG(D_CONF, "Configuring camera for VGA mode"); for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) { switch (VGA_s5k4aa[i][0]) { @@ -367,7 +369,7 @@ static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) u8 data = S5K4AA_PAGE_MAP_2; int err; - PDEBUG(D_V4L2, "Set exposure to %d", val); + PDEBUG(D_CONF, "Set exposure to %d", val); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) return err; @@ -389,7 +391,7 @@ static int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev) int hflip = sd->hflip->val; int vflip = sd->vflip->val; - PDEBUG(D_V4L2, "Set hvflip %d %d", hflip, vflip); + PDEBUG(D_CONF, "Set hvflip %d %d", hflip, vflip); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) return err; @@ -439,7 +441,7 @@ static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) u8 data = S5K4AA_PAGE_MAP_2; int err; - PDEBUG(D_V4L2, "Set gain to %d", val); + PDEBUG(D_CONF, "Set gain to %d", val); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) return err; @@ -456,7 +458,7 @@ static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val) u8 data = S5K4AA_PAGE_MAP_2; int err; - PDEBUG(D_V4L2, "Set brightness to %d", val); + PDEBUG(D_CONF, "Set brightness to %d", val); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) return err; @@ -471,7 +473,7 @@ static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val) u8 data = S5K4AA_PAGE_MAP_2; int err; - PDEBUG(D_V4L2, "Set noise to %d", val); + PDEBUG(D_CONF, "Set noise to %d", val); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) return err; diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c index 69ee6e26b8ea..7cbc3a00bda8 100644 --- a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c +++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c @@ -51,6 +51,7 @@ int s5k83a_probe(struct sd *sd) { u8 prod_id = 0, ver_id = 0; int i, err = 0; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; if (force_sensor) { if (force_sensor == S5K83A_SENSOR) { diff --git a/drivers/media/usb/gspca/mr97310a.c b/drivers/media/usb/gspca/mr97310a.c index 8f4714df5990..68bb2f359666 100644 --- a/drivers/media/usb/gspca/mr97310a.c +++ b/drivers/media/usb/gspca/mr97310a.c @@ -289,7 +289,7 @@ static int zero_the_pointer(struct gspca_dev *gspca_dev) return err_code; } if (status != 0x0a) - PDEBUG(D_ERR, "status is %02x", status); + PERR("status is %02x", status); tries = 0; while (tries < 4) { @@ -330,7 +330,7 @@ static void stream_stop(struct gspca_dev *gspca_dev) gspca_dev->usb_buf[0] = 0x01; gspca_dev->usb_buf[1] = 0x00; if (mr_write(gspca_dev, 2) < 0) - PDEBUG(D_ERR, "Stream Stop failed"); + PERR("Stream Stop failed"); } static void lcd_stop(struct gspca_dev *gspca_dev) @@ -338,7 +338,7 @@ static void lcd_stop(struct gspca_dev *gspca_dev) gspca_dev->usb_buf[0] = 0x19; gspca_dev->usb_buf[1] = 0x54; if (mr_write(gspca_dev, 2) < 0) - PDEBUG(D_ERR, "LCD Stop failed"); + PERR("LCD Stop failed"); } static int isoc_enable(struct gspca_dev *gspca_dev) @@ -1026,7 +1026,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; unsigned char *sof; - sof = pac_find_sof(&sd->sof_read, data, len); + sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len); if (sof) { int n; diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c index 9ad19a7ef81b..a3958ee86816 100644 --- a/drivers/media/usb/gspca/ov519.c +++ b/drivers/media/usb/gspca/ov519.c @@ -2034,6 +2034,7 @@ static unsigned char ov7670_abs_to_sm(unsigned char v) /* Write a OV519 register */ static void reg_w(struct sd *sd, u16 index, u16 value) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int ret, req = 0; if (sd->gspca_dev.usb_err < 0) @@ -2071,7 +2072,7 @@ static void reg_w(struct sd *sd, u16 index, u16 value) sd->gspca_dev.usb_buf, 1, 500); leave: if (ret < 0) { - pr_err("reg_w %02x failed %d\n", index, ret); + PERR("reg_w %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; return; } @@ -2081,6 +2082,7 @@ leave: /* returns: negative is error, pos or zero is data */ static int reg_r(struct sd *sd, u16 index) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int ret; int req; @@ -2110,7 +2112,7 @@ static int reg_r(struct sd *sd, u16 index) PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", req, index, ret); } else { - pr_err("reg_r %02x failed %d\n", index, ret); + PERR("reg_r %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; } @@ -2121,6 +2123,7 @@ static int reg_r(struct sd *sd, u16 index) static int reg_r8(struct sd *sd, u16 index) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int ret; if (sd->gspca_dev.usb_err < 0) @@ -2135,7 +2138,7 @@ static int reg_r8(struct sd *sd, if (ret >= 0) { ret = sd->gspca_dev.usb_buf[0]; } else { - pr_err("reg_r8 %02x failed %d\n", index, ret); + PERR("reg_r8 %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; } @@ -2174,6 +2177,7 @@ static void reg_w_mask(struct sd *sd, */ static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int ret; if (sd->gspca_dev.usb_err < 0) @@ -2188,13 +2192,14 @@ static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n) 0, index, sd->gspca_dev.usb_buf, n, 500); if (ret < 0) { - pr_err("reg_w32 %02x failed %d\n", index, ret); + PERR("reg_w32 %02x failed %d\n", index, ret); sd->gspca_dev.usb_err = ret; } } static void ov511_i2c_w(struct sd *sd, u8 reg, u8 value) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int rc, retries; PDEBUG(D_USBO, "ov511_i2c_w %02x %02x", reg, value); @@ -2228,6 +2233,7 @@ static void ov511_i2c_w(struct sd *sd, u8 reg, u8 value) static int ov511_i2c_r(struct sd *sd, u8 reg) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int rc, value, retries; /* Two byte write cycle */ @@ -2300,6 +2306,8 @@ static void ov518_i2c_w(struct sd *sd, u8 reg, u8 value) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; + PDEBUG(D_USBO, "ov518_i2c_w %02x %02x", reg, value); /* Select camera register */ @@ -2325,6 +2333,7 @@ static void ov518_i2c_w(struct sd *sd, */ static int ov518_i2c_r(struct sd *sd, u8 reg) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int value; /* Select camera register */ @@ -2345,6 +2354,7 @@ static int ov518_i2c_r(struct sd *sd, u8 reg) static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int ret; if (sd->gspca_dev.usb_err < 0) @@ -2357,7 +2367,7 @@ static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value) (u16) value, (u16) reg, NULL, 0, 500); if (ret < 0) { - pr_err("ovfx2_i2c_w %02x failed %d\n", reg, ret); + PERR("ovfx2_i2c_w %02x failed %d\n", reg, ret); sd->gspca_dev.usb_err = ret; } @@ -2366,6 +2376,7 @@ static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value) static int ovfx2_i2c_r(struct sd *sd, u8 reg) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int ret; if (sd->gspca_dev.usb_err < 0) @@ -2381,7 +2392,7 @@ static int ovfx2_i2c_r(struct sd *sd, u8 reg) ret = sd->gspca_dev.usb_buf[0]; PDEBUG(D_USBI, "ovfx2_i2c_r %02x %02x", reg, ret); } else { - pr_err("ovfx2_i2c_r %02x failed %d\n", reg, ret); + PERR("ovfx2_i2c_r %02x failed %d\n", reg, ret); sd->gspca_dev.usb_err = ret; } @@ -2478,6 +2489,8 @@ static void i2c_w_mask(struct sd *sd, * registers while the camera is streaming */ static inline void ov51x_stop(struct sd *sd) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; + PDEBUG(D_STREAM, "stopping"); sd->stopped = 1; switch (sd->bridge) { @@ -2507,6 +2520,8 @@ static inline void ov51x_stop(struct sd *sd) * actually stopped (for performance). */ static inline void ov51x_restart(struct sd *sd) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; + PDEBUG(D_STREAM, "restarting"); if (!sd->stopped) return; @@ -2545,6 +2560,7 @@ static void ov51x_set_slave_ids(struct sd *sd, u8 slave); static int init_ov_sensor(struct sd *sd, u8 slave) { int i; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; ov51x_set_slave_ids(sd, slave); @@ -2624,10 +2640,11 @@ static void write_i2c_regvals(struct sd *sd, /* This initializes the OV2x10 / OV3610 / OV3620 / OV9600 */ static void ov_hires_configure(struct sd *sd) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int high, low; if (sd->bridge != BRIDGE_OVFX2) { - pr_err("error hires sensors only supported with ovfx2\n"); + PERR("error hires sensors only supported with ovfx2\n"); return; } @@ -2662,7 +2679,7 @@ static void ov_hires_configure(struct sd *sd) } break; } - pr_err("Error unknown sensor type: %02x%02x\n", high, low); + PERR("Error unknown sensor type: %02x%02x\n", high, low); } /* This initializes the OV8110, OV8610 sensor. The OV8110 uses @@ -2670,6 +2687,7 @@ static void ov_hires_configure(struct sd *sd) */ static void ov8xx0_configure(struct sd *sd) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int rc; PDEBUG(D_PROBE, "starting ov8xx0 configuration"); @@ -2677,13 +2695,13 @@ static void ov8xx0_configure(struct sd *sd) /* Detect sensor (sub)type */ rc = i2c_r(sd, OV7610_REG_COM_I); if (rc < 0) { - PDEBUG(D_ERR, "Error detecting sensor type"); + PERR("Error detecting sensor type"); return; } if ((rc & 3) == 1) sd->sensor = SEN_OV8610; else - pr_err("Unknown image sensor version: %d\n", rc & 3); + PERR("Unknown image sensor version: %d\n", rc & 3); } /* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses @@ -2691,6 +2709,7 @@ static void ov8xx0_configure(struct sd *sd) */ static void ov7xx0_configure(struct sd *sd) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int rc, high, low; PDEBUG(D_PROBE, "starting OV7xx0 configuration"); @@ -2701,7 +2720,7 @@ static void ov7xx0_configure(struct sd *sd) /* add OV7670 here * it appears to be wrongly detected as a 7610 by default */ if (rc < 0) { - pr_err("Error detecting sensor type\n"); + PERR("Error detecting sensor type\n"); return; } if ((rc & 3) == 3) { @@ -2729,19 +2748,19 @@ static void ov7xx0_configure(struct sd *sd) /* try to read product id registers */ high = i2c_r(sd, 0x0a); if (high < 0) { - pr_err("Error detecting camera chip PID\n"); + PERR("Error detecting camera chip PID\n"); return; } low = i2c_r(sd, 0x0b); if (low < 0) { - pr_err("Error detecting camera chip VER\n"); + PERR("Error detecting camera chip VER\n"); return; } if (high == 0x76) { switch (low) { case 0x30: - pr_err("Sensor is an OV7630/OV7635\n"); - pr_err("7630 is not supported by this driver\n"); + PERR("Sensor is an OV7630/OV7635\n"); + PERR("7630 is not supported by this driver\n"); return; case 0x40: PDEBUG(D_PROBE, "Sensor is an OV7645"); @@ -2760,7 +2779,7 @@ static void ov7xx0_configure(struct sd *sd) sd->sensor = SEN_OV7660; break; default: - pr_err("Unknown sensor: 0x76%02x\n", low); + PERR("Unknown sensor: 0x76%02x\n", low); return; } } else { @@ -2768,20 +2787,22 @@ static void ov7xx0_configure(struct sd *sd) sd->sensor = SEN_OV7620; } } else { - pr_err("Unknown image sensor version: %d\n", rc & 3); + PERR("Unknown image sensor version: %d\n", rc & 3); } } /* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */ static void ov6xx0_configure(struct sd *sd) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int rc; + PDEBUG(D_PROBE, "starting OV6xx0 configuration"); /* Detect sensor (sub)type */ rc = i2c_r(sd, OV7610_REG_COM_I); if (rc < 0) { - pr_err("Error detecting sensor type\n"); + PERR("Error detecting sensor type\n"); return; } @@ -2810,7 +2831,7 @@ static void ov6xx0_configure(struct sd *sd) pr_warn("WARNING: Sensor is an OV66307. Your camera may have been misdetected in previous driver versions.\n"); break; default: - pr_err("FATAL: Unknown sensor version: 0x%02x\n", rc); + PERR("FATAL: Unknown sensor version: 0x%02x\n", rc); return; } @@ -2907,6 +2928,7 @@ static void ov51x_upload_quan_tables(struct sd *sd) 7, 7, 7, 7, 7, 7, 8, 8 }; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; const unsigned char *pYTable, *pUVTable; unsigned char val0, val1; int i, size, reg = R51x_COMP_LUT_BEGIN; @@ -3300,7 +3322,7 @@ static int sd_init(struct gspca_dev *gspca_dev) } else if (init_ov_sensor(sd, OV_HIRES_SID) >= 0) { ov_hires_configure(sd); } else { - pr_err("Can't determine sensor slave IDs\n"); + PERR("Can't determine sensor slave IDs\n"); goto error; } @@ -3433,7 +3455,7 @@ static int sd_init(struct gspca_dev *gspca_dev) } return gspca_dev->usb_err; error: - PDEBUG(D_ERR, "OV519 Config failed"); + PERR("OV519 Config failed"); return -EINVAL; } @@ -3459,6 +3481,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) */ static void ov511_mode_init_regs(struct sd *sd) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int hsegs, vsegs, packet_size, fps, needed; int interlaced = 0; struct usb_host_interface *alt; @@ -3467,7 +3490,7 @@ static void ov511_mode_init_regs(struct sd *sd) intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); if (!alt) { - pr_err("Couldn't get altsetting\n"); + PERR("Couldn't get altsetting\n"); sd->gspca_dev.usb_err = -EIO; return; } @@ -3583,6 +3606,7 @@ static void ov511_mode_init_regs(struct sd *sd) */ static void ov518_mode_init_regs(struct sd *sd) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int hsegs, vsegs, packet_size; struct usb_host_interface *alt; struct usb_interface *intf; @@ -3590,7 +3614,7 @@ static void ov518_mode_init_regs(struct sd *sd) intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); if (!alt) { - pr_err("Couldn't get altsetting\n"); + PERR("Couldn't get altsetting\n"); sd->gspca_dev.usb_err = -EIO; return; } @@ -3750,6 +3774,8 @@ static void ov519_mode_init_regs(struct sd *sd) /* windows reads 0x55 at this point, why? */ }; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; + /******** Set the mode ********/ switch (sd->sensor) { default: @@ -3865,11 +3891,10 @@ static void ov519_mode_init_regs(struct sd *sd) static void mode_init_ov_sensor_regs(struct sd *sd) { - struct gspca_dev *gspca_dev; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int qvga, xstart, xend, ystart, yend; u8 v; - gspca_dev = &sd->gspca_dev; qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1; /******** Mode (VGA/QVGA) and sensor specific regs ********/ @@ -4304,7 +4329,7 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev, /* Frame end */ if ((in[9] + 1) * 8 != gspca_dev->width || (in[10] + 1) * 8 != gspca_dev->height) { - PDEBUG(D_ERR, "Invalid frame size, got: %dx%d," + PERR("Invalid frame size, got: %dx%d," " requested: %dx%d\n", (in[9] + 1) * 8, (in[10] + 1) * 8, gspca_dev->width, gspca_dev->height); @@ -4355,7 +4380,7 @@ static void ov518_pkt_scan(struct gspca_dev *gspca_dev, except that they may contain part of the footer), are numbered 0 */ else if (sd->packet_nr == 0 || data[len]) { - PDEBUG(D_ERR, "Invalid packet nr: %d (expect: %d)", + PERR("Invalid packet nr: %d (expect: %d)", (int)data[len], (int)sd->packet_nr); gspca_dev->last_packet_type = DISCARD_PACKET; return; @@ -4898,7 +4923,7 @@ static int sd_init_controls(struct gspca_dev *gspca_dev) QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF); if (hdl->error) { - pr_err("Could not initialize controls\n"); + PERR("Could not initialize controls\n"); return hdl->error; } if (gspca_dev->autogain) diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c index bb09d7884b89..2e28c81a03ab 100644 --- a/drivers/media/usb/gspca/ov534.c +++ b/drivers/media/usb/gspca/ov534.c @@ -690,7 +690,7 @@ static int sccb_check_status(struct gspca_dev *gspca_dev) case 0x03: break; default: - PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5", + PERR("sccb status 0x%02x, attempt %d/5", data, i + 1); } } diff --git a/drivers/media/usb/gspca/pac207.c b/drivers/media/usb/gspca/pac207.c index 3b75097dd34e..83519be94e58 100644 --- a/drivers/media/usb/gspca/pac207.c +++ b/drivers/media/usb/gspca/pac207.c @@ -373,7 +373,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; unsigned char *sof; - sof = pac_find_sof(&sd->sof_read, data, len); + sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len); if (sof) { int n; diff --git a/drivers/media/usb/gspca/pac7302.c b/drivers/media/usb/gspca/pac7302.c index add6f725ba50..682ef3340911 100644 --- a/drivers/media/usb/gspca/pac7302.c +++ b/drivers/media/usb/gspca/pac7302.c @@ -344,13 +344,10 @@ static void reg_w_var(struct gspca_dev *gspca_dev, reg_w_page(gspca_dev, page3, page3_len); break; default: -#ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - PDEBUG(D_ERR|D_STREAM, - "Incorrect variable sequence"); + PERR("Incorrect variable sequence"); return; } -#endif while (len > 0) { if (len < 8) { reg_w_buf(gspca_dev, @@ -795,7 +792,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *image; u8 *sof; - sof = pac_find_sof(&sd->sof_read, data, len); + sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len); if (sof) { int n, lum_offset, footer_length; diff --git a/drivers/media/usb/gspca/pac7311.c b/drivers/media/usb/gspca/pac7311.c index a12dfbf6e051..1a5bdc853a80 100644 --- a/drivers/media/usb/gspca/pac7311.c +++ b/drivers/media/usb/gspca/pac7311.c @@ -262,8 +262,7 @@ static void reg_w_var(struct gspca_dev *gspca_dev, break; default: if (len > USB_BUF_SZ) { - PDEBUG(D_ERR|D_STREAM, - "Incorrect variable sequence"); + PERR("Incorrect variable sequence"); return; } while (len > 0) { @@ -575,7 +574,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *image; unsigned char *sof; - sof = pac_find_sof(&sd->sof_read, data, len); + sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len); if (sof) { int n, lum_offset, footer_length; diff --git a/drivers/media/usb/gspca/pac_common.h b/drivers/media/usb/gspca/pac_common.h index 8462a7c1a338..fbc5e226c3e4 100644 --- a/drivers/media/usb/gspca/pac_common.h +++ b/drivers/media/usb/gspca/pac_common.h @@ -71,7 +71,7 @@ static const unsigned char pac_sof_marker[5] = +----------+ */ -static unsigned char *pac_find_sof(u8 *sof_read, +static unsigned char *pac_find_sof(struct gspca_dev *gspca_dev, u8 *sof_read, unsigned char *m, int len) { int i; diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c index 03fa3fd940b4..39b6b2e02963 100644 --- a/drivers/media/usb/gspca/sn9c2028.c +++ b/drivers/media/usb/gspca/sn9c2028.c @@ -650,13 +650,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev) result = sn9c2028_read1(gspca_dev); if (result < 0) - PDEBUG(D_ERR, "Camera Stop read failed"); + PERR("Camera Stop read failed"); memset(data, 0, 6); data[0] = 0x14; result = sn9c2028_command(gspca_dev, data); if (result < 0) - PDEBUG(D_ERR, "Camera Stop command failed"); + PERR("Camera Stop command failed"); } /* Include sn9c2028 sof detection functions */ diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c index 8246e1dc3e9d..3b5ccb1c4cdf 100644 --- a/drivers/media/usb/gspca/sonixj.c +++ b/drivers/media/usb/gspca/sonixj.c @@ -1159,12 +1159,11 @@ static void reg_r(struct gspca_dev *gspca_dev, if (gspca_dev->usb_err < 0) return; -#ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - pr_err("reg_r: buffer overflow\n"); + PERR("reg_r: buffer overflow\n"); return; } -#endif + ret = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), 0, @@ -1213,12 +1212,12 @@ static void reg_w(struct gspca_dev *gspca_dev, return; PDEBUG(D_USBO, "reg_w [%04x] = %02x %02x ..", value, buffer[0], buffer[1]); -#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { - pr_err("reg_w: buffer overflow\n"); + PERR("reg_w: buffer overflow\n"); return; } -#endif + memcpy(gspca_dev->usb_buf, buffer, len); ret = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), diff --git a/drivers/media/usb/gspca/spca1528.c b/drivers/media/usb/gspca/spca1528.c index 14d635277d71..688592b289ea 100644 --- a/drivers/media/usb/gspca/spca1528.c +++ b/drivers/media/usb/gspca/spca1528.c @@ -146,7 +146,7 @@ static void wait_status_0(struct gspca_dev *gspca_dev) w += 15; msleep(w); } while (--i > 0); - PDEBUG(D_ERR, "wait_status_0 timeout"); + PERR("wait_status_0 timeout"); gspca_dev->usb_err = -ETIME; } @@ -164,7 +164,7 @@ static void wait_status_1(struct gspca_dev *gspca_dev) return; } } while (--i > 0); - PDEBUG(D_ERR, "wait_status_1 timeout"); + PERR("wait_status_1 timeout"); gspca_dev->usb_err = -ETIME; } diff --git a/drivers/media/usb/gspca/spca500.c b/drivers/media/usb/gspca/spca500.c index 25cb68d0556d..9f8bf51fd64b 100644 --- a/drivers/media/usb/gspca/spca500.c +++ b/drivers/media/usb/gspca/spca500.c @@ -489,7 +489,7 @@ static int spca500_full_reset(struct gspca_dev *gspca_dev) return err; err = reg_r_wait(gspca_dev, 0x06, 0, 0); if (err < 0) { - PDEBUG(D_ERR, "reg_r_wait() failed"); + PERR("reg_r_wait() failed"); return err; } /* all ok */ @@ -505,7 +505,7 @@ static int spca500_full_reset(struct gspca_dev *gspca_dev) static int spca500_synch310(struct gspca_dev *gspca_dev) { if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0) < 0) { - PDEBUG(D_ERR, "Set packet size: set interface error"); + PERR("Set packet size: set interface error"); goto error; } spca500_ping310(gspca_dev); @@ -519,7 +519,7 @@ static int spca500_synch310(struct gspca_dev *gspca_dev) if (usb_set_interface(gspca_dev->dev, gspca_dev->iface, gspca_dev->alt) < 0) { - PDEBUG(D_ERR, "Set packet size: set interface error"); + PERR("Set packet size: set interface error"); goto error; } return 0; @@ -544,7 +544,7 @@ static void spca500_reinit(struct gspca_dev *gspca_dev) err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840, qtable_pocketdv); if (err < 0) - PDEBUG(D_ERR|D_STREAM, "spca50x_setup_qtable failed on init"); + PERR("spca50x_setup_qtable failed on init"); /* set qtable index */ reg_w(gspca_dev, 0x00, 0x8880, 2); @@ -639,7 +639,7 @@ static int sd_start(struct gspca_dev *gspca_dev) 0x00, 0x8800, 0x8840, qtable_creative_pccam); if (err < 0) - PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + PERR("spca50x_setup_qtable failed"); /* Init SDRAM - needed for SDRAM access */ reg_w(gspca_dev, 0x00, 0x870a, 0x04); @@ -647,7 +647,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x00, 0x8000, 0x0004); msleep(500); if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) - PDEBUG(D_ERR, "reg_r_wait() failed"); + PERR("reg_r_wait() failed"); reg_r(gspca_dev, 0x816b, 1); Data = gspca_dev->usb_buf[0]; @@ -660,13 +660,13 @@ static int sd_start(struct gspca_dev *gspca_dev) /* enable drop packet */ err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001); if (err < 0) - PDEBUG(D_ERR, "failed to enable drop packet"); + PERR("failed to enable drop packet"); reg_w(gspca_dev, 0x00, 0x8880, 3); err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840, qtable_creative_pccam); if (err < 0) - PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + PERR("spca50x_setup_qtable failed"); /* Init SDRAM - needed for SDRAM access */ reg_w(gspca_dev, 0x00, 0x870a, 0x04); @@ -675,7 +675,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x00, 0x8000, 0x0004); if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) - PDEBUG(D_ERR, "reg_r_wait() failed"); + PERR("reg_r_wait() failed"); reg_r(gspca_dev, 0x816b, 1); Data = gspca_dev->usb_buf[0]; @@ -689,18 +689,18 @@ static int sd_start(struct gspca_dev *gspca_dev) /* do a full reset */ err = spca500_full_reset(gspca_dev); if (err < 0) - PDEBUG(D_ERR, "spca500_full_reset failed"); + PERR("spca500_full_reset failed"); /* enable drop packet */ err = reg_w(gspca_dev, 0x00, 0x850a, 0x0001); if (err < 0) - PDEBUG(D_ERR, "failed to enable drop packet"); + PERR("failed to enable drop packet"); reg_w(gspca_dev, 0x00, 0x8880, 3); err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840, qtable_creative_pccam); if (err < 0) - PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + PERR("spca50x_setup_qtable failed"); spca500_setmode(gspca_dev, xmult, ymult); reg_w(gspca_dev, 0x20, 0x0001, 0x0004); @@ -709,7 +709,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x00, 0x8000, 0x0004); if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) - PDEBUG(D_ERR, "reg_r_wait() failed"); + PERR("reg_r_wait() failed"); reg_r(gspca_dev, 0x816b, 1); Data = gspca_dev->usb_buf[0]; @@ -722,7 +722,7 @@ static int sd_start(struct gspca_dev *gspca_dev) /* do a full reset */ err = spca500_full_reset(gspca_dev); if (err < 0) - PDEBUG(D_ERR, "spca500_full_reset failed"); + PERR("spca500_full_reset failed"); /* enable drop packet */ reg_w(gspca_dev, 0x00, 0x850a, 0x0001); reg_w(gspca_dev, 0x00, 0x8880, 0); @@ -730,7 +730,7 @@ static int sd_start(struct gspca_dev *gspca_dev) 0x00, 0x8800, 0x8840, qtable_kodak_ez200); if (err < 0) - PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + PERR("spca50x_setup_qtable failed"); spca500_setmode(gspca_dev, xmult, ymult); reg_w(gspca_dev, 0x20, 0x0001, 0x0004); @@ -739,7 +739,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x00, 0x8000, 0x0004); if (reg_r_wait(gspca_dev, 0, 0x8000, 0x44) != 0) - PDEBUG(D_ERR, "reg_r_wait() failed"); + PERR("reg_r_wait() failed"); reg_r(gspca_dev, 0x816b, 1); Data = gspca_dev->usb_buf[0]; @@ -765,7 +765,7 @@ static int sd_start(struct gspca_dev *gspca_dev) err = spca50x_setup_qtable(gspca_dev, 0x00, 0x8800, 0x8840, qtable_pocketdv); if (err < 0) - PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + PERR("spca50x_setup_qtable failed"); reg_w(gspca_dev, 0x00, 0x8880, 2); /* familycam Quicksmart pocketDV stuff */ @@ -795,7 +795,7 @@ static int sd_start(struct gspca_dev *gspca_dev) 0x00, 0x8800, 0x8840, qtable_creative_pccam); if (err < 0) - PDEBUG(D_ERR, "spca50x_setup_qtable failed"); + PERR("spca50x_setup_qtable failed"); reg_w(gspca_dev, 0x00, 0x8880, 3); reg_w(gspca_dev, 0x00, 0x800a, 0x00); /* Init SDRAM - needed for SDRAM access */ diff --git a/drivers/media/usb/gspca/spca501.c b/drivers/media/usb/gspca/spca501.c index 3b7f777785b4..d92fd17d6701 100644 --- a/drivers/media/usb/gspca/spca501.c +++ b/drivers/media/usb/gspca/spca501.c @@ -1756,10 +1756,11 @@ static const __u16 spca501c_mysterious_init_data[][3] = { {} }; -static int reg_write(struct usb_device *dev, - __u16 req, __u16 index, __u16 value) +static int reg_write(struct gspca_dev *gspca_dev, + __u16 req, __u16 index, __u16 value) { int ret; + struct usb_device *dev = gspca_dev->dev; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), @@ -1774,17 +1775,15 @@ static int reg_write(struct usb_device *dev, } -static int write_vector(struct gspca_dev *gspca_dev, - const __u16 data[][3]) +static int write_vector(struct gspca_dev *gspca_dev, const __u16 data[][3]) { - struct usb_device *dev = gspca_dev->dev; int ret, i = 0; while (data[i][0] != 0 || data[i][1] != 0 || data[i][2] != 0) { - ret = reg_write(dev, data[i][0], data[i][2], data[i][1]); + ret = reg_write(gspca_dev, data[i][0], data[i][2], + data[i][1]); if (ret < 0) { - PDEBUG(D_ERR, - "Reg write failed for 0x%02x,0x%02x,0x%02x", + PERR("Reg write failed for 0x%02x,0x%02x,0x%02x", data[i][0], data[i][1], data[i][2]); return ret; } @@ -1795,30 +1794,28 @@ static int write_vector(struct gspca_dev *gspca_dev, static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x12, val); + reg_write(gspca_dev, SPCA501_REG_CCDSP, 0x12, val); } static void setcontrast(struct gspca_dev *gspca_dev, s32 val) { - reg_write(gspca_dev->dev, 0x00, 0x00, - (val >> 8) & 0xff); - reg_write(gspca_dev->dev, 0x00, 0x01, - val & 0xff); + reg_write(gspca_dev, 0x00, 0x00, (val >> 8) & 0xff); + reg_write(gspca_dev, 0x00, 0x01, val & 0xff); } static void setcolors(struct gspca_dev *gspca_dev, s32 val) { - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x0c, val); + reg_write(gspca_dev, SPCA501_REG_CCDSP, 0x0c, val); } static void setblue_balance(struct gspca_dev *gspca_dev, s32 val) { - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x11, val); + reg_write(gspca_dev, SPCA501_REG_CCDSP, 0x11, val); } static void setred_balance(struct gspca_dev *gspca_dev, s32 val) { - reg_write(gspca_dev->dev, SPCA501_REG_CCDSP, 0x13, val); + reg_write(gspca_dev, SPCA501_REG_CCDSP, 0x13, val); } /* this function is called at probe time */ @@ -1868,7 +1865,6 @@ error: static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; int mode; switch (sd->subtype) { @@ -1895,20 +1891,20 @@ static int sd_start(struct gspca_dev *gspca_dev) /* Enable ISO packet machine CTRL reg=2, * index=1 bitmask=0x2 (bit ordinal 1) */ - reg_write(dev, SPCA50X_REG_USB, 0x6, 0x94); + reg_write(gspca_dev, SPCA50X_REG_USB, 0x6, 0x94); switch (mode) { case 0: /* 640x480 */ - reg_write(dev, SPCA50X_REG_USB, 0x07, 0x004a); + reg_write(gspca_dev, SPCA50X_REG_USB, 0x07, 0x004a); break; case 1: /* 320x240 */ - reg_write(dev, SPCA50X_REG_USB, 0x07, 0x104a); + reg_write(gspca_dev, SPCA50X_REG_USB, 0x07, 0x104a); break; default: /* case 2: * 160x120 */ - reg_write(dev, SPCA50X_REG_USB, 0x07, 0x204a); + reg_write(gspca_dev, SPCA50X_REG_USB, 0x07, 0x204a); break; } - reg_write(dev, SPCA501_REG_CTLRL, 0x01, 0x02); + reg_write(gspca_dev, SPCA501_REG_CTLRL, 0x01, 0x02); return 0; } @@ -1917,7 +1913,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) { /* Disable ISO packet * machine CTRL reg=2, index=1 bitmask=0x0 (bit ordinal 1) */ - reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x01, 0x00); + reg_write(gspca_dev, SPCA501_REG_CTLRL, 0x01, 0x00); } /* called on streamoff with alt 0 and on disconnect */ @@ -1925,7 +1921,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev) { if (!gspca_dev->present) return; - reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00); + reg_write(gspca_dev, SPCA501_REG_CTLRL, 0x05, 0x00); } static void sd_pkt_scan(struct gspca_dev *gspca_dev, diff --git a/drivers/media/usb/gspca/spca505.c b/drivers/media/usb/gspca/spca505.c index bc7d67c3cb04..232b330d2dd3 100644 --- a/drivers/media/usb/gspca/spca505.c +++ b/drivers/media/usb/gspca/spca505.c @@ -544,10 +544,11 @@ static const u8 spca505b_open_data_ccd[][3] = { {} }; -static int reg_write(struct usb_device *dev, +static int reg_write(struct gspca_dev *gspca_dev, u16 req, u16 index, u16 value) { int ret; + struct usb_device *dev = gspca_dev->dev; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), @@ -584,11 +585,11 @@ static int reg_read(struct gspca_dev *gspca_dev, static int write_vector(struct gspca_dev *gspca_dev, const u8 data[][3]) { - struct usb_device *dev = gspca_dev->dev; int ret, i = 0; while (data[i][0] != 0) { - ret = reg_write(dev, data[i][0], data[i][2], data[i][1]); + ret = reg_write(gspca_dev, data[i][0], data[i][2], + data[i][1]); if (ret < 0) return ret; i++; @@ -629,14 +630,13 @@ static int sd_init(struct gspca_dev *gspca_dev) static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness) { - reg_write(gspca_dev->dev, 0x05, 0x00, (255 - brightness) >> 6); - reg_write(gspca_dev->dev, 0x05, 0x01, (255 - brightness) << 2); + reg_write(gspca_dev, 0x05, 0x00, (255 - brightness) >> 6); + reg_write(gspca_dev, 0x05, 0x01, (255 - brightness) << 2); } static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; int ret, mode; static u8 mode_tb[][3] = { /* r00 r06 r07 */ @@ -654,9 +654,7 @@ static int sd_start(struct gspca_dev *gspca_dev) ret = reg_read(gspca_dev, 0x06, 0x16); if (ret < 0) { - PDEBUG(D_ERR|D_CONF, - "register read failed err: %d", - ret); + PERR("register read failed err: %d", ret); return ret; } if (ret != 0x0101) { @@ -664,22 +662,22 @@ static int sd_start(struct gspca_dev *gspca_dev) ret); } - ret = reg_write(gspca_dev->dev, 0x06, 0x16, 0x0a); + ret = reg_write(gspca_dev, 0x06, 0x16, 0x0a); if (ret < 0) return ret; - reg_write(gspca_dev->dev, 0x05, 0xc2, 0x12); + reg_write(gspca_dev, 0x05, 0xc2, 0x12); /* necessary because without it we can see stream * only once after loading module */ /* stopping usb registers Tomasz change */ - reg_write(dev, 0x02, 0x00, 0x00); + reg_write(gspca_dev, 0x02, 0x00, 0x00); mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - reg_write(dev, SPCA50X_REG_COMPRESS, 0x00, mode_tb[mode][0]); - reg_write(dev, SPCA50X_REG_COMPRESS, 0x06, mode_tb[mode][1]); - reg_write(dev, SPCA50X_REG_COMPRESS, 0x07, mode_tb[mode][2]); + reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0x00, mode_tb[mode][0]); + reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0x06, mode_tb[mode][1]); + reg_write(gspca_dev, SPCA50X_REG_COMPRESS, 0x07, mode_tb[mode][2]); - return reg_write(dev, SPCA50X_REG_USB, + return reg_write(gspca_dev, SPCA50X_REG_USB, SPCA50X_USB_CTRL, SPCA50X_CUSB_ENABLE); } @@ -687,7 +685,7 @@ static int sd_start(struct gspca_dev *gspca_dev) static void sd_stopN(struct gspca_dev *gspca_dev) { /* Disable ISO packet machine */ - reg_write(gspca_dev->dev, 0x02, 0x00, 0x00); + reg_write(gspca_dev, 0x02, 0x00, 0x00); } /* called on streamoff with alt 0 and on disconnect */ @@ -697,11 +695,11 @@ static void sd_stop0(struct gspca_dev *gspca_dev) return; /* This maybe reset or power control */ - reg_write(gspca_dev->dev, 0x03, 0x03, 0x20); - reg_write(gspca_dev->dev, 0x03, 0x01, 0x00); - reg_write(gspca_dev->dev, 0x03, 0x00, 0x01); - reg_write(gspca_dev->dev, 0x05, 0x10, 0x01); - reg_write(gspca_dev->dev, 0x05, 0x11, 0x0f); + reg_write(gspca_dev, 0x03, 0x03, 0x20); + reg_write(gspca_dev, 0x03, 0x01, 0x00); + reg_write(gspca_dev, 0x03, 0x00, 0x01); + reg_write(gspca_dev, 0x05, 0x10, 0x01); + reg_write(gspca_dev, 0x05, 0x11, 0x0f); } static void sd_pkt_scan(struct gspca_dev *gspca_dev, diff --git a/drivers/media/usb/gspca/spca508.c b/drivers/media/usb/gspca/spca508.c index 1286b4170b88..75f2beb2ea5a 100644 --- a/drivers/media/usb/gspca/spca508.c +++ b/drivers/media/usb/gspca/spca508.c @@ -1241,10 +1241,10 @@ static const u16 spca508_vista_init_data[][2] = { {} }; -static int reg_write(struct usb_device *dev, - u16 index, u16 value) +static int reg_write(struct gspca_dev *gspca_dev, u16 index, u16 value) { int ret; + struct usb_device *dev = gspca_dev->dev; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), @@ -1286,22 +1286,21 @@ static int reg_read(struct gspca_dev *gspca_dev, static int ssi_w(struct gspca_dev *gspca_dev, u16 reg, u16 val) { - struct usb_device *dev = gspca_dev->dev; int ret, retry; - ret = reg_write(dev, 0x8802, reg >> 8); + ret = reg_write(gspca_dev, 0x8802, reg >> 8); if (ret < 0) goto out; - ret = reg_write(dev, 0x8801, reg & 0x00ff); + ret = reg_write(gspca_dev, 0x8801, reg & 0x00ff); if (ret < 0) goto out; if ((reg & 0xff00) == 0x1000) { /* if 2 bytes */ - ret = reg_write(dev, 0x8805, val & 0x00ff); + ret = reg_write(gspca_dev, 0x8805, val & 0x00ff); if (ret < 0) goto out; val >>= 8; } - ret = reg_write(dev, 0x8800, val); + ret = reg_write(gspca_dev, 0x8800, val); if (ret < 0) goto out; @@ -1314,8 +1313,7 @@ static int ssi_w(struct gspca_dev *gspca_dev, if (gspca_dev->usb_buf[0] == 0) break; if (--retry <= 0) { - PDEBUG(D_ERR, "ssi_w busy %02x", - gspca_dev->usb_buf[0]); + PERR("ssi_w busy %02x", gspca_dev->usb_buf[0]); ret = -1; break; } @@ -1329,7 +1327,6 @@ out: static int write_vector(struct gspca_dev *gspca_dev, const u16 (*data)[2]) { - struct usb_device *dev = gspca_dev->dev; int ret = 0; while ((*data)[1] != 0) { @@ -1337,7 +1334,8 @@ static int write_vector(struct gspca_dev *gspca_dev, if ((*data)[1] == 0xdd00) /* delay */ msleep((*data)[0]); else - ret = reg_write(dev, (*data)[1], (*data)[0]); + ret = reg_write(gspca_dev, (*data)[1], + (*data)[0]); } else { ret = ssi_w(gspca_dev, (*data)[1], (*data)[0]); } @@ -1363,8 +1361,6 @@ static int sd_config(struct gspca_dev *gspca_dev, spca508cs110_init_data, /* MicroInnovationIC200 4 */ spca508_init_data, /* ViewQuestVQ110 5 */ }; - -#ifdef GSPCA_DEBUG int data1, data2; /* Read from global register the USB product and vendor IDs, just to @@ -1381,7 +1377,6 @@ static int sd_config(struct gspca_dev *gspca_dev, data1 = reg_read(gspca_dev, 0x8621); PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1); -#endif cam = &gspca_dev->cam; cam->cam_mode = sif_mode; @@ -1404,26 +1399,26 @@ static int sd_start(struct gspca_dev *gspca_dev) int mode; mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; - reg_write(gspca_dev->dev, 0x8500, mode); + reg_write(gspca_dev, 0x8500, mode); switch (mode) { case 0: case 1: - reg_write(gspca_dev->dev, 0x8700, 0x28); /* clock */ + reg_write(gspca_dev, 0x8700, 0x28); /* clock */ break; default: /* case 2: */ /* case 3: */ - reg_write(gspca_dev->dev, 0x8700, 0x23); /* clock */ + reg_write(gspca_dev, 0x8700, 0x23); /* clock */ break; } - reg_write(gspca_dev->dev, 0x8112, 0x10 | 0x20); + reg_write(gspca_dev, 0x8112, 0x10 | 0x20); return 0; } static void sd_stopN(struct gspca_dev *gspca_dev) { /* Video ISO disable, Video Drop Packet enable: */ - reg_write(gspca_dev->dev, 0x8112, 0x20); + reg_write(gspca_dev, 0x8112, 0x20); } static void sd_pkt_scan(struct gspca_dev *gspca_dev, @@ -1450,10 +1445,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness) { /* MX seem contrast */ - reg_write(gspca_dev->dev, 0x8651, brightness); - reg_write(gspca_dev->dev, 0x8652, brightness); - reg_write(gspca_dev->dev, 0x8653, brightness); - reg_write(gspca_dev->dev, 0x8654, brightness); + reg_write(gspca_dev, 0x8651, brightness); + reg_write(gspca_dev, 0x8652, brightness); + reg_write(gspca_dev, 0x8653, brightness); + reg_write(gspca_dev, 0x8654, brightness); } static int sd_s_ctrl(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/usb/gspca/spca561.c b/drivers/media/usb/gspca/spca561.c index d1db3d8f6522..403d71cd65d9 100644 --- a/drivers/media/usb/gspca/spca561.c +++ b/drivers/media/usb/gspca/spca561.c @@ -285,9 +285,10 @@ static const __u16 spca561_161rev12A_data2[][2] = { {} }; -static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value) +static void reg_w_val(struct gspca_dev *gspca_dev, __u16 index, __u8 value) { int ret; + struct usb_device *dev = gspca_dev->dev; ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0, /* request */ @@ -301,12 +302,11 @@ static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value) static void write_vector(struct gspca_dev *gspca_dev, const __u16 data[][2]) { - struct usb_device *dev = gspca_dev->dev; int i; i = 0; while (data[i][1] != 0) { - reg_w_val(dev, data[i][1], data[i][0]); + reg_w_val(gspca_dev, data[i][1], data[i][0]); i++; } } @@ -339,9 +339,9 @@ static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg) { int retry = 60; - reg_w_val(gspca_dev->dev, 0x8801, reg); - reg_w_val(gspca_dev->dev, 0x8805, value); - reg_w_val(gspca_dev->dev, 0x8800, value >> 8); + reg_w_val(gspca_dev, 0x8801, reg); + reg_w_val(gspca_dev, 0x8805, value); + reg_w_val(gspca_dev, 0x8800, value >> 8); do { reg_r(gspca_dev, 0x8803, 1); if (!gspca_dev->usb_buf[0]) @@ -355,9 +355,9 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode) int retry = 60; __u8 value; - reg_w_val(gspca_dev->dev, 0x8804, 0x92); - reg_w_val(gspca_dev->dev, 0x8801, reg); - reg_w_val(gspca_dev->dev, 0x8802, mode | 0x01); + reg_w_val(gspca_dev, 0x8804, 0x92); + reg_w_val(gspca_dev, 0x8801, reg); + reg_w_val(gspca_dev, 0x8802, mode | 0x01); do { reg_r(gspca_dev, 0x8803, 1); if (!gspca_dev->usb_buf[0]) { @@ -459,14 +459,13 @@ static int sd_init_72a(struct gspca_dev *gspca_dev) write_sensor_72a(gspca_dev, rev72a_init_sensor1); write_vector(gspca_dev, rev72a_init_data2); write_sensor_72a(gspca_dev, rev72a_init_sensor2); - reg_w_val(gspca_dev->dev, 0x8112, 0x30); + reg_w_val(gspca_dev, 0x8112, 0x30); return 0; } static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; __u16 reg; if (sd->chip_revision == Rev012A) @@ -474,16 +473,15 @@ static void setbrightness(struct gspca_dev *gspca_dev, s32 val) else reg = 0x8611; - reg_w_val(dev, reg + 0, val); /* R */ - reg_w_val(dev, reg + 1, val); /* Gr */ - reg_w_val(dev, reg + 2, val); /* B */ - reg_w_val(dev, reg + 3, val); /* Gb */ + reg_w_val(gspca_dev, reg + 0, val); /* R */ + reg_w_val(gspca_dev, reg + 1, val); /* Gr */ + reg_w_val(gspca_dev, reg + 2, val); /* B */ + reg_w_val(gspca_dev, reg + 3, val); /* Gb */ } static void setwhite(struct gspca_dev *gspca_dev, s32 white, s32 contrast) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; __u8 blue, red; __u16 reg; @@ -496,11 +494,11 @@ static void setwhite(struct gspca_dev *gspca_dev, s32 white, s32 contrast) reg = 0x8651; red += contrast - 0x20; blue += contrast - 0x20; - reg_w_val(dev, 0x8652, contrast + 0x20); /* Gr */ - reg_w_val(dev, 0x8654, contrast + 0x20); /* Gb */ + reg_w_val(gspca_dev, 0x8652, contrast + 0x20); /* Gr */ + reg_w_val(gspca_dev, 0x8654, contrast + 0x20); /* Gb */ } - reg_w_val(dev, reg, red); - reg_w_val(dev, reg + 2, blue); + reg_w_val(gspca_dev, reg, red); + reg_w_val(gspca_dev, reg + 2, blue); } /* rev 12a only */ @@ -570,7 +568,6 @@ static void setautogain(struct gspca_dev *gspca_dev, s32 val) static int sd_start_12a(struct gspca_dev *gspca_dev) { - struct usb_device *dev = gspca_dev->dev; int mode; static const __u8 Reg8391[8] = {0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00}; @@ -578,34 +575,33 @@ static int sd_start_12a(struct gspca_dev *gspca_dev) mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; if (mode <= 1) { /* Use compression on 320x240 and above */ - reg_w_val(dev, 0x8500, 0x10 | mode); + reg_w_val(gspca_dev, 0x8500, 0x10 | mode); } else { /* I couldn't get the compression to work below 320x240 * Fortunately at these resolutions the bandwidth * is sufficient to push raw frames at ~20fps */ - reg_w_val(dev, 0x8500, mode); + reg_w_val(gspca_dev, 0x8500, mode); } /* -- qq@kuku.eu.org */ gspca_dev->usb_buf[0] = 0xaa; gspca_dev->usb_buf[1] = 0x00; reg_w_buf(gspca_dev, 0x8307, 2); /* clock - lower 0x8X values lead to fps > 30 */ - reg_w_val(gspca_dev->dev, 0x8700, 0x8a); + reg_w_val(gspca_dev, 0x8700, 0x8a); /* 0x8f 0x85 0x27 clock */ - reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20); - reg_w_val(gspca_dev->dev, 0x850b, 0x03); + reg_w_val(gspca_dev, 0x8112, 0x1e | 0x20); + reg_w_val(gspca_dev, 0x850b, 0x03); memcpy(gspca_dev->usb_buf, Reg8391, 8); reg_w_buf(gspca_dev, 0x8391, 8); reg_w_buf(gspca_dev, 0x8390, 8); /* Led ON (bit 3 -> 0 */ - reg_w_val(gspca_dev->dev, 0x8114, 0x00); + reg_w_val(gspca_dev, 0x8114, 0x00); return 0; } static int sd_start_72a(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; int Clck; int mode; @@ -630,15 +626,15 @@ static int sd_start_72a(struct gspca_dev *gspca_dev) Clck = 0x21; break; } - reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ - reg_w_val(dev, 0x8702, 0x81); - reg_w_val(dev, 0x8500, mode); /* mode */ + reg_w_val(gspca_dev, 0x8700, Clck); /* 0x27 clock */ + reg_w_val(gspca_dev, 0x8702, 0x81); + reg_w_val(gspca_dev, 0x8500, mode); /* mode */ write_sensor_72a(gspca_dev, rev72a_init_sensor2); setwhite(gspca_dev, v4l2_ctrl_g_ctrl(sd->hue), v4l2_ctrl_g_ctrl(sd->contrast)); /* setbrightness(gspca_dev); * fixme: bad values */ setautogain(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain)); - reg_w_val(dev, 0x8112, 0x10 | 0x20); + reg_w_val(gspca_dev, 0x8112, 0x10 | 0x20); return 0; } @@ -647,12 +643,12 @@ static void sd_stopN(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; if (sd->chip_revision == Rev012A) { - reg_w_val(gspca_dev->dev, 0x8112, 0x0e); + reg_w_val(gspca_dev, 0x8112, 0x0e); /* Led Off (bit 3 -> 1 */ - reg_w_val(gspca_dev->dev, 0x8114, 0x08); + reg_w_val(gspca_dev, 0x8114, 0x08); } else { - reg_w_val(gspca_dev->dev, 0x8112, 0x20); -/* reg_w_val(gspca_dev->dev, 0x8102, 0x00); ?? */ + reg_w_val(gspca_dev, 0x8112, 0x20); +/* reg_w_val(gspca_dev, 0x8102, 0x00); ?? */ } } @@ -736,7 +732,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* This should never happen */ if (len < 2) { - PDEBUG(D_ERR, "Short SOF packet, ignoring"); + PERR("Short SOF packet, ignoring"); gspca_dev->last_packet_type = DISCARD_PACKET; return; } diff --git a/drivers/media/usb/gspca/sq905.c b/drivers/media/usb/gspca/sq905.c index 1d99f10a3e19..a7ae0ec9fa91 100644 --- a/drivers/media/usb/gspca/sq905.c +++ b/drivers/media/usb/gspca/sq905.c @@ -387,7 +387,7 @@ static int sd_start(struct gspca_dev *gspca_dev) } if (ret < 0) { - PDEBUG(D_ERR, "Start streaming command failed"); + PERR("Start streaming command failed"); return ret; } /* Start the workqueue function to do the streaming */ diff --git a/drivers/media/usb/gspca/sq905c.c b/drivers/media/usb/gspca/sq905c.c index 410cdcbb55d4..acb19fb9a3df 100644 --- a/drivers/media/usb/gspca/sq905c.c +++ b/drivers/media/usb/gspca/sq905c.c @@ -215,13 +215,13 @@ static int sd_config(struct gspca_dev *gspca_dev, ret = sq905c_command(gspca_dev, SQ905C_GET_ID, 0); if (ret < 0) { - PDEBUG(D_ERR, "Get version command failed"); + PERR("Get version command failed"); return ret; } ret = sq905c_read(gspca_dev, 0xf5, 0, 20); if (ret < 0) { - PDEBUG(D_ERR, "Reading version command failed"); + PERR("Reading version command failed"); return ret; } /* Note we leave out the usb id and the manufacturing date */ @@ -286,7 +286,7 @@ static int sd_start(struct gspca_dev *gspca_dev) } if (ret < 0) { - PDEBUG(D_ERR, "Start streaming command failed"); + PERR("Start streaming command failed"); return ret; } /* Start the workqueue function to do the streaming */ diff --git a/drivers/media/usb/gspca/sq930x.c b/drivers/media/usb/gspca/sq930x.c index 7e8748b31e85..b10d0821111c 100644 --- a/drivers/media/usb/gspca/sq930x.c +++ b/drivers/media/usb/gspca/sq930x.c @@ -541,13 +541,11 @@ static void ucbus_write(struct gspca_dev *gspca_dev, if (gspca_dev->usb_err < 0) return; -#ifdef GSPCA_DEBUG if ((batchsize - 1) * 3 > USB_BUF_SZ) { - pr_err("Bug: usb_buf overflow\n"); + PERR("Bug: usb_buf overflow\n"); gspca_dev->usb_err = -ENOMEM; return; } -#endif for (;;) { len = ncmds; diff --git a/drivers/media/usb/gspca/stv0680.c b/drivers/media/usb/gspca/stv0680.c index 67605272aaa8..9c0827631b9c 100644 --- a/drivers/media/usb/gspca/stv0680.c +++ b/drivers/media/usb/gspca/stv0680.c @@ -86,7 +86,7 @@ static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val, static int stv0680_handle_error(struct gspca_dev *gspca_dev, int ret) { stv_sndctrl(gspca_dev, 0, 0x80, 0, 0x02); /* Get Last Error */ - PDEBUG(D_ERR, "last error: %i, command = 0x%x", + PERR("last error: %i, command = 0x%x", gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]); return ret; } @@ -98,7 +98,7 @@ static int stv0680_get_video_mode(struct gspca_dev *gspca_dev) gspca_dev->usb_buf[0] = 0x0f; if (stv_sndctrl(gspca_dev, 0, 0x87, 0, 0x08) != 0x08) { - PDEBUG(D_ERR, "Get_Camera_Mode failed"); + PERR("Get_Camera_Mode failed"); return stv0680_handle_error(gspca_dev, -EIO); } @@ -116,13 +116,13 @@ static int stv0680_set_video_mode(struct gspca_dev *gspca_dev, u8 mode) gspca_dev->usb_buf[0] = mode; if (stv_sndctrl(gspca_dev, 3, 0x07, 0x0100, 0x08) != 0x08) { - PDEBUG(D_ERR, "Set_Camera_Mode failed"); + PERR("Set_Camera_Mode failed"); return stv0680_handle_error(gspca_dev, -EIO); } /* Verify we got what we've asked for */ if (stv0680_get_video_mode(gspca_dev) != mode) { - PDEBUG(D_ERR, "Error setting camera video mode!"); + PERR("Error setting camera video mode!"); return -EIO; } @@ -146,7 +146,7 @@ static int sd_config(struct gspca_dev *gspca_dev, /* ping camera to be sure STV0680 is present */ if (stv_sndctrl(gspca_dev, 0, 0x88, 0x5678, 0x02) != 0x02 || gspca_dev->usb_buf[0] != 0x56 || gspca_dev->usb_buf[1] != 0x78) { - PDEBUG(D_ERR, "STV(e): camera ping failed!!"); + PERR("STV(e): camera ping failed!!"); return stv0680_handle_error(gspca_dev, -ENODEV); } @@ -156,7 +156,7 @@ static int sd_config(struct gspca_dev *gspca_dev, if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0200, 0x22) != 0x22 || gspca_dev->usb_buf[7] != 0xa0 || gspca_dev->usb_buf[8] != 0x23) { - PDEBUG(D_ERR, "Could not get descriptor 0200."); + PERR("Could not get descriptor 0200."); return stv0680_handle_error(gspca_dev, -ENODEV); } if (stv_sndctrl(gspca_dev, 0, 0x8a, 0, 0x02) != 0x02) @@ -167,7 +167,7 @@ static int sd_config(struct gspca_dev *gspca_dev, return stv0680_handle_error(gspca_dev, -ENODEV); if (!(gspca_dev->usb_buf[7] & 0x09)) { - PDEBUG(D_ERR, "Camera supports neither CIF nor QVGA mode"); + PERR("Camera supports neither CIF nor QVGA mode"); return -ENODEV; } if (gspca_dev->usb_buf[7] & 0x01) diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx.c b/drivers/media/usb/gspca/stv06xx/stv06xx.c index 657160b4a1f7..55ee7a61c67f 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c @@ -42,8 +42,10 @@ static bool dump_sensor; int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data) { int err; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; struct usb_device *udev = sd->gspca_dev.dev; __u8 *buf = sd->gspca_dev.usb_buf; + u8 len = (i2c_data > 0xff) ? 2 : 1; buf[0] = i2c_data & 0xff; @@ -62,6 +64,7 @@ int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data) int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data) { int err; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; struct usb_device *udev = sd->gspca_dev.dev; __u8 *buf = sd->gspca_dev.usb_buf; @@ -110,6 +113,7 @@ static int stv06xx_write_sensor_finish(struct sd *sd) int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len) { int err, i, j; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; struct usb_device *udev = sd->gspca_dev.dev; __u8 *buf = sd->gspca_dev.usb_buf; @@ -139,6 +143,7 @@ int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len) int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len) { int err, i, j; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; struct usb_device *udev = sd->gspca_dev.dev; __u8 *buf = sd->gspca_dev.usb_buf; @@ -170,6 +175,7 @@ int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len) int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value) { int err; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; struct usb_device *udev = sd->gspca_dev.dev; __u8 *buf = sd->gspca_dev.usb_buf; @@ -283,7 +289,7 @@ static int stv06xx_start(struct gspca_dev *gspca_dev) intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt); if (!alt) { - PDEBUG(D_ERR, "Couldn't get altsetting"); + PERR("Couldn't get altsetting"); return -EIO; } @@ -341,7 +347,7 @@ static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev) ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1); if (ret < 0) - PDEBUG(D_ERR|D_STREAM, "set alt 1 err %d", ret); + PERR("set alt 1 err %d", ret); return ret; } @@ -406,7 +412,7 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev, len -= 4; if (len < chunk_len) { - PDEBUG(D_ERR, "URB packet length is smaller" + PERR("URB packet length is smaller" " than the specified chunk length"); gspca_dev->last_packet_type = DISCARD_PACKET; return; @@ -449,7 +455,7 @@ frame_data: sd->to_skip = gspca_dev->width * 4; if (chunk_len) - PDEBUG(D_ERR, "Chunk length is " + PERR("Chunk length is " "non-zero on a SOF"); break; @@ -463,7 +469,7 @@ frame_data: NULL, 0); if (chunk_len) - PDEBUG(D_ERR, "Chunk length is " + PERR("Chunk length is " "non-zero on a EOF"); break; @@ -596,7 +602,6 @@ MODULE_DEVICE_TABLE(usb, device_table); static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { - PDEBUG(D_PROBE, "Probing for a stv06xx device"); return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), THIS_MODULE); } diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c index 06fa54c5efb2..2220b70d47e6 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx_hdcs.c @@ -255,7 +255,7 @@ static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val) if (err < 0) return err; } - PDEBUG(D_V4L2, "Writing exposure %d, rowexp %d, srowexp %d", + PDEBUG(D_CONF, "Writing exposure %d, rowexp %d, srowexp %d", val, rowexp, srowexp); return err; } @@ -280,7 +280,7 @@ static int hdcs_set_gains(struct sd *sd, u8 g) static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val) { - PDEBUG(D_V4L2, "Writing gain %d", val); + PDEBUG(D_CONF, "Writing gain %d", val); return hdcs_set_gains((struct sd *) gspca_dev, val & 0xff); } @@ -467,6 +467,8 @@ static int hdcs_probe_1020(struct sd *sd) static int hdcs_start(struct sd *sd) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; + PDEBUG(D_STREAM, "Starting stream"); return hdcs_set_state(sd, HDCS_STATE_RUN); @@ -474,6 +476,8 @@ static int hdcs_start(struct sd *sd) static int hdcs_stop(struct sd *sd) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; + PDEBUG(D_STREAM, "Halting stream"); return hdcs_set_state(sd, HDCS_STATE_SLEEP); diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c index cdfc3d05ab6b..8206b7743300 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx_pb0100.c @@ -190,6 +190,7 @@ static int pb0100_start(struct sd *sd) int err, packet_size, max_packet_size; struct usb_host_interface *alt; struct usb_interface *intf; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; struct cam *cam = &sd->gspca_dev.cam; u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv; @@ -239,6 +240,7 @@ static int pb0100_start(struct sd *sd) static int pb0100_stop(struct sd *sd) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int err; err = stv06xx_write_sensor(sd, PB_ABORTFRAME, 1); @@ -334,7 +336,7 @@ static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val) err = stv06xx_write_sensor(sd, PB_G1GAIN, val); if (!err) err = stv06xx_write_sensor(sd, PB_G2GAIN, val); - PDEBUG(D_V4L2, "Set green gain to %d, status: %d", val, err); + PDEBUG(D_CONF, "Set green gain to %d, status: %d", val, err); if (!err) err = pb0100_set_red_balance(gspca_dev, ctrls->red->val); @@ -357,7 +359,7 @@ static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) val = 255; err = stv06xx_write_sensor(sd, PB_RGAIN, val); - PDEBUG(D_V4L2, "Set red gain to %d, status: %d", val, err); + PDEBUG(D_CONF, "Set red gain to %d, status: %d", val, err); return err; } @@ -375,7 +377,7 @@ static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) val = 255; err = stv06xx_write_sensor(sd, PB_BGAIN, val); - PDEBUG(D_V4L2, "Set blue gain to %d, status: %d", val, err); + PDEBUG(D_CONF, "Set blue gain to %d, status: %d", val, err); return err; } @@ -386,7 +388,7 @@ static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val) int err; err = stv06xx_write_sensor(sd, PB_RINTTIME, val); - PDEBUG(D_V4L2, "Set exposure to %d, status: %d", val, err); + PDEBUG(D_CONF, "Set exposure to %d, status: %d", val, err); return err; } @@ -406,7 +408,7 @@ static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val) val = 0; err = stv06xx_write_sensor(sd, PB_EXPGAIN, val); - PDEBUG(D_V4L2, "Set autogain to %d (natural: %d), status: %d", + PDEBUG(D_CONF, "Set autogain to %d (natural: %d), status: %d", val, ctrls->natural->val, err); return err; @@ -428,7 +430,7 @@ static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val) if (!err) err = stv06xx_write_sensor(sd, PB_R22, darkpixels); - PDEBUG(D_V4L2, "Set autogain target to %d, status: %d", val, err); + PDEBUG(D_CONF, "Set autogain target to %d, status: %d", val, err); return err; } diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c index 8a57990dfe0f..515a9e121653 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx_st6422.c @@ -279,6 +279,8 @@ static int st6422_start(struct sd *sd) static int st6422_stop(struct sd *sd) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; + PDEBUG(D_STREAM, "Halting stream"); return 0; diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c index e95fa8997d22..bf3e5c317a26 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx_vv6410.c @@ -131,6 +131,7 @@ static int vv6410_init(struct sd *sd) static int vv6410_start(struct sd *sd) { int err; + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; struct cam *cam = &sd->gspca_dev.cam; u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv; @@ -163,6 +164,7 @@ static int vv6410_start(struct sd *sd) static int vv6410_stop(struct sd *sd) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int err; /* Turn off LED */ @@ -208,7 +210,7 @@ static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val) else i2c_data &= ~VV6410_HFLIP; - PDEBUG(D_V4L2, "Set horizontal flip to %d", val); + PDEBUG(D_CONF, "Set horizontal flip to %d", val); err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); return (err < 0) ? err : 0; @@ -229,7 +231,7 @@ static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val) else i2c_data &= ~VV6410_VFLIP; - PDEBUG(D_V4L2, "Set vertical flip to %d", val); + PDEBUG(D_CONF, "Set vertical flip to %d", val); err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); return (err < 0) ? err : 0; @@ -240,7 +242,7 @@ static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val) int err; struct sd *sd = (struct sd *) gspca_dev; - PDEBUG(D_V4L2, "Set analog gain to %d", val); + PDEBUG(D_CONF, "Set analog gain to %d", val); err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf)); return (err < 0) ? err : 0; @@ -257,7 +259,7 @@ static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val) fine = val % VV6410_CIF_LINELENGTH; coarse = min(512, val / VV6410_CIF_LINELENGTH); - PDEBUG(D_V4L2, "Set coarse exposure to %d, fine expsure to %d", + PDEBUG(D_CONF, "Set coarse exposure to %d, fine expsure to %d", coarse, fine); err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8); diff --git a/drivers/media/usb/gspca/sunplus.c b/drivers/media/usb/gspca/sunplus.c index 9ccfcb1c6479..af8767a9bd4c 100644 --- a/drivers/media/usb/gspca/sunplus.c +++ b/drivers/media/usb/gspca/sunplus.c @@ -251,12 +251,10 @@ static void reg_r(struct gspca_dev *gspca_dev, { int ret; -#ifdef GSPCA_DEBUG if (len > USB_BUF_SZ) { - pr_err("reg_r: buffer overflow\n"); + PERR("reg_r: buffer overflow\n"); return; } -#endif if (gspca_dev->usb_err < 0) return; ret = usb_control_msg(gspca_dev->dev, @@ -357,12 +355,14 @@ static void spca504_acknowledged_command(struct gspca_dev *gspca_dev, PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]); } -#ifdef GSPCA_DEBUG static void spca504_read_info(struct gspca_dev *gspca_dev) { int i; u8 info[6]; + if (gspca_debug < D_STREAM) + return; + for (i = 0; i < 6; i++) { reg_r(gspca_dev, 0, i, 1); info[i] = gspca_dev->usb_buf[0]; @@ -373,7 +373,6 @@ static void spca504_read_info(struct gspca_dev *gspca_dev) info[0], info[1], info[2], info[3], info[4], info[5]); } -#endif static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev, u8 req, @@ -432,11 +431,13 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) } } -#ifdef GSPCA_DEBUG static void spca50x_GetFirmware(struct gspca_dev *gspca_dev) { u8 *data; + if (gspca_debug < D_STREAM) + return; + data = gspca_dev->usb_buf; reg_r(gspca_dev, 0x20, 0, 5); PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d", @@ -444,7 +445,6 @@ static void spca50x_GetFirmware(struct gspca_dev *gspca_dev) reg_r(gspca_dev, 0x23, 0, 64); reg_r(gspca_dev, 0x23, 1, 64); } -#endif static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) { @@ -457,9 +457,8 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) reg_w_riv(gspca_dev, 0x31, 0, 0); spca504B_WaitCmdStatus(gspca_dev); spca504B_PollingDataReady(gspca_dev); -#ifdef GSPCA_DEBUG spca50x_GetFirmware(gspca_dev); -#endif + reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */ reg_r(gspca_dev, 0x24, 8, 1); @@ -645,14 +644,10 @@ static int sd_init(struct gspca_dev *gspca_dev) /* fall thru */ case BRIDGE_SPCA533: spca504B_PollingDataReady(gspca_dev); -#ifdef GSPCA_DEBUG spca50x_GetFirmware(gspca_dev); -#endif break; case BRIDGE_SPCA536: -#ifdef GSPCA_DEBUG spca50x_GetFirmware(gspca_dev); -#endif reg_r(gspca_dev, 0x00, 0x5002, 1); reg_w_1(gspca_dev, 0x24, 0, 0, 0); reg_r(gspca_dev, 0x24, 0, 1); @@ -678,9 +673,7 @@ static int sd_init(struct gspca_dev *gspca_dev) /* case BRIDGE_SPCA504: */ PDEBUG(D_STREAM, "Opening SPCA504"); if (sd->subtype == AiptekMiniPenCam13) { -#ifdef GSPCA_DEBUG spca504_read_info(gspca_dev); -#endif /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ spca504A_acknowledged_command(gspca_dev, 0x24, @@ -752,9 +745,7 @@ static int sd_start(struct gspca_dev *gspca_dev) break; case BRIDGE_SPCA504: if (sd->subtype == AiptekMiniPenCam13) { -#ifdef GSPCA_DEBUG spca504_read_info(gspca_dev); -#endif /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */ spca504A_acknowledged_command(gspca_dev, 0x24, @@ -766,9 +757,7 @@ static int sd_start(struct gspca_dev *gspca_dev) 0, 0, 0x9d, 1); } else { spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); -#ifdef GSPCA_DEBUG spca504_read_info(gspca_dev); -#endif spca504_acknowledged_command(gspca_dev, 0x24, 8, 3); spca504_acknowledged_command(gspca_dev, 0x24, 0, 0); } diff --git a/drivers/media/usb/gspca/vc032x.c b/drivers/media/usb/gspca/vc032x.c index e50079503d96..c00ac57de510 100644 --- a/drivers/media/usb/gspca/vc032x.c +++ b/drivers/media/usb/gspca/vc032x.c @@ -2927,7 +2927,6 @@ static void reg_r(struct gspca_dev *gspca_dev, u16 len) { reg_r_i(gspca_dev, req, index, len); -#ifdef GSPCA_DEBUG if (gspca_dev->usb_err < 0) return; if (len == 1) @@ -2936,7 +2935,6 @@ static void reg_r(struct gspca_dev *gspca_dev, else PDEBUG(D_USBI, "GET %02x 0001 %04x %*ph", req, index, 3, gspca_dev->usb_buf); -#endif } static void reg_w_i(struct gspca_dev *gspca_dev, @@ -2964,11 +2962,9 @@ static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index) { -#ifdef GSPCA_DEBUG if (gspca_dev->usb_err < 0) return; PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index); -#endif reg_w_i(gspca_dev, req, value, index); } @@ -3044,8 +3040,7 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev) if (value == 0 && ptsensor_info->IdAdd == 0x82) value = read_sensor_register(gspca_dev, 0x83); if (value != 0) { - PDEBUG(D_ERR|D_PROBE, "Sensor ID %04x (%d)", - value, i); + PDEBUG(D_PROBE, "Sensor ID %04x (%d)", value, i); if (value == ptsensor_info->VpId) return ptsensor_info->sensorId; @@ -3069,14 +3064,12 @@ static void i2c_write(struct gspca_dev *gspca_dev, { int retry; -#ifdef GSPCA_DEBUG if (gspca_dev->usb_err < 0) return; if (size == 1) PDEBUG(D_USBO, "i2c_w %02x %02x", reg, *val); else PDEBUG(D_USBO, "i2c_w %02x %02x%02x", reg, *val, val[1]); -#endif reg_r_i(gspca_dev, 0xa1, 0xb33f, 1); /*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/ reg_w_i(gspca_dev, 0xa0, size, 0xb334); diff --git a/drivers/media/usb/gspca/w996Xcf.c b/drivers/media/usb/gspca/w996Xcf.c index 9e3a909e0a00..2165da0c7ce1 100644 --- a/drivers/media/usb/gspca/w996Xcf.c +++ b/drivers/media/usb/gspca/w996Xcf.c @@ -232,6 +232,7 @@ static void w9968cf_smbus_write_nack(struct sd *sd) static void w9968cf_smbus_read_ack(struct sd *sd) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int sda; /* Ensure SDA is high before raising clock to avoid a spurious stop */ @@ -248,6 +249,7 @@ static void w9968cf_smbus_read_ack(struct sd *sd) /* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */ static void w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; u16* data = (u16 *)sd->gspca_dev.usb_buf; data[0] = 0x082f | ((sd->sensor_addr & 0x80) ? 0x1500 : 0x0); @@ -297,6 +299,7 @@ static void w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value) /* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */ static int w9968cf_i2c_r(struct sd *sd, u8 reg) { + struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; int ret = 0; u8 value; @@ -326,7 +329,7 @@ static int w9968cf_i2c_r(struct sd *sd, u8 reg) ret = value; PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value); } else - PDEBUG(D_ERR, "i2c read [0x%02x] failed", reg); + PERR("i2c read [0x%02x] failed", reg); return ret; } diff --git a/drivers/media/usb/gspca/zc3xx.c b/drivers/media/usb/gspca/zc3xx.c index a8dc421f9f1f..cbfc2f921427 100644 --- a/drivers/media/usb/gspca/zc3xx.c +++ b/drivers/media/usb/gspca/zc3xx.c @@ -6259,12 +6259,11 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev) retword |= i2c_read(gspca_dev, 0x01); /* ID 1 */ PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", retword); if (retword == 0x2030) { -#ifdef GSPCA_DEBUG u8 retbyte; retbyte = i2c_read(gspca_dev, 0x02); /* revision number */ PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte); -#endif + send_unknown(gspca_dev, SENSOR_PO2030); return retword; } -- cgit v1.2.3 From 8b21eb17e749c9693eaea065f0eb95365006495c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Feb 2013 07:58:41 -0300 Subject: [media] radio-isa: fix querycap capabilities code The device_caps and capabilities fields were swapped. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-isa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c index 84b7b9f4385e..fe0a4f85c422 100644 --- a/drivers/media/radio/radio-isa.c +++ b/drivers/media/radio/radio-isa.c @@ -51,8 +51,8 @@ static int radio_isa_querycap(struct file *file, void *priv, strlcpy(v->card, isa->drv->card, sizeof(v->card)); snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name); - v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - v->device_caps = v->capabilities | V4L2_CAP_DEVICE_CAPS; + v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } -- cgit v1.2.3 From 4ca286610f664acf3153634f3930acd2de993a9f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Feb 2013 08:00:15 -0300 Subject: [media] radio-rtrack2: fix mute bug Setting the frequency would unmute the card. Fixed the mute handling in the s_frequency code. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-rtrack2.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index b1f844c64fde..09cfbc373c92 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -8,6 +8,8 @@ * * Converted to the radio-isa framework by Hans Verkuil * Converted to V4L2 API by Mauro Carvalho Chehab + * + * Fully tested with actual hardware and the v4l2-compliance tool. */ #include /* Modules */ @@ -81,8 +83,7 @@ static int rtrack2_s_frequency(struct radio_isa_card *isa, u32 freq) zero(isa); outb_p(0xc8, isa->io); - if (!v4l2_ctrl_g_ctrl(isa->mute)) - outb_p(0, isa->io); + outb_p(v4l2_ctrl_g_ctrl(isa->mute), isa->io); return 0; } -- cgit v1.2.3 From 192f1e78cb9cbc1a2cee866f5e03a52857e648b6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 05:51:21 -0300 Subject: [media] s2255: convert to the control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 172 ++++++++++++------------------------- include/uapi/linux/v4l2-controls.h | 4 + 2 files changed, 59 insertions(+), 117 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 498c57ea5d32..2dcb29b647f0 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -217,6 +218,7 @@ struct s2255_dev; struct s2255_channel { struct video_device vdev; + struct v4l2_ctrl_handler hdl; int resources; struct s2255_dmaqueue vidq; struct s2255_bufferi buffer; @@ -336,7 +338,7 @@ struct s2255_fh { */ #define S2255_V4L2_YC_ON 1 #define S2255_V4L2_YC_OFF 0 -#define V4L2_CID_PRIVATE_COLORFILTER (V4L2_CID_PRIVATE_BASE + 0) +#define V4L2_CID_S2255_COLORFILTER (V4L2_CID_USER_S2255_BASE + 0) /* frame prefix size (sent once every frame) */ #define PREFIX_SIZE 512 @@ -810,28 +812,6 @@ static void res_free(struct s2255_fh *fh) dprintk(1, "res: put\n"); } -static int vidioc_querymenu(struct file *file, void *priv, - struct v4l2_querymenu *qmenu) -{ - static const char *colorfilter[] = { - "Off", - "On", - NULL - }; - if (qmenu->id == V4L2_CID_PRIVATE_COLORFILTER) { - int i; - const char **menu_items = colorfilter; - for (i = 0; i < qmenu->index && menu_items[i]; i++) - ; /* do nothing (from v4l2-common.c) */ - if (menu_items[i] == NULL || menu_items[i][0] == '\0') - return -EINVAL; - strlcpy(qmenu->name, menu_items[qmenu->index], - sizeof(qmenu->name)); - return 0; - } - return v4l2_ctrl_query_menu(qmenu, NULL, NULL); -} - static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -1427,109 +1407,32 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) return 0; } -/* --- controls ---------------------------------------------- */ -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) +static int s2255_s_ctrl(struct v4l2_ctrl *ctrl) { - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - struct s2255_dev *dev = fh->dev; - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - v4l2_ctrl_query_fill(qc, -127, 127, 1, DEF_BRIGHT); - break; - case V4L2_CID_CONTRAST: - v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_CONTRAST); - break; - case V4L2_CID_SATURATION: - v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_SATURATION); - break; - case V4L2_CID_HUE: - v4l2_ctrl_query_fill(qc, 0, 255, 1, DEF_HUE); - break; - case V4L2_CID_PRIVATE_COLORFILTER: - if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) - return -EINVAL; - if ((dev->pid == 0x2257) && (channel->idx > 1)) - return -EINVAL; - strlcpy(qc->name, "Color Filter", sizeof(qc->name)); - qc->type = V4L2_CTRL_TYPE_MENU; - qc->minimum = 0; - qc->maximum = 1; - qc->step = 1; - qc->default_value = 1; - qc->flags = 0; - break; - default: - return -EINVAL; - } - dprintk(4, "%s, id %d\n", __func__, qc->id); - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct s2255_fh *fh = priv; - struct s2255_dev *dev = fh->dev; - struct s2255_channel *channel = fh->channel; - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = channel->mode.bright; - break; - case V4L2_CID_CONTRAST: - ctrl->value = channel->mode.contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = channel->mode.saturation; - break; - case V4L2_CID_HUE: - ctrl->value = channel->mode.hue; - break; - case V4L2_CID_PRIVATE_COLORFILTER: - if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) - return -EINVAL; - if ((dev->pid == 0x2257) && (channel->idx > 1)) - return -EINVAL; - ctrl->value = !((channel->mode.color & MASK_INPUT_TYPE) >> 16); - break; - default: - return -EINVAL; - } - dprintk(4, "%s, id %d val %d\n", __func__, ctrl->id, ctrl->value); - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct s2255_fh *fh = priv; - struct s2255_channel *channel = fh->channel; - struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); + struct s2255_channel *channel = + container_of(ctrl->handler, struct s2255_channel, hdl); struct s2255_mode mode; + mode = channel->mode; dprintk(4, "%s\n", __func__); + /* update the mode to the corresponding value */ switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - mode.bright = ctrl->value; + mode.bright = ctrl->val; break; case V4L2_CID_CONTRAST: - mode.contrast = ctrl->value; + mode.contrast = ctrl->val; break; case V4L2_CID_HUE: - mode.hue = ctrl->value; + mode.hue = ctrl->val; break; case V4L2_CID_SATURATION: - mode.saturation = ctrl->value; + mode.saturation = ctrl->val; break; - case V4L2_CID_PRIVATE_COLORFILTER: - if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) - return -EINVAL; - if ((dev->pid == 0x2257) && (channel->idx > 1)) - return -EINVAL; + case V4L2_CID_S2255_COLORFILTER: mode.color &= ~MASK_INPUT_TYPE; - mode.color |= ((ctrl->value ? 0 : 1) << 16); + mode.color |= !ctrl->val << 16; break; default: return -EINVAL; @@ -1539,7 +1442,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, some V4L programs restart stream unnecessarily after a s_crtl. */ - s2255_set_mode(fh->channel, &mode); + s2255_set_mode(channel, &mode); return 0; } @@ -1886,7 +1789,6 @@ static const struct v4l2_file_operations s2255_fops_v4l = { }; static const struct v4l2_ioctl_ops s2255_ioctl_ops = { - .vidioc_querymenu = vidioc_querymenu, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1900,9 +1802,6 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_s_jpegcomp = vidioc_s_jpegcomp, @@ -1915,8 +1814,13 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { static void s2255_video_device_release(struct video_device *vdev) { struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev); - dprintk(4, "%s, chnls: %d \n", __func__, + struct s2255_channel *channel = + container_of(vdev, struct s2255_channel, vdev); + + v4l2_ctrl_handler_free(&channel->hdl); + dprintk(4, "%s, chnls: %d\n", __func__, atomic_read(&dev->num_channels)); + if (atomic_dec_and_test(&dev->num_channels)) s2255_destroy(dev); return; @@ -1931,6 +1835,20 @@ static struct video_device template = { .current_norm = V4L2_STD_NTSC_M, }; +static const struct v4l2_ctrl_ops s2255_ctrl_ops = { + .s_ctrl = s2255_s_ctrl, +}; + +static const struct v4l2_ctrl_config color_filter_ctrl = { + .ops = &s2255_ctrl_ops, + .name = "Color Filter", + .id = V4L2_CID_S2255_COLORFILTER, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, + .def = 1, +}; + static int s2255_probe_v4l(struct s2255_dev *dev) { int ret; @@ -1945,9 +1863,29 @@ static int s2255_probe_v4l(struct s2255_dev *dev) for (i = 0; i < MAX_CHANNELS; i++) { channel = &dev->channel[i]; INIT_LIST_HEAD(&channel->vidq.active); + + v4l2_ctrl_handler_init(&channel->hdl, 5); + v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, + V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT); + v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST); + v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION); + v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, + V4L2_CID_HUE, 0, 255, 1, DEF_HUE); + if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER && + (dev->pid != 0x2257 || channel->idx <= 1)) + v4l2_ctrl_new_custom(&channel->hdl, &color_filter_ctrl, NULL); + if (channel->hdl.error) { + ret = channel->hdl.error; + v4l2_ctrl_handler_free(&channel->hdl); + dev_err(&dev->udev->dev, "couldn't register control\n"); + break; + } channel->vidq.dev = dev; /* register 4 video devices */ channel->vdev = template; + channel->vdev.ctrl_handler = &channel->hdl; channel->vdev.lock = &dev->lock; channel->vdev.v4l2_dev = &dev->v4l2_dev; video_set_drvdata(&channel->vdev, channel); diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 1d00ca9f0ba3..7eab0b91827b 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -151,6 +151,10 @@ enum v4l2_colorfx { #define V4L2_CID_USER_BTTV_BASE (V4L2_CID_USER_BASE + 0x1010) +/* The base for the s2255 driver controls. + * We reserve 8 controls for this driver. */ +#define V4L2_CID_USER_S2255_BASE (V4L2_CID_USER_BASE + 0x1010) + /* MPEG-class control IDs */ #define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) -- cgit v1.2.3 From 7041dec7a93039d1386ad0f5070dc2318d66a18d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 05:53:45 -0300 Subject: [media] s2255: add V4L2_CID_JPEG_COMPRESSION_QUALITY The use of the V4L2_CID_JPEG_COMPRESSION_QUALITY control is recommended over the G/S_JPEGCOMP ioctls. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 2dcb29b647f0..42c3afe215b2 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -219,12 +219,13 @@ struct s2255_dev; struct s2255_channel { struct video_device vdev; struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *jpegqual_ctrl; int resources; struct s2255_dmaqueue vidq; struct s2255_bufferi buffer; struct s2255_mode mode; /* jpeg compression */ - struct v4l2_jpegcompression jc; + unsigned jpegqual; /* capture parameters (for high quality mode full size) */ struct v4l2_captureparm cap_parm; int cur_frame; @@ -1015,7 +1016,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, case V4L2_PIX_FMT_MJPEG: mode.color &= ~MASK_COLOR; mode.color |= COLOR_JPG; - mode.color |= (channel->jc.quality << 8); + mode.color |= (channel->jpegqual << 8); break; case V4L2_PIX_FMT_YUV422P: mode.color &= ~MASK_COLOR; @@ -1185,7 +1186,7 @@ static int s2255_set_mode(struct s2255_channel *channel, mode->color &= ~MASK_COLOR; mode->color |= COLOR_JPG; mode->color &= ~MASK_JPG_QUALITY; - mode->color |= (channel->jc.quality << 8); + mode->color |= (channel->jpegqual << 8); } /* save the mode */ channel->mode = *mode; @@ -1434,6 +1435,9 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl) mode.color &= ~MASK_INPUT_TYPE; mode.color |= !ctrl->val << 16; break; + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + channel->jpegqual = ctrl->val; + return 0; default: return -EINVAL; } @@ -1451,7 +1455,9 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv, { struct s2255_fh *fh = priv; struct s2255_channel *channel = fh->channel; - *jc = channel->jc; + + memset(jc, 0, sizeof(*jc)); + jc->quality = channel->jpegqual; dprintk(2, "%s: quality %d\n", __func__, jc->quality); return 0; } @@ -1463,7 +1469,7 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv, struct s2255_channel *channel = fh->channel; if (jc->quality < 0 || jc->quality > 100) return -EINVAL; - channel->jc.quality = jc->quality; + v4l2_ctrl_s_ctrl(channel->jpegqual_ctrl, jc->quality); dprintk(2, "%s: quality %d\n", __func__, jc->quality); return 0; } @@ -1864,7 +1870,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev) channel = &dev->channel[i]; INIT_LIST_HEAD(&channel->vidq.active); - v4l2_ctrl_handler_init(&channel->hdl, 5); + v4l2_ctrl_handler_init(&channel->hdl, 6); v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT); v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, @@ -1873,6 +1879,10 @@ static int s2255_probe_v4l(struct s2255_dev *dev) V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION); v4l2_ctrl_new_std(&channel->hdl, &s2255_ctrl_ops, V4L2_CID_HUE, 0, 255, 1, DEF_HUE); + channel->jpegqual_ctrl = v4l2_ctrl_new_std(&channel->hdl, + &s2255_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, + 0, 100, 1, S2255_DEF_JPEG_QUAL); if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER && (dev->pid != 0x2257 || channel->idx <= 1)) v4l2_ctrl_new_custom(&channel->hdl, &color_filter_ctrl, NULL); @@ -2238,7 +2248,7 @@ static int s2255_board_init(struct s2255_dev *dev) channel->mode = mode_def; if (dev->pid == 0x2257 && j > 1) channel->mode.color |= (1 << 16); - channel->jc.quality = S2255_DEF_JPEG_QUAL; + channel->jpegqual = S2255_DEF_JPEG_QUAL; channel->width = LINE_SZ_4CIFS_NTSC; channel->height = NUM_LINES_4CIFS_NTSC * 2; channel->fmt = &formats[0]; -- cgit v1.2.3 From 44d06d8273e032119c5ae0d0f90bb57ab8118a5b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 05:59:00 -0300 Subject: [media] s2255: add support for control events and prio handling Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 42c3afe215b2..55c972a0dbed 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -43,13 +43,14 @@ #include #include #include +#include +#include #include #include #include #include #include -#include -#include +#include #define S2255_VERSION "1.22.1" #define FIRMWARE_FILE_NAME "f2255usb.bin" @@ -295,6 +296,8 @@ struct s2255_buffer { }; struct s2255_fh { + /* this must be the first field in this struct */ + struct v4l2_fh fh; struct s2255_dev *dev; struct videobuf_queue vb_vidq; enum v4l2_buf_type type; @@ -1666,7 +1669,9 @@ static int __s2255_open(struct file *file) fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (NULL == fh) return -ENOMEM; - file->private_data = fh; + v4l2_fh_init(&fh->fh, vdev); + v4l2_fh_add(&fh->fh); + file->private_data = &fh->fh; fh->dev = dev; fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fh->channel = channel; @@ -1709,12 +1714,13 @@ static unsigned int s2255_poll(struct file *file, { struct s2255_fh *fh = file->private_data; struct s2255_dev *dev = fh->dev; - int rc; + int rc = v4l2_ctrl_poll(file, wait); + dprintk(100, "%s\n", __func__); if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) return POLLERR; mutex_lock(&dev->lock); - rc = videobuf_poll_stream(file, &fh->vb_vidq, wait); + rc |= videobuf_poll_stream(file, &fh->vb_vidq, wait); mutex_unlock(&dev->lock); return rc; } @@ -1761,6 +1767,8 @@ static int s2255_release(struct file *file) videobuf_mmap_free(&fh->vb_vidq); mutex_unlock(&dev->lock); dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev)); + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); kfree(fh); return 0; } @@ -1815,6 +1823,9 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { .vidioc_s_parm = vidioc_s_parm, .vidioc_g_parm = vidioc_g_parm, .vidioc_enum_frameintervals = vidioc_enum_frameintervals, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static void s2255_video_device_release(struct video_device *vdev) @@ -1898,6 +1909,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev) channel->vdev.ctrl_handler = &channel->hdl; channel->vdev.lock = &dev->lock; channel->vdev.v4l2_dev = &dev->v4l2_dev; + set_bit(V4L2_FL_USE_FH_PRIO, &channel->vdev.flags); video_set_drvdata(&channel->vdev, channel); if (video_nr == -1) ret = video_register_device(&channel->vdev, -- cgit v1.2.3 From 39696009d0d4472606b7fb90fc635a0d0fecba60 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 7 Feb 2013 07:06:21 -0300 Subject: [media] s2255: add device_caps support to querycap Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 55c972a0dbed..9cb832517040 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -821,10 +821,12 @@ static int vidioc_querycap(struct file *file, void *priv, { struct s2255_fh *fh = file->private_data; struct s2255_dev *dev = fh->dev; + strlcpy(cap->driver, "s2255", sizeof(cap->driver)); strlcpy(cap->card, "s2255", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } -- cgit v1.2.3 From 469af77a178510ed43d4d527b1b7a607c5c18bcb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 06:12:58 -0300 Subject: [media] s2255: fixes in the way standards are handled Instead of comparing against STD_NTSC and STD_PAL compare against 60 and 50 Hz formats. That's what you really want. When the standard is changed, make sure the width and height of the format are also updated to reflect the current standard. Also replace the deprecated current_norm by the g_std ioctl. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 61 ++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 22 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 9cb832517040..88f728d3b24f 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -225,6 +225,7 @@ struct s2255_channel { struct s2255_dmaqueue vidq; struct s2255_bufferi buffer; struct s2255_mode mode; + v4l2_std_id std; /* jpeg compression */ unsigned jpegqual; /* capture parameters (for high quality mode full size) */ @@ -312,7 +313,7 @@ struct s2255_fh { /* Need DSP version 5+ for video status feature */ #define S2255_MIN_DSP_STATUS 5 #define S2255_MIN_DSP_COLORFILTER 8 -#define S2255_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC) +#define S2255_NORMS (V4L2_STD_ALL) /* private V4L2 controls */ @@ -443,27 +444,27 @@ static const struct s2255_fmt formats[] = { } }; -static int norm_maxw(struct video_device *vdev) +static int norm_maxw(struct s2255_channel *channel) { - return (vdev->current_norm & V4L2_STD_NTSC) ? + return (channel->std & V4L2_STD_525_60) ? LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL; } -static int norm_maxh(struct video_device *vdev) +static int norm_maxh(struct s2255_channel *channel) { - return (vdev->current_norm & V4L2_STD_NTSC) ? + return (channel->std & V4L2_STD_525_60) ? (NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2); } -static int norm_minw(struct video_device *vdev) +static int norm_minw(struct s2255_channel *channel) { - return (vdev->current_norm & V4L2_STD_NTSC) ? + return (channel->std & V4L2_STD_525_60) ? LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL; } -static int norm_minh(struct video_device *vdev) +static int norm_minh(struct s2255_channel *channel) { - return (vdev->current_norm & V4L2_STD_NTSC) ? + return (channel->std & V4L2_STD_525_60) ? (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL); } @@ -725,10 +726,10 @@ static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, if (channel->fmt == NULL) return -EINVAL; - if ((w < norm_minw(&channel->vdev)) || - (w > norm_maxw(&channel->vdev)) || - (h < norm_minh(&channel->vdev)) || - (h > norm_maxh(&channel->vdev))) { + if ((w < norm_minw(channel)) || + (w > norm_maxw(channel)) || + (h < norm_minh(channel)) || + (h > norm_maxh(channel))) { dprintk(4, "invalid buffer prepare\n"); return -EINVAL; } @@ -870,8 +871,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct s2255_fh *fh = priv; struct s2255_channel *channel = fh->channel; int is_ntsc; - is_ntsc = - (channel->vdev.current_norm & V4L2_STD_NTSC) ? 1 : 0; + is_ntsc = (channel->std & V4L2_STD_525_60) ? 1 : 0; fmt = format_by_fourcc(f->fmt.pix.pixelformat); @@ -998,8 +998,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, channel->height = f->fmt.pix.height; fh->vb_vidq.field = f->fmt.pix.field; fh->type = f->type; - if (channel->width > norm_minw(&channel->vdev)) { - if (channel->height > norm_minh(&channel->vdev)) { + if (channel->width > norm_minw(channel)) { + if (channel->height > norm_minh(channel)) { if (channel->cap_parm.capturemode & V4L2_MODE_HIGHQUALITY) mode.scale = SCALE_4CIFSI; @@ -1323,7 +1323,9 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) struct s2255_fh *fh = priv; struct s2255_mode mode; struct videobuf_queue *q = &fh->vb_vidq; + struct s2255_channel *channel = fh->channel; int ret = 0; + mutex_lock(&q->vb_lock); if (videobuf_queue_is_busy(q)) { dprintk(1, "queue busy\n"); @@ -1336,24 +1338,30 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) goto out_s_std; } mode = fh->channel->mode; - if (*i & V4L2_STD_NTSC) { - dprintk(4, "%s NTSC\n", __func__); + if (*i & V4L2_STD_525_60) { + dprintk(4, "%s 60 Hz\n", __func__); /* if changing format, reset frame decimation/intervals */ if (mode.format != FORMAT_NTSC) { mode.restart = 1; mode.format = FORMAT_NTSC; mode.fdec = FDEC_1; + channel->width = LINE_SZ_4CIFS_NTSC; + channel->height = NUM_LINES_4CIFS_NTSC * 2; } - } else if (*i & V4L2_STD_PAL) { - dprintk(4, "%s PAL\n", __func__); + } else if (*i & V4L2_STD_625_50) { + dprintk(4, "%s 50 Hz\n", __func__); if (mode.format != FORMAT_PAL) { mode.restart = 1; mode.format = FORMAT_PAL; mode.fdec = FDEC_1; + channel->width = LINE_SZ_4CIFS_PAL; + channel->height = NUM_LINES_4CIFS_PAL * 2; } } else { ret = -EINVAL; + goto out_s_std; } + fh->channel->std = *i; if (mode.restart) s2255_set_mode(fh->channel, &mode); out_s_std: @@ -1361,6 +1369,14 @@ out_s_std: return ret; } +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i) +{ + struct s2255_fh *fh = priv; + + *i = fh->channel->std; + return 0; +} + /* Sensoray 2255 is a multiple channel capture device. It does not have a "crossbar" of inputs. We use one V4L device per channel. The user must @@ -1815,6 +1831,7 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, @@ -1851,7 +1868,6 @@ static struct video_device template = { .ioctl_ops = &s2255_ioctl_ops, .release = s2255_video_device_release, .tvnorms = S2255_NORMS, - .current_norm = V4L2_STD_NTSC_M, }; static const struct v4l2_ctrl_ops s2255_ctrl_ops = { @@ -2265,6 +2281,7 @@ static int s2255_board_init(struct s2255_dev *dev) channel->jpegqual = S2255_DEF_JPEG_QUAL; channel->width = LINE_SZ_4CIFS_NTSC; channel->height = NUM_LINES_4CIFS_NTSC * 2; + channel->std = V4L2_STD_NTSC_M; channel->fmt = &formats[0]; channel->mode.restart = 1; channel->req_image_size = get_transfer_size(&mode_def); -- cgit v1.2.3 From 29ceb1101e9b39eaac2f20281a93c2afaf07aa10 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 06:03:26 -0300 Subject: [media] s2255: zero priv and set colorspace Set priv field of struct v4l2_pix_format to 0 and fill in colorspace. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 88f728d3b24f..a16bc6cdd007 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -859,6 +859,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.pixelformat = channel->fmt->fourcc; f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3); f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.priv = 0; return 0; } @@ -954,6 +956,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.field = field; f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.priv = 0; dprintk(50, "%s: set width %d height %d field %d\n", __func__, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); return 0; -- cgit v1.2.3 From 92513611fa5864b8aec216db5a93bafaa299d623 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 06:05:08 -0300 Subject: [media] s2255: fix field handling Just set the field value based on the chosen format. It's either INTERLACED or TOP. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 61 ++++++++++---------------------------- 1 file changed, 15 insertions(+), 46 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index a16bc6cdd007..9693eb9d9e8d 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -852,10 +852,15 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, { struct s2255_fh *fh = priv; struct s2255_channel *channel = fh->channel; + int is_ntsc = channel->std & V4L2_STD_525_60; f->fmt.pix.width = channel->width; f->fmt.pix.height = channel->height; - f->fmt.pix.field = fh->vb_vidq.field; + if (f->fmt.pix.height >= + (is_ntsc ? NUM_LINES_1CIFS_NTSC : NUM_LINES_1CIFS_PAL) * 2) + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + else + f->fmt.pix.field = V4L2_FIELD_TOP; f->fmt.pix.pixelformat = channel->fmt->fourcc; f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3); f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; @@ -869,11 +874,9 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, { const struct s2255_fmt *fmt; enum v4l2_field field; - int b_any_field = 0; struct s2255_fh *fh = priv; struct s2255_channel *channel = fh->channel; - int is_ntsc; - is_ntsc = (channel->std & V4L2_STD_525_60) ? 1 : 0; + int is_ntsc = channel->std & V4L2_STD_525_60; fmt = format_by_fourcc(f->fmt.pix.pixelformat); @@ -881,8 +884,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; field = f->fmt.pix.field; - if (field == V4L2_FIELD_ANY) - b_any_field = 1; dprintk(50, "%s NTSC: %d suggested width: %d, height: %d\n", __func__, is_ntsc, f->fmt.pix.width, f->fmt.pix.height); @@ -890,24 +891,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, /* NTSC */ if (f->fmt.pix.height >= NUM_LINES_1CIFS_NTSC * 2) { f->fmt.pix.height = NUM_LINES_1CIFS_NTSC * 2; - if (b_any_field) { - field = V4L2_FIELD_SEQ_TB; - } else if (!((field == V4L2_FIELD_INTERLACED) || - (field == V4L2_FIELD_SEQ_TB) || - (field == V4L2_FIELD_INTERLACED_TB))) { - dprintk(1, "unsupported field setting\n"); - return -EINVAL; - } + field = V4L2_FIELD_INTERLACED; } else { f->fmt.pix.height = NUM_LINES_1CIFS_NTSC; - if (b_any_field) { - field = V4L2_FIELD_TOP; - } else if (!((field == V4L2_FIELD_TOP) || - (field == V4L2_FIELD_BOTTOM))) { - dprintk(1, "unsupported field setting\n"); - return -EINVAL; - } - + field = V4L2_FIELD_TOP; } if (f->fmt.pix.width >= LINE_SZ_4CIFS_NTSC) f->fmt.pix.width = LINE_SZ_4CIFS_NTSC; @@ -921,37 +908,19 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, /* PAL */ if (f->fmt.pix.height >= NUM_LINES_1CIFS_PAL * 2) { f->fmt.pix.height = NUM_LINES_1CIFS_PAL * 2; - if (b_any_field) { - field = V4L2_FIELD_SEQ_TB; - } else if (!((field == V4L2_FIELD_INTERLACED) || - (field == V4L2_FIELD_SEQ_TB) || - (field == V4L2_FIELD_INTERLACED_TB))) { - dprintk(1, "unsupported field setting\n"); - return -EINVAL; - } + field = V4L2_FIELD_INTERLACED; } else { f->fmt.pix.height = NUM_LINES_1CIFS_PAL; - if (b_any_field) { - field = V4L2_FIELD_TOP; - } else if (!((field == V4L2_FIELD_TOP) || - (field == V4L2_FIELD_BOTTOM))) { - dprintk(1, "unsupported field setting\n"); - return -EINVAL; - } + field = V4L2_FIELD_TOP; } - if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) { + if (f->fmt.pix.width >= LINE_SZ_4CIFS_PAL) f->fmt.pix.width = LINE_SZ_4CIFS_PAL; - field = V4L2_FIELD_SEQ_TB; - } else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL) { + else if (f->fmt.pix.width >= LINE_SZ_2CIFS_PAL) f->fmt.pix.width = LINE_SZ_2CIFS_PAL; - field = V4L2_FIELD_TOP; - } else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL) { + else if (f->fmt.pix.width >= LINE_SZ_1CIFS_PAL) f->fmt.pix.width = LINE_SZ_1CIFS_PAL; - field = V4L2_FIELD_TOP; - } else { + else f->fmt.pix.width = LINE_SZ_1CIFS_PAL; - field = V4L2_FIELD_TOP; - } } f->fmt.pix.field = field; f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; -- cgit v1.2.3 From 3c728118e00c42a177f9a5d0295b2a08591bddcb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 06:07:13 -0300 Subject: [media] s2255: don't zero struct v4l2_streamparm All fields after 'type' are already zeroed by the core framework. Clearing the full struct also clears 'type', which causes a wrong type value to be returned. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 9693eb9d9e8d..eaae9d167e76 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -1476,7 +1476,6 @@ static int vidioc_g_parm(struct file *file, void *priv, struct s2255_channel *channel = fh->channel; if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - memset(sp, 0, sizeof(struct v4l2_streamparm)); sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; sp->parm.capture.capturemode = channel->cap_parm.capturemode; def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000; -- cgit v1.2.3 From 05e5d44b078fdd628a2b47c294dd78bbca524afc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 06:09:18 -0300 Subject: [media] s2255: Add ENUM_FRAMESIZES support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 73 ++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 22 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index eaae9d167e76..59d40e614e94 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -1545,36 +1545,64 @@ static int vidioc_s_parm(struct file *file, void *priv, return 0; } +#define NUM_SIZE_ENUMS 3 +static const struct v4l2_frmsize_discrete ntsc_sizes[] = { + { 640, 480 }, + { 640, 240 }, + { 320, 240 }, +}; +static const struct v4l2_frmsize_discrete pal_sizes[] = { + { 704, 576 }, + { 704, 288 }, + { 352, 288 }, +}; + +static int vidioc_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fe) +{ + struct s2255_fh *fh = priv; + struct s2255_channel *channel = fh->channel; + int is_ntsc = channel->std & V4L2_STD_525_60; + const struct s2255_fmt *fmt; + + if (fe->index >= NUM_SIZE_ENUMS) + return -EINVAL; + + fmt = format_by_fourcc(fe->pixel_format); + if (fmt == NULL) + return -EINVAL; + fe->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fe->discrete = is_ntsc ? ntsc_sizes[fe->index] : pal_sizes[fe->index]; + return 0; +} + static int vidioc_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fe) { - int is_ntsc = 0; + struct s2255_fh *fh = priv; + struct s2255_channel *channel = fh->channel; + const struct s2255_fmt *fmt; + const struct v4l2_frmsize_discrete *sizes; + int is_ntsc = channel->std & V4L2_STD_525_60; #define NUM_FRAME_ENUMS 4 int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5}; + int i; + if (fe->index >= NUM_FRAME_ENUMS) return -EINVAL; - switch (fe->width) { - case 640: - if (fe->height != 240 && fe->height != 480) - return -EINVAL; - is_ntsc = 1; - break; - case 320: - if (fe->height != 240) - return -EINVAL; - is_ntsc = 1; - break; - case 704: - if (fe->height != 288 && fe->height != 576) - return -EINVAL; - break; - case 352: - if (fe->height != 288) - return -EINVAL; - break; - default: + + fmt = format_by_fourcc(fe->pixel_format); + if (fmt == NULL) return -EINVAL; - } + + sizes = is_ntsc ? ntsc_sizes : pal_sizes; + for (i = 0; i < NUM_SIZE_ENUMS; i++, sizes++) + if (fe->width == sizes->width && + fe->height == sizes->height) + break; + if (i == NUM_SIZE_ENUMS) + return -EINVAL; + fe->type = V4L2_FRMIVAL_TYPE_DISCRETE; fe->discrete.denominator = is_ntsc ? 30000 : 25000; fe->discrete.numerator = (is_ntsc ? 1001 : 1000) * frm_dec[fe->index]; @@ -1813,6 +1841,7 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { .vidioc_g_jpegcomp = vidioc_g_jpegcomp, .vidioc_s_parm = vidioc_s_parm, .vidioc_g_parm = vidioc_g_parm, + .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_enum_frameintervals = vidioc_enum_frameintervals, .vidioc_log_status = v4l2_ctrl_log_status, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, -- cgit v1.2.3 From 5c632b223a31fa6dd63598e2a250ccc193a8bb4e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 26 Feb 2013 14:29:04 -0300 Subject: [media] s2255: choose YUYV as the default format, not YUV422P The planar YUV422P is quite unusual and few if any applications support it. Instead choose the common YUYV format as the default. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 59d40e614e94..cd06f3cc4f98 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -416,11 +416,6 @@ MODULE_DEVICE_TABLE(usb, s2255_table); /* JPEG formats must be defined last to support jpeg_enable parameter */ static const struct s2255_fmt formats[] = { { - .name = "4:2:2, planar, YUV422P", - .fourcc = V4L2_PIX_FMT_YUV422P, - .depth = 16 - - }, { .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16 @@ -429,6 +424,11 @@ static const struct s2255_fmt formats[] = { .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .depth = 16 + }, { + .name = "4:2:2, planar, YUV422P", + .fourcc = V4L2_PIX_FMT_YUV422P, + .depth = 16 + }, { .name = "8bpp GREY", .fourcc = V4L2_PIX_FMT_GREY, -- cgit v1.2.3 From 0b84caab364f40fdbf85828c9309f0c1c4dc0014 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 26 Feb 2013 14:14:19 -0300 Subject: [media] s2255: fix big-endian support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index cd06f3cc4f98..2bd86132d3e3 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -522,7 +522,7 @@ static void s2255_timer(unsigned long user_data) /* this loads the firmware asynchronously. - Originally this was done synchroously in probe. + Originally this was done synchronously in probe. But it is better to load it asynchronously here than block inside the probe function. Blocking inside probe affects boot time. FW loading is triggered by the timer in the probe function @@ -1157,6 +1157,8 @@ static int s2255_set_mode(struct s2255_channel *channel, __le32 *buffer; unsigned long chn_rev; struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev); + int i; + chn_rev = G_chnmap[channel->idx]; dprintk(3, "%s channel: %d\n", __func__, channel->idx); /* if JPEG, set the quality */ @@ -1179,7 +1181,8 @@ static int s2255_set_mode(struct s2255_channel *channel, buffer[0] = IN_DATA_TOKEN; buffer[1] = (__le32) cpu_to_le32(chn_rev); buffer[2] = CMD_SET_MODE; - memcpy(&buffer[3], &channel->mode, sizeof(struct s2255_mode)); + for (i = 0; i < sizeof(struct s2255_mode) / sizeof(u32); i++) + buffer[3 + i] = cpu_to_le32(((u32 *)&channel->mode)[i]); channel->setmode_ready = 0; res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); if (debug) @@ -2511,7 +2514,7 @@ static int s2255_probe(struct usb_interface *interface, return -ENOMEM; } atomic_set(&dev->num_channels, 0); - dev->pid = id->idProduct; + dev->pid = le16_to_cpu(id->idProduct); dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL); if (!dev->fw_data) goto errorFWDATA1; @@ -2581,7 +2584,7 @@ static int s2255_probe(struct usb_interface *interface, /* make sure firmware is the latest */ __le32 *pRel; pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4]; - printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel); + printk(KERN_INFO "s2255 dsp fw version %x\n", le32_to_cpu(*pRel)); dev->dsp_fw_ver = le32_to_cpu(*pRel); if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER) printk(KERN_INFO "s2255: f2255usb.bin out of date.\n"); -- cgit v1.2.3 From e6a60d768bc7b767439c56e34e345eb2fe873b06 Mon Sep 17 00:00:00 2001 From: Fabrizio Gazzato Date: Fri, 15 Feb 2013 18:54:54 -0300 Subject: [media] rtl28xxu: Add USB ID for MaxMedia HU394-T Add USB ID for MaxMedia HU394-T USB DVB-T Multi (FM, DAB, DAB+) dongle (RTL2832U+FC0012) In Italy, is branded as "DIKOM USB-DVBT HD" lsusb: ID 1b80:d394 Afatech Signed-off-by: Fabrizio Gazzato Acked-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index d98387a3c95e..3d128a5e4794 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -1372,6 +1372,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = { &rtl2832u_props, "Digivox Micro Hd", NULL) }, { DVB_USB_DEVICE(USB_VID_COMPRO, 0x0620, &rtl2832u_props, "Compro VideoMate U620F", NULL) }, + { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394, + &rtl2832u_props, "MaxMedia HU394-T", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table); -- cgit v1.2.3 From fa563073281d7be6c685a0bb8ca6b2737e00f368 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 17 Feb 2013 09:40:05 -0300 Subject: [media] bttv: make remote controls of devices with i2c ir decoder working MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Request module ir-kbd-i2c if an i2c ir decoder is detected. Tested with device "Hauppauge WinTV Theatre" (model 37284 rev B421). Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-input.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c index 04207a799055..01c71214f9ec 100644 --- a/drivers/media/pci/bt8xx/bttv-input.c +++ b/drivers/media/pci/bt8xx/bttv-input.c @@ -375,6 +375,7 @@ void init_bttv_i2c_ir(struct bttv *btv) I2C_CLIENT_END }; struct i2c_board_info info; + struct i2c_client *i2c_dev; if (0 != btv->i2c_rc) return; @@ -390,7 +391,12 @@ void init_bttv_i2c_ir(struct bttv *btv) btv->init_data.ir_codes = RC_MAP_PV951; info.addr = 0x4b; break; - default: + } + + if (btv->init_data.name) { + info.platform_data = &btv->init_data; + i2c_dev = i2c_new_device(&btv->c.i2c_adap, &info); + } else { /* * The external IR receiver is at i2c address 0x34 (0x35 for * reads). Future Hauppauge cards will have an internal @@ -399,16 +405,14 @@ void init_bttv_i2c_ir(struct bttv *btv) * internal. * That's why we probe 0x1a (~0x34) first. CB */ - - i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL); - return; + i2c_dev = i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL); } + if (NULL == i2c_dev) + return; - if (btv->init_data.name) - info.platform_data = &btv->init_data; - i2c_new_device(&btv->c.i2c_adap, &info); - - return; +#if defined(CONFIG_MODULES) && defined(MODULE) + request_module("ir-kbd-i2c"); +#endif } int fini_bttv_i2c(struct bttv *btv) -- cgit v1.2.3 From 457ba4ce4f435d0b4dd82a0acc6c796e541a2ea7 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 17 Feb 2013 09:41:29 -0300 Subject: [media] bttv: move fini_bttv_i2c() from bttv-input.c to bttv-i2c.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like init_bttv_i2c(), fini_bttv_i2c() belongs to bttv-i2c.c. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-i2c.c | 8 ++++++++ drivers/media/pci/bt8xx/bttv-input.c | 8 -------- drivers/media/pci/bt8xx/bttvp.h | 5 ++++- 3 files changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-i2c.c b/drivers/media/pci/bt8xx/bttv-i2c.c index c63c643ed1f8..b7c52dc8999c 100644 --- a/drivers/media/pci/bt8xx/bttv-i2c.c +++ b/drivers/media/pci/bt8xx/bttv-i2c.c @@ -394,3 +394,11 @@ int init_bttv_i2c(struct bttv *btv) return btv->i2c_rc; } + +int fini_bttv_i2c(struct bttv *btv) +{ + if (0 != btv->i2c_rc) + return 0; + + return i2c_del_adapter(&btv->c.i2c_adap); +} diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c index 01c71214f9ec..f36821367d8d 100644 --- a/drivers/media/pci/bt8xx/bttv-input.c +++ b/drivers/media/pci/bt8xx/bttv-input.c @@ -415,14 +415,6 @@ void init_bttv_i2c_ir(struct bttv *btv) #endif } -int fini_bttv_i2c(struct bttv *btv) -{ - if (0 != btv->i2c_rc) - return 0; - - return i2c_del_adapter(&btv->c.i2c_adap); -} - int bttv_input_init(struct bttv *btv) { struct bttv_ir *ir; diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index eb13be7ae3f4..e7910e0ffa05 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -300,6 +300,10 @@ extern int no_overlay; /* bttv-input.c */ extern void init_bttv_i2c_ir(struct bttv *btv); + +/* ---------------------------------------------------------- */ +/* bttv-i2c.c */ +extern int init_bttv_i2c(struct bttv *btv); extern int fini_bttv_i2c(struct bttv *btv); /* ---------------------------------------------------------- */ @@ -310,7 +314,6 @@ extern unsigned int bttv_verbose; extern unsigned int bttv_debug; extern unsigned int bttv_gpio; extern void bttv_gpio_tracking(struct bttv *btv, char *comment); -extern int init_bttv_i2c(struct bttv *btv); #define dprintk(fmt, ...) \ do { \ -- cgit v1.2.3 From 9bb05696af3f808c3ad684c9fcf4b870ddbff804 Mon Sep 17 00:00:00 2001 From: Gianluca Gennari Date: Thu, 7 Mar 2013 12:19:29 -0300 Subject: [media] cx231xx: fix undefined function cx231xx_g_chip_ident() This patch: http://git.linuxtv.org/media_tree.git/commit/b86d15440b683f8634c0cb26fc0861a5bc4913ac is missing a chunk when compared to an older version: https://patchwork.kernel.org/patch/2063281/ probably because of an unresolved merging conflict. This causes the following error: WARNING: "cx231xx_g_chip_ident" [/home/jena/media_build/v4l/cx231xx.ko] undefined! Signed-off-by: Gianluca Gennari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 41c5c996ed2c..ac6200870a62 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1227,7 +1227,7 @@ int cx231xx_s_frequency(struct file *file, void *priv, return rc; } -int vidioc_g_chip_ident(struct file *file, void *fh, +int cx231xx_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip) { chip->ident = V4L2_IDENT_NONE; -- cgit v1.2.3 From d9b7595bed61930987308be946563ce084148c14 Mon Sep 17 00:00:00 2001 From: Fabrizio Gazzato Date: Sun, 17 Feb 2013 18:25:34 -0300 Subject: [media] af9035: add ID [0ccd:00aa] TerraTec Cinergy T Stick (rev. 2) This patch adds USB ID for alternative "Terratec Cinergy T Stick". Tested by a friend: works similarly to 0ccd:0093 version (af9035+tua9001) Signed-off-by: Fabrizio Gazzato Acked-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index f11cc42454f0..d3cb8d55febc 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -1312,6 +1312,8 @@ static const struct usb_device_id af9035_id_table[] = { &af9035_props, "AVerMedia Twinstar (A825)", NULL) }, { DVB_USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100MINI_PLUS, &af9035_props, "Asus U3100Mini Plus", NULL) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00aa, + &af9035_props, "TerraTec Cinergy T Stick (rev. 2)", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, af9035_id_table); -- cgit v1.2.3 From a9fc36afc074db2d5995136b50b018c2ca77f48f Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 19 Feb 2013 08:00:36 -0300 Subject: [media] timblogiw: Fix sparse warning Fixes the below warning: drivers/media/platform/timblogiw.c:81:31: warning: symbol 'timblogiw_tvnorms' was not declared. Should it be static? Signed-off-by: Sachin Kamat Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/timblogiw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/timblogiw.c b/drivers/media/platform/timblogiw.c index c3a2a4484401..2d91eeb1d2ae 100644 --- a/drivers/media/platform/timblogiw.c +++ b/drivers/media/platform/timblogiw.c @@ -78,7 +78,7 @@ struct timblogiw_buffer { struct timblogiw_fh *fh; }; -const struct timblogiw_tvnorm timblogiw_tvnorms[] = { +static const struct timblogiw_tvnorm timblogiw_tvnorms[] = { { .std = V4L2_STD_PAL, .width = 720, -- cgit v1.2.3 From c67d2f074073b39e5eba84e852c894c22057d159 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Tue, 19 Feb 2013 14:58:53 -0300 Subject: [media] stv090x: do not unlock unheld mutex in stv090x_sleep() goto err and goto err_gateoff before mutex_lock(&state->internal->demod_lock) lead to unlock of unheld mutex in stv090x_sleep(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Cc: Manu Abraham Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv090x.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c index f36eeefb76a6..56d470ad5a82 100644 --- a/drivers/media/dvb-frontends/stv090x.c +++ b/drivers/media/dvb-frontends/stv090x.c @@ -3906,12 +3906,12 @@ static int stv090x_sleep(struct dvb_frontend *fe) reg = stv090x_read_reg(state, STV090x_TSTTNR1); STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0); if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0) - goto err; + goto err_unlock; /* power off DiSEqC 1 */ reg = stv090x_read_reg(state, STV090x_TSTTNR2); STV090x_SETFIELD(reg, DISEQC1_PON_FIELD, 0); if (stv090x_write_reg(state, STV090x_TSTTNR2, reg) < 0) - goto err; + goto err_unlock; /* check whether path 2 is already sleeping, that is when ADC2 is off */ @@ -3930,7 +3930,7 @@ static int stv090x_sleep(struct dvb_frontend *fe) if (full_standby) STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1); if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0) - goto err; + goto err_unlock; reg = stv090x_read_reg(state, STV090x_STOPCLK2); /* sampling 1 clock */ STV090x_SETFIELD(reg, STOP_CLKSAMP1_FIELD, 1); @@ -3941,7 +3941,7 @@ static int stv090x_sleep(struct dvb_frontend *fe) if (full_standby) STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1); if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) - goto err; + goto err_unlock; break; case STV090x_DEMODULATOR_1: @@ -3949,12 +3949,12 @@ static int stv090x_sleep(struct dvb_frontend *fe) reg = stv090x_read_reg(state, STV090x_TSTTNR3); STV090x_SETFIELD(reg, ADC2_PON_FIELD, 0); if (stv090x_write_reg(state, STV090x_TSTTNR3, reg) < 0) - goto err; + goto err_unlock; /* power off DiSEqC 2 */ reg = stv090x_read_reg(state, STV090x_TSTTNR4); STV090x_SETFIELD(reg, DISEQC2_PON_FIELD, 0); if (stv090x_write_reg(state, STV090x_TSTTNR4, reg) < 0) - goto err; + goto err_unlock; /* check whether path 1 is already sleeping, that is when ADC1 is off */ @@ -3973,7 +3973,7 @@ static int stv090x_sleep(struct dvb_frontend *fe) if (full_standby) STV090x_SETFIELD(reg, STOP_CLKFEC_FIELD, 1); if (stv090x_write_reg(state, STV090x_STOPCLK1, reg) < 0) - goto err; + goto err_unlock; reg = stv090x_read_reg(state, STV090x_STOPCLK2); /* sampling 2 clock */ STV090x_SETFIELD(reg, STOP_CLKSAMP2_FIELD, 1); @@ -3984,7 +3984,7 @@ static int stv090x_sleep(struct dvb_frontend *fe) if (full_standby) STV090x_SETFIELD(reg, STOP_CLKTS_FIELD, 1); if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0) - goto err; + goto err_unlock; break; default: @@ -3997,7 +3997,7 @@ static int stv090x_sleep(struct dvb_frontend *fe) reg = stv090x_read_reg(state, STV090x_SYNTCTRL); STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01); if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0) - goto err; + goto err_unlock; } mutex_unlock(&state->internal->demod_lock); @@ -4005,8 +4005,10 @@ static int stv090x_sleep(struct dvb_frontend *fe) err_gateoff: stv090x_i2c_gate_ctrl(state, 0); -err: + goto err; +err_unlock: mutex_unlock(&state->internal->demod_lock); +err: dprintk(FE_ERROR, 1, "I/O error"); return -1; } -- cgit v1.2.3 From 44122dd6b6b872d6f1ec151f89942f66b715222c Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Thu, 21 Feb 2013 08:11:41 -0300 Subject: [media] media: Terratec Cinergy S2 USB HD Rev.2 Terratec Cinergy S2 USB HD Rev.2 support. This commit is a corrected cherry-pick of 03228792 which got reverted in b7e38636 because it was rebased incorrectly and introduced compilation errors. Signed-off-by: Stephan Hilb Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dw2102.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 9578a6761f1b..24cfd4bbbc8a 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -1548,6 +1548,7 @@ enum dw2102_table_entry { X3M_SPC1400HD, TEVII_S421, TEVII_S632, + TERRATEC_CINERGY_S2_R2, }; static struct usb_device_id dw2102_table[] = { @@ -1568,6 +1569,7 @@ static struct usb_device_id dw2102_table[] = { [X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)}, [TEVII_S421] = {USB_DEVICE(0x9022, USB_PID_TEVII_S421)}, [TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)}, + [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00b0)}, { } }; @@ -1968,7 +1970,7 @@ static struct dvb_usb_device_properties su3000_properties = { }}, } }, - .num_device_descs = 3, + .num_device_descs = 4, .devices = { { "SU3000HD DVB-S USB2.0", { &dw2102_table[GENIATECH_SU3000], NULL }, @@ -1982,6 +1984,10 @@ static struct dvb_usb_device_properties su3000_properties = { { &dw2102_table[X3M_SPC1400HD], NULL }, { NULL }, }, + { "Terratec Cinergy S2 USB HD Rev.2", + { &dw2102_table[TERRATEC_CINERGY_S2_R2], NULL }, + { NULL }, + }, } }; -- cgit v1.2.3 From 0169ab28b3992d46ac703d13940c415fe0795974 Mon Sep 17 00:00:00 2001 From: Thiago Farina Date: Thu, 21 Feb 2013 16:18:16 -0300 Subject: [media] media/usb: cx231xx-pcb-cfg.h: Remove unused enum _true_false Signed-off-by: Thiago Farina Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h index f5e46e89f3ab..b3c6190e0c69 100644 --- a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h +++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h @@ -68,11 +68,6 @@ enum USB_SPEED{ HIGH_SPEED = 0x1 /* 1: high speed */ }; -enum _true_false{ - FALSE = 0, - TRUE = 1 -}; - #define TS_MASK 0x6 enum TS_PORT{ NO_TS_PORT = 0x0, /* 2'b00: Neither port used. PCB not a Hybrid, -- cgit v1.2.3 From 06f950f43f29eb0b5631c6d037d78319649ac3b0 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Sun, 24 Feb 2013 18:47:18 -0300 Subject: [media] lmedm04: Fix possible NULL pointer dereference Check for (adap == NULL) has to done before accessing adap. Signed-off-by: Syam Sidhardhan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/lmedm04.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index f30c58cecbba..96804be0fffe 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -1241,10 +1241,13 @@ static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, struct usb_data_stream_properties *stream) { struct dvb_usb_adapter *adap = fe_to_adap(fe); - struct dvb_usb_device *d = adap_to_d(adap); + struct dvb_usb_device *d; if (adap == NULL) return 0; + + d = adap_to_d(adap); + /* Turn PID filter on the fly by module option */ if (pid_filter == 2) { adap->pid_filtering = 1; -- cgit v1.2.3 From 972b072a83316e0d5a1fd0cb78eb99a57a305dce Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Sun, 24 Feb 2013 18:49:43 -0300 Subject: [media] hdpvr: Fix memory leak This patch fixes the print_buf leaking. Signed-off-by: Syam Sidhardhan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index 5c6193536399..73195fe7871c 100644 --- a/drivers/media/usb/hdpvr/hdpvr-core.c +++ b/drivers/media/usb/hdpvr/hdpvr-core.c @@ -196,6 +196,7 @@ static int device_authorization(struct hdpvr_device *dev) hex_dump_to_buffer(response, 8, 16, 1, print_buf, 5*buf_size+1, 0); v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, " response: %s\n", print_buf); + kfree(print_buf); #endif msleep(100); -- cgit v1.2.3 From acb0549acc270c8206ecfdd35d34fc349c3457a0 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Feb 2013 13:01:48 -0300 Subject: [media] dvb_usb_v2: locked versions of USB bulk IO functions Implement: dvb_usbv2_generic_rw_locked() dvb_usbv2_generic_write_locked() Caller must hold device lock when locked versions are called. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvb_usb.h | 4 ++++ drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c | 38 ++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index 3cac8bd0b116..42801f8ecaa8 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -400,5 +400,9 @@ extern int dvb_usbv2_reset_resume(struct usb_interface *); /* the generic read/write method for device control */ extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16); extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16); +/* caller must hold lock when locked versions are called */ +extern int dvb_usbv2_generic_rw_locked(struct dvb_usb_device *, + u8 *, u16, u8 *, u16); +extern int dvb_usbv2_generic_write_locked(struct dvb_usb_device *, u8 *, u16); #endif diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c index 5716662b4834..74c911fa1fe6 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c @@ -21,8 +21,8 @@ #include "dvb_usb_common.h" -int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, - u16 rlen) +int dvb_usb_v2_generic_io(struct dvb_usb_device *d, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) { int ret, actual_length; @@ -32,8 +32,6 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, return -EINVAL; } - mutex_lock(&d->usb_mutex); - dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, wlen, wbuf); ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, @@ -63,13 +61,43 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, actual_length, rbuf); } + return ret; +} + +int dvb_usbv2_generic_rw(struct dvb_usb_device *d, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + int ret; + + mutex_lock(&d->usb_mutex); + ret = dvb_usb_v2_generic_io(d, wbuf, wlen, rbuf, rlen); mutex_unlock(&d->usb_mutex); + return ret; } EXPORT_SYMBOL(dvb_usbv2_generic_rw); int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len) { - return dvb_usbv2_generic_rw(d, buf, len, NULL, 0); + int ret; + + mutex_lock(&d->usb_mutex); + ret = dvb_usb_v2_generic_io(d, buf, len, NULL, 0); + mutex_unlock(&d->usb_mutex); + + return ret; } EXPORT_SYMBOL(dvb_usbv2_generic_write); + +int dvb_usbv2_generic_rw_locked(struct dvb_usb_device *d, + u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) +{ + return dvb_usb_v2_generic_io(d, wbuf, wlen, rbuf, rlen); +} +EXPORT_SYMBOL(dvb_usbv2_generic_rw_locked); + +int dvb_usbv2_generic_write_locked(struct dvb_usb_device *d, u8 *buf, u16 len) +{ + return dvb_usb_v2_generic_io(d, buf, len, NULL, 0); +} +EXPORT_SYMBOL(dvb_usbv2_generic_write_locked); -- cgit v1.2.3 From aff8c2d475cb660ee246099dd15f269e9ebb7b1d Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Feb 2013 13:25:19 -0300 Subject: [media] af9015: do not use buffers from stack for usb_bulk_msg() WARNING: at lib/dma-debug.c:947 check_for_stack+0xa7/0xf0() ehci-pci 0000:00:04.1: DMA-API: device driver maps memory fromstack Reported-by: poma Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9015.c | 39 +++++++++++++++++++---------------- drivers/media/usb/dvb-usb-v2/af9015.h | 2 ++ 2 files changed, 23 insertions(+), 18 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index b86d0f27a398..2fa7c6ee5a70 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -30,22 +30,22 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) { -#define BUF_LEN 63 #define REQ_HDR_LEN 8 /* send header size */ #define ACK_HDR_LEN 2 /* rece header size */ struct af9015_state *state = d_to_priv(d); int ret, wlen, rlen; - u8 buf[BUF_LEN]; u8 write = 1; - buf[0] = req->cmd; - buf[1] = state->seq++; - buf[2] = req->i2c_addr; - buf[3] = req->addr >> 8; - buf[4] = req->addr & 0xff; - buf[5] = req->mbox; - buf[6] = req->addr_len; - buf[7] = req->data_len; + mutex_lock(&d->usb_mutex); + + state->buf[0] = req->cmd; + state->buf[1] = state->seq++; + state->buf[2] = req->i2c_addr; + state->buf[3] = req->addr >> 8; + state->buf[4] = req->addr & 0xff; + state->buf[5] = req->mbox; + state->buf[6] = req->addr_len; + state->buf[7] = req->data_len; switch (req->cmd) { case GET_CONFIG: @@ -55,14 +55,14 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) break; case READ_I2C: write = 0; - buf[2] |= 0x01; /* set I2C direction */ + state->buf[2] |= 0x01; /* set I2C direction */ case WRITE_I2C: - buf[0] = READ_WRITE_I2C; + state->buf[0] = READ_WRITE_I2C; break; case WRITE_MEMORY: if (((req->addr & 0xff00) == 0xff00) || ((req->addr & 0xff00) == 0xae00)) - buf[0] = WRITE_VIRTUAL_MEMORY; + state->buf[0] = WRITE_VIRTUAL_MEMORY; case WRITE_VIRTUAL_MEMORY: case COPY_FIRMWARE: case DOWNLOAD_FIRMWARE: @@ -90,7 +90,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) rlen = ACK_HDR_LEN; if (write) { wlen += req->data_len; - memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len); + memcpy(&state->buf[REQ_HDR_LEN], req->data, req->data_len); } else { rlen += req->data_len; } @@ -99,22 +99,25 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req) if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB) rlen = 0; - ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen); + ret = dvb_usbv2_generic_rw_locked(d, + state->buf, wlen, state->buf, rlen); if (ret) goto error; /* check status */ - if (rlen && buf[1]) { + if (rlen && state->buf[1]) { dev_err(&d->udev->dev, "%s: command failed=%d\n", - KBUILD_MODNAME, buf[1]); + KBUILD_MODNAME, state->buf[1]); ret = -EIO; goto error; } /* read request, copy returned data to return buf */ if (!write) - memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len); + memcpy(req->data, &state->buf[ACK_HDR_LEN], req->data_len); error: + mutex_unlock(&d->usb_mutex); + return ret; } diff --git a/drivers/media/usb/dvb-usb-v2/af9015.h b/drivers/media/usb/dvb-usb-v2/af9015.h index 533637dedd23..3a6f3ad1eadb 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.h +++ b/drivers/media/usb/dvb-usb-v2/af9015.h @@ -115,7 +115,9 @@ enum af9015_ir_mode { AF9015_IR_MODE_POLLING, /* just guess */ }; +#define BUF_LEN 63 struct af9015_state { + u8 buf[BUF_LEN]; /* bulk USB control message */ u8 ir_mode; u8 rc_repeat; u32 rc_keycode; -- cgit v1.2.3 From 3484d37a66bb45dc9b4f70868b68739262bf6832 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Feb 2013 13:56:34 -0300 Subject: [media] af9035: do not use buffers from stack for usb_bulk_msg() Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 44 +++++++++++++++++------------------ drivers/media/usb/dvb-usb-v2/af9035.h | 2 ++ 2 files changed, 24 insertions(+), 22 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index d3cb8d55febc..66f65197c40d 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -41,43 +41,45 @@ static u16 af9035_checksum(const u8 *buf, size_t len) static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) { -#define BUF_LEN 64 #define REQ_HDR_LEN 4 /* send header size */ #define ACK_HDR_LEN 3 /* rece header size */ #define CHECKSUM_LEN 2 #define USB_TIMEOUT 2000 struct state *state = d_to_priv(d); int ret, wlen, rlen; - u8 buf[BUF_LEN]; u16 checksum, tmp_checksum; + mutex_lock(&d->usb_mutex); + /* buffer overflow check */ if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) || req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) { dev_err(&d->udev->dev, "%s: too much data wlen=%d rlen=%d\n", __func__, req->wlen, req->rlen); - return -EINVAL; + ret = -EINVAL; + goto err; } - buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1; - buf[1] = req->mbox; - buf[2] = req->cmd; - buf[3] = state->seq++; - memcpy(&buf[REQ_HDR_LEN], req->wbuf, req->wlen); + state->buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1; + state->buf[1] = req->mbox; + state->buf[2] = req->cmd; + state->buf[3] = state->seq++; + memcpy(&state->buf[REQ_HDR_LEN], req->wbuf, req->wlen); wlen = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN; rlen = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN; /* calc and add checksum */ - checksum = af9035_checksum(buf, buf[0] - 1); - buf[buf[0] - 1] = (checksum >> 8); - buf[buf[0] - 0] = (checksum & 0xff); + checksum = af9035_checksum(state->buf, state->buf[0] - 1); + state->buf[state->buf[0] - 1] = (checksum >> 8); + state->buf[state->buf[0] - 0] = (checksum & 0xff); /* no ack for these packets */ if (req->cmd == CMD_FW_DL) rlen = 0; - ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen); + ret = dvb_usbv2_generic_rw_locked(d, + state->buf, wlen, state->buf, rlen); if (ret) goto err; @@ -86,8 +88,8 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) goto exit; /* verify checksum */ - checksum = af9035_checksum(buf, rlen - 2); - tmp_checksum = (buf[rlen - 2] << 8) | buf[rlen - 1]; + checksum = af9035_checksum(state->buf, rlen - 2); + tmp_checksum = (state->buf[rlen - 2] << 8) | state->buf[rlen - 1]; if (tmp_checksum != checksum) { dev_err(&d->udev->dev, "%s: command=%02x checksum mismatch " \ "(%04x != %04x)\n", KBUILD_MODNAME, req->cmd, @@ -97,23 +99,21 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) } /* check status */ - if (buf[2]) { + if (state->buf[2]) { dev_dbg(&d->udev->dev, "%s: command=%02x failed fw error=%d\n", - __func__, req->cmd, buf[2]); + __func__, req->cmd, state->buf[2]); ret = -EIO; goto err; } /* read request, copy returned data to return buf */ if (req->rlen) - memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen); - + memcpy(req->rbuf, &state->buf[ACK_HDR_LEN], req->rlen); exit: - return 0; - err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - + mutex_unlock(&d->usb_mutex); + if (ret) + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index 29f3eec22c2c..6d098a93d5ab 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -52,6 +52,8 @@ struct usb_req { }; struct state { +#define BUF_LEN 64 + u8 buf[BUF_LEN]; u8 seq; /* packet sequence number */ bool dual_mode; struct af9033_config af9033_config[2]; -- cgit v1.2.3 From 6c604e8e8611385d48cd9dea8926b2a309ed85c0 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Feb 2013 14:13:41 -0300 Subject: [media] anysee: do not use buffers from stack for usb_bulk_msg() Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/anysee.c | 27 ++++++++++++--------------- drivers/media/usb/dvb-usb-v2/anysee.h | 3 ++- 2 files changed, 14 insertions(+), 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index a20d691d0b63..85ba24650f01 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -45,25 +45,24 @@ #include "cxd2820r.h" DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -static DEFINE_MUTEX(anysee_usb_mutex); static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, u8 *rbuf, u8 rlen) { struct anysee_state *state = d_to_priv(d); int act_len, ret, i; - u8 buf[64]; - memcpy(&buf[0], sbuf, slen); - buf[60] = state->seq++; + mutex_lock(&d->usb_mutex); - mutex_lock(&anysee_usb_mutex); + memcpy(&state->buf[0], sbuf, slen); + state->buf[60] = state->seq++; - dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, slen, buf); + dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, slen, state->buf); /* We need receive one message more after dvb_usb_generic_rw due to weird transaction flow, which is 1 x send + 2 x receive. */ - ret = dvb_usbv2_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf)); + ret = dvb_usbv2_generic_rw_locked(d, state->buf, sizeof(state->buf), + state->buf, sizeof(state->buf)); if (ret) goto error_unlock; @@ -82,17 +81,16 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, for (i = 0; i < 3; i++) { /* receive 2nd answer */ ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, - d->props->generic_bulk_ctrl_endpoint), buf, sizeof(buf), - &act_len, 2000); - + d->props->generic_bulk_ctrl_endpoint), + state->buf, sizeof(state->buf), &act_len, 2000); if (ret) { dev_dbg(&d->udev->dev, "%s: recv bulk message " \ "failed=%d\n", __func__, ret); } else { dev_dbg(&d->udev->dev, "%s: <<< %*ph\n", __func__, - rlen, buf); + rlen, state->buf); - if (buf[63] != 0x4f) + if (state->buf[63] != 0x4f) dev_dbg(&d->udev->dev, "%s: cmd failed\n", __func__); @@ -109,11 +107,10 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, /* read request, copy returned data to return buf */ if (rbuf && rlen) - memcpy(rbuf, buf, rlen); + memcpy(rbuf, state->buf, rlen); error_unlock: - mutex_unlock(&anysee_usb_mutex); - + mutex_unlock(&d->usb_mutex); return ret; } diff --git a/drivers/media/usb/dvb-usb-v2/anysee.h b/drivers/media/usb/dvb-usb-v2/anysee.h index c1a4273f14ff..8f426d9fc6e1 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.h +++ b/drivers/media/usb/dvb-usb-v2/anysee.h @@ -52,8 +52,9 @@ enum cmd { }; struct anysee_state { - u8 hw; /* PCB ID */ + u8 buf[64]; u8 seq; + u8 hw; /* PCB ID */ u8 fe_id:1; /* frondend ID */ u8 has_ci:1; u8 ci_attached:1; -- cgit v1.2.3 From 4458a54c5edce2a9bdf826273ceb7f4b3b7278c6 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Feb 2013 14:18:13 -0300 Subject: [media] anysee: coding style changes I did what I liked to do. Also corrected two long log writings as checkpatch.pl was complaining about those. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/anysee.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index 85ba24650f01..2e762742a4c7 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -46,8 +46,8 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, - u8 *rbuf, u8 rlen) +static int anysee_ctrl_msg(struct dvb_usb_device *d, + u8 *sbuf, u8 slen, u8 *rbuf, u8 rlen) { struct anysee_state *state = d_to_priv(d); int act_len, ret, i; @@ -84,16 +84,16 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, d->props->generic_bulk_ctrl_endpoint), state->buf, sizeof(state->buf), &act_len, 2000); if (ret) { - dev_dbg(&d->udev->dev, "%s: recv bulk message " \ - "failed=%d\n", __func__, ret); + dev_dbg(&d->udev->dev, + "%s: recv bulk message failed=%d\n", + __func__, ret); } else { dev_dbg(&d->udev->dev, "%s: <<< %*ph\n", __func__, rlen, state->buf); if (state->buf[63] != 0x4f) - dev_dbg(&d->udev->dev, "%s: cmd failed\n", - __func__); - + dev_dbg(&d->udev->dev, + "%s: cmd failed\n", __func__); break; } } @@ -881,9 +881,8 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) if (!adap->fe[0]) { /* we have no frontend :-( */ ret = -ENODEV; - dev_err(&d->udev->dev, "%s: Unsupported Anysee version. " \ - "Please report the " \ - ".\n", + dev_err(&d->udev->dev, + "%s: Unsupported Anysee version. Please report the .\n", KBUILD_MODNAME); } error: -- cgit v1.2.3 From bf30690029a3b8572a6fc2facb77fbde86992988 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 26 Feb 2013 03:17:27 -0300 Subject: [media] Media: remove incorrect __init/__exit markups Even if bus is not hot-pluggable, the devices can be unbound from the driver via sysfs, so we should not be using __exit annotations on remove() methods. The only exception is drivers registered with platform_driver_probe() which specifically disables sysfs bind/unbind attributes. Similarly probe() methods should not be marked __init unless platform_driver_probe() is used. Signed-off-by: Dmitry Torokhov Acked-by: Guennadi Liakhovetski Acked-by: Sakari Ailus Acked-by: Timo Kokkonen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adp1653.c | 4 ++-- drivers/media/i2c/smiapp/smiapp-core.c | 4 ++-- drivers/media/platform/soc_camera/omap1_camera.c | 6 +++--- drivers/media/radio/radio-si4713.c | 4 ++-- drivers/media/rc/ir-rx51.c | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c index df163800c8e1..ef75abe5984c 100644 --- a/drivers/media/i2c/adp1653.c +++ b/drivers/media/i2c/adp1653.c @@ -447,7 +447,7 @@ free_and_quit: return ret; } -static int __exit adp1653_remove(struct i2c_client *client) +static int adp1653_remove(struct i2c_client *client) { struct v4l2_subdev *subdev = i2c_get_clientdata(client); struct adp1653_flash *flash = to_adp1653_flash(subdev); @@ -476,7 +476,7 @@ static struct i2c_driver adp1653_i2c_driver = { .pm = &adp1653_pm_ops, }, .probe = adp1653_probe, - .remove = __exit_p(adp1653_remove), + .remove = adp1653_remove, .id_table = adp1653_id_table, }; diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 83c7ed7ffcc2..cae4f4683851 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2833,7 +2833,7 @@ static int smiapp_probe(struct i2c_client *client, sensor->src->pads, 0); } -static int __exit smiapp_remove(struct i2c_client *client) +static int smiapp_remove(struct i2c_client *client) { struct v4l2_subdev *subdev = i2c_get_clientdata(client); struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); @@ -2881,7 +2881,7 @@ static struct i2c_driver smiapp_i2c_driver = { .pm = &smiapp_pm_ops, }, .probe = smiapp_probe, - .remove = __exit_p(smiapp_remove), + .remove = smiapp_remove, .id_table = smiapp_id_table, }; diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c index 2547bf88f79f..9689a6e89b7f 100644 --- a/drivers/media/platform/soc_camera/omap1_camera.c +++ b/drivers/media/platform/soc_camera/omap1_camera.c @@ -1546,7 +1546,7 @@ static struct soc_camera_host_ops omap1_host_ops = { .poll = omap1_cam_poll, }; -static int __init omap1_cam_probe(struct platform_device *pdev) +static int omap1_cam_probe(struct platform_device *pdev) { struct omap1_cam_dev *pcdev; struct resource *res; @@ -1677,7 +1677,7 @@ exit: return err; } -static int __exit omap1_cam_remove(struct platform_device *pdev) +static int omap1_cam_remove(struct platform_device *pdev) { struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev); struct omap1_cam_dev *pcdev = container_of(soc_host, @@ -1709,7 +1709,7 @@ static struct platform_driver omap1_cam_driver = { .name = DRIVER_NAME, }, .probe = omap1_cam_probe, - .remove = __exit_p(omap1_cam_remove), + .remove = omap1_cam_remove, }; module_platform_driver(omap1_cam_driver); diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 1507c9d508d7..8ae8442d6f97 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -328,7 +328,7 @@ exit: } /* radio_si4713_pdriver_remove - remove the device */ -static int __exit radio_si4713_pdriver_remove(struct platform_device *pdev) +static int radio_si4713_pdriver_remove(struct platform_device *pdev) { struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); struct radio_si4713_device *rsdev = container_of(v4l2_dev, @@ -350,7 +350,7 @@ static struct platform_driver radio_si4713_pdriver = { .name = "radio-si4713", }, .probe = radio_si4713_pdriver_probe, - .remove = __exit_p(radio_si4713_pdriver_remove), + .remove = radio_si4713_pdriver_remove, }; module_platform_driver(radio_si4713_pdriver); diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c index 8ead492d03aa..31b955bf7664 100644 --- a/drivers/media/rc/ir-rx51.c +++ b/drivers/media/rc/ir-rx51.c @@ -464,14 +464,14 @@ static int lirc_rx51_probe(struct platform_device *dev) return 0; } -static int __exit lirc_rx51_remove(struct platform_device *dev) +static int lirc_rx51_remove(struct platform_device *dev) { return lirc_unregister_driver(lirc_rx51_driver.minor); } struct platform_driver lirc_rx51_platform_driver = { .probe = lirc_rx51_probe, - .remove = __exit_p(lirc_rx51_remove), + .remove = lirc_rx51_remove, .suspend = lirc_rx51_suspend, .resume = lirc_rx51_resume, .driver = { -- cgit v1.2.3 From 2da8eab97544266020a8cddb2936237abbb93859 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Tue, 26 Feb 2013 15:24:56 -0300 Subject: [media] siano: Remove redundant NULL check before kfree kfree on NULL pointer is a no-op. Signed-off-by: Syam Sidhardhan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 1842e64e6338..9565dcc8381f 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -719,8 +719,7 @@ void smscore_unregister_device(struct smscore_device_t *coredev) dma_free_coherent(NULL, coredev->common_buffer_size, coredev->common_buffer, coredev->common_buffer_phys); - if (coredev->fw_buf != NULL) - kfree(coredev->fw_buf); + kfree(coredev->fw_buf); list_del(&coredev->entry); kfree(coredev); -- cgit v1.2.3 From 18552ea1322e218b43f7692d9358c930a6d81df1 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Tue, 26 Feb 2013 15:28:15 -0300 Subject: [media] media: ivtv: Remove redundant NULL check before kfree kfree on NULL pointer is a no-op. Signed-off-by: Syam Sidhardhan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ivtv/ivtvfb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c index 05b94aa8ba32..9ff1230192e8 100644 --- a/drivers/media/pci/ivtv/ivtvfb.c +++ b/drivers/media/pci/ivtv/ivtvfb.c @@ -1171,8 +1171,7 @@ static void ivtvfb_release_buffers (struct ivtv *itv) fb_dealloc_cmap(&oi->ivtvfb_info.cmap); /* Release pseudo palette */ - if (oi->ivtvfb_info.pseudo_palette) - kfree(oi->ivtvfb_info.pseudo_palette); + kfree(oi->ivtvfb_info.pseudo_palette); #ifdef CONFIG_MTRR if (oi->fb_end_aligned_physaddr) { -- cgit v1.2.3 From f1065c964869aecd5af04291476c358fd5ab9a8f Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Tue, 26 Feb 2013 15:30:45 -0300 Subject: [media] media: tuners: Remove redundant NULL check before kfree kfree on NULL pointer is a no-op. Signed-off-by: Syam Sidhardhan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tuner-xc2028.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c index 09451737c77e..878d2c4d9e8e 100644 --- a/drivers/media/tuners/tuner-xc2028.c +++ b/drivers/media/tuners/tuner-xc2028.c @@ -1378,8 +1378,7 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) * For the firmware name, keep a local copy of the string, * in order to avoid troubles during device release. */ - if (priv->ctrl.fname) - kfree(priv->ctrl.fname); + kfree(priv->ctrl.fname); memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); if (p->fname) { priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); -- cgit v1.2.3 From 33cef283af68522dc0f0b398662885193048c7d0 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Tue, 26 Feb 2013 15:35:01 -0300 Subject: [media] dvb-usb: Remove redundant NULL check before kfree kfree on NULL pointer is a no-op. Signed-off-by: Syam Sidhardhan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/cinergyT2-fe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/cinergyT2-fe.c b/drivers/media/usb/dvb-usb/cinergyT2-fe.c index 1efc028a76c9..c890fe46acd3 100644 --- a/drivers/media/usb/dvb-usb/cinergyT2-fe.c +++ b/drivers/media/usb/dvb-usb/cinergyT2-fe.c @@ -300,8 +300,7 @@ static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe) static void cinergyt2_fe_release(struct dvb_frontend *fe) { struct cinergyt2_fe_state *state = fe->demodulator_priv; - if (state != NULL) - kfree(state); + kfree(state); } static struct dvb_frontend_ops cinergyt2_fe_ops; -- cgit v1.2.3 From 3ead1ba31b24cb521a7256e19e6243f951f46ec8 Mon Sep 17 00:00:00 2001 From: Matt Gomboc Date: Fri, 1 Mar 2013 19:53:30 -0300 Subject: [media] cx231xx : Add support for OTG102 aka EZGrabber2 Thanks for the response, I have done as you suggested. Below is an updated patch for the OTG102 device against http://git.linuxtv.org/hverkuil/media_tree.git/shortlog/refs/heads/cx231xx, kernel version 3.8. With further testing it appears the extra clauses in cx231xx-cards.c were not necessary (in static in cx231xx_init_dev and static int cx231xx_usb_probe), so those have been also been removed. Signed-off-by: Matt Gomboc Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-avcore.c | 2 ++ drivers/media/usb/cx231xx/cx231xx-cards.c | 35 ++++++++++++++++++++++++++++++ drivers/media/usb/cx231xx/cx231xx.h | 1 + 3 files changed, 38 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index 2e51fb9fd21c..235ba657d52e 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c @@ -357,6 +357,7 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev, case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL: case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC: + case CX231XX_BOARD_OTG102: if (avmode == POLARIS_AVMODE_ANALOGT_TV) { while (afe_power_status != (FLD_PWRDN_TUNING_BIAS | FLD_PWRDN_ENABLE_PLL)) { @@ -1720,6 +1721,7 @@ int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard) case CX231XX_BOARD_CNXT_RDU_250: case CX231XX_BOARD_CNXT_VIDEO_GRABBER: case CX231XX_BOARD_HAUPPAUGE_EXETER: + case CX231XX_BOARD_OTG102: func_mode = 0x03; break; case CX231XX_BOARD_CNXT_RDE_253S: diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index b7b1acd7e7b0..13249e5a7891 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -634,6 +634,39 @@ struct cx231xx_board cx231xx_boards[] = { .gpio = NULL, } }, }, + [CX231XX_BOARD_OTG102] = { + .name = "Geniatech OTG102", + .tuner_type = TUNER_ABSENT, + .decoder = CX231XX_AVDECODER, + .output_mode = OUT_MODE_VIP11, + .ctl_pin_status_mask = 0xFFFFFFC4, + .agc_analog_digital_select_gpio = 0x0c, + /* According with PV CxPlrCAP.inf file */ + .gpio_pin_status_mask = 0x4001000, + .norm = V4L2_STD_NTSC, + .no_alt_vanc = 1, + .external_av = 1, + .dont_use_port_3 = 1, + /*.has_417 = 1, */ + /* This board is believed to have a hardware encoding chip + * supporting mpeg1/2/4, but as the 417 is apparently not + * working for the reference board it is not here either. */ + + .input = {{ + .type = CX231XX_VMUX_COMPOSITE1, + .vmux = CX231XX_VIN_2_1, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + }, { + .type = CX231XX_VMUX_SVIDEO, + .vmux = CX231XX_VIN_1_1 | + (CX231XX_VIN_1_2 << 8) | + CX25840_SVIDEO_ON, + .amux = CX231XX_AMUX_LINE_IN, + .gpio = NULL, + } + }, + }, }; const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards); @@ -675,6 +708,8 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_ICONBIT_U100}, {USB_DEVICE(0x0fd9, 0x0037), .driver_info = CX231XX_BOARD_ELGATO_VIDEO_CAPTURE_V2}, + {USB_DEVICE(0x1f4d, 0x0102), + .driver_info = CX231XX_BOARD_OTG102}, {}, }; diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index a8e50d2d491c..dff3f1d73f28 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -71,6 +71,7 @@ #define CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL 14 #define CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC 15 #define CX231XX_BOARD_ELGATO_VIDEO_CAPTURE_V2 16 +#define CX231XX_BOARD_OTG102 17 /* Limits minimum and default number of buffers */ #define CX231XX_MIN_BUF 4 -- cgit v1.2.3 From 95a75544cfb1410af721911cd8accdbc1a080b40 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Sat, 2 Mar 2013 06:41:02 -0300 Subject: [media] s5p-mfc: Staticize some symbols in s5p_mfc_cmd_v6.c Since these symbols are used only in this file, they can be made static. Signed-off-by: Sachin Kamat Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c index 754bfbcb1c43..5708fc3d9b4d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c @@ -17,7 +17,7 @@ #include "s5p_mfc_intr.h" #include "s5p_mfc_opr.h" -int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, +static int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, struct s5p_mfc_cmd_args *args) { mfc_debug(2, "Issue the command: %d\n", cmd); @@ -32,7 +32,7 @@ int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, return 0; } -int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev) { struct s5p_mfc_cmd_args h2r_args; struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; @@ -44,7 +44,7 @@ int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev) &h2r_args); } -int s5p_mfc_sleep_cmd_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_sleep_cmd_v6(struct s5p_mfc_dev *dev) { struct s5p_mfc_cmd_args h2r_args; @@ -53,7 +53,7 @@ int s5p_mfc_sleep_cmd_v6(struct s5p_mfc_dev *dev) &h2r_args); } -int s5p_mfc_wakeup_cmd_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_wakeup_cmd_v6(struct s5p_mfc_dev *dev) { struct s5p_mfc_cmd_args h2r_args; @@ -63,7 +63,7 @@ int s5p_mfc_wakeup_cmd_v6(struct s5p_mfc_dev *dev) } /* Open a new instance and get its number */ -int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_cmd_args h2r_args; @@ -121,7 +121,7 @@ int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) } /* Close instance */ -int s5p_mfc_close_inst_cmd_v6(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_close_inst_cmd_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_cmd_args h2r_args; -- cgit v1.2.3 From 4294dcf7e335da72fe81538c46b4a8e83037ea20 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Sat, 2 Mar 2013 07:50:12 -0300 Subject: [media] s5p-mfc: Staticize some symbols in s5p_mfc_cmd_v5.c These symbols are used only in this file and can be made static. Signed-off-by: Sachin Kamat Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c index 138778083c63..ad4f1df0a18e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c @@ -16,7 +16,7 @@ #include "s5p_mfc_debug.h" /* This function is used to send a command to the MFC */ -int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd, +static int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd, struct s5p_mfc_cmd_args *args) { int cur_cmd; @@ -41,7 +41,7 @@ int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd, } /* Initialize the MFC */ -int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev) { struct s5p_mfc_cmd_args h2r_args; @@ -52,7 +52,7 @@ int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev) } /* Suspend the MFC hardware */ -int s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev *dev) { struct s5p_mfc_cmd_args h2r_args; @@ -61,7 +61,7 @@ int s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev *dev) } /* Wake up the MFC hardware */ -int s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev *dev) { struct s5p_mfc_cmd_args h2r_args; @@ -71,7 +71,7 @@ int s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev *dev) } -int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_cmd_args h2r_args; @@ -124,7 +124,7 @@ int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx) return ret; } -int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_cmd_args h2r_args; -- cgit v1.2.3 From b9571a577b570b24c4fa2ed79dade612294584d3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Sat, 2 Mar 2013 07:50:13 -0300 Subject: [media] s5p-mfc: Staticize symbols in s5p_mfc_opr_v6.c Symbols used only in this file should be made static. Signed-off-by: Sachin Kamat Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 112 ++++++++++++------------ 1 file changed, 57 insertions(+), 55 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index beb6dbacebd9..33de88b8e9d0 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -49,7 +49,7 @@ #define OFFSETB(x) (((x) - dev->port_b) >> S5P_FIMV_MEM_OFFSET) /* Allocate temporary buffers for decoding */ -int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx) { /* NOP */ @@ -57,19 +57,19 @@ int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx) } /* Release temproary buffers for decoding */ -void s5p_mfc_release_dec_desc_buffer_v6(struct s5p_mfc_ctx *ctx) +static void s5p_mfc_release_dec_desc_buffer_v6(struct s5p_mfc_ctx *ctx) { /* NOP */ } -int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev) { /* NOP */ return -1; } /* Allocate codec buffers */ -int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; unsigned int mb_width, mb_height; @@ -203,13 +203,13 @@ int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) } /* Release buffers allocated for codec */ -void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx) +static void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx) { s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->bank1); } /* Allocate memory for instance data buffer */ -int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; @@ -258,13 +258,13 @@ int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) } /* Release instance buffer */ -void s5p_mfc_release_instance_buffer_v6(struct s5p_mfc_ctx *ctx) +static void s5p_mfc_release_instance_buffer_v6(struct s5p_mfc_ctx *ctx) { s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->ctx); } /* Allocate context buffers for SYS_INIT */ -int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev) { struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; int ret; @@ -287,7 +287,7 @@ int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev) } /* Release context buffers for SYS_INIT */ -void s5p_mfc_release_dev_context_buffer_v6(struct s5p_mfc_dev *dev) +static void s5p_mfc_release_dev_context_buffer_v6(struct s5p_mfc_dev *dev) { s5p_mfc_release_priv_buf(dev->mem_dev_l, &dev->ctx_buf); } @@ -306,7 +306,7 @@ static int calc_plane(int width, int height) (mbY * S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6); } -void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) +static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) { ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6); ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6); @@ -326,7 +326,7 @@ void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) } } -void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx) +static void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx) { unsigned int mb_width, mb_height; @@ -339,8 +339,9 @@ void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx) } /* Set registers for decoding stream buffer */ -int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx, int buf_addr, - unsigned int start_num_byte, unsigned int strm_size) +static int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx, + int buf_addr, unsigned int start_num_byte, + unsigned int strm_size) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; @@ -359,7 +360,7 @@ int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx, int buf_addr, } /* Set decoding frame buffer */ -int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) { unsigned int frame_size, i; unsigned int frame_size_ch, frame_size_mv; @@ -440,7 +441,7 @@ int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) } /* Set registers for encoding stream buffer */ -int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx, +static int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx, unsigned long addr, unsigned int size) { struct s5p_mfc_dev *dev = ctx->dev; @@ -454,7 +455,7 @@ int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx, return 0; } -void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, +static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, unsigned long y_addr, unsigned long c_addr) { struct s5p_mfc_dev *dev = ctx->dev; @@ -466,7 +467,7 @@ void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, mfc_debug(2, "enc src c buf addr: 0x%08lx", c_addr); } -void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, +static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, unsigned long *y_addr, unsigned long *c_addr) { struct s5p_mfc_dev *dev = ctx->dev; @@ -483,7 +484,7 @@ void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, } /* Set encoding ref & codec buffer */ -int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; size_t buf_addr1; @@ -1147,7 +1148,7 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) } /* Initialize decoding */ -int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; unsigned int reg = 0; @@ -1215,7 +1216,7 @@ static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) } /* Decode a single frame */ -int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx, +static int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx, enum s5p_mfc_decode_arg last_frame) { struct s5p_mfc_dev *dev = ctx->dev; @@ -1244,7 +1245,7 @@ int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx, return 0; } -int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; @@ -1267,7 +1268,7 @@ int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx) return 0; } -int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_enc_params *p = &ctx->enc_params; @@ -1283,7 +1284,7 @@ int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx) } /* Encode a single frame */ -int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; @@ -1540,7 +1541,7 @@ static inline int s5p_mfc_run_init_enc_buffers(struct s5p_mfc_ctx *ctx) } /* Try running an operation on hardware */ -void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) +static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) { struct s5p_mfc_ctx *ctx; int new_ctx; @@ -1663,7 +1664,7 @@ void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) } -void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq) +static void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq) { struct s5p_mfc_buf *b; int i; @@ -1677,13 +1678,13 @@ void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq) } } -void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev) +static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev) { mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); mfc_write(dev, 0, S5P_FIMV_RISC2HOST_INT_V6); } -void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data, +static void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data, unsigned int ofs) { struct s5p_mfc_dev *dev = ctx->dev; @@ -1693,7 +1694,8 @@ void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data, s5p_mfc_clock_off(); } -unsigned int s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs) +static unsigned int +s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs) { struct s5p_mfc_dev *dev = ctx->dev; int ret; @@ -1705,140 +1707,140 @@ unsigned int s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs) return ret; } -int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6); } -int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_D_DECODED_LUMA_ADDR_V6); } -int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_D_DISPLAY_STATUS_V6); } -int s5p_mfc_get_decoded_status_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_decoded_status_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_D_DECODED_STATUS_V6); } -int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_D_DECODED_FRAME_TYPE_V6) & S5P_FIMV_DECODE_FRAME_MASK_V6; } -int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx) { return mfc_read(ctx->dev, S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6) & S5P_FIMV_DECODE_FRAME_MASK_V6; } -int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_D_DECODED_NAL_SIZE_V6); } -int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_RISC2HOST_CMD_V6) & S5P_FIMV_RISC2HOST_CMD_MASK; } -int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_ERROR_CODE_V6); } -int s5p_mfc_err_dec_v6(unsigned int err) +static int s5p_mfc_err_dec_v6(unsigned int err) { return (err & S5P_FIMV_ERR_DEC_MASK_V6) >> S5P_FIMV_ERR_DEC_SHIFT_V6; } -int s5p_mfc_err_dspl_v6(unsigned int err) +static int s5p_mfc_err_dspl_v6(unsigned int err) { return (err & S5P_FIMV_ERR_DSPL_MASK_V6) >> S5P_FIMV_ERR_DSPL_SHIFT_V6; } -int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6); } -int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6); } -int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_D_MIN_NUM_DPB_V6); } -int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_D_MIN_NUM_MV_V6); } -int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_RET_INSTANCE_ID_V6); } -int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_E_NUM_DPB_V6); } -int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_E_STREAM_SIZE_V6); } -int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_E_SLICE_TYPE_V6); } -int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_E_PICTURE_COUNT_V6); } -int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx) { return mfc_read(ctx->dev, S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6); } -int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_D_MVC_NUM_VIEWS_V6); } -int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_D_MVC_VIEW_ID_V6); } -unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx) +static unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v6(ctx, PIC_TIME_TOP_V6); } -unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx) +static unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v6(ctx, PIC_TIME_BOT_V6); } -unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx) +static unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v6(ctx, CROP_INFO_H_V6); } -unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx) +static unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v6(ctx, CROP_INFO_V_V6); } -- cgit v1.2.3 From 3c75a2e1cfcabe01e5914a92e949188720918933 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Sat, 2 Mar 2013 07:50:14 -0300 Subject: [media] s5p-mfc: Staticize symbols in s5p_mfc_opr_v5.c Some symbols are used only in this file. Make them static. Signed-off-by: Sachin Kamat Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 103 ++++++++++++------------ 1 file changed, 52 insertions(+), 51 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index f61dba837899..c7ad329ca889 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -34,7 +34,7 @@ #define OFFSETB(x) (((x) - dev->bank2) >> MFC_OFFSET_SHIFT) /* Allocate temporary buffers for decoding */ -int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; @@ -55,13 +55,13 @@ int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) /* Release temporary buffers for decoding */ -void s5p_mfc_release_dec_desc_buffer_v5(struct s5p_mfc_ctx *ctx) +static void s5p_mfc_release_dec_desc_buffer_v5(struct s5p_mfc_ctx *ctx) { s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->dsc); } /* Allocate codec buffers */ -int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; unsigned int enc_ref_y_size = 0; @@ -193,14 +193,14 @@ int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx) } /* Release buffers allocated for codec */ -void s5p_mfc_release_codec_buffers_v5(struct s5p_mfc_ctx *ctx) +static void s5p_mfc_release_codec_buffers_v5(struct s5p_mfc_ctx *ctx) { s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->bank1); s5p_mfc_release_priv_buf(ctx->dev->mem_dev_r, &ctx->bank2); } /* Allocate memory for instance data buffer */ -int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; @@ -241,20 +241,20 @@ int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) } /* Release instance buffer */ -void s5p_mfc_release_instance_buffer_v5(struct s5p_mfc_ctx *ctx) +static void s5p_mfc_release_instance_buffer_v5(struct s5p_mfc_ctx *ctx) { s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->ctx); s5p_mfc_release_priv_buf(ctx->dev->mem_dev_l, &ctx->shm); } -int s5p_mfc_alloc_dev_context_buffer_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_alloc_dev_context_buffer_v5(struct s5p_mfc_dev *dev) { /* NOP */ return 0; } -void s5p_mfc_release_dev_context_buffer_v5(struct s5p_mfc_dev *dev) +static void s5p_mfc_release_dev_context_buffer_v5(struct s5p_mfc_dev *dev) { /* NOP */ } @@ -273,7 +273,7 @@ static unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx, return readl(ctx->shm.virt + ofs); } -void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx) +static void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx) { unsigned int guard_width, guard_height; @@ -315,7 +315,7 @@ void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx) } } -void s5p_mfc_enc_calc_src_size_v5(struct s5p_mfc_ctx *ctx) +static void s5p_mfc_enc_calc_src_size_v5(struct s5p_mfc_ctx *ctx) { if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN); @@ -361,8 +361,9 @@ static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx) } /* Set registers for decoding stream buffer */ -int s5p_mfc_set_dec_stream_buffer_v5(struct s5p_mfc_ctx *ctx, int buf_addr, - unsigned int start_num_byte, unsigned int buf_size) +static int s5p_mfc_set_dec_stream_buffer_v5(struct s5p_mfc_ctx *ctx, + int buf_addr, unsigned int start_num_byte, + unsigned int buf_size) { struct s5p_mfc_dev *dev = ctx->dev; @@ -374,7 +375,7 @@ int s5p_mfc_set_dec_stream_buffer_v5(struct s5p_mfc_ctx *ctx, int buf_addr, } /* Set decoding frame buffer */ -int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx) { unsigned int frame_size, i; unsigned int frame_size_ch, frame_size_mv; @@ -506,7 +507,7 @@ int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx) } /* Set registers for encoding stream buffer */ -int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx, +static int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx, unsigned long addr, unsigned int size) { struct s5p_mfc_dev *dev = ctx->dev; @@ -516,7 +517,7 @@ int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx, return 0; } -void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, +static void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, unsigned long y_addr, unsigned long c_addr) { struct s5p_mfc_dev *dev = ctx->dev; @@ -525,7 +526,7 @@ void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR); } -void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, +static void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, unsigned long *y_addr, unsigned long *c_addr) { struct s5p_mfc_dev *dev = ctx->dev; @@ -537,7 +538,7 @@ void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, } /* Set encoding ref & codec buffer */ -int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; size_t buf_addr1, buf_addr2; @@ -1041,7 +1042,7 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) } /* Initialize decoding */ -int s5p_mfc_init_decode_v5(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_init_decode_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; @@ -1077,7 +1078,7 @@ static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) } /* Decode a single frame */ -int s5p_mfc_decode_one_frame_v5(struct s5p_mfc_ctx *ctx, +static int s5p_mfc_decode_one_frame_v5(struct s5p_mfc_ctx *ctx, enum s5p_mfc_decode_arg last_frame) { struct s5p_mfc_dev *dev = ctx->dev; @@ -1106,7 +1107,7 @@ int s5p_mfc_decode_one_frame_v5(struct s5p_mfc_ctx *ctx, return 0; } -int s5p_mfc_init_encode_v5(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_init_encode_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; @@ -1128,7 +1129,7 @@ int s5p_mfc_init_encode_v5(struct s5p_mfc_ctx *ctx) } /* Encode a single frame */ -int s5p_mfc_encode_one_frame_v5(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_encode_one_frame_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; int cmd; @@ -1353,7 +1354,7 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) } /* Try running an operation on hardware */ -void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) +static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) { struct s5p_mfc_ctx *ctx; int new_ctx; @@ -1469,7 +1470,7 @@ void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) } -void s5p_mfc_cleanup_queue_v5(struct list_head *lh, struct vb2_queue *vq) +static void s5p_mfc_cleanup_queue_v5(struct list_head *lh, struct vb2_queue *vq) { struct s5p_mfc_buf *b; int i; @@ -1483,52 +1484,52 @@ void s5p_mfc_cleanup_queue_v5(struct list_head *lh, struct vb2_queue *vq) } } -void s5p_mfc_clear_int_flags_v5(struct s5p_mfc_dev *dev) +static void s5p_mfc_clear_int_flags_v5(struct s5p_mfc_dev *dev) { mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT); mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); mfc_write(dev, 0xffff, S5P_FIMV_SI_RTN_CHID); } -int s5p_mfc_get_dspl_y_adr_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_dspl_y_adr_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_SI_DISPLAY_Y_ADR) << MFC_OFFSET_SHIFT; } -int s5p_mfc_get_dec_y_adr_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_dec_y_adr_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_SI_DECODE_Y_ADR) << MFC_OFFSET_SHIFT; } -int s5p_mfc_get_dspl_status_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_dspl_status_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_SI_DISPLAY_STATUS); } -int s5p_mfc_get_dec_status_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_dec_status_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_SI_DECODE_STATUS); } -int s5p_mfc_get_dec_frame_type_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_dec_frame_type_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_DECODE_FRAME_TYPE) & S5P_FIMV_DECODE_FRAME_MASK; } -int s5p_mfc_get_disp_frame_type_v5(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_get_disp_frame_type_v5(struct s5p_mfc_ctx *ctx) { return (s5p_mfc_read_info_v5(ctx, DISP_PIC_FRAME_TYPE) >> S5P_FIMV_SHARED_DISP_FRAME_TYPE_SHIFT) & S5P_FIMV_DECODE_FRAME_MASK; } -int s5p_mfc_get_consumed_stream_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_consumed_stream_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_SI_CONSUMED_BYTES); } -int s5p_mfc_get_int_reason_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_int_reason_v5(struct s5p_mfc_dev *dev) { int reason; reason = mfc_read(dev, S5P_FIMV_RISC2HOST_CMD) & @@ -1576,98 +1577,98 @@ int s5p_mfc_get_int_reason_v5(struct s5p_mfc_dev *dev) return reason; } -int s5p_mfc_get_int_err_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_int_err_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_RISC2HOST_ARG2); } -int s5p_mfc_err_dec_v5(unsigned int err) +static int s5p_mfc_err_dec_v5(unsigned int err) { return (err & S5P_FIMV_ERR_DEC_MASK) >> S5P_FIMV_ERR_DEC_SHIFT; } -int s5p_mfc_err_dspl_v5(unsigned int err) +static int s5p_mfc_err_dspl_v5(unsigned int err) { return (err & S5P_FIMV_ERR_DSPL_MASK) >> S5P_FIMV_ERR_DSPL_SHIFT; } -int s5p_mfc_get_img_width_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_img_width_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_SI_HRESOL); } -int s5p_mfc_get_img_height_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_img_height_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_SI_VRESOL); } -int s5p_mfc_get_dpb_count_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_dpb_count_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_SI_BUF_NUMBER); } -int s5p_mfc_get_mv_count_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_mv_count_v5(struct s5p_mfc_dev *dev) { /* NOP */ return -1; } -int s5p_mfc_get_inst_no_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_inst_no_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_RISC2HOST_ARG1); } -int s5p_mfc_get_enc_strm_size_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_enc_strm_size_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_ENC_SI_STRM_SIZE); } -int s5p_mfc_get_enc_slice_type_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_enc_slice_type_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_ENC_SI_SLICE_TYPE); } -int s5p_mfc_get_enc_dpb_count_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_enc_dpb_count_v5(struct s5p_mfc_dev *dev) { return -1; } -int s5p_mfc_get_enc_pic_count_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_enc_pic_count_v5(struct s5p_mfc_dev *dev) { return mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT); } -int s5p_mfc_get_sei_avail_status_v5(struct s5p_mfc_ctx *ctx) +static int s5p_mfc_get_sei_avail_status_v5(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v5(ctx, FRAME_PACK_SEI_AVAIL); } -int s5p_mfc_get_mvc_num_views_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_mvc_num_views_v5(struct s5p_mfc_dev *dev) { return -1; } -int s5p_mfc_get_mvc_view_id_v5(struct s5p_mfc_dev *dev) +static int s5p_mfc_get_mvc_view_id_v5(struct s5p_mfc_dev *dev) { return -1; } -unsigned int s5p_mfc_get_pic_type_top_v5(struct s5p_mfc_ctx *ctx) +static unsigned int s5p_mfc_get_pic_type_top_v5(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP); } -unsigned int s5p_mfc_get_pic_type_bot_v5(struct s5p_mfc_ctx *ctx) +static unsigned int s5p_mfc_get_pic_type_bot_v5(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT); } -unsigned int s5p_mfc_get_crop_info_h_v5(struct s5p_mfc_ctx *ctx) +static unsigned int s5p_mfc_get_crop_info_h_v5(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v5(ctx, CROP_INFO_H); } -unsigned int s5p_mfc_get_crop_info_v_v5(struct s5p_mfc_ctx *ctx) +static unsigned int s5p_mfc_get_crop_info_v_v5(struct s5p_mfc_ctx *ctx) { return s5p_mfc_read_info_v5(ctx, CROP_INFO_V); } -- cgit v1.2.3 From b78a1f372210ae8c19426cb3ae708bf85aa70124 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Mon, 4 Mar 2013 09:43:20 -0300 Subject: [media] m920x: let GCC see 'ret' is used initialized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 7543f344e9b06afe86b55a2620f5c11b38bd5642 ("[media] m920x: factor out a m920x_write_seq() function") building m920x.o triggers this GCC warning: drivers/media/usb/dvb-usb/m920x.c: In function ‘m920x_probe’: drivers/media/usb/dvb-usb/m920x.c:91:6: warning: ‘ret’ may be used uninitialized in this function [-Wuninitialized] This warning is caused by m920x_write_seq(), which is apparently inlined into m920x_probe(). It is clear why GCC thinks 'ret' may be used uninitialized. But in practice the first seq->address will always be non-zero when this function is called. That means we can change the while()-do{} loop into a do{}-while() loop. And that suffices to make GCC see that 'ret' will not be used uninitialized. Signed-off-by: Paul Bolle Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/m920x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index 92afeb20650f..79b31ae66a9c 100644 --- a/drivers/media/usb/dvb-usb/m920x.c +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -68,13 +68,13 @@ static inline int m920x_write_seq(struct usb_device *udev, u8 request, struct m920x_inits *seq) { int ret; - while (seq->address) { + do { ret = m920x_write(udev, request, seq->data, seq->address); if (ret != 0) return ret; seq++; - } + } while (seq->address); return ret; } -- cgit v1.2.3 From da508f5799659241a359e2d07abb8af905f6291c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 4 Mar 2013 16:52:36 -0300 Subject: [media] media/v4l2: VIDEOBUF2_DMA_CONTIG should depend on HAS_DMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit m68k/sun3: drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_mmap’: drivers/media/v4l2-core/videobuf2-dma-contig.c:204: error: implicit declaration of function ‘dma_mmap_coherent’ drivers/media/v4l2-core/videobuf2-dma-contig.c: In function ‘vb2_dc_get_base_sgt’: drivers/media/v4l2-core/videobuf2-dma-contig.c:387: error: implicit declaration of function ‘dma_get_sgtable’ Make VIDEOBUF2_DMA_CONTIG and VIDEO_SH_VEU (which selects the former and doesn't have a platform dependency) depend on HAS_DMA to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 2 +- drivers/media/v4l2-core/Kconfig | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 05d7b6333461..42c62aa33e11 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -204,7 +204,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC config VIDEO_SH_VEU tristate "SuperH VEU mem2mem video processing driver" - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 976d029e9925..8c05565a240e 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -67,6 +67,7 @@ config VIDEOBUF2_MEMOPS config VIDEOBUF2_DMA_CONTIG tristate + depends on HAS_DMA select VIDEOBUF2_CORE select VIDEOBUF2_MEMOPS select DMA_SHARED_BUFFER -- cgit v1.2.3 From c7a45e5b4f8c2f96cd242ae1b1c06e7fb19a08d0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 5 Mar 2013 06:55:26 -0300 Subject: [media] em28xx: Prepare to support 2 different I2C buses Newer em28xx devices have 2 buses. Change the logic to allow using both buses. This patch was generated by this small script: for i in drivers/media/usb/em28xx/*.c; do sed 's,->i2c_adap,->i2c_adap[dev->def_i2c_bus],g;s,->i2c_client,->i2c_client[dev->def_i2c_bus],' done Of course, em28xx.h needed manual edit. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 32 ++++++------ drivers/media/usb/em28xx/em28xx-dvb.c | 86 ++++++++++++++++----------------- drivers/media/usb/em28xx/em28xx-i2c.c | 30 ++++++------ drivers/media/usb/em28xx/em28xx-input.c | 5 +- drivers/media/usb/em28xx/em28xx.h | 10 +++- 5 files changed, 85 insertions(+), 78 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 4dcef9d6d561..d81f7ee94c41 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2249,7 +2249,7 @@ static int em28xx_initialize_mt9m111(struct em28xx *dev) }; for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client, ®s[i][0], 3); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], ®s[i][0], 3); return 0; } @@ -2276,7 +2276,7 @@ static int em28xx_initialize_mt9m001(struct em28xx *dev) }; for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client, ®s[i][0], 3); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], ®s[i][0], 3); return 0; } @@ -2294,10 +2294,10 @@ static int em28xx_hint_sensor(struct em28xx *dev) u16 version; /* Micron sensor detection */ - dev->i2c_client.addr = 0xba >> 1; + dev->i2c_client[dev->def_i2c_bus].addr = 0xba >> 1; cmd = 0; - i2c_master_send(&dev->i2c_client, &cmd, 1); - rc = i2c_master_recv(&dev->i2c_client, (char *)&version_be, 2); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], &cmd, 1); + rc = i2c_master_recv(&dev->i2c_client[dev->def_i2c_bus], (char *)&version_be, 2); if (rc != 2) return -EINVAL; @@ -2748,8 +2748,8 @@ static void em28xx_card_setup(struct em28xx *dev) #endif /* Call first TVeeprom */ - dev->i2c_client.addr = 0xa0 >> 1; - tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); + dev->i2c_client[dev->def_i2c_bus].addr = 0xa0 >> 1; + tveeprom_hauppauge_analog(&dev->i2c_client[dev->def_i2c_bus], &tv, dev->eedata); dev->tuner_type = tv.tuner_type; @@ -2841,15 +2841,15 @@ static void em28xx_card_setup(struct em28xx *dev) /* request some modules */ if (dev->board.has_msp34xx) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], "msp3400", 0, msp3400_addrs); if (dev->board.decoder == EM28XX_SAA711X) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], "saa7115_auto", 0, saa711x_addrs); if (dev->board.decoder == EM28XX_TVP5150) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], "tvp5150", 0, tvp5150_addrs); if (dev->em28xx_sensor == EM28XX_MT9V011) { @@ -2861,25 +2861,25 @@ static void em28xx_card_setup(struct em28xx *dev) }; pdata.xtal = dev->sensor_xtal; - v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap, + v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], &mt9v011_info, NULL); } if (dev->board.adecoder == EM28XX_TVAUDIO) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], "tvaudio", dev->board.tvaudio_addr, NULL); if (dev->board.tuner_type != TUNER_ABSENT) { int has_demod = (dev->tda9887_conf & TDA9887_PRESENT); if (dev->board.radio.type) - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], "tuner", dev->board.radio_addr, NULL); if (has_demod) v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, "tuner", + &dev->i2c_adap[dev->def_i2c_bus], "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); if (dev->tuner_addr == 0) { enum v4l2_i2c_tuner_type type = @@ -2887,13 +2887,13 @@ static void em28xx_card_setup(struct em28xx *dev) struct v4l2_subdev *sd; sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, - &dev->i2c_adap, "tuner", + &dev->i2c_adap[dev->def_i2c_bus], "tuner", 0, v4l2_i2c_tuner_addrs(type)); if (sd) dev->tuner_addr = v4l2_i2c_subdev_addr(sd); } else { - v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, + v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], "tuner", dev->tuner_addr, NULL); } } diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 7200dfe59ef9..98b95be3be6e 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -463,10 +463,10 @@ static void hauppauge_hvr930c_init(struct em28xx *dev) em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); msleep(10); - dev->i2c_client.addr = 0x82 >> 1; + dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); em28xx_gpio_set(dev, hauppauge_hvr930c_end); msleep(100); @@ -520,10 +520,10 @@ static void terratec_h5_init(struct em28xx *dev) em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45); msleep(10); - dev->i2c_client.addr = 0x82 >> 1; + dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); em28xx_gpio_set(dev, terratec_h5_end); }; @@ -573,10 +573,10 @@ static void terratec_htc_stick_init(struct em28xx *dev) em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); msleep(10); - dev->i2c_client.addr = 0x82 >> 1; + dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); em28xx_gpio_set(dev, terratec_htc_stick_end); }; @@ -631,10 +631,10 @@ static void terratec_htc_usb_xs_init(struct em28xx *dev) em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); msleep(10); - dev->i2c_client.addr = 0x82 >> 1; + dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); em28xx_gpio_set(dev, terratec_htc_usb_xs_end); }; @@ -660,10 +660,10 @@ static void pctv_520e_init(struct em28xx *dev) {{ 0x01, 0x00, 0x73, 0xaf }, 4}, }; - dev->i2c_client.addr = 0x82 >> 1; /* 0x41 */ + dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; /* 0x41 */ for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], regs[i].r, regs[i].len); }; static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe) @@ -777,7 +777,7 @@ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) struct xc2028_config cfg; memset(&cfg, 0, sizeof(cfg)); - cfg.i2c_adap = &dev->i2c_adap; + cfg.i2c_adap = &dev->i2c_adap[dev->def_i2c_bus]; cfg.i2c_addr = addr; if (!dev->dvb->fe[0]) { @@ -960,7 +960,7 @@ static int em28xx_dvb_init(struct em28xx *dev) switch (dev->model) { case EM2874_BOARD_LEADERSHIP_ISDBT: dvb->fe[0] = dvb_attach(s921_attach, - &sharp_isdbt, &dev->i2c_adap); + &sharp_isdbt, &dev->i2c_adap[dev->def_i2c_bus]); if (!dvb->fe[0]) { result = -EINVAL; @@ -974,7 +974,7 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: dvb->fe[0] = dvb_attach(lgdt330x_attach, &em2880_lgdt3303_dev, - &dev->i2c_adap); + &dev->i2c_adap[dev->def_i2c_bus]); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; @@ -983,7 +983,7 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2880_BOARD_KWORLD_DVB_310U: dvb->fe[0] = dvb_attach(zl10353_attach, &em28xx_zl10353_with_xc3028, - &dev->i2c_adap); + &dev->i2c_adap[dev->def_i2c_bus]); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; @@ -994,7 +994,7 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2880_BOARD_EMPIRE_DUAL_TV: dvb->fe[0] = dvb_attach(zl10353_attach, &em28xx_zl10353_xc3028_no_i2c_gate, - &dev->i2c_adap); + &dev->i2c_adap[dev->def_i2c_bus]); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; @@ -1007,13 +1007,13 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2882_BOARD_KWORLD_VS_DVBT: dvb->fe[0] = dvb_attach(zl10353_attach, &em28xx_zl10353_xc3028_no_i2c_gate, - &dev->i2c_adap); + &dev->i2c_adap[dev->def_i2c_bus]); if (dvb->fe[0] == NULL) { /* This board could have either a zl10353 or a mt352. If the chip id isn't for zl10353, try mt352 */ dvb->fe[0] = dvb_attach(mt352_attach, &terratec_xs_mt352_cfg, - &dev->i2c_adap); + &dev->i2c_adap[dev->def_i2c_bus]); } if (em28xx_attach_xc3028(0x61, dev) < 0) { @@ -1024,16 +1024,16 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2870_BOARD_KWORLD_355U: dvb->fe[0] = dvb_attach(zl10353_attach, &em28xx_zl10353_no_i2c_gate_dev, - &dev->i2c_adap); + &dev->i2c_adap[dev->def_i2c_bus]); if (dvb->fe[0] != NULL) dvb_attach(qt1010_attach, dvb->fe[0], - &dev->i2c_adap, &em28xx_qt1010_config); + &dev->i2c_adap[dev->def_i2c_bus], &em28xx_qt1010_config); break; case EM2883_BOARD_KWORLD_HYBRID_330U: case EM2882_BOARD_EVGA_INDTUBE: dvb->fe[0] = dvb_attach(s5h1409_attach, &em28xx_s5h1409_with_xc3028, - &dev->i2c_adap); + &dev->i2c_adap[dev->def_i2c_bus]); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; @@ -1042,10 +1042,10 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2882_BOARD_KWORLD_ATSC_315U: dvb->fe[0] = dvb_attach(lgdt330x_attach, &em2880_lgdt3303_dev, - &dev->i2c_adap); + &dev->i2c_adap[dev->def_i2c_bus]); if (dvb->fe[0] != NULL) { if (!dvb_attach(simple_tuner_attach, dvb->fe[0], - &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) { + &dev->i2c_adap[dev->def_i2c_bus], 0x61, TUNER_THOMSON_DTT761X)) { result = -EINVAL; goto out_free; } @@ -1054,7 +1054,7 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL, - &dev->i2c_adap, &dev->udev->dev); + &dev->i2c_adap[dev->def_i2c_bus], &dev->udev->dev); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; @@ -1064,10 +1064,10 @@ static int em28xx_dvb_init(struct em28xx *dev) /* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */ dvb->fe[0] = dvb_attach(tda10023_attach, &em28xx_tda10023_config, - &dev->i2c_adap, 0x48); + &dev->i2c_adap[dev->def_i2c_bus], 0x48); if (dvb->fe[0]) { if (!dvb_attach(simple_tuner_attach, dvb->fe[0], - &dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) { + &dev->i2c_adap[dev->def_i2c_bus], 0x60, TUNER_PHILIPS_CU1216L)) { result = -EINVAL; goto out_free; } @@ -1076,10 +1076,10 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2870_BOARD_KWORLD_A340: dvb->fe[0] = dvb_attach(lgdt3305_attach, &em2870_lgdt3304_dev, - &dev->i2c_adap); + &dev->i2c_adap[dev->def_i2c_bus]); if (dvb->fe[0] != NULL) dvb_attach(tda18271_attach, dvb->fe[0], 0x60, - &dev->i2c_adap, &kworld_a340_config); + &dev->i2c_adap[dev->def_i2c_bus], &kworld_a340_config); break; case EM28174_BOARD_PCTV_290E: /* set default GPIO0 for LNA, used if GPIOLIB is undefined */ @@ -1087,14 +1087,14 @@ static int em28xx_dvb_init(struct em28xx *dev) CXD2820R_GPIO_L; dvb->fe[0] = dvb_attach(cxd2820r_attach, &em28xx_cxd2820r_config, - &dev->i2c_adap, + &dev->i2c_adap[dev->def_i2c_bus], &dvb->lna_gpio); if (dvb->fe[0]) { /* FE 0 attach tuner */ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, - &dev->i2c_adap, + &dev->i2c_adap[dev->def_i2c_bus], &em28xx_cxd2820r_tda18271_config)) { dvb_frontend_detach(dvb->fe[0]); @@ -1124,7 +1124,7 @@ static int em28xx_dvb_init(struct em28xx *dev) hauppauge_hvr930c_init(dev); dvb->fe[0] = dvb_attach(drxk_attach, - &hauppauge_930c_drxk, &dev->i2c_adap); + &hauppauge_930c_drxk, &dev->i2c_adap[dev->def_i2c_bus]); if (!dvb->fe[0]) { result = -EINVAL; goto out_free; @@ -1142,7 +1142,7 @@ static int em28xx_dvb_init(struct em28xx *dev) if (dvb->fe[0]->ops.i2c_gate_ctrl) dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1); - if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap, + if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], &cfg)) { result = -EINVAL; goto out_free; @@ -1155,7 +1155,7 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2884_BOARD_TERRATEC_H5: terratec_h5_init(dev); - dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap); + dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap[dev->def_i2c_bus]); if (!dvb->fe[0]) { result = -EINVAL; goto out_free; @@ -1169,7 +1169,7 @@ static int em28xx_dvb_init(struct em28xx *dev) /* Attach tda18271 to DVB-C frontend */ if (dvb->fe[0]->ops.i2c_gate_ctrl) dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1); - if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap, 0x60)) { + if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], 0x60)) { result = -EINVAL; goto out_free; } @@ -1180,17 +1180,17 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM28174_BOARD_PCTV_460E: /* attach demod */ dvb->fe[0] = dvb_attach(tda10071_attach, - &em28xx_tda10071_config, &dev->i2c_adap); + &em28xx_tda10071_config, &dev->i2c_adap[dev->def_i2c_bus]); /* attach SEC */ if (dvb->fe[0]) - dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap, + dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], &em28xx_a8293_config); break; case EM2874_BOARD_MAXMEDIA_UB425_TC: /* attach demodulator */ dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk, - &dev->i2c_adap); + &dev->i2c_adap[dev->def_i2c_bus]); if (dvb->fe[0]) { /* disable I2C-gate */ @@ -1198,7 +1198,7 @@ static int em28xx_dvb_init(struct em28xx *dev) /* attach tuner */ if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], - &dev->i2c_adap, 0x60)) { + &dev->i2c_adap[dev->def_i2c_bus], 0x60)) { dvb_frontend_detach(dvb->fe[0]); result = -EINVAL; goto out_free; @@ -1216,12 +1216,12 @@ static int em28xx_dvb_init(struct em28xx *dev) /* attach demodulator */ dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk, - &dev->i2c_adap); + &dev->i2c_adap[dev->def_i2c_bus]); if (dvb->fe[0]) { /* attach tuner */ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, - &dev->i2c_adap, + &dev->i2c_adap[dev->def_i2c_bus], &em28xx_cxd2820r_tda18271_config)) { dvb_frontend_detach(dvb->fe[0]); result = -EINVAL; @@ -1234,7 +1234,7 @@ static int em28xx_dvb_init(struct em28xx *dev) /* attach demodulator */ dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk, - &dev->i2c_adap); + &dev->i2c_adap[dev->def_i2c_bus]); if (!dvb->fe[0]) { result = -EINVAL; goto out_free; @@ -1242,7 +1242,7 @@ static int em28xx_dvb_init(struct em28xx *dev) /* Attach the demodulator. */ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, - &dev->i2c_adap, + &dev->i2c_adap[dev->def_i2c_bus], &em28xx_cxd2820r_tda18271_config)) { result = -EINVAL; goto out_free; @@ -1253,7 +1253,7 @@ static int em28xx_dvb_init(struct em28xx *dev) /* attach demodulator */ dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk, - &dev->i2c_adap); + &dev->i2c_adap[dev->def_i2c_bus]); if (!dvb->fe[0]) { result = -EINVAL; goto out_free; @@ -1261,7 +1261,7 @@ static int em28xx_dvb_init(struct em28xx *dev) /* Attach the demodulator. */ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, - &dev->i2c_adap, + &dev->i2c_adap[dev->def_i2c_bus], &em28xx_cxd2820r_tda18271_config)) { result = -EINVAL; goto out_free; diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 6152423bef76..9086e57914e6 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -384,7 +384,7 @@ static int em28xx_i2c_read_block(struct em28xx *dev, u16 addr, bool addr_w16, /* Select address */ buf[0] = addr >> 8; buf[1] = addr & 0xff; - ret = i2c_master_send(&dev->i2c_client, buf + !addr_w16, 1 + addr_w16); + ret = i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], buf + !addr_w16, 1 + addr_w16); if (ret < 0) return ret; /* Read data */ @@ -398,7 +398,7 @@ static int em28xx_i2c_read_block(struct em28xx *dev, u16 addr, bool addr_w16, else rsize = remain; - ret = i2c_master_recv(&dev->i2c_client, data, rsize); + ret = i2c_master_recv(&dev->i2c_client[dev->def_i2c_bus], data, rsize); if (ret < 0) return ret; @@ -422,10 +422,10 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, u8 **eedata, u16 *eedata_len) *eedata = NULL; *eedata_len = 0; - dev->i2c_client.addr = 0xa0 >> 1; + dev->i2c_client[dev->def_i2c_bus].addr = 0xa0 >> 1; /* Check if board has eeprom */ - err = i2c_master_recv(&dev->i2c_client, &buf, 0); + err = i2c_master_recv(&dev->i2c_client[dev->def_i2c_bus], &buf, 0); if (err < 0) { em28xx_info("board has no eeprom\n"); return -ENODEV; @@ -652,8 +652,8 @@ void em28xx_do_i2c_scan(struct em28xx *dev) memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist)); for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { - dev->i2c_client.addr = i; - rc = i2c_master_recv(&dev->i2c_client, &buf, 0); + dev->i2c_client[dev->def_i2c_bus].addr = i; + rc = i2c_master_recv(&dev->i2c_client[dev->def_i2c_bus], &buf, 0); if (rc < 0) continue; i2c_devicelist[i] = i; @@ -675,21 +675,21 @@ int em28xx_i2c_register(struct em28xx *dev) BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg); BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req); - dev->i2c_adap = em28xx_adap_template; - dev->i2c_adap.dev.parent = &dev->udev->dev; - strcpy(dev->i2c_adap.name, dev->name); - dev->i2c_adap.algo_data = dev; - i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev); + dev->i2c_adap[dev->def_i2c_bus] = em28xx_adap_template; + dev->i2c_adap[dev->def_i2c_bus].dev.parent = &dev->udev->dev; + strcpy(dev->i2c_adap[dev->def_i2c_bus].name, dev->name); + dev->i2c_adap[dev->def_i2c_bus].algo_data = dev; + i2c_set_adapdata(&dev->i2c_adap[dev->def_i2c_bus], &dev->v4l2_dev); - retval = i2c_add_adapter(&dev->i2c_adap); + retval = i2c_add_adapter(&dev->i2c_adap[dev->def_i2c_bus]); if (retval < 0) { em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n", __func__, retval); return retval; } - dev->i2c_client = em28xx_client_template; - dev->i2c_client.adapter = &dev->i2c_adap; + dev->i2c_client[dev->def_i2c_bus] = em28xx_client_template; + dev->i2c_client[dev->def_i2c_bus].adapter = &dev->i2c_adap[dev->def_i2c_bus]; retval = em28xx_i2c_eeprom(dev, &dev->eedata, &dev->eedata_len); if ((retval < 0) && (retval != -ENODEV)) { @@ -711,6 +711,6 @@ int em28xx_i2c_register(struct em28xx *dev) */ int em28xx_i2c_unregister(struct em28xx *dev) { - i2c_del_adapter(&dev->i2c_adap); + i2c_del_adapter(&dev->i2c_adap[dev->def_i2c_bus]); return 0; } diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 1bef990b3f18..466b19d0d767 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -280,11 +280,12 @@ static int em2874_polling_getkey(struct em28xx_IR *ir, static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir) { + struct em28xx *dev = ir->dev; static u32 ir_key; int rc; struct i2c_client client; - client.adapter = &ir->dev->i2c_adap; + client.adapter = &ir->dev->i2c_adap[dev->def_i2c_bus]; client.addr = ir->i2c_dev_addr; rc = ir->get_key_i2c(&client, &ir_key); @@ -461,7 +462,7 @@ static int em28xx_probe_i2c_ir(struct em28xx *dev) }; while (addr_list[i] != I2C_CLIENT_END) { - if (i2c_probe_func_quick_read(&dev->i2c_adap, addr_list[i]) == 1) + if (i2c_probe_func_quick_read(&dev->i2c_adap[dev->def_i2c_bus], addr_list[i]) == 1) return addr_list[i]; i++; } diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 2d6d31ace733..5de7b6c93857 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -157,6 +157,9 @@ #define EM28XX_NUM_BUFS 5 #define EM28XX_DVB_NUM_BUFS 5 +/* max number of I2C buses on em28xx devices */ +#define NUM_I2C_BUSES 2 + /* isoc transfers: number of packets for each buffer windows requests only 64 packets .. so we better do the same this is what I found out for all alternate numbers there! @@ -507,10 +510,13 @@ struct em28xx { int tuner_type; /* type of the tuner */ int tuner_addr; /* tuner address */ int tda9887_conf; + /* i2c i/o */ - struct i2c_adapter i2c_adap; - struct i2c_client i2c_client; + struct i2c_adapter i2c_adap[NUM_I2C_BUSES]; + struct i2c_client i2c_client[NUM_I2C_BUSES]; unsigned char eeprom_addrwidth_16bit:1; + int def_i2c_bus; /* Default I2C bus */ + /* video for linux */ int users; /* user count for exclusive use */ int streaming_users; /* Number of actively streaming users */ -- cgit v1.2.3 From 3aa2b3b9cc7cf58d044f30dcad849bff037abd25 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 5 Mar 2013 06:55:27 -0300 Subject: [media] em28xx: Add a separate config dir for secondary bus Prepare to register a separate bus for the second bus. For now, just add a new field. A latter patch will add the bits to make it work. This patch was generated by this script: perl -e 'while (<>) { if (s/EM2874_I2C_SECONDARY_BUS_SELECT.*\n//) { printf "\t\t.def_i2c_bus = 1,\n"; $found = 1; print $_ } else { if ($found) { s/^\s+// }; $found = 0; print $_; } }' \ drivers/media/usb/em28xx/em28xx-cards.c >a && mv a drivers/media/usb/em28xx/em28xx-cards.c Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 43 ++++++++++++++++++--------------- drivers/media/usb/em28xx/em28xx.h | 1 + 2 files changed, 24 insertions(+), 20 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index d81f7ee94c41..16ab4d7780b3 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -958,8 +958,8 @@ struct em28xx_board em28xx_boards[] = { #else .tuner_type = TUNER_ABSENT, #endif - .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | - EM28XX_I2C_CLK_WAIT_ENABLE | + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, [EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C] = { @@ -974,8 +974,8 @@ struct em28xx_board em28xx_boards[] = { .tuner_type = TUNER_ABSENT, #endif .ir_codes = RC_MAP_HAUPPAUGE, - .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | - EM28XX_I2C_CLK_WAIT_ENABLE | + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, [EM2884_BOARD_CINERGY_HTC_STICK] = { @@ -983,8 +983,8 @@ struct em28xx_board em28xx_boards[] = { .has_dvb = 1, .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, .tuner_type = TUNER_ABSENT, - .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | - EM28XX_I2C_CLK_WAIT_ENABLE | + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { @@ -1404,8 +1404,8 @@ struct em28xx_board em28xx_boards[] = { }, [EM2874_BOARD_LEADERSHIP_ISDBT] = { - .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | - EM28XX_I2C_CLK_WAIT_ENABLE | + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ, .xclk = EM28XX_XCLK_FREQUENCY_10MHZ, .name = "EM2874 Leadership ISDBT", @@ -1917,8 +1917,8 @@ struct em28xx_board em28xx_boards[] = { * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */ [EM28174_BOARD_PCTV_290E] = { .name = "PCTV nanoStick T2 290e", - .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | - EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ, + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ, .tuner_type = TUNER_ABSENT, .tuner_gpio = pctv_290e, .has_dvb = 1, @@ -1927,8 +1927,8 @@ struct em28xx_board em28xx_boards[] = { /* 2013:024f PCTV DVB-S2 Stick 460e * Empia EM28174, NXP TDA10071, Conexant CX24118A and Allegro A8293 */ [EM28174_BOARD_PCTV_460E] = { - .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | - EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, .name = "PCTV DVB-S2 Stick (460e)", .tuner_type = TUNER_ABSENT, .tuner_gpio = pctv_460e, @@ -1958,8 +1958,8 @@ struct em28xx_board em28xx_boards[] = { .tuner_type = TUNER_ABSENT, .tuner_gpio = maxmedia_ub425_tc, .has_dvb = 1, - .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | - EM28XX_I2C_CLK_WAIT_ENABLE | + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, /* 2304:0242 PCTV QuatroStick (510e) @@ -1970,8 +1970,8 @@ struct em28xx_board em28xx_boards[] = { .tuner_gpio = pctv_510e, .has_dvb = 1, .ir_codes = RC_MAP_PINNACLE_PCTV_HD, - .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | - EM28XX_I2C_CLK_WAIT_ENABLE | + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, /* 2013:0251 PCTV QuatroStick nano (520e) @@ -1982,8 +1982,8 @@ struct em28xx_board em28xx_boards[] = { .tuner_gpio = pctv_520e, .has_dvb = 1, .ir_codes = RC_MAP_PINNACLE_PCTV_HD, - .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | - EM28XX_I2C_CLK_WAIT_ENABLE | + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, [EM2884_BOARD_TERRATEC_HTC_USB_XS] = { @@ -1991,8 +1991,8 @@ struct em28xx_board em28xx_boards[] = { .has_dvb = 1, .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, .tuner_type = TUNER_ABSENT, - .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | - EM28XX_I2C_CLK_WAIT_ENABLE | + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, }; @@ -2234,6 +2234,9 @@ static inline void em28xx_set_model(struct em28xx *dev) if (!dev->board.i2c_speed) dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ; + + if (dev->board.def_i2c_bus == 1) + dev->board.i2c_speed |= EM2874_I2C_SECONDARY_BUS_SELECT; } diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 5de7b6c93857..43eb1c69e3f2 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -375,6 +375,7 @@ struct em28xx_board { int vchannels; int tuner_type; int tuner_addr; + int def_i2c_bus; /* Default I2C bus */ /* i2c flags */ unsigned int tda9887_conf; -- cgit v1.2.3 From aab3125c43d8fecc7134e5f1e729fabf4dd196da Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 5 Mar 2013 06:55:28 -0300 Subject: [media] em28xx: add support for registering multiple i2c buses Register both buses 0 and 1 via I2C API. For now, bus 0 is used only by eeprom on all known devices. Later patches will be needed if this changes in the future. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 31 ++++++--- drivers/media/usb/em28xx/em28xx-i2c.c | 119 ++++++++++++++++++++++---------- drivers/media/usb/em28xx/em28xx.h | 21 ++++-- 3 files changed, 120 insertions(+), 51 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 16ab4d7780b3..6e62b72376b0 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2235,8 +2235,8 @@ static inline void em28xx_set_model(struct em28xx *dev) dev->board.i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ; - if (dev->board.def_i2c_bus == 1) - dev->board.i2c_speed |= EM2874_I2C_SECONDARY_BUS_SELECT; + /* Should be initialized early, for I2C to work */ + dev->def_i2c_bus = dev->board.def_i2c_bus; } @@ -2642,7 +2642,7 @@ static int em28xx_hint_board(struct em28xx *dev) /* user did not request i2c scanning => do it now */ if (!dev->i2c_hash) - em28xx_do_i2c_scan(dev); + em28xx_do_i2c_scan(dev, dev->def_i2c_bus); for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) { if (dev->i2c_hash == em28xx_i2c_hash[i].hash) { @@ -2953,7 +2953,9 @@ void em28xx_release_resources(struct em28xx *dev) em28xx_release_analog_resources(dev); - em28xx_i2c_unregister(dev); + if (dev->def_i2c_bus) + em28xx_i2c_unregister(dev, 1); + em28xx_i2c_unregister(dev, 0); v4l2_ctrl_handler_free(&dev->ctrl_handler); @@ -3109,14 +3111,25 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, v4l2_ctrl_handler_init(hdl, 8); dev->v4l2_dev.ctrl_handler = hdl; - /* register i2c bus */ - retval = em28xx_i2c_register(dev); + rt_mutex_init(&dev->i2c_bus_lock); + + /* register i2c bus 0 */ + retval = em28xx_i2c_register(dev, 0); if (retval < 0) { - em28xx_errdev("%s: em28xx_i2c_register - error [%d]!\n", + em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n", __func__, retval); goto unregister_dev; } + if (dev->def_i2c_bus) { + retval = em28xx_i2c_register(dev, 1); + if (retval < 0) { + em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n", + __func__, retval); + goto unregister_dev; + } + } + /* * Default format, used for tvp5150 or saa711x output formats */ @@ -3186,7 +3199,9 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, return 0; fail: - em28xx_i2c_unregister(dev); + if (dev->def_i2c_bus) + em28xx_i2c_unregister(dev, 1); + em28xx_i2c_unregister(dev, 0); v4l2_ctrl_handler_free(&dev->ctrl_handler); unregister_dev: diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 9086e57914e6..d4a48cb1202e 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -280,11 +280,29 @@ static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr) static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) { - struct em28xx *dev = i2c_adap->algo_data; + struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data; + struct em28xx *dev = i2c_bus->dev; + unsigned bus = i2c_bus->bus; int addr, rc, i, byte; - if (num <= 0) + rc = rt_mutex_trylock(&dev->i2c_bus_lock); + if (rc < 0) + return rc; + + /* Switch I2C bus if needed */ + if (bus != dev->cur_i2c_bus) { + if (bus == 1) + dev->cur_i2c_bus |= EM2874_I2C_SECONDARY_BUS_SELECT; + else + dev->cur_i2c_bus &= ~EM2874_I2C_SECONDARY_BUS_SELECT; + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->cur_i2c_bus); + dev->cur_i2c_bus = bus; + } + + if (num <= 0) { + rt_mutex_unlock(&dev->i2c_bus_lock); return 0; + } for (i = 0; i < num; i++) { addr = msgs[i].addr << 1; if (i2c_debug) @@ -301,6 +319,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, if (rc == -ENODEV) { if (i2c_debug) printk(" no device\n"); + rt_mutex_unlock(&dev->i2c_bus_lock); return rc; } } else if (msgs[i].flags & I2C_M_RD) { @@ -336,12 +355,14 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, if (rc < 0) { if (i2c_debug) printk(" ERROR: %i\n", rc); + rt_mutex_unlock(&dev->i2c_bus_lock); return rc; } if (i2c_debug) printk("\n"); } + rt_mutex_unlock(&dev->i2c_bus_lock); return num; } @@ -372,8 +393,8 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) /* Helper function to read data blocks from i2c clients with 8 or 16 bit * address width, 8 bit register width and auto incrementation been activated */ -static int em28xx_i2c_read_block(struct em28xx *dev, u16 addr, bool addr_w16, - u16 len, u8 *data) +static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr, + bool addr_w16, u16 len, u8 *data) { int remain = len, rsize, rsize_max, ret; u8 buf[2]; @@ -384,7 +405,7 @@ static int em28xx_i2c_read_block(struct em28xx *dev, u16 addr, bool addr_w16, /* Select address */ buf[0] = addr >> 8; buf[1] = addr & 0xff; - ret = i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], buf + !addr_w16, 1 + addr_w16); + ret = i2c_master_send(&dev->i2c_client[bus], buf + !addr_w16, 1 + addr_w16); if (ret < 0) return ret; /* Read data */ @@ -398,7 +419,7 @@ static int em28xx_i2c_read_block(struct em28xx *dev, u16 addr, bool addr_w16, else rsize = remain; - ret = i2c_master_recv(&dev->i2c_client[dev->def_i2c_bus], data, rsize); + ret = i2c_master_recv(&dev->i2c_client[bus], data, rsize); if (ret < 0) return ret; @@ -409,7 +430,8 @@ static int em28xx_i2c_read_block(struct em28xx *dev, u16 addr, bool addr_w16, return len; } -static int em28xx_i2c_eeprom(struct em28xx *dev, u8 **eedata, u16 *eedata_len) +static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, + u8 **eedata, u16 *eedata_len) { const u16 len = 256; /* FIXME common length/size for bytes to read, to display, hash @@ -422,10 +444,12 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, u8 **eedata, u16 *eedata_len) *eedata = NULL; *eedata_len = 0; - dev->i2c_client[dev->def_i2c_bus].addr = 0xa0 >> 1; + /* EEPROM is always on i2c bus 0 on all known devices. */ + + dev->i2c_client[bus].addr = 0xa0 >> 1; /* Check if board has eeprom */ - err = i2c_master_recv(&dev->i2c_client[dev->def_i2c_bus], &buf, 0); + err = i2c_master_recv(&dev->i2c_client[bus], &buf, 0); if (err < 0) { em28xx_info("board has no eeprom\n"); return -ENODEV; @@ -436,7 +460,8 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, u8 **eedata, u16 *eedata_len) return -ENOMEM; /* Read EEPROM content */ - err = em28xx_i2c_read_block(dev, 0x0000, dev->eeprom_addrwidth_16bit, + err = em28xx_i2c_read_block(dev, bus, 0x0000, + dev->eeprom_addrwidth_16bit, len, data); if (err != len) { em28xx_errdev("failed to read eeprom (err=%d)\n", err); @@ -485,7 +510,8 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, u8 **eedata, u16 *eedata_len) /* Read hardware config dataset offset from address * (microcode start + 46) */ - err = em28xx_i2c_read_block(dev, mc_start + 46, 1, 2, data); + err = em28xx_i2c_read_block(dev, bus, mc_start + 46, 1, 2, + data); if (err != 2) { em28xx_errdev("failed to read hardware configuration data from eeprom (err=%d)\n", err); @@ -501,7 +527,8 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, u8 **eedata, u16 *eedata_len) * the old eeprom and not longer than 256 bytes. * tveeprom is currently also limited to 256 bytes. */ - err = em28xx_i2c_read_block(dev, hwconf_offset, 1, len, data); + err = em28xx_i2c_read_block(dev, bus, hwconf_offset, 1, len, + data); if (err != len) { em28xx_errdev("failed to read hardware configuration data from eeprom (err=%d)\n", err); @@ -590,9 +617,11 @@ error: /* * functionality() */ -static u32 functionality(struct i2c_adapter *adap) +static u32 functionality(struct i2c_adapter *i2c_adap) { - struct em28xx *dev = adap->algo_data; + struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data; + struct em28xx *dev = i2c_bus->dev; + u32 func_flags = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; if (dev->board.is_em2800) func_flags &= ~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA; @@ -643,7 +672,7 @@ static char *i2c_devs[128] = { * do_i2c_scan() * check i2c address range for devices */ -void em28xx_do_i2c_scan(struct em28xx *dev) +void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus) { u8 i2c_devicelist[128]; unsigned char buf; @@ -652,55 +681,66 @@ void em28xx_do_i2c_scan(struct em28xx *dev) memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist)); for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { - dev->i2c_client[dev->def_i2c_bus].addr = i; - rc = i2c_master_recv(&dev->i2c_client[dev->def_i2c_bus], &buf, 0); + dev->i2c_client[bus].addr = i; + rc = i2c_master_recv(&dev->i2c_client[bus], &buf, 0); if (rc < 0) continue; i2c_devicelist[i] = i; - em28xx_info("found i2c device @ 0x%x [%s]\n", - i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + em28xx_info("found i2c device @ 0x%x on bus %d [%s]\n", + i << 1, bus, i2c_devs[i] ? i2c_devs[i] : "???"); } - dev->i2c_hash = em28xx_hash_mem(i2c_devicelist, - ARRAY_SIZE(i2c_devicelist), 32); + if (bus == dev->def_i2c_bus) + dev->i2c_hash = em28xx_hash_mem(i2c_devicelist, + ARRAY_SIZE(i2c_devicelist), 32); } /* * em28xx_i2c_register() * register i2c bus */ -int em28xx_i2c_register(struct em28xx *dev) +int em28xx_i2c_register(struct em28xx *dev, unsigned bus) { int retval; BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg); BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req); - dev->i2c_adap[dev->def_i2c_bus] = em28xx_adap_template; - dev->i2c_adap[dev->def_i2c_bus].dev.parent = &dev->udev->dev; - strcpy(dev->i2c_adap[dev->def_i2c_bus].name, dev->name); - dev->i2c_adap[dev->def_i2c_bus].algo_data = dev; - i2c_set_adapdata(&dev->i2c_adap[dev->def_i2c_bus], &dev->v4l2_dev); - retval = i2c_add_adapter(&dev->i2c_adap[dev->def_i2c_bus]); + if (bus >= NUM_I2C_BUSES) + return -ENODEV; + + dev->i2c_adap[bus] = em28xx_adap_template; + dev->i2c_adap[bus].dev.parent = &dev->udev->dev; + strcpy(dev->i2c_adap[bus].name, dev->name); + + dev->i2c_bus[bus].bus = bus; + dev->i2c_bus[bus].dev = dev; + dev->i2c_adap[bus].algo_data = &dev->i2c_bus[bus]; + i2c_set_adapdata(&dev->i2c_adap[bus], &dev->v4l2_dev); + + retval = i2c_add_adapter(&dev->i2c_adap[bus]); if (retval < 0) { em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n", __func__, retval); return retval; } - dev->i2c_client[dev->def_i2c_bus] = em28xx_client_template; - dev->i2c_client[dev->def_i2c_bus].adapter = &dev->i2c_adap[dev->def_i2c_bus]; + dev->i2c_client[bus] = em28xx_client_template; + dev->i2c_client[bus].adapter = &dev->i2c_adap[bus]; - retval = em28xx_i2c_eeprom(dev, &dev->eedata, &dev->eedata_len); - if ((retval < 0) && (retval != -ENODEV)) { - em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n", - __func__, retval); + /* Up to now, all eeproms are at bus 0 */ + if (!bus) { + retval = em28xx_i2c_eeprom(dev, bus, &dev->eedata, &dev->eedata_len); + if ((retval < 0) && (retval != -ENODEV)) { + em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n", + __func__, retval); - return retval; + return retval; + } } if (i2c_scan) - em28xx_do_i2c_scan(dev); + em28xx_do_i2c_scan(dev, bus); return 0; } @@ -709,8 +749,11 @@ int em28xx_i2c_register(struct em28xx *dev) * em28xx_i2c_unregister() * unregister i2c_bus */ -int em28xx_i2c_unregister(struct em28xx *dev) +int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus) { - i2c_del_adapter(&dev->i2c_adap[dev->def_i2c_bus]); + if (bus >= NUM_I2C_BUSES) + return -ENODEV; + + i2c_del_adapter(&dev->i2c_adap[bus]); return 0; } diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 43eb1c69e3f2..f6ac1df83816 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -375,7 +375,7 @@ struct em28xx_board { int vchannels; int tuner_type; int tuner_addr; - int def_i2c_bus; /* Default I2C bus */ + unsigned def_i2c_bus; /* Default I2C bus */ /* i2c flags */ unsigned int tda9887_conf; @@ -460,6 +460,13 @@ struct em28xx_fh { enum v4l2_buf_type type; }; +struct em28xx_i2c_bus { + struct em28xx *dev; + + unsigned bus; +}; + + /* main device struct */ struct em28xx { /* generic device properties */ @@ -515,8 +522,12 @@ struct em28xx { /* i2c i/o */ struct i2c_adapter i2c_adap[NUM_I2C_BUSES]; struct i2c_client i2c_client[NUM_I2C_BUSES]; + struct em28xx_i2c_bus i2c_bus[NUM_I2C_BUSES]; + unsigned char eeprom_addrwidth_16bit:1; - int def_i2c_bus; /* Default I2C bus */ + unsigned def_i2c_bus; /* Default I2C bus */ + unsigned cur_i2c_bus; /* Current I2C bus */ + struct rt_mutex i2c_bus_lock; /* video for linux */ int users; /* user count for exclusive use */ @@ -638,9 +649,9 @@ struct em28xx_ops { }; /* Provided by em28xx-i2c.c */ -void em28xx_do_i2c_scan(struct em28xx *dev); -int em28xx_i2c_register(struct em28xx *dev); -int em28xx_i2c_unregister(struct em28xx *dev); +void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus); +int em28xx_i2c_register(struct em28xx *dev, unsigned bus); +int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus); /* Provided by em28xx-core.c */ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, -- cgit v1.2.3 From 195281d0dc6a2fc1824d5da9abd2924bce0fa698 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sat, 9 Mar 2013 06:53:01 -0300 Subject: [media] em28xx: set the timestamp type for video and vbi vb2_queues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The em28xx driver obtains the timestamps using function v4l2_get_timestamp(), which produces a montonic timestamp. Fixes the warnings appearing in the system log since commit 6aa69f99 "[media] vb2: Add support for non monotonic timestamps" Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 93fc6204df6c..d585c19a5d9c 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -700,6 +700,7 @@ int em28xx_vb2_setup(struct em28xx *dev) q = &dev->vb_vidq; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->drv_priv = dev; q->buf_struct_size = sizeof(struct em28xx_buffer); q->ops = &em28xx_video_qops; @@ -713,6 +714,7 @@ int em28xx_vb2_setup(struct em28xx *dev) q = &dev->vb_vbiq; q->type = V4L2_BUF_TYPE_VBI_CAPTURE; q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->drv_priv = dev; q->buf_struct_size = sizeof(struct em28xx_buffer); q->ops = &em28xx_vbi_qops; -- cgit v1.2.3 From 7f6301d1257505d35e87ef1cb8eeee268e63a123 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 10 Mar 2013 07:25:25 -0300 Subject: [media] em28xx-i2c: relax error check in em28xx_i2c_recv_bytes() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It turned out that some devices return less bytes then requested via i2c when ALL of the following 3 conditions are met: - i2c bus B is used - there was no attempt to write to the specified slave address before - no device present at the specified slave address With the current code, this triggers an -EIO error and prints a message to the system log. Because it can happen very often during device probing, it is better to ignore this error and bail out silently after the follwing i2c transaction success check with -ENODEV. [mchehab@redhat.com: a small CodingStyle fix] Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index d4a48cb1202e..de9b2086ab2d 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -227,18 +227,18 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) /* Read data from i2c device */ ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); - if (ret != len) { - if (ret < 0) { - em28xx_warn("reading from i2c device at 0x%x failed " - "(error=%i)\n", addr, ret); - return ret; - } else { - em28xx_warn("%i bytes requested from i2c device at " - "0x%x, but %i bytes received\n", - len, addr, ret); - return -EIO; - } + if (ret < 0) { + em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n", + addr, ret); + return ret; } + /* NOTE: some devices with two i2c busses have the bad habit to return 0 + * bytes if we are on bus B AND there was no write attempt to the + * specified slave address before AND no device is present at the + * requested slave address. + * Anyway, the next check will fail with -ENODEV in this case, so avoid + * spamming the system log on device probing and do nothing here. + */ /* Check success of the i2c operation */ ret = dev->em28xx_read_reg(dev, 0x05); -- cgit v1.2.3 From be431b16c6bd22020abc5f5f30a89f1e2934de8e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 18 Mar 2013 15:25:36 -0300 Subject: [media] dvb-frontend: split set_delivery_system() This function is complex, and has different workflows, one for DVBv3 calls, and another one for DVBv5 calls. Break it into 3 functions, in order to make easier to understand what each block does. No functional changes so far. A few comments got improved. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 294 +++++++++++++++++++--------------- 1 file changed, 165 insertions(+), 129 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 6e50a7581568..d0d193d1404a 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1509,132 +1509,12 @@ static bool is_dvbv3_delsys(u32 delsys) return status; } -static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system) +static int emulate_delivery_system(struct dvb_frontend *fe, + enum dvbv3_emulation_type type, + u32 delsys, u32 desired_system) { - int ncaps, i; - u32 delsys = SYS_UNDEFINED; + int i; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - enum dvbv3_emulation_type type; - - /* - * It was reported that some old DVBv5 applications were - * filling delivery_system with SYS_UNDEFINED. If this happens, - * assume that the application wants to use the first supported - * delivery system. - */ - if (c->delivery_system == SYS_UNDEFINED) - c->delivery_system = fe->ops.delsys[0]; - - if (desired_system == SYS_UNDEFINED) { - /* - * A DVBv3 call doesn't know what's the desired system. - * Also, DVBv3 applications don't know that ops.info->type - * could be changed, and they simply dies when it doesn't - * match. - * So, don't change the current delivery system, as it - * may be trying to do the wrong thing, like setting an - * ISDB-T frontend as DVB-T. Instead, find the closest - * DVBv3 system that matches the delivery system. - */ - if (is_dvbv3_delsys(c->delivery_system)) { - dev_dbg(fe->dvb->device, - "%s: Using delivery system to %d\n", - __func__, c->delivery_system); - return 0; - } - type = dvbv3_type(c->delivery_system); - switch (type) { - case DVBV3_QPSK: - desired_system = SYS_DVBS; - break; - case DVBV3_QAM: - desired_system = SYS_DVBC_ANNEX_A; - break; - case DVBV3_ATSC: - desired_system = SYS_ATSC; - break; - case DVBV3_OFDM: - desired_system = SYS_DVBT; - break; - default: - dev_dbg(fe->dvb->device, "%s: This frontend doesn't support DVBv3 calls\n", - __func__); - return -EINVAL; - } - /* - * Get a delivery system that is compatible with DVBv3 - * NOTE: in order for this to work with softwares like Kaffeine that - * uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to - * DVB-S, drivers that support both should put the SYS_DVBS entry - * before the SYS_DVBS2, otherwise it won't switch back to DVB-S. - * The real fix is that userspace applications should not use DVBv3 - * and not trust on calling FE_SET_FRONTEND to switch the delivery - * system. - */ - ncaps = 0; - while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { - if (fe->ops.delsys[ncaps] == desired_system) { - delsys = desired_system; - break; - } - ncaps++; - } - if (delsys == SYS_UNDEFINED) { - dev_dbg(fe->dvb->device, "%s: Couldn't find a delivery system that matches %d\n", - __func__, desired_system); - } - } else { - /* - * This is a DVBv5 call. So, it likely knows the supported - * delivery systems. - */ - - /* Check if the desired delivery system is supported */ - ncaps = 0; - while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { - if (fe->ops.delsys[ncaps] == desired_system) { - c->delivery_system = desired_system; - dev_dbg(fe->dvb->device, - "%s: Changing delivery system to %d\n", - __func__, desired_system); - return 0; - } - ncaps++; - } - type = dvbv3_type(desired_system); - - /* - * The delivery system is not supported. See if it can be - * emulated. - * The emulation only works if the desired system is one of the - * DVBv3 delivery systems - */ - if (!is_dvbv3_delsys(desired_system)) { - dev_dbg(fe->dvb->device, - "%s: can't use a DVBv3 FE_SET_FRONTEND call on this frontend\n", - __func__); - return -EINVAL; - } - - /* - * Get the last non-DVBv3 delivery system that has the same type - * of the desired system - */ - ncaps = 0; - while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { - if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) && - !is_dvbv3_delsys(fe->ops.delsys[ncaps])) - delsys = fe->ops.delsys[ncaps]; - ncaps++; - } - /* There's nothing compatible with the desired delivery system */ - if (delsys == SYS_UNDEFINED) { - dev_dbg(fe->dvb->device, - "%s: Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n", - __func__); - return -EINVAL; - } - } c->delivery_system = delsys; @@ -1648,8 +1528,8 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system) * delivery system is the last one at the ops.delsys[] array */ dev_dbg(fe->dvb->device, - "%s: Using delivery system %d emulated as if it were a %d\n", - __func__, delsys, desired_system); + "%s: Using delivery system %d emulated as if it were a %d\n", + __func__, delsys, desired_system); /* * For now, handles ISDB-T calls. More code may be needed here for the @@ -1684,6 +1564,162 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system) return 0; } +static int dvbv5_set_delivery_system(struct dvb_frontend *fe, + u32 desired_system) +{ + int ncaps; + u32 delsys = SYS_UNDEFINED; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + enum dvbv3_emulation_type type; + + /* + * It was reported that some old DVBv5 applications were + * filling delivery_system with SYS_UNDEFINED. If this happens, + * assume that the application wants to use the first supported + * delivery system. + */ + if (c->delivery_system == SYS_UNDEFINED) + c->delivery_system = fe->ops.delsys[0]; + + /* + * This is a DVBv5 call. So, it likely knows the supported + * delivery systems. + */ + + /* Check if the desired delivery system is supported */ + ncaps = 0; + while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { + if (fe->ops.delsys[ncaps] == desired_system) { + c->delivery_system = desired_system; + dev_dbg(fe->dvb->device, + "%s: Changing delivery system to %d\n", + __func__, desired_system); + return 0; + } + ncaps++; + } + + /* + * Need to emulate a delivery system + */ + + type = dvbv3_type(desired_system); + + /* + * The delivery system is not supported. See if it can be + * emulated. + * The emulation only works if the desired system is one of the + * DVBv3 delivery systems + */ + if (!is_dvbv3_delsys(desired_system)) { + dev_dbg(fe->dvb->device, + "%s: can't use a DVBv3 FE_SET_FRONTEND call for this frontend\n", + __func__); + return -EINVAL; + } + + /* + * Get the last non-DVBv3 delivery system that has the same type + * of the desired system + */ + ncaps = 0; + while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { + if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) && + !is_dvbv3_delsys(fe->ops.delsys[ncaps])) + delsys = fe->ops.delsys[ncaps]; + ncaps++; + } + /* There's nothing compatible with the desired delivery system */ + if (delsys == SYS_UNDEFINED) { + dev_dbg(fe->dvb->device, + "%s: Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n", + __func__); + return -EINVAL; + } + + return emulate_delivery_system(fe, type, delsys, desired_system); +} + +static int dvbv3_set_delivery_system(struct dvb_frontend *fe) +{ + int ncaps; + u32 desired_system; + u32 delsys = SYS_UNDEFINED; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + enum dvbv3_emulation_type type; + + /* If not set yet, defaults to the first supported delivery system */ + if (c->delivery_system == SYS_UNDEFINED) + c->delivery_system = fe->ops.delsys[0]; + + /* + * A DVBv3 call doesn't know what's the desired system. + * Also, DVBv3 applications don't know that ops.info->type + * could be changed, and they simply don't tune when it doesn't + * match. + * So, don't change the current delivery system, as it + * may be trying to do the wrong thing, like setting an + * ISDB-T frontend as DVB-T. Instead, find the closest + * DVBv3 system that matches the delivery system. + */ + + /* + * Trivial case: just use the current one, if it already a DVBv3 + * delivery system + */ + if (is_dvbv3_delsys(c->delivery_system)) { + dev_dbg(fe->dvb->device, + "%s: Using delivery system to %d\n", + __func__, c->delivery_system); + return 0; + } + + /* Convert from DVBv3 into DVBv5 namespace */ + type = dvbv3_type(c->delivery_system); + switch (type) { + case DVBV3_QPSK: + desired_system = SYS_DVBS; + break; + case DVBV3_QAM: + desired_system = SYS_DVBC_ANNEX_A; + break; + case DVBV3_ATSC: + desired_system = SYS_ATSC; + break; + case DVBV3_OFDM: + desired_system = SYS_DVBT; + break; + default: + dev_dbg(fe->dvb->device, "%s: This frontend doesn't support DVBv3 calls\n", + __func__); + return -EINVAL; + } + + /* + * Get a delivery system that is compatible with DVBv3 + * NOTE: in order for this to work with softwares like Kaffeine that + * uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to + * DVB-S, drivers that support both should put the SYS_DVBS entry + * before the SYS_DVBS2, otherwise it won't switch back to DVB-S. + * The real fix is that userspace applications should not use DVBv3 + * and not trust on calling FE_SET_FRONTEND to switch the delivery + * system. + */ + ncaps = 0; + while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { + if (fe->ops.delsys[ncaps] == desired_system) { + delsys = desired_system; + break; + } + ncaps++; + } + if (delsys == SYS_UNDEFINED) { + dev_dbg(fe->dvb->device, "%s: Couldn't find a delivery system that matches %d\n", + __func__, desired_system); + } + return emulate_delivery_system(fe, type, delsys, desired_system); +} + static int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, struct file *file) @@ -1742,7 +1778,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe, c->rolloff = tvp->u.data; break; case DTV_DELIVERY_SYSTEM: - r = set_delivery_system(fe, tvp->u.data); + r = dvbv5_set_delivery_system(fe, tvp->u.data); break; case DTV_VOLTAGE: c->voltage = tvp->u.data; @@ -2335,7 +2371,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, break; case FE_SET_FRONTEND: - err = set_delivery_system(fe, SYS_UNDEFINED); + err = dvbv3_set_delivery_system(fe); if (err) break; @@ -2594,7 +2630,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb, * first supported delivery system (ops->delsys[0]) */ - fe->dtv_property_cache.delivery_system = fe->ops.delsys[0]; + fe->dtv_property_cache.delivery_system = fe->ops.delsys[0]; dvb_frontend_clear_cache(fe); mutex_unlock(&frontend_mutex); -- cgit v1.2.3 From 52dee392f491e166cef21c787d1736f052a902cd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 18 Mar 2013 15:25:37 -0300 Subject: [media] dvb_frontend: Simplify the emulation logic The current logic was broken and too complex; while it works fine for DVB-S2/DVB-S, it is broken for ISDB-T. Make the logic simpler, fixes it for ISDB-T and make it clearer. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 219 +++++++++++++++++----------------- 1 file changed, 109 insertions(+), 110 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index d0d193d1404a..eaa0a74e6a87 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1509,9 +1509,17 @@ static bool is_dvbv3_delsys(u32 delsys) return status; } -static int emulate_delivery_system(struct dvb_frontend *fe, - enum dvbv3_emulation_type type, - u32 delsys, u32 desired_system) +/** + * emulate_delivery_system - emulate a DVBv5 delivery system with a DVBv3 type + * @fe: struct frontend; + * @delsys: DVBv5 type that will be used for emulation + * + * Provides emulation for delivery systems that are compatible with the old + * DVBv3 call. Among its usages, it provices support for ISDB-T, and allows + * using a DVB-S2 only frontend just like it were a DVB-S, if the frontent + * parameters are compatible with DVB-S spec. + */ +static int emulate_delivery_system(struct dvb_frontend *fe, u32 delsys) { int i; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -1519,51 +1527,52 @@ static int emulate_delivery_system(struct dvb_frontend *fe, c->delivery_system = delsys; /* - * The DVBv3 or DVBv5 call is requesting a different system. So, - * emulation is needed. - * - * Emulate newer delivery systems like ISDBT, DVBT and DTMB - * for older DVBv5 applications. The emulation will try to use - * the auto mode for most things, and will assume that the desired - * delivery system is the last one at the ops.delsys[] array + * If the call is for ISDB-T, put it into full-seg, auto mode, TV */ - dev_dbg(fe->dvb->device, - "%s: Using delivery system %d emulated as if it were a %d\n", - __func__, delsys, desired_system); + if (c->delivery_system == SYS_ISDBT) { + dev_dbg(fe->dvb->device, + "%s: Using defaults for SYS_ISDBT\n", + __func__); - /* - * For now, handles ISDB-T calls. More code may be needed here for the - * other emulated stuff - */ - if (type == DVBV3_OFDM) { - if (c->delivery_system == SYS_ISDBT) { - dev_dbg(fe->dvb->device, - "%s: Using defaults for SYS_ISDBT\n", - __func__); - - if (!c->bandwidth_hz) - c->bandwidth_hz = 6000000; - - c->isdbt_partial_reception = 0; - c->isdbt_sb_mode = 0; - c->isdbt_sb_subchannel = 0; - c->isdbt_sb_segment_idx = 0; - c->isdbt_sb_segment_count = 0; - c->isdbt_layer_enabled = 0; - for (i = 0; i < 3; i++) { - c->layer[i].fec = FEC_AUTO; - c->layer[i].modulation = QAM_AUTO; - c->layer[i].interleaving = 0; - c->layer[i].segment_count = 0; - } + if (!c->bandwidth_hz) + c->bandwidth_hz = 6000000; + + c->isdbt_partial_reception = 0; + c->isdbt_sb_mode = 0; + c->isdbt_sb_subchannel = 0; + c->isdbt_sb_segment_idx = 0; + c->isdbt_sb_segment_count = 0; + c->isdbt_layer_enabled = 7; + for (i = 0; i < 3; i++) { + c->layer[i].fec = FEC_AUTO; + c->layer[i].modulation = QAM_AUTO; + c->layer[i].interleaving = 0; + c->layer[i].segment_count = 0; } } dev_dbg(fe->dvb->device, "%s: change delivery system on cache to %d\n", - __func__, c->delivery_system); + __func__, c->delivery_system); return 0; } +/** + * dvbv5_set_delivery_system - Sets the delivery system for a DVBv5 API call + * @fe: frontend struct + * @desired_system: delivery system requested by the user + * + * A DVBv5 call know what's the desired system it wants. So, set it. + * + * There are, however, a few known issues with early DVBv5 applications that + * are also handled by this logic: + * + * 1) Some early apps use SYS_UNDEFINED as the desired delivery system. + * This is an API violation, but, as we don't want to break userspace, + * convert it to the first supported delivery system. + * 2) Some apps might be using a DVBv5 call in a wrong way, passing, for + * example, SYS_DVBT instead of SYS_ISDBT. This is because early usage of + * ISDB-T provided backward compat with DVB-T. + */ static int dvbv5_set_delivery_system(struct dvb_frontend *fe, u32 desired_system) { @@ -1578,15 +1587,14 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe, * assume that the application wants to use the first supported * delivery system. */ - if (c->delivery_system == SYS_UNDEFINED) - c->delivery_system = fe->ops.delsys[0]; + if (desired_system == SYS_UNDEFINED) + desired_system = fe->ops.delsys[0]; /* - * This is a DVBv5 call. So, it likely knows the supported - * delivery systems. - */ - - /* Check if the desired delivery system is supported */ + * This is a DVBv5 call. So, it likely knows the supported + * delivery systems. So, check if the desired delivery system is + * supported + */ ncaps = 0; while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { if (fe->ops.delsys[ncaps] == desired_system) { @@ -1600,69 +1608,85 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe, } /* - * Need to emulate a delivery system + * The requested delivery system isn't supported. Maybe userspace + * is requesting a DVBv3 compatible delivery system. + * + * The emulation only works if the desired system is one of the + * delivery systems supported by DVBv3 API */ - - type = dvbv3_type(desired_system); - - /* - * The delivery system is not supported. See if it can be - * emulated. - * The emulation only works if the desired system is one of the - * DVBv3 delivery systems - */ if (!is_dvbv3_delsys(desired_system)) { dev_dbg(fe->dvb->device, - "%s: can't use a DVBv3 FE_SET_FRONTEND call for this frontend\n", - __func__); + "%s: Delivery system %d not supported.\n", + __func__, desired_system); return -EINVAL; } + type = dvbv3_type(desired_system); + /* * Get the last non-DVBv3 delivery system that has the same type * of the desired system */ ncaps = 0; while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { - if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) && - !is_dvbv3_delsys(fe->ops.delsys[ncaps])) + if (dvbv3_type(fe->ops.delsys[ncaps]) == type) delsys = fe->ops.delsys[ncaps]; ncaps++; } + /* There's nothing compatible with the desired delivery system */ if (delsys == SYS_UNDEFINED) { dev_dbg(fe->dvb->device, - "%s: Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n", - __func__); + "%s: Delivery system %d not supported on emulation mode.\n", + __func__, desired_system); return -EINVAL; } - return emulate_delivery_system(fe, type, delsys, desired_system); + dev_dbg(fe->dvb->device, + "%s: Using delivery system %d emulated as if it were %d\n", + __func__, delsys, desired_system); + + return emulate_delivery_system(fe, desired_system); } +/** + * dvbv3_set_delivery_system - Sets the delivery system for a DVBv3 API call + * @fe: frontend struct + * + * A DVBv3 call doesn't know what's the desired system it wants. It also + * doesn't allow to switch between different types. Due to that, userspace + * should use DVBv5 instead. + * However, in order to avoid breaking userspace API, limited backward + * compatibility support is provided. + * + * There are some delivery systems that are incompatible with DVBv3 calls. + * + * This routine should work fine for frontends that support just one delivery + * system. + * + * For frontends that support multiple frontends: + * 1) It defaults to use the first supported delivery system. There's an + * userspace application that allows changing it at runtime; + * + * 2) If the current delivery system is not compatible with DVBv3, it gets + * the first one that it is compatible. + * + * NOTE: in order for this to work with applications like Kaffeine that + * uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to + * DVB-S, drivers that support both DVB-S and DVB-S2 should have the + * SYS_DVBS entry before the SYS_DVBS2, otherwise it won't switch back + * to DVB-S. + */ static int dvbv3_set_delivery_system(struct dvb_frontend *fe) { int ncaps; - u32 desired_system; u32 delsys = SYS_UNDEFINED; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - enum dvbv3_emulation_type type; /* If not set yet, defaults to the first supported delivery system */ if (c->delivery_system == SYS_UNDEFINED) c->delivery_system = fe->ops.delsys[0]; - /* - * A DVBv3 call doesn't know what's the desired system. - * Also, DVBv3 applications don't know that ops.info->type - * could be changed, and they simply don't tune when it doesn't - * match. - * So, don't change the current delivery system, as it - * may be trying to do the wrong thing, like setting an - * ISDB-T frontend as DVB-T. Instead, find the closest - * DVBv3 system that matches the delivery system. - */ - /* * Trivial case: just use the current one, if it already a DVBv3 * delivery system @@ -1674,50 +1698,25 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe) return 0; } - /* Convert from DVBv3 into DVBv5 namespace */ - type = dvbv3_type(c->delivery_system); - switch (type) { - case DVBV3_QPSK: - desired_system = SYS_DVBS; - break; - case DVBV3_QAM: - desired_system = SYS_DVBC_ANNEX_A; - break; - case DVBV3_ATSC: - desired_system = SYS_ATSC; - break; - case DVBV3_OFDM: - desired_system = SYS_DVBT; - break; - default: - dev_dbg(fe->dvb->device, "%s: This frontend doesn't support DVBv3 calls\n", - __func__); - return -EINVAL; - } - /* - * Get a delivery system that is compatible with DVBv3 - * NOTE: in order for this to work with softwares like Kaffeine that - * uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to - * DVB-S, drivers that support both should put the SYS_DVBS entry - * before the SYS_DVBS2, otherwise it won't switch back to DVB-S. - * The real fix is that userspace applications should not use DVBv3 - * and not trust on calling FE_SET_FRONTEND to switch the delivery - * system. + * Seek for the first delivery system that it is compatible with a + * DVBv3 standard */ ncaps = 0; while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { - if (fe->ops.delsys[ncaps] == desired_system) { - delsys = desired_system; + if (dvbv3_type(fe->ops.delsys[ncaps]) != DVBV3_UNKNOWN) { + delsys = fe->ops.delsys[ncaps]; break; } ncaps++; } if (delsys == SYS_UNDEFINED) { - dev_dbg(fe->dvb->device, "%s: Couldn't find a delivery system that matches %d\n", - __func__, desired_system); + dev_dbg(fe->dvb->device, + "%s: Couldn't find a delivery system that works with FE_SET_FRONTEND\n", + __func__); + return -EINVAL; } - return emulate_delivery_system(fe, type, delsys, desired_system); + return emulate_delivery_system(fe, delsys); } static int dtv_property_process_set(struct dvb_frontend *fe, -- cgit v1.2.3 From cab3e1ffbe1b9c7a607506338f590dc1e6ca9909 Mon Sep 17 00:00:00 2001 From: Peter Senna Tschudin Date: Mon, 17 Sep 2012 04:04:58 -0300 Subject: [media] cx25821: Cleanup filename assignment code I'm pasting the original code and my proposal on the commit message for make it easy to compare the two versions. Line 62 of cx25821-audio-upstream.h contains: char *_defaultAudioName = "/root/audioGOOD.wav"; Original code after replace kmemdup for kstrdup, and after fix return error code: if (dev->input_audiofilename) { dev->_audiofilename = kstrdup(dev->input_audiofilename, GFP_KERNEL); if (!dev->_audiofilename) { err = -ENOMEM; goto error; } /* Default if filename is empty string */ if (strcmp(dev->input_audiofilename, "") == 0) dev->_audiofilename = "/root/audioGOOD.wav"; } else { dev->_audiofilename = kstrdup(_defaultAudioName, GFP_KERNEL); if (!dev->_audiofilename) { err = -ENOMEM; goto error; } } Code proposed in this patch: if ((dev->input_audiofilename) && (strcmp(dev->input_audiofilename, "") != 0)) dev->_audiofilename = kstrdup(dev->input_audiofilename, GFP_KERNEL); else dev->_audiofilename = kstrdup(_defaultAudioName, GFP_KERNEL); if (!dev->_audiofilename) { err = -ENOMEM; goto error; } Signed-off-by: Peter Senna Tschudin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-audio-upstream.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-audio-upstream.c b/drivers/media/pci/cx25821/cx25821-audio-upstream.c index 87491ca05ee5..ea973202a66c 100644 --- a/drivers/media/pci/cx25821/cx25821-audio-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-audio-upstream.c @@ -728,26 +728,17 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) dev->_audio_lines_count = LINES_PER_AUDIO_BUFFER; _line_size = AUDIO_LINE_SIZE; - if (dev->input_audiofilename) { + if ((dev->input_audiofilename) && + (strcmp(dev->input_audiofilename, "") != 0)) dev->_audiofilename = kstrdup(dev->input_audiofilename, GFP_KERNEL); - - if (!dev->_audiofilename) { - err = -ENOMEM; - goto error; - } - - /* Default if filename is empty string */ - if (strcmp(dev->input_audiofilename, "") == 0) - dev->_audiofilename = "/root/audioGOOD.wav"; - } else { + else dev->_audiofilename = kstrdup(_defaultAudioName, GFP_KERNEL); - if (!dev->_audiofilename) { - err = -ENOMEM; - goto error; - } + if (!dev->_audiofilename) { + err = -ENOMEM; + goto error; } cx25821_sram_channel_setup_upstream_audio(dev, sram_ch, -- cgit v1.2.3 From c6c1d50b51e76b57fbf0651d38a7ae0c3fb9d5cc Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 22 Jan 2013 12:27:55 -0300 Subject: [media] media: Add 64--32 bit compat ioctl handler Provide an ioctl handler for 32-bit binaries on 64-bit systems. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Tested-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-devnode.c | 31 ++++++++++++++++++++++++++++--- include/media/media-devnode.h | 1 + 2 files changed, 29 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index 023b2a1cbb9b..fb0f0469fad7 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -116,19 +116,41 @@ static unsigned int media_poll(struct file *filp, return mdev->fops->poll(filp, poll); } -static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +static long +__media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, + long (*ioctl_func)(struct file *filp, unsigned int cmd, + unsigned long arg)) { struct media_devnode *mdev = media_devnode_data(filp); - if (!mdev->fops->ioctl) + if (!ioctl_func) return -ENOTTY; if (!media_devnode_is_registered(mdev)) return -EIO; - return mdev->fops->ioctl(filp, cmd, arg); + return ioctl_func(filp, cmd, arg); +} + +static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct media_devnode *mdev = media_devnode_data(filp); + + return __media_ioctl(filp, cmd, arg, mdev->fops->ioctl); } +#ifdef CONFIG_COMPAT + +static long media_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct media_devnode *mdev = media_devnode_data(filp); + + return __media_ioctl(filp, cmd, arg, mdev->fops->compat_ioctl); +} + +#endif /* CONFIG_COMPAT */ + /* Override for the open function */ static int media_open(struct inode *inode, struct file *filp) { @@ -188,6 +210,9 @@ static const struct file_operations media_devnode_fops = { .write = media_write, .open = media_open, .unlocked_ioctl = media_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = media_compat_ioctl, +#endif /* CONFIG_COMPAT */ .release = media_release, .poll = media_poll, .llseek = no_llseek, diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h index f6caafc874cb..3446af279fca 100644 --- a/include/media/media-devnode.h +++ b/include/media/media-devnode.h @@ -46,6 +46,7 @@ struct media_file_operations { ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); unsigned int (*poll) (struct file *, struct poll_table_struct *); long (*ioctl) (struct file *, unsigned int, unsigned long); + long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*open) (struct file *); int (*release) (struct file *); }; -- cgit v1.2.3 From b0a1f2a8420782ccb83fb4f68df37af642790560 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 22 Jan 2013 12:27:56 -0300 Subject: [media] media: implement 32-on-64 bit compat IOCTL handling Use the same handlers where the structs are the same. Implement a new handler for link enumeration since struct media_links_enum is different on 32-bit and 64-bit systems. Signed-off-by: Sakari Ailus Acked-by: Laurent Pinchart Tested-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 102 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 13 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index d01fcb7e87c2..99b80b6f7f67 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -20,10 +20,11 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include +#include #include #include -#include +#include #include #include @@ -124,35 +125,31 @@ static void media_device_kpad_to_upad(const struct media_pad *kpad, upad->flags = kpad->flags; } -static long media_device_enum_links(struct media_device *mdev, - struct media_links_enum __user *ulinks) +static long __media_device_enum_links(struct media_device *mdev, + struct media_links_enum *links) { struct media_entity *entity; - struct media_links_enum links; - if (copy_from_user(&links, ulinks, sizeof(links))) - return -EFAULT; - - entity = find_entity(mdev, links.entity); + entity = find_entity(mdev, links->entity); if (entity == NULL) return -EINVAL; - if (links.pads) { + if (links->pads) { unsigned int p; for (p = 0; p < entity->num_pads; p++) { struct media_pad_desc pad; media_device_kpad_to_upad(&entity->pads[p], &pad); - if (copy_to_user(&links.pads[p], &pad, sizeof(pad))) + if (copy_to_user(&links->pads[p], &pad, sizeof(pad))) return -EFAULT; } } - if (links.links) { + if (links->links) { struct media_link_desc __user *ulink; unsigned int l; - for (l = 0, ulink = links.links; l < entity->num_links; l++) { + for (l = 0, ulink = links->links; l < entity->num_links; l++) { struct media_link_desc link; /* Ignore backlinks. */ @@ -169,8 +166,26 @@ static long media_device_enum_links(struct media_device *mdev, ulink++; } } + + return 0; +} + +static long media_device_enum_links(struct media_device *mdev, + struct media_links_enum __user *ulinks) +{ + struct media_links_enum links; + int rval; + + if (copy_from_user(&links, ulinks, sizeof(links))) + return -EFAULT; + + rval = __media_device_enum_links(mdev, &links); + if (rval < 0) + return rval; + if (copy_to_user(ulinks, &links, sizeof(*ulinks))) return -EFAULT; + return 0; } @@ -251,10 +266,71 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, return ret; } +#ifdef CONFIG_COMPAT + +struct media_links_enum32 { + __u32 entity; + compat_uptr_t pads; /* struct media_pad_desc * */ + compat_uptr_t links; /* struct media_link_desc * */ + __u32 reserved[4]; +}; + +static long media_device_enum_links32(struct media_device *mdev, + struct media_links_enum32 __user *ulinks) +{ + struct media_links_enum links; + compat_uptr_t pads_ptr, links_ptr; + + memset(&links, 0, sizeof(links)); + + if (get_user(links.entity, &ulinks->entity) + || get_user(pads_ptr, &ulinks->pads) + || get_user(links_ptr, &ulinks->links)) + return -EFAULT; + + links.pads = compat_ptr(pads_ptr); + links.links = compat_ptr(links_ptr); + + return __media_device_enum_links(mdev, &links); +} + +#define MEDIA_IOC_ENUM_LINKS32 _IOWR('|', 0x02, struct media_links_enum32) + +static long media_device_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct media_devnode *devnode = media_devnode_data(filp); + struct media_device *dev = to_media_device(devnode); + long ret; + + switch (cmd) { + case MEDIA_IOC_DEVICE_INFO: + case MEDIA_IOC_ENUM_ENTITIES: + case MEDIA_IOC_SETUP_LINK: + return media_device_ioctl(filp, cmd, arg); + + case MEDIA_IOC_ENUM_LINKS32: + mutex_lock(&dev->graph_mutex); + ret = media_device_enum_links32(dev, + (struct media_links_enum32 __user *)arg); + mutex_unlock(&dev->graph_mutex); + break; + + default: + ret = -ENOIOCTLCMD; + } + + return ret; +} +#endif /* CONFIG_COMPAT */ + static const struct media_file_operations media_device_fops = { .owner = THIS_MODULE, .open = media_device_open, .ioctl = media_device_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = media_device_compat_ioctl, +#endif /* CONFIG_COMPAT */ .release = media_device_close, }; -- cgit v1.2.3 From f1a0569be680a1bfb9d624cc4893cba0c6ad4172 Mon Sep 17 00:00:00 2001 From: John Sheu Date: Wed, 6 Feb 2013 20:03:00 -0300 Subject: [media] v4l2-mem2mem: use CAPTURE queue lock In v4l2_m2m_try_schedule(), use the CAPTURE queue lock when accessing the CAPTURE queue, instead of relying on just holding the OUTPUT queue lock. Signed-off-by: John Sheu Acked-by: Pawel Osciak Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-mem2mem.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index da99cf727162..27ddb3d15251 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -230,12 +230,15 @@ static void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx) dprintk("No input buffers available\n"); return; } + spin_lock_irqsave(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags); if (list_empty(&m2m_ctx->cap_q_ctx.rdy_queue)) { + spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags); spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags); spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); dprintk("No output buffers available\n"); return; } + spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags); spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags); if (m2m_dev->m2m_ops->job_ready -- cgit v1.2.3 From 401f6a2729988c7229c3a78bba0d2f73851e3f51 Mon Sep 17 00:00:00 2001 From: John Sheu Date: Wed, 6 Feb 2013 20:03:01 -0300 Subject: [media] v4l2-mem2mem: drop rdy_queue on STREAMOFF When a v4l2-mem2mem context gets a STREAMOFF call on either its CAPTURE or OUTPUT queues, we should: * Drop the corresponding rdy_queue, since a subsequent STREAMON expects an empty queue. * Deschedule the context, as it now has at least one empty queue and cannot run. Signed-off-by: John Sheu Acked-by: Pawel Osciak Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-mem2mem.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 27ddb3d15251..66f599fcb829 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -408,10 +408,35 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_streamon); int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type) { - struct vb2_queue *vq; + struct v4l2_m2m_dev *m2m_dev; + struct v4l2_m2m_queue_ctx *q_ctx; + unsigned long flags_job, flags; + int ret; - vq = v4l2_m2m_get_vq(m2m_ctx, type); - return vb2_streamoff(vq, type); + q_ctx = get_queue_ctx(m2m_ctx, type); + ret = vb2_streamoff(&q_ctx->q, type); + if (ret) + return ret; + + m2m_dev = m2m_ctx->m2m_dev; + spin_lock_irqsave(&m2m_dev->job_spinlock, flags_job); + /* We should not be scheduled anymore, since we're dropping a queue. */ + INIT_LIST_HEAD(&m2m_ctx->queue); + m2m_ctx->job_flags = 0; + + spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); + /* Drop queue, since streamoff returns device to the same state as after + * calling reqbufs. */ + INIT_LIST_HEAD(&q_ctx->rdy_queue); + spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags); + + if (m2m_dev->curr_ctx == m2m_ctx) { + m2m_dev->curr_ctx = NULL; + wake_up(&m2m_ctx->finished); + } + spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job); + + return 0; } EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff); -- cgit v1.2.3 From 4159d01bea38ee82f6e49383b7e73e328c118755 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 28 Feb 2013 10:35:56 -0300 Subject: [media] em28xx: Add ISDB support for c3tech Digital duo This is an hybrid board. However, for analog, it requires a new driver for saa7136. So, for now, let's just add support for Digital TV. Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.em28xx | 1 + drivers/media/usb/em28xx/Kconfig | 1 + drivers/media/usb/em28xx/em28xx-cards.c | 24 ++++++++++++++++++++++++ drivers/media/usb/em28xx/em28xx-dvb.c | 26 ++++++++++++++++++++++++++ drivers/media/usb/em28xx/em28xx.h | 1 + 5 files changed, 53 insertions(+) (limited to 'drivers/media') diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index 3f12865b2a88..c59181431df5 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -85,3 +85,4 @@ 85 -> PCTV QuatroStick (510e) (em2884) [2304:0242] 86 -> PCTV QuatroStick nano (520e) (em2884) [2013:0251] 87 -> Terratec Cinergy HTC USB XS (em2884) [0ccd:008e,0ccd:00ac] + 88 -> C3 Tech Digital Duo HDTV/SDTV USB (em2884) [1b80:e755] diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig index c754a80a8d8b..ca5ee6aceb62 100644 --- a/drivers/media/usb/em28xx/Kconfig +++ b/drivers/media/usb/em28xx/Kconfig @@ -46,6 +46,7 @@ config VIDEO_EM28XX_DVB select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT + select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT ---help--- diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 6e62b72376b0..46fff5c3335b 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -345,6 +345,18 @@ static struct em28xx_reg_seq pctv_460e[] = { { -1, -1, -1, -1}, }; +static struct em28xx_reg_seq c3tech_digital_duo_digital[] = { + {EM2874_R80_GPIO, 0xff, 0xff, 10}, + {EM2874_R80_GPIO, 0xfd, 0xff, 10}, /* xc5000 reset */ + {EM2874_R80_GPIO, 0xf9, 0xff, 35}, + {EM2874_R80_GPIO, 0xfd, 0xff, 10}, + {EM2874_R80_GPIO, 0xff, 0xff, 10}, + {EM2874_R80_GPIO, 0xfe, 0xff, 10}, + {EM2874_R80_GPIO, 0xbe, 0xff, 10}, + {EM2874_R80_GPIO, 0xfe, 0xff, 20}, + { -1, -1, -1, -1}, +}; + #if 0 static struct em28xx_reg_seq hauppauge_930c_gpio[] = { {EM2874_R80_GPIO, 0x6f, 0xff, 10}, @@ -978,6 +990,16 @@ struct em28xx_board em28xx_boards[] = { .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, + [EM2884_BOARD_C3TECH_DIGITAL_DUO] = { + .name = "C3 Tech Digital Duo HDTV/SDTV USB", + .has_dvb = 1, + /* FIXME: Add analog support - need a saa7136 driver */ + .tuner_type = TUNER_ABSENT, /* Digital-only TDA18271HD */ + .ir_codes = RC_MAP_EMPTY, + .def_i2c_bus = 1, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE, + .dvb_gpio = c3tech_digital_duo_digital, + }, [EM2884_BOARD_CINERGY_HTC_STICK] = { .name = "Terratec Cinergy HTC Stick", .has_dvb = 1, @@ -2144,6 +2166,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM28174_BOARD_PCTV_460E }, { USB_DEVICE(0x2040, 0x1605), .driver_info = EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C }, + { USB_DEVICE(0x1b80, 0xe755), + .driver_info = EM2884_BOARD_C3TECH_DIGITAL_DUO }, { USB_DEVICE(0xeb1a, 0x5006), .driver_info = EM2860_BOARD_HT_VIDBOX_NW03 }, { USB_DEVICE(0x1b80, 0xe309), /* Sveon STV40 */ diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 98b95be3be6e..42a6a2696224 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -50,6 +50,7 @@ #include "tda10071.h" #include "a8293.h" #include "qt1010.h" +#include "mb86a20s.h" MODULE_DESCRIPTION("driver for em28xx based DVB cards"); MODULE_AUTHOR("Mauro Carvalho Chehab "); @@ -766,9 +767,25 @@ static struct zl10353_config em28xx_zl10353_no_i2c_gate_dev = { }; static struct qt1010_config em28xx_qt1010_config = { .i2c_address = 0x62 +}; + +static const struct mb86a20s_config c3tech_duo_mb86a20s_config = { + .demod_address = 0x10, + .is_serial = true, +}; + +static struct tda18271_std_map mb86a20s_tda18271_config = { + .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4, + .if_lvl = 1, .rfagc_top = 0x37, }, +}; +static struct tda18271_config c3tech_duo_tda18271_config = { + .std_map = &mb86a20s_tda18271_config, + .gate = TDA18271_GATE_DIGITAL, + .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, }; + /* ------------------------------------------------------------------ */ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) @@ -1177,6 +1194,15 @@ static int em28xx_dvb_init(struct em28xx *dev) dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0); break; + case EM2884_BOARD_C3TECH_DIGITAL_DUO: + dvb->fe[0] = dvb_attach(mb86a20s_attach, + &c3tech_duo_mb86a20s_config, + &dev->i2c_adap[dev->def_i2c_bus]); + if (dvb->fe[0] != NULL) + dvb_attach(tda18271_attach, dvb->fe[0], 0x60, + &dev->i2c_adap[dev->def_i2c_bus], + &c3tech_duo_tda18271_config); + break; case EM28174_BOARD_PCTV_460E: /* attach demod */ dvb->fe[0] = dvb_attach(tda10071_attach, diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index f6ac1df83816..4c667fd1661d 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -129,6 +129,7 @@ #define EM2884_BOARD_PCTV_510E 85 #define EM2884_BOARD_PCTV_520E 86 #define EM2884_BOARD_TERRATEC_HTC_USB_XS 87 +#define EM2884_BOARD_C3TECH_DIGITAL_DUO 88 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 -- cgit v1.2.3 From 801b69f2570e2556c6d5a060df85ce9bd0d38119 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 16 Feb 2013 17:25:43 -0300 Subject: [media] redrat3: limit periods to hardware limits The redrat hardware cannot handle periods of larger than 32767us, limit appropriately. Also fix memory leak in redrat3_get_timeout. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 53 +++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 29 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 1b37fe2779f8..842bdcded27c 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -209,9 +209,6 @@ struct redrat3_dev { u16 pktlen; u16 pkttype; u16 bytes_read; - /* indicate whether we are going to reprocess - * the USB callback with a bigger buffer */ - int buftoosmall; char *datap; u32 carrier; @@ -396,7 +393,6 @@ static u32 redrat3_us_to_len(u32 microsec) /* don't allow zero lengths to go back, breaks lirc */ return result ? result : 1; - } /* timer callback to send reset event */ @@ -515,8 +511,6 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) rr3_dbg(dev, "calling ir_raw_event_handle\n"); ir_raw_event_handle(rr3->rc); - - return; } /* Util fn to send rr3 cmds */ @@ -613,7 +607,7 @@ static inline void redrat3_delete(struct redrat3_dev *rr3, static u32 redrat3_get_timeout(struct redrat3_dev *rr3) { - u32 *tmp; + __be32 *tmp; u32 timeout = MS_TO_US(150); /* a sane default, if things go haywire */ int len, ret, pipe; @@ -628,14 +622,16 @@ static u32 redrat3_get_timeout(struct redrat3_dev *rr3) ret = usb_control_msg(rr3->udev, pipe, RR3_GET_IR_PARAM, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, HZ * 5); - if (ret != len) { + if (ret != len) dev_warn(rr3->dev, "Failed to read timeout from hardware\n"); - return timeout; + else { + timeout = redrat3_len_to_us(be32_to_cpup(tmp)); + + rr3_dbg(rr3->dev, "Got timeout of %d ms\n", timeout / 1000); } - timeout = redrat3_len_to_us(be32_to_cpu(*tmp)); + kfree(tmp); - rr3_dbg(rr3->dev, "Got timeout of %d ms\n", timeout / 1000); return timeout; } @@ -755,7 +751,6 @@ static void redrat3_read_packet_start(struct redrat3_dev *rr3, int len) static void redrat3_read_packet_continue(struct redrat3_dev *rr3, int len) { - rr3_ftr(rr3->dev, "Entering %s\n", __func__); memcpy(rr3->datap, (unsigned char *)rr3->bulk_in_buf, len); @@ -815,7 +810,7 @@ out: } /* callback function from USB when async USB request has completed */ -static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs) +static void redrat3_handle_async(struct urb *urb) { struct redrat3_dev *rr3; int ret; @@ -857,7 +852,7 @@ static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs) } } -static void redrat3_write_bulk_callback(struct urb *urb, struct pt_regs *regs) +static void redrat3_write_bulk_callback(struct urb *urb) { struct redrat3_dev *rr3; int len; @@ -901,7 +896,7 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, struct redrat3_dev *rr3 = rcdev->priv; struct device *dev = rr3->dev; struct redrat3_signal_header header; - int i, j, ret, ret_len, offset; + int i, ret, ret_len, offset; int lencheck, cur_sample_len, pipe; char *buffer = NULL, *sigdata = NULL; int *sample_lens = NULL; @@ -931,8 +926,19 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, goto out; } + sigdata = kzalloc((count + RR3_TX_TRAILER_LEN), GFP_KERNEL); + if (!sigdata) { + ret = -ENOMEM; + goto out; + } + for (i = 0; i < count; i++) { cur_sample_len = redrat3_us_to_len(txbuf[i]); + if (cur_sample_len > 0xffff) { + dev_warn(dev, "transmit period of %uus truncated to %uus\n", + txbuf[i], redrat3_len_to_us(0xffff)); + cur_sample_len = 0xffff; + } for (lencheck = 0; lencheck < curlencheck; lencheck++) { if (sample_lens[lencheck] == cur_sample_len) break; @@ -950,22 +956,11 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, break; } } - } - - sigdata = kzalloc((count + RR3_TX_TRAILER_LEN), GFP_KERNEL); - if (!sigdata) { - ret = -ENOMEM; - goto out; + sigdata[i] = lencheck; } sigdata[count] = RR3_END_OF_SIGNAL; sigdata[count + 1] = RR3_END_OF_SIGNAL; - for (i = 0; i < count; i++) { - for (j = 0; j < curlencheck; j++) { - if (sample_lens[j] == redrat3_us_to_len(txbuf[i])) - sigdata[i] = j; - } - } offset = RR3_TX_HEADER_OFFSET; sendbuf_len = RR3_HEADER_LENGTH + (sizeof(u16) * RR3_DRIVER_MAXLENS) @@ -1175,7 +1170,7 @@ static int redrat3_dev_probe(struct usb_interface *intf, pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress); usb_fill_bulk_urb(rr3->read_urb, udev, pipe, rr3->bulk_in_buf, ep_in->wMaxPacketSize, - (usb_complete_t)redrat3_handle_async, rr3); + redrat3_handle_async, rr3); /* set up bulk-out endpoint*/ rr3->write_urb = usb_alloc_urb(0, GFP_KERNEL); @@ -1195,7 +1190,7 @@ static int redrat3_dev_probe(struct usb_interface *intf, pipe = usb_sndbulkpipe(udev, ep_out->bEndpointAddress); usb_fill_bulk_urb(rr3->write_urb, udev, pipe, rr3->bulk_out_buf, ep_out->wMaxPacketSize, - (usb_complete_t)redrat3_write_bulk_callback, rr3); + redrat3_write_bulk_callback, rr3); rr3->udev = udev; -- cgit v1.2.3 From 4c055a5ae94c76b1139d6e071812d39eed3b67cd Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 16 Feb 2013 17:25:44 -0300 Subject: [media] redrat3: remove memcpys and fix unaligned memory access In stead of doing a memcpy from #defined offset, declare structs which describe the incoming and outgoing data accurately. Tested on first generation RedRat. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 351 +++++++++++++-------------------------------- 1 file changed, 103 insertions(+), 248 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 842bdcded27c..ec655b8ef4d3 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -45,6 +45,7 @@ * */ +#include #include #include #include @@ -129,25 +130,11 @@ static int debug; /* USB bulk-in IR data endpoint address */ #define RR3_BULK_IN_EP_ADDR 0x82 -/* Raw Modulated signal data value offsets */ -#define RR3_PAUSE_OFFSET 0 -#define RR3_FREQ_COUNT_OFFSET 4 -#define RR3_NUM_PERIOD_OFFSET 6 -#define RR3_MAX_LENGTHS_OFFSET 8 -#define RR3_NUM_LENGTHS_OFFSET 9 -#define RR3_MAX_SIGS_OFFSET 10 -#define RR3_NUM_SIGS_OFFSET 12 -#define RR3_REPEATS_OFFSET 14 - /* Size of the fixed-length portion of the signal */ -#define RR3_HEADER_LENGTH 15 #define RR3_DRIVER_MAXLENS 128 #define RR3_MAX_SIG_SIZE 512 -#define RR3_MAX_BUF_SIZE \ - ((2 * RR3_HEADER_LENGTH) + RR3_DRIVER_MAXLENS + RR3_MAX_SIG_SIZE) #define RR3_TIME_UNIT 50 #define RR3_END_OF_SIGNAL 0x7f -#define RR3_TX_HEADER_OFFSET 4 #define RR3_TX_TRAILER_LEN 2 #define RR3_RX_MIN_TIMEOUT 5 #define RR3_RX_MAX_TIMEOUT 2000 @@ -159,6 +146,32 @@ static int debug; #define USB_RR3USB_PRODUCT_ID 0x0001 #define USB_RR3IIUSB_PRODUCT_ID 0x0005 +struct redrat3_header { + __be16 length; + __be16 transfer_type; +} __packed; + +/* sending and receiving irdata */ +struct redrat3_irdata { + struct redrat3_header header; + __be32 pause; + __be16 mod_freq_count; + __be16 num_periods; + __u8 max_lengths; + __u8 no_lengths; + __be16 max_sig_size; + __be16 sig_size; + __u8 no_repeats; + __be16 lens[RR3_DRIVER_MAXLENS]; /* not aligned */ + __u8 sigdata[RR3_MAX_SIG_SIZE]; +} __packed; + +/* firmware errors */ +struct redrat3_error { + struct redrat3_header header; + __be16 fw_error; +} __packed; + /* table of devices that work with this driver */ static struct usb_device_id redrat3_dev_table[] = { /* Original version of the RedRat3 */ @@ -180,7 +193,7 @@ struct redrat3_dev { /* the receive endpoint */ struct usb_endpoint_descriptor *ep_in; /* the buffer to receive data */ - unsigned char *bulk_in_buf; + void *bulk_in_buf; /* urb used to read ir data */ struct urb *read_urb; @@ -205,69 +218,15 @@ struct redrat3_dev { bool transmitting; /* store for current packet */ - char pbuf[RR3_MAX_BUF_SIZE]; - u16 pktlen; - u16 pkttype; + struct redrat3_irdata irdata; u16 bytes_read; - char *datap; u32 carrier; - char name[128]; + char name[64]; char phys[64]; }; -/* All incoming data buffers adhere to a very specific data format */ -struct redrat3_signal_header { - u16 length; /* Length of data being transferred */ - u16 transfer_type; /* Type of data transferred */ - u32 pause; /* Pause between main and repeat signals */ - u16 mod_freq_count; /* Value of timer on mod. freq. measurement */ - u16 no_periods; /* No. of periods over which mod. freq. is measured */ - u8 max_lengths; /* Max no. of lengths (i.e. size of array) */ - u8 no_lengths; /* Actual no. of elements in lengths array */ - u16 max_sig_size; /* Max no. of values in signal data array */ - u16 sig_size; /* Acuto no. of values in signal data array */ - u8 no_repeats; /* No. of repeats of repeat signal section */ - /* Here forward is the lengths and signal data */ -}; - -static void redrat3_dump_signal_header(struct redrat3_signal_header *header) -{ - pr_info("%s:\n", __func__); - pr_info(" * length: %u, transfer_type: 0x%02x\n", - header->length, header->transfer_type); - pr_info(" * pause: %u, freq_count: %u, no_periods: %u\n", - header->pause, header->mod_freq_count, header->no_periods); - pr_info(" * lengths: %u (max: %u)\n", - header->no_lengths, header->max_lengths); - pr_info(" * sig_size: %u (max: %u)\n", - header->sig_size, header->max_sig_size); - pr_info(" * repeats: %u\n", header->no_repeats); -} - -static void redrat3_dump_signal_data(char *buffer, u16 len) -{ - int offset, i; - char *data_vals; - - pr_info("%s:", __func__); - - offset = RR3_TX_HEADER_OFFSET + RR3_HEADER_LENGTH - + (RR3_DRIVER_MAXLENS * sizeof(u16)); - - /* read RR3_DRIVER_MAXLENS from ctrl msg */ - data_vals = buffer + offset; - - for (i = 0; i < len; i++) { - if (i % 10 == 0) - pr_cont("\n * "); - pr_cont("%02x ", *data_vals++); - } - - pr_cont("\n"); -} - /* * redrat3_issue_async * @@ -349,13 +308,14 @@ static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) } } -static u32 redrat3_val_to_mod_freq(struct redrat3_signal_header *ph) +static u32 redrat3_val_to_mod_freq(struct redrat3_irdata *irdata) { u32 mod_freq = 0; + u16 mod_freq_count = be16_to_cpu(irdata->mod_freq_count); - if (ph->mod_freq_count != 0) - mod_freq = (RR3_CLK * ph->no_periods) / - (ph->mod_freq_count * RR3_CLK_PER_COUNT); + if (mod_freq_count != 0) + mod_freq = (RR3_CLK * be16_to_cpu(irdata->num_periods)) / + (mod_freq_count * RR3_CLK_PER_COUNT); return mod_freq; } @@ -407,16 +367,11 @@ static void redrat3_rx_timeout(unsigned long data) static void redrat3_process_ir_data(struct redrat3_dev *rr3) { DEFINE_IR_RAW_EVENT(rawir); - struct redrat3_signal_header header; struct device *dev; int i, trailer = 0; + unsigned sig_size, single_len, offset, val; unsigned long delay; - u32 mod_freq, single_len; - u16 *len_vals; - u8 *data_vals; - u32 tmp32; - u16 tmp16; - char *sig_data; + u32 mod_freq; if (!rr3) { pr_err("%s called with no context!\n", __func__); @@ -426,57 +381,20 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) rr3_ftr(rr3->dev, "Entered %s\n", __func__); dev = rr3->dev; - sig_data = rr3->pbuf; - - header.length = rr3->pktlen; - header.transfer_type = rr3->pkttype; - - /* Sanity check */ - if (!(header.length >= RR3_HEADER_LENGTH)) - dev_warn(dev, "read returned less than rr3 header len\n"); /* Make sure we reset the IR kfifo after a bit of inactivity */ delay = usecs_to_jiffies(rr3->hw_timeout); mod_timer(&rr3->rx_timeout, jiffies + delay); - memcpy(&tmp32, sig_data + RR3_PAUSE_OFFSET, sizeof(tmp32)); - header.pause = be32_to_cpu(tmp32); - - memcpy(&tmp16, sig_data + RR3_FREQ_COUNT_OFFSET, sizeof(tmp16)); - header.mod_freq_count = be16_to_cpu(tmp16); - - memcpy(&tmp16, sig_data + RR3_NUM_PERIOD_OFFSET, sizeof(tmp16)); - header.no_periods = be16_to_cpu(tmp16); - - header.max_lengths = sig_data[RR3_MAX_LENGTHS_OFFSET]; - header.no_lengths = sig_data[RR3_NUM_LENGTHS_OFFSET]; - - memcpy(&tmp16, sig_data + RR3_MAX_SIGS_OFFSET, sizeof(tmp16)); - header.max_sig_size = be16_to_cpu(tmp16); - - memcpy(&tmp16, sig_data + RR3_NUM_SIGS_OFFSET, sizeof(tmp16)); - header.sig_size = be16_to_cpu(tmp16); - - header.no_repeats= sig_data[RR3_REPEATS_OFFSET]; - - if (debug) { - redrat3_dump_signal_header(&header); - redrat3_dump_signal_data(sig_data, header.sig_size); - } - - mod_freq = redrat3_val_to_mod_freq(&header); + mod_freq = redrat3_val_to_mod_freq(&rr3->irdata); rr3_dbg(dev, "Got mod_freq of %u\n", mod_freq); - /* Here we pull out the 'length' values from the signal */ - len_vals = (u16 *)(sig_data + RR3_HEADER_LENGTH); - - data_vals = sig_data + RR3_HEADER_LENGTH + - (header.max_lengths * sizeof(u16)); - /* process each rr3 encoded byte into an int */ - for (i = 0; i < header.sig_size; i++) { - u16 val = len_vals[data_vals[i]]; - single_len = redrat3_len_to_us((u32)be16_to_cpu(val)); + sig_size = be16_to_cpu(rr3->irdata.sig_size); + for (i = 0; i < sig_size; i++) { + offset = rr3->irdata.sigdata[i]; + val = get_unaligned_be16(&rr3->irdata.lens[offset]); + single_len = redrat3_len_to_us(val); /* we should always get pulse/space/pulse/space samples */ if (i % 2) @@ -534,7 +452,7 @@ static u8 redrat3_send_cmd(int cmd, struct redrat3_dev *rr3) __func__, res, *data); res = -EIO; } else - res = (u8)data[0]; + res = data[0]; kfree(data); @@ -704,79 +622,72 @@ static void redrat3_get_firmware_rev(struct redrat3_dev *rr3) static void redrat3_read_packet_start(struct redrat3_dev *rr3, int len) { - u16 tx_error; - u16 hdrlen; + struct redrat3_header *header = rr3->bulk_in_buf; + unsigned pktlen, pkttype; rr3_ftr(rr3->dev, "Entering %s\n", __func__); /* grab the Length and type of transfer */ - memcpy(&(rr3->pktlen), (unsigned char *) rr3->bulk_in_buf, - sizeof(rr3->pktlen)); - memcpy(&(rr3->pkttype), ((unsigned char *) rr3->bulk_in_buf + - sizeof(rr3->pktlen)), - sizeof(rr3->pkttype)); + pktlen = be16_to_cpu(header->length); + pkttype = be16_to_cpu(header->transfer_type); - /*data needs conversion to know what its real values are*/ - rr3->pktlen = be16_to_cpu(rr3->pktlen); - rr3->pkttype = be16_to_cpu(rr3->pkttype); + if (pktlen > sizeof(rr3->irdata)) { + dev_warn(rr3->dev, "packet length %u too large\n", pktlen); + return; + } - switch (rr3->pkttype) { + switch (pkttype) { case RR3_ERROR: - memcpy(&tx_error, ((unsigned char *)rr3->bulk_in_buf - + (sizeof(rr3->pktlen) + sizeof(rr3->pkttype))), - sizeof(tx_error)); - tx_error = be16_to_cpu(tx_error); - redrat3_dump_fw_error(rr3, tx_error); + if (len >= sizeof(struct redrat3_error)) { + struct redrat3_error *error = rr3->bulk_in_buf; + unsigned fw_error = be16_to_cpu(error->fw_error); + redrat3_dump_fw_error(rr3, fw_error); + } break; case RR3_MOD_SIGNAL_IN: - hdrlen = sizeof(rr3->pktlen) + sizeof(rr3->pkttype); + memcpy(&rr3->irdata, rr3->bulk_in_buf, len); rr3->bytes_read = len; - rr3->bytes_read -= hdrlen; - rr3->datap = &(rr3->pbuf[0]); - - memcpy(rr3->datap, ((unsigned char *)rr3->bulk_in_buf + hdrlen), - rr3->bytes_read); - rr3->datap += rr3->bytes_read; rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n", - rr3->bytes_read, rr3->pktlen); + rr3->bytes_read, pktlen); break; default: - rr3_dbg(rr3->dev, "ignoring packet with type 0x%02x, " - "len of %d, 0x%02x\n", rr3->pkttype, len, rr3->pktlen); + rr3_dbg(rr3->dev, "ignoring packet with type 0x%02x, len of %d, 0x%02x\n", + pkttype, len, pktlen); break; } } static void redrat3_read_packet_continue(struct redrat3_dev *rr3, int len) { + void *irdata = &rr3->irdata; + rr3_ftr(rr3->dev, "Entering %s\n", __func__); - memcpy(rr3->datap, (unsigned char *)rr3->bulk_in_buf, len); - rr3->datap += len; + if (len + rr3->bytes_read > sizeof(rr3->irdata)) { + dev_warn(rr3->dev, "too much data for packet\n"); + rr3->bytes_read = 0; + return; + } + + memcpy(irdata + rr3->bytes_read, rr3->bulk_in_buf, len); rr3->bytes_read += len; - rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n", - rr3->bytes_read, rr3->pktlen); + rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n", rr3->bytes_read, + be16_to_cpu(rr3->irdata.header.length)); } /* gather IR data from incoming urb, process it when we have enough */ static int redrat3_get_ir_data(struct redrat3_dev *rr3, int len) { struct device *dev = rr3->dev; + unsigned pkttype; int ret = 0; rr3_ftr(dev, "Entering %s\n", __func__); - if (rr3->pktlen > RR3_MAX_BUF_SIZE) { - dev_err(rr3->dev, "error: packet larger than buffer\n"); - ret = -EINVAL; - goto out; - } - - if ((rr3->bytes_read == 0) && - (len >= (sizeof(rr3->pkttype) + sizeof(rr3->pktlen)))) { + if (rr3->bytes_read == 0 && len >= sizeof(struct redrat3_header)) { redrat3_read_packet_start(rr3, len); } else if (rr3->bytes_read != 0) { redrat3_read_packet_continue(rr3, len); @@ -786,26 +697,20 @@ static int redrat3_get_ir_data(struct redrat3_dev *rr3, int len) goto out; } - if (rr3->bytes_read > rr3->pktlen) { - dev_err(dev, "bytes_read (%d) greater than pktlen (%d)\n", - rr3->bytes_read, rr3->pktlen); - ret = -EINVAL; - goto out; - } else if (rr3->bytes_read < rr3->pktlen) + if (rr3->bytes_read < be16_to_cpu(rr3->irdata.header.length)) /* we're still accumulating data */ return 0; /* if we get here, we've got IR data to decode */ - if (rr3->pkttype == RR3_MOD_SIGNAL_IN) + pkttype = be16_to_cpu(rr3->irdata.header.transfer_type); + if (pkttype == RR3_MOD_SIGNAL_IN) redrat3_process_ir_data(rr3); else - rr3_dbg(dev, "discarding non-signal data packet " - "(type 0x%02x)\n", rr3->pkttype); + rr3_dbg(dev, "discarding non-signal data packet (type 0x%02x)\n", + pkttype); out: rr3->bytes_read = 0; - rr3->pktlen = 0; - rr3->pkttype = 0; return ret; } @@ -846,8 +751,6 @@ static void redrat3_handle_async(struct urb *urb) default: dev_warn(rr3->dev, "Error: urb status = %d\n", urb->status); rr3->bytes_read = 0; - rr3->pktlen = 0; - rr3->pkttype = 0; break; } } @@ -873,7 +776,7 @@ static u16 mod_freq_to_val(unsigned int mod_freq) int mult = 6000000; /* Clk used in mod. freq. generation is CLK24/4. */ - return (u16)(65536 - (mult / mod_freq)); + return 65536 - (mult / mod_freq); } static int redrat3_set_tx_carrier(struct rc_dev *rcdev, u32 carrier) @@ -895,16 +798,11 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, { struct redrat3_dev *rr3 = rcdev->priv; struct device *dev = rr3->dev; - struct redrat3_signal_header header; - int i, ret, ret_len, offset; + struct redrat3_irdata *irdata = NULL; + int i, ret, ret_len; int lencheck, cur_sample_len, pipe; - char *buffer = NULL, *sigdata = NULL; int *sample_lens = NULL; - u32 tmpi; - u16 tmps; - u8 *datap; u8 curlencheck = 0; - u16 *lengths_ptr; int sendbuf_len; rr3_ftr(dev, "Entering %s\n", __func__); @@ -926,8 +824,8 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, goto out; } - sigdata = kzalloc((count + RR3_TX_TRAILER_LEN), GFP_KERNEL); - if (!sigdata) { + irdata = kzalloc(sizeof(*irdata), GFP_KERNEL); + if (!irdata) { ret = -ENOMEM; goto out; } @@ -950,83 +848,41 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, /* now convert the value to a proper * rr3 value.. */ sample_lens[curlencheck] = cur_sample_len; + put_unaligned_be16(cur_sample_len, + &irdata->lens[curlencheck]); curlencheck++; } else { count = i - 1; break; } } - sigdata[i] = lencheck; + irdata->sigdata[i] = lencheck; } - sigdata[count] = RR3_END_OF_SIGNAL; - sigdata[count + 1] = RR3_END_OF_SIGNAL; - - offset = RR3_TX_HEADER_OFFSET; - sendbuf_len = RR3_HEADER_LENGTH + (sizeof(u16) * RR3_DRIVER_MAXLENS) - + count + RR3_TX_TRAILER_LEN + offset; - - buffer = kzalloc(sendbuf_len, GFP_KERNEL); - if (!buffer) { - ret = -ENOMEM; - goto out; - } + irdata->sigdata[count] = RR3_END_OF_SIGNAL; + irdata->sigdata[count + 1] = RR3_END_OF_SIGNAL; + sendbuf_len = offsetof(struct redrat3_irdata, + sigdata[count + RR3_TX_TRAILER_LEN]); /* fill in our packet header */ - header.length = sendbuf_len - offset; - header.transfer_type = RR3_MOD_SIGNAL_OUT; - header.pause = redrat3_len_to_us(100); - header.mod_freq_count = mod_freq_to_val(rr3->carrier); - header.no_periods = 0; /* n/a to transmit */ - header.max_lengths = RR3_DRIVER_MAXLENS; - header.no_lengths = curlencheck; - header.max_sig_size = RR3_MAX_SIG_SIZE; - header.sig_size = count + RR3_TX_TRAILER_LEN; - /* we currently rely on repeat handling in the IR encoding source */ - header.no_repeats = 0; - - tmps = cpu_to_be16(header.length); - memcpy(buffer, &tmps, 2); - - tmps = cpu_to_be16(header.transfer_type); - memcpy(buffer + 2, &tmps, 2); - - tmpi = cpu_to_be32(header.pause); - memcpy(buffer + offset, &tmpi, sizeof(tmpi)); - - tmps = cpu_to_be16(header.mod_freq_count); - memcpy(buffer + offset + RR3_FREQ_COUNT_OFFSET, &tmps, 2); - - buffer[offset + RR3_NUM_LENGTHS_OFFSET] = header.no_lengths; - - tmps = cpu_to_be16(header.sig_size); - memcpy(buffer + offset + RR3_NUM_SIGS_OFFSET, &tmps, 2); - - buffer[offset + RR3_REPEATS_OFFSET] = header.no_repeats; - - lengths_ptr = (u16 *)(buffer + offset + RR3_HEADER_LENGTH); - for (i = 0; i < curlencheck; ++i) - lengths_ptr[i] = cpu_to_be16(sample_lens[i]); - - datap = (u8 *)(buffer + offset + RR3_HEADER_LENGTH + - (sizeof(u16) * RR3_DRIVER_MAXLENS)); - memcpy(datap, sigdata, (count + RR3_TX_TRAILER_LEN)); - - if (debug) { - redrat3_dump_signal_header(&header); - redrat3_dump_signal_data(buffer, header.sig_size); - } + irdata->header.length = cpu_to_be16(sendbuf_len - + sizeof(struct redrat3_header)); + irdata->header.transfer_type = cpu_to_be16(RR3_MOD_SIGNAL_OUT); + irdata->pause = cpu_to_be32(redrat3_len_to_us(100)); + irdata->mod_freq_count = cpu_to_be16(mod_freq_to_val(rr3->carrier)); + irdata->no_lengths = curlencheck; + irdata->sig_size = cpu_to_be16(count + RR3_TX_TRAILER_LEN); pipe = usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress); - tmps = usb_bulk_msg(rr3->udev, pipe, buffer, + ret = usb_bulk_msg(rr3->udev, pipe, irdata, sendbuf_len, &ret_len, 10 * HZ); - rr3_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, tmps); + rr3_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, ret); /* now tell the hardware to transmit what we sent it */ pipe = usb_rcvctrlpipe(rr3->udev, 0); ret = usb_control_msg(rr3->udev, pipe, RR3_TX_SEND_SIGNAL, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0, 0, buffer, 2, HZ * 10); + 0, 0, irdata, 2, HZ * 10); if (ret < 0) dev_err(dev, "Error: control msg send failed, rc %d\n", ret); @@ -1035,8 +891,7 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, out: kfree(sample_lens); - kfree(buffer); - kfree(sigdata); + kfree(irdata); rr3->transmitting = false; /* rr3 re-enables rc detector because it was enabled before */ -- cgit v1.2.3 From fa7b9ac2e25e149fa9972fced79196c0c971a218 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 16 Feb 2013 17:25:45 -0300 Subject: [media] redrat3: missing endian conversions and warnings Spotted by sparse. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 71 ++++++++-------------------------------------- 1 file changed, 12 insertions(+), 59 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index ec655b8ef4d3..12167a6b5472 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -54,7 +54,6 @@ #include /* Driver Information */ -#define DRIVER_VERSION "0.70" #define DRIVER_AUTHOR "Jarod Wilson " #define DRIVER_AUTHOR2 "The Dweller, Stephen Cox" #define DRIVER_DESC "RedRat3 USB IR Transceiver Driver" @@ -199,14 +198,9 @@ struct redrat3_dev { /* the send endpoint */ struct usb_endpoint_descriptor *ep_out; - /* the buffer to send data */ - unsigned char *bulk_out_buf; - /* the urb used to send data */ - struct urb *write_urb; /* usb dma */ dma_addr_t dma_in; - dma_addr_t dma_out; /* rx signal timeout timer */ struct timer_list rx_timeout; @@ -239,7 +233,6 @@ static void redrat3_issue_async(struct redrat3_dev *rr3) rr3_ftr(rr3->dev, "Entering %s\n", __func__); - memset(rr3->bulk_in_buf, 0, rr3->ep_in->wMaxPacketSize); res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC); if (res) rr3_dbg(rr3->dev, "%s: receive request FAILED! " @@ -368,7 +361,7 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) { DEFINE_IR_RAW_EVENT(rawir); struct device *dev; - int i, trailer = 0; + unsigned i, trailer = 0; unsigned sig_size, single_len, offset, val; unsigned long delay; u32 mod_freq; @@ -510,15 +503,11 @@ static inline void redrat3_delete(struct redrat3_dev *rr3, { rr3_ftr(rr3->dev, "%s cleaning up\n", __func__); usb_kill_urb(rr3->read_urb); - usb_kill_urb(rr3->write_urb); usb_free_urb(rr3->read_urb); - usb_free_urb(rr3->write_urb); - usb_free_coherent(udev, rr3->ep_in->wMaxPacketSize, + usb_free_coherent(udev, le16_to_cpu(rr3->ep_in->wMaxPacketSize), rr3->bulk_in_buf, rr3->dma_in); - usb_free_coherent(udev, rr3->ep_out->wMaxPacketSize, - rr3->bulk_out_buf, rr3->dma_out); kfree(rr3); } @@ -566,7 +555,7 @@ static void redrat3_reset(struct redrat3_dev *rr3) rxpipe = usb_rcvctrlpipe(udev, 0); txpipe = usb_sndctrlpipe(udev, 0); - val = kzalloc(len, GFP_KERNEL); + val = kmalloc(len, GFP_KERNEL); if (!val) { dev_err(dev, "Memory allocation failure\n"); return; @@ -620,7 +609,7 @@ static void redrat3_get_firmware_rev(struct redrat3_dev *rr3) rr3_ftr(rr3->dev, "Exiting %s\n", __func__); } -static void redrat3_read_packet_start(struct redrat3_dev *rr3, int len) +static void redrat3_read_packet_start(struct redrat3_dev *rr3, unsigned len) { struct redrat3_header *header = rr3->bulk_in_buf; unsigned pktlen, pkttype; @@ -659,7 +648,7 @@ static void redrat3_read_packet_start(struct redrat3_dev *rr3, int len) } } -static void redrat3_read_packet_continue(struct redrat3_dev *rr3, int len) +static void redrat3_read_packet_continue(struct redrat3_dev *rr3, unsigned len) { void *irdata = &rr3->irdata; @@ -679,7 +668,7 @@ static void redrat3_read_packet_continue(struct redrat3_dev *rr3, int len) } /* gather IR data from incoming urb, process it when we have enough */ -static int redrat3_get_ir_data(struct redrat3_dev *rr3, int len) +static int redrat3_get_ir_data(struct redrat3_dev *rr3, unsigned len) { struct device *dev = rr3->dev; unsigned pkttype; @@ -755,22 +744,6 @@ static void redrat3_handle_async(struct urb *urb) } } -static void redrat3_write_bulk_callback(struct urb *urb) -{ - struct redrat3_dev *rr3; - int len; - - if (!urb) - return; - - rr3 = urb->context; - if (rr3) { - len = urb->actual_length; - rr3_ftr(rr3->dev, "%s: called (status=%d len=%d)\n", - __func__, urb->status, len); - } -} - static u16 mod_freq_to_val(unsigned int mod_freq) { int mult = 6000000; @@ -799,11 +772,11 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, struct redrat3_dev *rr3 = rcdev->priv; struct device *dev = rr3->dev; struct redrat3_irdata *irdata = NULL; - int i, ret, ret_len; + int ret, ret_len; int lencheck, cur_sample_len, pipe; int *sample_lens = NULL; u8 curlencheck = 0; - int sendbuf_len; + unsigned i, sendbuf_len; rr3_ftr(dev, "Entering %s\n", __func__); @@ -1015,38 +988,18 @@ static int redrat3_dev_probe(struct usb_interface *intf, } rr3->ep_in = ep_in; - rr3->bulk_in_buf = usb_alloc_coherent(udev, ep_in->wMaxPacketSize, - GFP_ATOMIC, &rr3->dma_in); + rr3->bulk_in_buf = usb_alloc_coherent(udev, + le16_to_cpu(ep_in->wMaxPacketSize), GFP_ATOMIC, &rr3->dma_in); if (!rr3->bulk_in_buf) { dev_err(dev, "Read buffer allocation failure\n"); goto error; } pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress); - usb_fill_bulk_urb(rr3->read_urb, udev, pipe, - rr3->bulk_in_buf, ep_in->wMaxPacketSize, - redrat3_handle_async, rr3); - - /* set up bulk-out endpoint*/ - rr3->write_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!rr3->write_urb) { - dev_err(dev, "Write urb allocation failure\n"); - goto error; - } + usb_fill_bulk_urb(rr3->read_urb, udev, pipe, rr3->bulk_in_buf, + le16_to_cpu(ep_in->wMaxPacketSize), redrat3_handle_async, rr3); rr3->ep_out = ep_out; - rr3->bulk_out_buf = usb_alloc_coherent(udev, ep_out->wMaxPacketSize, - GFP_ATOMIC, &rr3->dma_out); - if (!rr3->bulk_out_buf) { - dev_err(dev, "Write buffer allocation failure\n"); - goto error; - } - - pipe = usb_sndbulkpipe(udev, ep_out->bEndpointAddress); - usb_fill_bulk_urb(rr3->write_urb, udev, pipe, - rr3->bulk_out_buf, ep_out->wMaxPacketSize, - redrat3_write_bulk_callback, rr3); - rr3->udev = udev; redrat3_reset(rr3); -- cgit v1.2.3 From 5144f5b76028dbfdbbf2f10721b73a553451c83a Mon Sep 17 00:00:00 2001 From: John Smith Date: Tue, 5 Mar 2013 18:02:43 -0300 Subject: [media] dvb_demux: Transport stream continuity check fix This patch avoids incrementing continuity counter demux->cnt_storage[pid] for TS packets without payload in accordance with ISO /IEC 13818-1. [mchehab@redhat.com: unmangle whitespacing and fix CodingStyle. Also checked ISO/IEC spec: patch is according with it] Reviewed-by: Mauro Carvalho Chehab Signed-off-by: John Smith Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_demux.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index d319717eb535..71641b2dde6b 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -440,20 +440,22 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) if (!dvb_demux_feed_err_pkts) return; } else /* if TEI bit is set, pid may be wrong- skip pkt counter */ - if (demux->cnt_storage && dvb_demux_tscheck) { - /* check pkt counter */ - if (pid < MAX_PID) { - if ((buf[3] & 0xf) != demux->cnt_storage[pid]) - dprintk_tscheck("TS packet counter mismatch. " - "PID=0x%x expected 0x%x " - "got 0x%x\n", + if (demux->cnt_storage && dvb_demux_tscheck) { + /* check pkt counter */ + if (pid < MAX_PID) { + if (buf[3] & 0x10) + demux->cnt_storage[pid] = + (demux->cnt_storage[pid] + 1) & 0xf; + + if ((buf[3] & 0xf) != demux->cnt_storage[pid]) { + dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n", pid, demux->cnt_storage[pid], buf[3] & 0xf); - - demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf; + demux->cnt_storage[pid] = buf[3] & 0xf; + } + } + /* end check */ } - /* end check */ - } list_for_each_entry(feed, &demux->feed_list, list_head) { if ((feed->pid != pid) && (feed->pid != 0x2000)) -- cgit v1.2.3 From 72873e51c578ae29463a5d146f68881fcd0924c0 Mon Sep 17 00:00:00 2001 From: Syam Sidhardhan Date: Wed, 6 Mar 2013 16:44:46 -0300 Subject: [media] lmedm04: Remove redundant NULL check before kfree kfree on NULL pointer is a no-op. Signed-off-by: Syam Sidhardhan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/lmedm04.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 96804be0fffe..b3fd0ffa3c3f 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -1302,8 +1302,7 @@ static void lme2510_exit(struct dvb_usb_device *d) if (d != NULL) { usb_buffer = lme2510_exit_int(d); - if (usb_buffer != NULL) - kfree(usb_buffer); + kfree(usb_buffer); } } -- cgit v1.2.3 From e76d4ce49f574b6d94324239f8b7d655774d062c Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Wed, 6 Mar 2013 16:52:15 -0300 Subject: [media] rc-core: initialize rc-core earlier if built-in MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rc-core is a subsystem so it should be registered earlier if built into the kernel. Signed-off-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 759a40a42eaa..a92b8c536c89 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1207,7 +1207,7 @@ static void __exit rc_core_exit(void) rc_map_unregister(&empty_map); } -module_init(rc_core_init); +subsys_initcall(rc_core_init); module_exit(rc_core_exit); int rc_core_debug; /* ir_debug level (0,1,2) */ -- cgit v1.2.3 From 40fc5325e1b6764754116cc36dd34adfb964ef65 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Wed, 6 Mar 2013 16:52:10 -0300 Subject: [media] rc-core: rename ir_input_class to rc_class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The name is already misleading and will be more so in the future as the connection to the input subsystem is obscured away further. Signed-off-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index a92b8c536c89..f3047920b8c0 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -715,14 +715,14 @@ static void ir_close(struct input_dev *idev) } /* class for /sys/class/rc */ -static char *ir_devnode(struct device *dev, umode_t *mode) +static char *rc_devnode(struct device *dev, umode_t *mode) { return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev)); } -static struct class ir_input_class = { +static struct class rc_class = { .name = "rc", - .devnode = ir_devnode, + .devnode = rc_devnode, }; /* @@ -1016,7 +1016,7 @@ struct rc_dev *rc_allocate_device(void) setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev); dev->dev.type = &rc_dev_type; - dev->dev.class = &ir_input_class; + dev->dev.class = &rc_class; device_initialize(&dev->dev); __module_get(THIS_MODULE); @@ -1190,7 +1190,7 @@ EXPORT_SYMBOL_GPL(rc_unregister_device); static int __init rc_core_init(void) { - int rc = class_register(&ir_input_class); + int rc = class_register(&rc_class); if (rc) { printk(KERN_ERR "rc_core: unable to register rc class\n"); return rc; @@ -1203,7 +1203,7 @@ static int __init rc_core_init(void) static void __exit rc_core_exit(void) { - class_unregister(&ir_input_class); + class_unregister(&rc_class); rc_map_unregister(&empty_map); } -- cgit v1.2.3 From f08e9f0d5c138fcf8b0a1a952011cd044ae4e859 Mon Sep 17 00:00:00 2001 From: Andrey Pavlenko Date: Thu, 7 Mar 2013 09:36:22 -0300 Subject: [media] [1/1,dvb-usb] GOTVIEW SatelliteHD card support Added support for the GOTVIEW SatelliteHD card which is based on Montage M88DS3000 and works very well with this driver. Signed-off-by: Andrey Pavlenko Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dw2102.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 24cfd4bbbc8a..d5957b0299d3 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -79,6 +79,10 @@ #define USB_PID_TEVII_S632 0xd632 #endif +#ifndef USB_PID_GOTVIEW_SAT_HD +#define USB_PID_GOTVIEW_SAT_HD 0x5456 +#endif + #define DW210X_READ_MSG 0 #define DW210X_WRITE_MSG 1 @@ -1549,6 +1553,7 @@ enum dw2102_table_entry { TEVII_S421, TEVII_S632, TERRATEC_CINERGY_S2_R2, + GOTVIEW_SAT_HD, }; static struct usb_device_id dw2102_table[] = { @@ -1570,6 +1575,7 @@ static struct usb_device_id dw2102_table[] = { [TEVII_S421] = {USB_DEVICE(0x9022, USB_PID_TEVII_S421)}, [TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)}, [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00b0)}, + [GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)}, { } }; @@ -1970,7 +1976,7 @@ static struct dvb_usb_device_properties su3000_properties = { }}, } }, - .num_device_descs = 4, + .num_device_descs = 5, .devices = { { "SU3000HD DVB-S USB2.0", { &dw2102_table[GENIATECH_SU3000], NULL }, @@ -1988,6 +1994,10 @@ static struct dvb_usb_device_properties su3000_properties = { { &dw2102_table[TERRATEC_CINERGY_S2_R2], NULL }, { NULL }, }, + { "GOTVIEW Satellite HD", + { &dw2102_table[GOTVIEW_SAT_HD], NULL }, + { NULL }, + }, } }; -- cgit v1.2.3 From f0cd015e31d3818c96a9b436357b39929c2a361b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 14:33:51 -0300 Subject: [media] tvp7002: replace 'preset' by 'timings' in various structs/variables This is the first step towards removing the deprecated preset support of this driver. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp7002.c | 90 ++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 45 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 537f6b4d4918..7995eeb8f847 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -326,8 +326,8 @@ static const struct i2c_reg_value tvp7002_parms_720P50[] = { { TVP7002_EOR, 0xff, TVP7002_RESERVED } }; -/* Preset definition for handling device operation */ -struct tvp7002_preset_definition { +/* Timings definition for handling device operation */ +struct tvp7002_timings_definition { u32 preset; struct v4l2_dv_timings timings; const struct i2c_reg_value *p_settings; @@ -339,8 +339,8 @@ struct tvp7002_preset_definition { u16 cpl_max; }; -/* Struct list for digital video presets */ -static const struct tvp7002_preset_definition tvp7002_presets[] = { +/* Struct list for digital video timings */ +static const struct tvp7002_timings_definition tvp7002_timings[] = { { V4L2_DV_720P60, V4L2_DV_BT_CEA_1280X720P60, @@ -420,7 +420,7 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = { } }; -#define NUM_PRESETS ARRAY_SIZE(tvp7002_presets) +#define NUM_TIMINGS ARRAY_SIZE(tvp7002_timings) /* Device definition */ struct tvp7002 { @@ -431,7 +431,7 @@ struct tvp7002 { int ver; int streaming; - const struct tvp7002_preset_definition *current_preset; + const struct tvp7002_timings_definition *current_timings; }; /* @@ -603,11 +603,11 @@ static int tvp7002_s_dv_preset(struct v4l2_subdev *sd, u32 preset; int i; - for (i = 0; i < NUM_PRESETS; i++) { - preset = tvp7002_presets[i].preset; + for (i = 0; i < NUM_TIMINGS; i++) { + preset = tvp7002_timings[i].preset; if (preset == dv_preset->preset) { - device->current_preset = &tvp7002_presets[i]; - return tvp7002_write_inittab(sd, tvp7002_presets[i].p_settings); + device->current_timings = &tvp7002_timings[i]; + return tvp7002_write_inittab(sd, tvp7002_timings[i].p_settings); } } @@ -623,12 +623,12 @@ static int tvp7002_s_dv_timings(struct v4l2_subdev *sd, if (dv_timings->type != V4L2_DV_BT_656_1120) return -EINVAL; - for (i = 0; i < NUM_PRESETS; i++) { - const struct v4l2_bt_timings *t = &tvp7002_presets[i].timings.bt; + for (i = 0; i < NUM_TIMINGS; i++) { + const struct v4l2_bt_timings *t = &tvp7002_timings[i].timings.bt; if (!memcmp(bt, t, &bt->standards - &bt->width)) { - device->current_preset = &tvp7002_presets[i]; - return tvp7002_write_inittab(sd, tvp7002_presets[i].p_settings); + device->current_timings = &tvp7002_timings[i]; + return tvp7002_write_inittab(sd, tvp7002_timings[i].p_settings); } } return -EINVAL; @@ -639,7 +639,7 @@ static int tvp7002_g_dv_timings(struct v4l2_subdev *sd, { struct tvp7002 *device = to_tvp7002(sd); - *dv_timings = device->current_preset->timings; + *dv_timings = device->current_timings->timings; return 0; } @@ -681,15 +681,15 @@ static int tvp7002_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f int error; /* Calculate height and width based on current standard */ - error = v4l_fill_dv_preset_info(device->current_preset->preset, &e_preset); + error = v4l_fill_dv_preset_info(device->current_timings->preset, &e_preset); if (error) return error; f->width = e_preset.width; f->height = e_preset.height; f->code = V4L2_MBUS_FMT_YUYV10_1X20; - f->field = device->current_preset->scanmode; - f->colorspace = device->current_preset->color_space; + f->field = device->current_timings->scanmode; + f->colorspace = device->current_timings->color_space; v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d", f->width, f->height); @@ -697,16 +697,16 @@ static int tvp7002_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f } /* - * tvp7002_query_dv_preset() - query DV preset + * tvp7002_query_dv() - query DV timings * @sd: pointer to standard V4L2 sub-device structure - * @qpreset: standard V4L2 v4l2_dv_preset structure + * @index: index into the tvp7002_timings array * - * Returns the current DV preset by TVP7002. If no active input is + * Returns the current DV timings detected by TVP7002. If no active input is * detected, returns -EINVAL */ static int tvp7002_query_dv(struct v4l2_subdev *sd, int *index) { - const struct tvp7002_preset_definition *presets = tvp7002_presets; + const struct tvp7002_timings_definition *timings = tvp7002_timings; u8 progressive; u32 lpfr; u32 cpln; @@ -717,7 +717,7 @@ static int tvp7002_query_dv(struct v4l2_subdev *sd, int *index) u8 cpl_msb; /* Return invalid index if no active input is detected */ - *index = NUM_PRESETS; + *index = NUM_TIMINGS; /* Read standards from device registers */ tvp7002_read_err(sd, TVP7002_L_FRAME_STAT_LSBS, &lpf_lsb, &error); @@ -738,23 +738,23 @@ static int tvp7002_query_dv(struct v4l2_subdev *sd, int *index) progressive = (lpf_msb & TVP7002_INPR_MASK) >> TVP7002_IP_SHIFT; /* Do checking of video modes */ - for (*index = 0; *index < NUM_PRESETS; (*index)++, presets++) - if (lpfr == presets->lines_per_frame && - progressive == presets->progressive) { - if (presets->cpl_min == 0xffff) + for (*index = 0; *index < NUM_TIMINGS; (*index)++, timings++) + if (lpfr == timings->lines_per_frame && + progressive == timings->progressive) { + if (timings->cpl_min == 0xffff) break; - if (cpln >= presets->cpl_min && cpln <= presets->cpl_max) + if (cpln >= timings->cpl_min && cpln <= timings->cpl_max) break; } - if (*index == NUM_PRESETS) { + if (*index == NUM_TIMINGS) { v4l2_dbg(1, debug, sd, "detection failed: lpf = %x, cpl = %x\n", lpfr, cpln); return -ENOLINK; } /* Update lines per frame and clocks per line info */ - v4l2_dbg(1, debug, sd, "detected preset: %d\n", *index); + v4l2_dbg(1, debug, sd, "detected timings: %d\n", *index); return 0; } @@ -764,13 +764,13 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd, int index; int err = tvp7002_query_dv(sd, &index); - if (err || index == NUM_PRESETS) { + if (err || index == NUM_TIMINGS) { qpreset->preset = V4L2_DV_INVALID; if (err == -ENOLINK) err = 0; return err; } - qpreset->preset = tvp7002_presets[index].preset; + qpreset->preset = tvp7002_timings[index].preset; return 0; } @@ -782,7 +782,7 @@ static int tvp7002_query_dv_timings(struct v4l2_subdev *sd, if (err) return err; - *timings = tvp7002_presets[index].timings; + *timings = tvp7002_timings[index].timings; return 0; } @@ -896,7 +896,7 @@ static int tvp7002_s_stream(struct v4l2_subdev *sd, int enable) */ static int tvp7002_log_status(struct v4l2_subdev *sd) { - const struct tvp7002_preset_definition *presets = tvp7002_presets; + const struct tvp7002_timings_definition *timings = tvp7002_timings; struct tvp7002 *device = to_tvp7002(sd); struct v4l2_dv_enum_preset e_preset; struct v4l2_dv_preset detected; @@ -907,20 +907,20 @@ static int tvp7002_log_status(struct v4l2_subdev *sd) tvp7002_query_dv_preset(sd, &detected); /* Print standard related code values */ - for (i = 0; i < NUM_PRESETS; i++, presets++) - if (presets->preset == detected.preset) + for (i = 0; i < NUM_TIMINGS; i++, timings++) + if (timings->preset == detected.preset) break; - if (v4l_fill_dv_preset_info(device->current_preset->preset, &e_preset)) + if (v4l_fill_dv_preset_info(device->current_timings->preset, &e_preset)) return -EINVAL; v4l2_info(sd, "Selected DV Preset: %s\n", e_preset.name); v4l2_info(sd, " Pixels per line: %u\n", e_preset.width); v4l2_info(sd, " Lines per frame: %u\n\n", e_preset.height); - if (i == NUM_PRESETS) { + if (i == NUM_TIMINGS) { v4l2_info(sd, "Detected DV Preset: None\n"); } else { - if (v4l_fill_dv_preset_info(presets->preset, &e_preset)) + if (v4l_fill_dv_preset_info(timings->preset, &e_preset)) return -EINVAL; v4l2_info(sd, "Detected DV Preset: %s\n", e_preset.name); v4l2_info(sd, " Pixels per line: %u\n", e_preset.width); @@ -946,20 +946,20 @@ static int tvp7002_enum_dv_presets(struct v4l2_subdev *sd, struct v4l2_dv_enum_preset *preset) { /* Check requested format index is within range */ - if (preset->index >= NUM_PRESETS) + if (preset->index >= NUM_TIMINGS) return -EINVAL; - return v4l_fill_dv_preset_info(tvp7002_presets[preset->index].preset, preset); + return v4l_fill_dv_preset_info(tvp7002_timings[preset->index].preset, preset); } static int tvp7002_enum_dv_timings(struct v4l2_subdev *sd, struct v4l2_enum_dv_timings *timings) { /* Check requested format index is within range */ - if (timings->index >= NUM_PRESETS) + if (timings->index >= NUM_TIMINGS) return -EINVAL; - timings->timings = tvp7002_presets[timings->index].timings; + timings->timings = tvp7002_timings[timings->index].timings; return 0; } @@ -1043,7 +1043,7 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id) sd = &device->sd; device->pdata = c->dev.platform_data; - device->current_preset = tvp7002_presets; + device->current_timings = tvp7002_timings; /* Tell v4l2 the device is ready */ v4l2_i2c_subdev_init(sd, c, &tvp7002_ops); @@ -1080,7 +1080,7 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id) return error; /* Set registers according to default video mode */ - preset.preset = device->current_preset->preset; + preset.preset = device->current_timings->preset; error = tvp7002_s_dv_preset(sd, &preset); v4l2_ctrl_handler_init(&device->hdl, 1); -- cgit v1.2.3 From f96067af1f2313fd0e29c131368f33364f0ad98c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 14:46:40 -0300 Subject: [media] tvp7002: use dv_timings structs instead of presets In the functions tvp7002_mbus_fmt(), tvp7002_log_status and tvp7002_probe() we should use the dv_timings data structures instead of dv_preset data structures and functions. This is the second step towards removing the deprecated preset support of this driver. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp7002.c | 54 ++++++++++++++------------------------------- 1 file changed, 17 insertions(+), 37 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 7995eeb8f847..d7a08bc49622 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -677,16 +677,10 @@ static int tvp7002_s_ctrl(struct v4l2_ctrl *ctrl) static int tvp7002_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) { struct tvp7002 *device = to_tvp7002(sd); - struct v4l2_dv_enum_preset e_preset; - int error; - - /* Calculate height and width based on current standard */ - error = v4l_fill_dv_preset_info(device->current_timings->preset, &e_preset); - if (error) - return error; + const struct v4l2_bt_timings *bt = &device->current_timings->timings.bt; - f->width = e_preset.width; - f->height = e_preset.height; + f->width = bt->width; + f->height = bt->height; f->code = V4L2_MBUS_FMT_YUYV10_1X20; f->field = device->current_timings->scanmode; f->colorspace = device->current_timings->color_space; @@ -896,35 +890,21 @@ static int tvp7002_s_stream(struct v4l2_subdev *sd, int enable) */ static int tvp7002_log_status(struct v4l2_subdev *sd) { - const struct tvp7002_timings_definition *timings = tvp7002_timings; struct tvp7002 *device = to_tvp7002(sd); - struct v4l2_dv_enum_preset e_preset; - struct v4l2_dv_preset detected; - int i; + const struct v4l2_bt_timings *bt; + int detected; - detected.preset = V4L2_DV_INVALID; - /* Find my current standard*/ - tvp7002_query_dv_preset(sd, &detected); + /* Find my current timings */ + tvp7002_query_dv(sd, &detected); - /* Print standard related code values */ - for (i = 0; i < NUM_TIMINGS; i++, timings++) - if (timings->preset == detected.preset) - break; - - if (v4l_fill_dv_preset_info(device->current_timings->preset, &e_preset)) - return -EINVAL; - - v4l2_info(sd, "Selected DV Preset: %s\n", e_preset.name); - v4l2_info(sd, " Pixels per line: %u\n", e_preset.width); - v4l2_info(sd, " Lines per frame: %u\n\n", e_preset.height); - if (i == NUM_TIMINGS) { - v4l2_info(sd, "Detected DV Preset: None\n"); + bt = &device->current_timings->timings.bt; + v4l2_info(sd, "Selected DV Timings: %ux%u\n", bt->width, bt->height); + if (detected == NUM_TIMINGS) { + v4l2_info(sd, "Detected DV Timings: None\n"); } else { - if (v4l_fill_dv_preset_info(timings->preset, &e_preset)) - return -EINVAL; - v4l2_info(sd, "Detected DV Preset: %s\n", e_preset.name); - v4l2_info(sd, " Pixels per line: %u\n", e_preset.width); - v4l2_info(sd, " Lines per frame: %u\n\n", e_preset.height); + bt = &tvp7002_timings[detected].timings.bt; + v4l2_info(sd, "Detected DV Timings: %ux%u\n", + bt->width, bt->height); } v4l2_info(sd, "Streaming enabled: %s\n", device->streaming ? "yes" : "no"); @@ -1019,7 +999,7 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id) { struct v4l2_subdev *sd; struct tvp7002 *device; - struct v4l2_dv_preset preset; + struct v4l2_dv_timings timings; int polarity_a; int polarity_b; u8 revision; @@ -1080,8 +1060,8 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id) return error; /* Set registers according to default video mode */ - preset.preset = device->current_timings->preset; - error = tvp7002_s_dv_preset(sd, &preset); + timings = device->current_timings->timings; + error = tvp7002_s_dv_timings(sd, &timings); v4l2_ctrl_handler_init(&device->hdl, 1); v4l2_ctrl_new_std(&device->hdl, &tvp7002_ctrl_ops, -- cgit v1.2.3 From 416d307651ffa035a1e9f5ccc9f915cb2235d415 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 14:49:15 -0300 Subject: [media] tvp7002: remove dv_preset support Finally remove the dv_preset support from this driver. Note that dv_preset support was already removed from any bridge drivers that use this i2c driver, so the dv_preset ops were no longer called and can be removed safely. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp7002.c | 70 --------------------------------------------- 1 file changed, 70 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index d7a08bc49622..7406de9b45db 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -328,7 +328,6 @@ static const struct i2c_reg_value tvp7002_parms_720P50[] = { /* Timings definition for handling device operation */ struct tvp7002_timings_definition { - u32 preset; struct v4l2_dv_timings timings; const struct i2c_reg_value *p_settings; enum v4l2_colorspace color_space; @@ -342,7 +341,6 @@ struct tvp7002_timings_definition { /* Struct list for digital video timings */ static const struct tvp7002_timings_definition tvp7002_timings[] = { { - V4L2_DV_720P60, V4L2_DV_BT_CEA_1280X720P60, tvp7002_parms_720P60, V4L2_COLORSPACE_REC709, @@ -353,7 +351,6 @@ static const struct tvp7002_timings_definition tvp7002_timings[] = { 153 }, { - V4L2_DV_1080I60, V4L2_DV_BT_CEA_1920X1080I60, tvp7002_parms_1080I60, V4L2_COLORSPACE_REC709, @@ -364,7 +361,6 @@ static const struct tvp7002_timings_definition tvp7002_timings[] = { 205 }, { - V4L2_DV_1080I50, V4L2_DV_BT_CEA_1920X1080I50, tvp7002_parms_1080I50, V4L2_COLORSPACE_REC709, @@ -375,7 +371,6 @@ static const struct tvp7002_timings_definition tvp7002_timings[] = { 245 }, { - V4L2_DV_720P50, V4L2_DV_BT_CEA_1280X720P50, tvp7002_parms_720P50, V4L2_COLORSPACE_REC709, @@ -386,7 +381,6 @@ static const struct tvp7002_timings_definition tvp7002_timings[] = { 183 }, { - V4L2_DV_1080P60, V4L2_DV_BT_CEA_1920X1080P60, tvp7002_parms_1080P60, V4L2_COLORSPACE_REC709, @@ -397,7 +391,6 @@ static const struct tvp7002_timings_definition tvp7002_timings[] = { 102 }, { - V4L2_DV_480P59_94, V4L2_DV_BT_CEA_720X480P59_94, tvp7002_parms_480P, V4L2_COLORSPACE_SMPTE170M, @@ -408,7 +401,6 @@ static const struct tvp7002_timings_definition tvp7002_timings[] = { 0xffff }, { - V4L2_DV_576P50, V4L2_DV_BT_CEA_720X576P50, tvp7002_parms_576P, V4L2_COLORSPACE_SMPTE170M, @@ -588,32 +580,6 @@ static int tvp7002_write_inittab(struct v4l2_subdev *sd, return error; } -/* - * tvp7002_s_dv_preset() - Set digital video preset - * @sd: ptr to v4l2_subdev struct - * @dv_preset: ptr to v4l2_dv_preset struct - * - * Set the digital video preset for a TVP7002 decoder device. - * Returns zero when successful or -EINVAL if register access fails. - */ -static int tvp7002_s_dv_preset(struct v4l2_subdev *sd, - struct v4l2_dv_preset *dv_preset) -{ - struct tvp7002 *device = to_tvp7002(sd); - u32 preset; - int i; - - for (i = 0; i < NUM_TIMINGS; i++) { - preset = tvp7002_timings[i].preset; - if (preset == dv_preset->preset) { - device->current_timings = &tvp7002_timings[i]; - return tvp7002_write_inittab(sd, tvp7002_timings[i].p_settings); - } - } - - return -EINVAL; -} - static int tvp7002_s_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *dv_timings) { @@ -752,22 +718,6 @@ static int tvp7002_query_dv(struct v4l2_subdev *sd, int *index) return 0; } -static int tvp7002_query_dv_preset(struct v4l2_subdev *sd, - struct v4l2_dv_preset *qpreset) -{ - int index; - int err = tvp7002_query_dv(sd, &index); - - if (err || index == NUM_TIMINGS) { - qpreset->preset = V4L2_DV_INVALID; - if (err == -ENOLINK) - err = 0; - return err; - } - qpreset->preset = tvp7002_timings[index].preset; - return 0; -} - static int tvp7002_query_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { @@ -915,23 +865,6 @@ static int tvp7002_log_status(struct v4l2_subdev *sd) return 0; } -/* - * tvp7002_enum_dv_presets() - Enum supported digital video formats - * @sd: pointer to standard V4L2 sub-device structure - * @preset: pointer to format struct - * - * Enumerate supported digital video formats. - */ -static int tvp7002_enum_dv_presets(struct v4l2_subdev *sd, - struct v4l2_dv_enum_preset *preset) -{ - /* Check requested format index is within range */ - if (preset->index >= NUM_TIMINGS) - return -EINVAL; - - return v4l_fill_dv_preset_info(tvp7002_timings[preset->index].preset, preset); -} - static int tvp7002_enum_dv_timings(struct v4l2_subdev *sd, struct v4l2_enum_dv_timings *timings) { @@ -966,9 +899,6 @@ static const struct v4l2_subdev_core_ops tvp7002_core_ops = { /* Specific video subsystem operation handlers */ static const struct v4l2_subdev_video_ops tvp7002_video_ops = { - .enum_dv_presets = tvp7002_enum_dv_presets, - .s_dv_preset = tvp7002_s_dv_preset, - .query_dv_preset = tvp7002_query_dv_preset, .g_dv_timings = tvp7002_g_dv_timings, .s_dv_timings = tvp7002_s_dv_timings, .enum_dv_timings = tvp7002_enum_dv_timings, -- cgit v1.2.3 From ef2d41b19b8100ce63eabba9ee87953aa685921a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 15:06:28 -0300 Subject: [media] davinci: remove VPBE_ENC_DV_PRESET and rename VPBE_ENC_CUSTOM_TIMINGS Remove VPBE_ENC_DV_PRESET (the DV_PRESET API is no longer supported) and VPBE_ENC_CUSTOM_TIMINGS is renamed to VPBE_ENC_DV_TIMINGS since the old "CUSTOM_TIMINGS" name is deprecated in favor of "DV_TIMINGS". Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Acked-by: Sekhar Nori Signed-off-by: Mauro Carvalho Chehab --- arch/arm/mach-davinci/board-dm644x-evm.c | 4 ++-- arch/arm/mach-davinci/dm644x.c | 2 +- drivers/media/platform/davinci/vpbe.c | 8 ++++---- drivers/media/platform/davinci/vpbe_display.c | 2 +- drivers/media/platform/davinci/vpbe_venc.c | 8 ++++---- include/media/davinci/vpbe_types.h | 3 +-- 6 files changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers/media') diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 71735e7797cc..a02180052a76 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -649,7 +649,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = { static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = { { .name = "480p59_94", - .timings_type = VPBE_ENC_CUSTOM_TIMINGS, + .timings_type = VPBE_ENC_DV_TIMINGS, .dv_timings = V4L2_DV_BT_CEA_720X480P59_94, .interlaced = 0, .xres = 720, @@ -661,7 +661,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_preset_timing[] = { }, { .name = "576p50", - .timings_type = VPBE_ENC_CUSTOM_TIMINGS, + .timings_type = VPBE_ENC_DV_TIMINGS, .dv_timings = V4L2_DV_BT_CEA_720X576P50, .interlaced = 0, .xres = 720, diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index db1dd92e00af..ee0e994748e0 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -706,7 +706,7 @@ static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type, v |= DM644X_VPSS_DACCLKEN; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); break; - case VPBE_ENC_CUSTOM_TIMINGS: + case VPBE_ENC_DV_TIMINGS: if (pclock <= 27000000) { v |= DM644X_VPSS_DACCLKEN; writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL)); diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 4ca0f9a2ad8a..2a49f00c4543 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -344,7 +344,7 @@ static int vpbe_s_dv_timings(struct vpbe_device *vpbe_dev, return -EINVAL; for (i = 0; i < output->num_modes; i++) { - if (output->modes[i].timings_type == VPBE_ENC_CUSTOM_TIMINGS && + if (output->modes[i].timings_type == VPBE_ENC_DV_TIMINGS && !memcmp(&output->modes[i].dv_timings, dv_timings, sizeof(*dv_timings))) break; @@ -385,7 +385,7 @@ static int vpbe_g_dv_timings(struct vpbe_device *vpbe_dev, struct v4l2_dv_timings *dv_timings) { if (vpbe_dev->current_timings.timings_type & - VPBE_ENC_CUSTOM_TIMINGS) { + VPBE_ENC_DV_TIMINGS) { *dv_timings = vpbe_dev->current_timings.dv_timings; return 0; } @@ -412,7 +412,7 @@ static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev, return -EINVAL; for (i = 0; i < output->num_modes; i++) { - if (output->modes[i].timings_type == VPBE_ENC_CUSTOM_TIMINGS) { + if (output->modes[i].timings_type == VPBE_ENC_DV_TIMINGS) { if (j == timings->index) break; j++; @@ -515,7 +515,7 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev, return vpbe_s_std(vpbe_dev, &preset_mode->std_id); if (preset_mode->timings_type & - VPBE_ENC_CUSTOM_TIMINGS) { + VPBE_ENC_DV_TIMINGS) { dv_timings = preset_mode->dv_timings; return vpbe_s_dv_timings(vpbe_dev, &dv_timings); diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 9f9f2c1a073f..8290fddbd47d 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -1202,7 +1202,7 @@ vpbe_display_g_dv_timings(struct file *file, void *priv, /* Get the given standard in the encoder */ if (vpbe_dev->current_timings.timings_type & - VPBE_ENC_CUSTOM_TIMINGS) { + VPBE_ENC_DV_TIMINGS) { *dv_timings = vpbe_dev->current_timings.dv_timings; } else { return -EINVAL; diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c index bdbebd59df98..9546d268e2db 100644 --- a/drivers/media/platform/davinci/vpbe_venc.c +++ b/drivers/media/platform/davinci/vpbe_venc.c @@ -313,7 +313,7 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd) return -EINVAL; /* Setup clock at VPSS & VENC for SD */ - if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 27000000) < 0) + if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -360,7 +360,7 @@ static int venc_set_576p50(struct v4l2_subdev *sd) venc->venc_type != VPBE_VERSION_2) return -EINVAL; /* Setup clock at VPSS & VENC for SD */ - if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 27000000) < 0) + if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -400,7 +400,7 @@ static int venc_set_720p60_internal(struct v4l2_subdev *sd) struct venc_state *venc = to_state(sd); struct venc_platform_data *pdata = venc->pdata; - if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 74250000) < 0) + if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); @@ -428,7 +428,7 @@ static int venc_set_1080i30_internal(struct v4l2_subdev *sd) struct venc_state *venc = to_state(sd); struct venc_platform_data *pdata = venc->pdata; - if (pdata->setup_clock(VPBE_ENC_CUSTOM_TIMINGS, 74250000) < 0) + if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0) return -EINVAL; venc_enabledigitaloutput(sd, 0); diff --git a/include/media/davinci/vpbe_types.h b/include/media/davinci/vpbe_types.h index 9b85396514be..05dbe0ba514c 100644 --- a/include/media/davinci/vpbe_types.h +++ b/include/media/davinci/vpbe_types.h @@ -26,8 +26,7 @@ enum vpbe_version { /* vpbe_timing_type - Timing types used in vpbe device */ enum vpbe_enc_timings_type { VPBE_ENC_STD = 0x1, - VPBE_ENC_DV_PRESET = 0x2, - VPBE_ENC_CUSTOM_TIMINGS = 0x4, + VPBE_ENC_DV_TIMINGS = 0x4, /* Used when set timings through FB device interface */ VPBE_ENC_TIMINGS_INVALID = 0x8, }; -- cgit v1.2.3 From 6f55dbaea5381831770025a98c04b5fc2f7e18ba Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Mar 2013 05:48:43 -0300 Subject: [media] davinci/vpfe_capture: convert to the control framework Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 47 ++++----------------------- 1 file changed, 7 insertions(+), 40 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 28d019da4c01..70facc03e6e0 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1107,6 +1107,7 @@ static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) static int vpfe_s_input(struct file *file, void *priv, unsigned int index) { struct vpfe_device *vpfe_dev = video_drvdata(file); + struct v4l2_subdev *sd; struct vpfe_subdev_info *sdinfo; int subdev_index, inp_index; struct vpfe_route *route; @@ -1138,14 +1139,15 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index) } sdinfo = &vpfe_dev->cfg->sub_devs[subdev_index]; + sd = vpfe_dev->sd[subdev_index]; route = &sdinfo->routes[inp_index]; if (route && sdinfo->can_route) { input = route->input; output = route->output; } - ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - video, s_routing, input, output, 0); + if (sd) + ret = v4l2_subdev_call(sd, video, s_routing, input, output, 0); if (ret) { v4l2_err(&vpfe_dev->v4l2_dev, @@ -1154,6 +1156,8 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index) goto unlock_out; } vpfe_dev->current_subdev = sdinfo; + if (sd) + vpfe_dev->v4l2_dev.ctrl_handler = sd->ctrl_handler; vpfe_dev->current_input = index; vpfe_dev->std_index = 0; @@ -1439,41 +1443,6 @@ static int vpfe_dqbuf(struct file *file, void *priv, buf, file->f_flags & O_NONBLOCK); } -static int vpfe_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - - sdinfo = vpfe_dev->current_subdev; - - return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, queryctrl, qctrl); - -} - -static int vpfe_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - - sdinfo = vpfe_dev->current_subdev; - - return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, g_ctrl, ctrl); -} - -static int vpfe_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) -{ - struct vpfe_device *vpfe_dev = video_drvdata(file); - struct vpfe_subdev_info *sdinfo; - - sdinfo = vpfe_dev->current_subdev; - - return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, s_ctrl, ctrl); -} - /* * vpfe_calculate_offsets : This function calculates buffers offset * for top and bottom field @@ -1781,9 +1750,6 @@ static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { .vidioc_querystd = vpfe_querystd, .vidioc_s_std = vpfe_s_std, .vidioc_g_std = vpfe_g_std, - .vidioc_queryctrl = vpfe_queryctrl, - .vidioc_g_ctrl = vpfe_g_ctrl, - .vidioc_s_ctrl = vpfe_s_ctrl, .vidioc_reqbufs = vpfe_reqbufs, .vidioc_querybuf = vpfe_querybuf, .vidioc_qbuf = vpfe_qbuf, @@ -2007,6 +1973,7 @@ static int vpfe_probe(struct platform_device *pdev) /* set first sub device as current one */ vpfe_dev->current_subdev = &vpfe_cfg->sub_devs[0]; + vpfe_dev->v4l2_dev.ctrl_handler = vpfe_dev->sd[0]->ctrl_handler; /* We have at least one sub device to work with */ mutex_unlock(&ccdc_lock); -- cgit v1.2.3 From 142b66e82c39ad7e8e7e80c738718aa653bcad1b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 19 Feb 2013 13:33:34 -0300 Subject: [media] davinci/vpbe_display: remove deprecated current_norm Since vpbe_display already provides a g_std op setting current_norm didn't do anything. Remove that code. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe_display.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 8290fddbd47d..30976dc9f346 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -1176,10 +1176,6 @@ vpbe_display_s_dv_timings(struct file *file, void *priv, "Failed to set the dv timings info\n"); return -EINVAL; } - /* set the current norm to zero to be consistent. If STD is used - * v4l2 layer will set the norm properly on successful s_std call - */ - layer->video_dev.current_norm = 0; return 0; } @@ -1694,12 +1690,8 @@ static int init_vpbe_layer(int i, struct vpbe_display *disp_dev, vbd->vfl_dir = VFL_DIR_TX; if (disp_dev->vpbe_dev->current_timings.timings_type & - VPBE_ENC_STD) { + VPBE_ENC_STD) vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50); - vbd->current_norm = - disp_dev->vpbe_dev->current_timings.std_id; - } else - vbd->current_norm = 0; snprintf(vbd->name, sizeof(vbd->name), "DaVinci_VPBE Display_DRIVER_V%d.%d.%d", -- cgit v1.2.3 From b12aed0ec518eb348ae0f6d196fd726c57670823 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 19 Feb 2013 13:34:52 -0300 Subject: [media] davinci/vpfe_capture: remove current_norm Since vpfe_capture already provided a g_std op setting current_norm does not actually do anything. Remove it. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 70facc03e6e0..3d1af6704822 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1884,7 +1884,6 @@ static int vpfe_probe(struct platform_device *pdev) vfd->fops = &vpfe_fops; vfd->ioctl_ops = &vpfe_ioctl_ops; vfd->tvnorms = 0; - vfd->current_norm = V4L2_STD_PAL; vfd->v4l2_dev = &vpfe_dev->v4l2_dev; snprintf(vfd->name, sizeof(vfd->name), "%s_V%d.%d.%d", -- cgit v1.2.3 From 1de1951930d4450d1645a0a907b710f268af42c3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Mar 2013 07:18:38 -0300 Subject: [media] davinci/dm644x_ccdc: fix compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/media/platform/davinci/dm644x_ccdc.c: In function ‘validate_ccdc_param’: drivers/media/platform/davinci/dm644x_ccdc.c:233:32: warning: comparison between ‘enum ccdc_gama_width’ and ‘enum ccdc_data_size’ [-Wenum-compare] It took a bit of work, see this thread of an earlier attempt to fix this: https://patchwork.kernel.org/patch/1923091/ I've chosen not to follow the suggestions in that thread since gamma_width is really a different property from data_size. What you really want is to know if gamma_width fits inside data_size and for that you need to translate each enum into a maximum bit number so you can safely compare the two. So I put in two static inline translation functions instead, keeping the rest of the code the same (except for fixing the 'gama' typo). Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/dm644x_ccdc.c | 13 +++++++----- drivers/media/platform/davinci/dm644x_ccdc_regs.h | 2 +- include/media/davinci/dm644x_ccdc.h | 24 +++++++++++++++++------ 3 files changed, 27 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c index 318e80512998..971d639b6674 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc.c +++ b/drivers/media/platform/davinci/dm644x_ccdc.c @@ -228,9 +228,12 @@ static void ccdc_readregs(void) static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) { if (ccdcparam->alaw.enable) { - if ((ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) || - (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_15_6) || - (ccdcparam->alaw.gama_wd < ccdcparam->data_sz)) { + u8 max_gamma = ccdc_gamma_width_max_bit(ccdcparam->alaw.gamma_wd); + u8 max_data = ccdc_data_size_max_bit(ccdcparam->data_sz); + + if ((ccdcparam->alaw.gamma_wd > CCDC_GAMMA_BITS_09_0) || + (ccdcparam->alaw.gamma_wd < CCDC_GAMMA_BITS_15_6) || + (max_gamma > max_data)) { dev_dbg(ccdc_cfg.dev, "\nInvalid data line select"); return -1; } @@ -560,8 +563,8 @@ void ccdc_config_raw(void) /* Enable and configure aLaw register if needed */ if (config_params->alaw.enable) { - val = ((config_params->alaw.gama_wd & - CCDC_ALAW_GAMA_WD_MASK) | CCDC_ALAW_ENABLE); + val = ((config_params->alaw.gamma_wd & + CCDC_ALAW_GAMMA_WD_MASK) | CCDC_ALAW_ENABLE); regw(val, CCDC_ALAW); dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to ALAW...\n", val); } diff --git a/drivers/media/platform/davinci/dm644x_ccdc_regs.h b/drivers/media/platform/davinci/dm644x_ccdc_regs.h index 90370e414e2c..2b0aca5383f0 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc_regs.h +++ b/drivers/media/platform/davinci/dm644x_ccdc_regs.h @@ -84,7 +84,7 @@ #define CCDC_VDHDEN_ENABLE (1 << 16) #define CCDC_LPF_ENABLE (1 << 14) #define CCDC_ALAW_ENABLE (1 << 3) -#define CCDC_ALAW_GAMA_WD_MASK 7 +#define CCDC_ALAW_GAMMA_WD_MASK 7 #define CCDC_BLK_CLAMP_ENABLE (1 << 31) #define CCDC_BLK_SGAIN_MASK 0x1F #define CCDC_BLK_ST_PXL_MASK 0x7FFF diff --git a/include/media/davinci/dm644x_ccdc.h b/include/media/davinci/dm644x_ccdc.h index 3e178eb52fb3..852e96c4bb46 100644 --- a/include/media/davinci/dm644x_ccdc.h +++ b/include/media/davinci/dm644x_ccdc.h @@ -38,17 +38,23 @@ enum ccdc_sample_line { CCDC_SAMPLE_16LINES }; -/* enum for Alaw gama width */ -enum ccdc_gama_width { - CCDC_GAMMA_BITS_15_6, +/* enum for Alaw gamma width */ +enum ccdc_gamma_width { + CCDC_GAMMA_BITS_15_6, /* use bits 15-6 for gamma */ CCDC_GAMMA_BITS_14_5, CCDC_GAMMA_BITS_13_4, CCDC_GAMMA_BITS_12_3, CCDC_GAMMA_BITS_11_2, CCDC_GAMMA_BITS_10_1, - CCDC_GAMMA_BITS_09_0 + CCDC_GAMMA_BITS_09_0 /* use bits 9-0 for gamma */ }; +/* returns the highest bit used for the gamma */ +static inline u8 ccdc_gamma_width_max_bit(enum ccdc_gamma_width width) +{ + return 15 - width; +} + enum ccdc_data_size { CCDC_DATA_16BITS, CCDC_DATA_15BITS, @@ -60,12 +66,18 @@ enum ccdc_data_size { CCDC_DATA_8BITS }; +/* returns the highest bit used for this data size */ +static inline u8 ccdc_data_size_max_bit(enum ccdc_data_size sz) +{ + return sz == CCDC_DATA_8BITS ? 7 : 15 - sz; +} + /* structure for ALaw */ struct ccdc_a_law { /* Enable/disable A-Law */ unsigned char enable; - /* Gama Width Input */ - enum ccdc_gama_width gama_wd; + /* Gamma Width Input */ + enum ccdc_gamma_width gamma_wd; }; /* structure for Black Clamping */ -- cgit v1.2.3 From db242f62bd18f6c689c0e04f3df14be2deb89462 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Mar 2013 07:24:07 -0300 Subject: [media] davinci: more gama -> gamma typo fixes Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/dm355_ccdc.c | 10 +++++----- drivers/media/platform/davinci/dm355_ccdc_regs.h | 2 +- drivers/media/platform/davinci/isif.c | 2 +- drivers/media/platform/davinci/isif_regs.h | 4 ++-- include/media/davinci/dm355_ccdc.h | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c index 4277e4ad810c..2364dbab8046 100644 --- a/drivers/media/platform/davinci/dm355_ccdc.c +++ b/drivers/media/platform/davinci/dm355_ccdc.c @@ -85,7 +85,7 @@ static struct ccdc_oper_config { .mfilt1 = CCDC_NO_MEDIAN_FILTER1, .mfilt2 = CCDC_NO_MEDIAN_FILTER2, .alaw = { - .gama_wd = 2, + .gamma_wd = 2, }, .blk_clamp = { .sample_pixel = 1, @@ -303,8 +303,8 @@ static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam) } if (ccdcparam->alaw.enable) { - if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 || - ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) { + if (ccdcparam->alaw.gamma_wd < CCDC_GAMMA_BITS_13_4 || + ccdcparam->alaw.gamma_wd > CCDC_GAMMA_BITS_09_0) { dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n"); return -EINVAL; } @@ -680,8 +680,8 @@ static int ccdc_config_raw(void) /* Enable and configure aLaw register if needed */ if (config_params->alaw.enable) { val |= (CCDC_ALAW_ENABLE | - ((config_params->alaw.gama_wd & - CCDC_ALAW_GAMA_WD_MASK) << + ((config_params->alaw.gamma_wd & + CCDC_ALAW_GAMMA_WD_MASK) << CCDC_GAMMAWD_INPUT_SHIFT)); } diff --git a/drivers/media/platform/davinci/dm355_ccdc_regs.h b/drivers/media/platform/davinci/dm355_ccdc_regs.h index d6d2ef0533b5..2e1946e0b99f 100644 --- a/drivers/media/platform/davinci/dm355_ccdc_regs.h +++ b/drivers/media/platform/davinci/dm355_ccdc_regs.h @@ -153,7 +153,7 @@ #define CCDC_VDHDEN_ENABLE (1 << 16) #define CCDC_LPF_ENABLE (1 << 14) #define CCDC_ALAW_ENABLE 1 -#define CCDC_ALAW_GAMA_WD_MASK 7 +#define CCDC_ALAW_GAMMA_WD_MASK 7 #define CCDC_REC656IF_BT656_EN 3 #define CCDC_FMTCFG_FMTMODE_MASK 3 diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c index 5050f9265f48..abc3ae36645c 100644 --- a/drivers/media/platform/davinci/isif.c +++ b/drivers/media/platform/davinci/isif.c @@ -604,7 +604,7 @@ static int isif_config_raw(void) if (module_params->compress.alg == ISIF_ALAW) val |= ISIF_ALAW_ENABLE; - val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT); + val |= (params->data_msb << ISIF_ALAW_GAMMA_WD_SHIFT); regw(val, CGAMMAWD); /* Configure DPCM compression settings */ diff --git a/drivers/media/platform/davinci/isif_regs.h b/drivers/media/platform/davinci/isif_regs.h index aa69a463c122..3993aece821b 100644 --- a/drivers/media/platform/davinci/isif_regs.h +++ b/drivers/media/platform/davinci/isif_regs.h @@ -203,8 +203,8 @@ #define ISIF_LPF_MASK 1 /* GAMMAWD registers */ -#define ISIF_ALAW_GAMA_WD_MASK 0xF -#define ISIF_ALAW_GAMA_WD_SHIFT 1 +#define ISIF_ALAW_GAMMA_WD_MASK 0xF +#define ISIF_ALAW_GAMMA_WD_SHIFT 1 #define ISIF_ALAW_ENABLE 1 #define ISIF_GAMMAWD_CFA_SHIFT 5 diff --git a/include/media/davinci/dm355_ccdc.h b/include/media/davinci/dm355_ccdc.h index adf2fe4bf0bb..c669a9fb75e5 100644 --- a/include/media/davinci/dm355_ccdc.h +++ b/include/media/davinci/dm355_ccdc.h @@ -38,7 +38,7 @@ enum ccdc_sample_line { CCDC_SAMPLE_16LINES }; -/* enum for Alaw gama width */ +/* enum for Alaw gamma width */ enum ccdc_gamma_width { CCDC_GAMMA_BITS_13_4, CCDC_GAMMA_BITS_12_3, @@ -97,8 +97,8 @@ enum ccdc_mfilt2 { struct ccdc_a_law { /* Enable/disable A-Law */ unsigned char enable; - /* Gama Width Input */ - enum ccdc_gamma_width gama_wd; + /* Gamma Width Input */ + enum ccdc_gamma_width gamma_wd; }; /* structure for Black Clamping */ -- cgit v1.2.3 From a8451ed205774398084de4a71e6794b86c94b5e5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 15:12:01 -0300 Subject: [media] blackfin: replace V4L2_IN/OUT_CAP_CUSTOM_TIMINGS by DV_TIMINGS The use of V4L2_IN/OUT_CAP_CUSTOM_TIMINGS is obsolete, use DV_TIMINGS instead. Note that V4L2_IN/OUT_CAP_CUSTOM_TIMINGS is just a #define for V4L2_IN/OUT_CAP_DV_TIMINGS. At some point in the future these CUSTOM_TIMINGS defines might be removed. Signed-off-by: Hans Verkuil Acked-by: Scott Jiang Signed-off-by: Mauro Carvalho Chehab --- arch/blackfin/mach-bf609/boards/ezkit.c | 8 ++++---- drivers/media/platform/blackfin/bfin_capture.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/arch/blackfin/mach-bf609/boards/ezkit.c b/arch/blackfin/mach-bf609/boards/ezkit.c index 61c1f47a4bf2..97d701639585 100644 --- a/arch/blackfin/mach-bf609/boards/ezkit.c +++ b/arch/blackfin/mach-bf609/boards/ezkit.c @@ -936,19 +936,19 @@ static struct v4l2_input adv7842_inputs[] = { .index = 2, .name = "Component", .type = V4L2_INPUT_TYPE_CAMERA, - .capabilities = V4L2_IN_CAP_CUSTOM_TIMINGS, + .capabilities = V4L2_IN_CAP_DV_TIMINGS, }, { .index = 3, .name = "VGA", .type = V4L2_INPUT_TYPE_CAMERA, - .capabilities = V4L2_IN_CAP_CUSTOM_TIMINGS, + .capabilities = V4L2_IN_CAP_DV_TIMINGS, }, { .index = 4, .name = "HDMI", .type = V4L2_INPUT_TYPE_CAMERA, - .capabilities = V4L2_IN_CAP_CUSTOM_TIMINGS, + .capabilities = V4L2_IN_CAP_DV_TIMINGS, }, }; @@ -1074,7 +1074,7 @@ static struct v4l2_output adv7511_outputs[] = { .index = 0, .name = "HDMI", .type = V4L2_INPUT_TYPE_CAMERA, - .capabilities = V4L2_OUT_CAP_CUSTOM_TIMINGS, + .capabilities = V4L2_OUT_CAP_DV_TIMINGS, }, }; diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 8ffe42aabd85..476cfc88d144 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -384,7 +384,7 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) params.ppi_control = bcap_dev->cfg->ppi_control; params.int_mask = bcap_dev->cfg->int_mask; if (bcap_dev->cfg->inputs[bcap_dev->cur_input].capabilities - & V4L2_IN_CAP_CUSTOM_TIMINGS) { + & V4L2_IN_CAP_DV_TIMINGS) { struct v4l2_bt_timings *bt = &bcap_dev->dv_timings.bt; params.hdelay = bt->hsync + bt->hbackporch; @@ -1111,7 +1111,7 @@ static int bcap_probe(struct platform_device *pdev) } bcap_dev->std = std; } - if (config->inputs[0].capabilities & V4L2_IN_CAP_CUSTOM_TIMINGS) { + if (config->inputs[0].capabilities & V4L2_IN_CAP_DV_TIMINGS) { struct v4l2_dv_timings dv_timings; ret = v4l2_subdev_call(bcap_dev->sd, video, g_dv_timings, &dv_timings); -- cgit v1.2.3 From 0ea21a524070f17f0bc06aafd43a2efaa0940d8f Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Fri, 8 Mar 2013 06:22:10 -0300 Subject: [media] davinci: vpbe: fix module build add a null entry in platform_device_id {}. This patch fixes following error: drivers/media/platform/davinci/vpbe_venc: struct platform_device_id is 24 bytes. The last of 3 is: 0x64 0x6d 0x33 0x35 0x35 0x2c 0x76 0x70 0x62 0x65 0x2d 0x76 0x65 0x6e 0x63 0x00 0x00 0x00 0x00 0x00 0x03 0x00 0x00 0x00 FATAL: drivers/media/platform/davinci/vpbe_venc: struct platform_device_id is not terminated with a NULL entry! make[1]: *** [__modpost] Error 1 Reported-by: Sekhar Nori Signed-off-by: Lad, Prabhakar Tested-by: Sekhar Nori Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe_osd.c | 3 +++ drivers/media/platform/davinci/vpbe_venc.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c index 12ad17c52ef3..396a51cbede7 100644 --- a/drivers/media/platform/davinci/vpbe_osd.c +++ b/drivers/media/platform/davinci/vpbe_osd.c @@ -52,6 +52,9 @@ static struct platform_device_id vpbe_osd_devtype[] = { .name = DM355_VPBE_OSD_SUBDEV_NAME, .driver_data = VPBE_VERSION_3, }, + { + /* sentinel */ + } }; MODULE_DEVICE_TABLE(platform, vpbe_osd_devtype); diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c index 9546d268e2db..f15f211a5508 100644 --- a/drivers/media/platform/davinci/vpbe_venc.c +++ b/drivers/media/platform/davinci/vpbe_venc.c @@ -51,6 +51,9 @@ static struct platform_device_id vpbe_venc_devtype[] = { .name = DM355_VPBE_VENC_SUBDEV_NAME, .driver_data = VPBE_VERSION_3, }, + { + /* sentinel */ + } }; MODULE_DEVICE_TABLE(platform, vpbe_venc_devtype); -- cgit v1.2.3 From f82757d912b916348976c464ddc80539d89c851d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 6 Mar 2013 07:09:54 -0300 Subject: [media] siano: Change GPIO voltage setting names Siano changed the namespace on more recent API, and re-used some of the old names. In order to be able to update the API to support newer chips, the better is to follow this change. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/sms-cards.c | 2 +- drivers/media/common/siano/smscoreapi.c | 8 ++++---- drivers/media/common/siano/smscoreapi.h | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 680c781c8dd6..8ee2e92b9b1a 100644 --- a/drivers/media/common/siano/sms-cards.c +++ b/drivers/media/common/siano/sms-cards.c @@ -183,7 +183,7 @@ static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable) .pullupdown = SMS_GPIO_PULLUPDOWN_NONE, .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL, .outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST, - .outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA, + .outputdriving = SMS_GPIO_OUTPUTDRIVING_S_4mA, }; if (pin == 0) diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 9565dcc8381f..3b2fc872ca0b 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1305,16 +1305,16 @@ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, msg.data[2] = pinconfig->outputslewrate == 0 ? 3 : 0; switch (pinconfig->outputdriving) { - case SMS_GPIO_OUTPUTDRIVING_16mA: + case SMS_GPIO_OUTPUTDRIVING_S_16mA: msg.data[3] = 7; /* Nova - 16mA */ break; - case SMS_GPIO_OUTPUTDRIVING_12mA: + case SMS_GPIO_OUTPUTDRIVING_S_12mA: msg.data[3] = 5; /* Nova - 11mA */ break; - case SMS_GPIO_OUTPUTDRIVING_8mA: + case SMS_GPIO_OUTPUTDRIVING_S_8mA: msg.data[3] = 3; /* Nova - 7mA */ break; - case SMS_GPIO_OUTPUTDRIVING_4mA: + case SMS_GPIO_OUTPUTDRIVING_S_4mA: default: msg.data[3] = 2; /* Nova - 4mA */ break; diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index c592ae090397..a6d29a2426a1 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -642,10 +642,10 @@ struct smscore_config_gpio { #define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1 u8 outputslewrate; -#define SMS_GPIO_OUTPUTDRIVING_4mA 0 -#define SMS_GPIO_OUTPUTDRIVING_8mA 1 -#define SMS_GPIO_OUTPUTDRIVING_12mA 2 -#define SMS_GPIO_OUTPUTDRIVING_16mA 3 +#define SMS_GPIO_OUTPUTDRIVING_S_4mA 0 +#define SMS_GPIO_OUTPUTDRIVING_S_8mA 1 +#define SMS_GPIO_OUTPUTDRIVING_S_12mA 2 +#define SMS_GPIO_OUTPUTDRIVING_S_16mA 3 u8 outputdriving; }; -- cgit v1.2.3 From 739a8c91a39cd2bc3fce23ab4368816150fcf27a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 6 Mar 2013 07:14:51 -0300 Subject: [media] siano: Add the new voltage definitions for GPIO Those new definitions came from this patch, from Doron Cohen: http://patchwork.linuxtv.org/patch/7882/ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index a6d29a2426a1..62f05e89da0e 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -642,10 +642,22 @@ struct smscore_config_gpio { #define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1 u8 outputslewrate; + /* 10xx */ #define SMS_GPIO_OUTPUTDRIVING_S_4mA 0 #define SMS_GPIO_OUTPUTDRIVING_S_8mA 1 #define SMS_GPIO_OUTPUTDRIVING_S_12mA 2 #define SMS_GPIO_OUTPUTDRIVING_S_16mA 3 + + /* 11xx*/ +#define SMS_GPIO_OUTPUTDRIVING_1_5mA 0 +#define SMS_GPIO_OUTPUTDRIVING_2_8mA 1 +#define SMS_GPIO_OUTPUTDRIVING_4mA 2 +#define SMS_GPIO_OUTPUTDRIVING_7mA 3 +#define SMS_GPIO_OUTPUTDRIVING_10mA 4 +#define SMS_GPIO_OUTPUTDRIVING_11mA 5 +#define SMS_GPIO_OUTPUTDRIVING_14mA 6 +#define SMS_GPIO_OUTPUTDRIVING_16mA 7 + u8 outputdriving; }; -- cgit v1.2.3 From c31b9fb26069d0beedb3125a4ff3c1d0f8051d26 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 6 Mar 2013 08:30:08 -0300 Subject: [media] siano: remove a duplicated structure definition The same GPIO config struct was declared twice at the driver, with different names and different macros: struct smscore_config_gpio struct smscore_config_gpio Remove the one that uses CamelCase and fix the references to its attributes/macros. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/sms-cards.c | 18 +++++------ drivers/media/common/siano/smscoreapi.c | 20 ++++++------ drivers/media/common/siano/smscoreapi.h | 55 +++++++-------------------------- 3 files changed, 30 insertions(+), 63 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 8ee2e92b9b1a..b22b61dbc0e2 100644 --- a/drivers/media/common/siano/sms-cards.c +++ b/drivers/media/common/siano/sms-cards.c @@ -109,18 +109,18 @@ struct sms_board *sms_get_board(unsigned id) } EXPORT_SYMBOL_GPL(sms_get_board); static inline void sms_gpio_assign_11xx_default_led_config( - struct smscore_gpio_config *pGpioConfig) { - pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT; - pGpioConfig->InputCharacteristics = - SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL; - pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA; - pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS; - pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE; + struct smscore_config_gpio *pGpioConfig) { + pGpioConfig->direction = SMS_GPIO_DIRECTION_OUTPUT; + pGpioConfig->inputcharacteristics = + SMS_GPIO_INPUTCHARACTERISTICS_NORMAL; + pGpioConfig->outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA; + pGpioConfig->outputslewrate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS; + pGpioConfig->pullupdown = SMS_GPIO_PULLUPDOWN_NONE; } int sms_board_event(struct smscore_device_t *coredev, enum SMS_BOARD_EVENTS gevent) { - struct smscore_gpio_config MyGpioConfig; + struct smscore_config_gpio MyGpioConfig; sms_gpio_assign_11xx_default_led_config(&MyGpioConfig); @@ -182,7 +182,7 @@ static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable) .direction = SMS_GPIO_DIRECTION_OUTPUT, .pullupdown = SMS_GPIO_PULLUPDOWN_NONE, .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL, - .outputslewrate = SMS_GPIO_OUTPUTSLEWRATE_FAST, + .outputslewrate = SMS_GPIO_OUTPUT_SLEW_RATE_FAST, .outputdriving = SMS_GPIO_OUTPUTDRIVING_S_4mA, }; diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 3b2fc872ca0b..804eb32fd8cc 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1405,7 +1405,7 @@ static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum, } int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, - struct smscore_gpio_config *pGpioConfig) { + struct smscore_config_gpio *pGpioConfig) { u32 totalLen; u32 TranslatedPinNum = 0; @@ -1452,19 +1452,19 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, pMsg->msgData[1] = TranslatedPinNum; pMsg->msgData[2] = GroupNum; - ElectricChar = (pGpioConfig->PullUpDown) - | (pGpioConfig->InputCharacteristics << 2) - | (pGpioConfig->OutputSlewRate << 3) - | (pGpioConfig->OutputDriving << 4); + ElectricChar = (pGpioConfig->pullupdown) + | (pGpioConfig->inputcharacteristics << 2) + | (pGpioConfig->outputslewrate << 3) + | (pGpioConfig->outputdriving << 4); pMsg->msgData[3] = ElectricChar; - pMsg->msgData[4] = pGpioConfig->Direction; + pMsg->msgData[4] = pGpioConfig->direction; pMsg->msgData[5] = groupCfg; } else { pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; - pMsg->msgData[1] = pGpioConfig->PullUpDown; - pMsg->msgData[2] = pGpioConfig->OutputSlewRate; - pMsg->msgData[3] = pGpioConfig->OutputDriving; - pMsg->msgData[4] = pGpioConfig->Direction; + pMsg->msgData[1] = pGpioConfig->pullupdown; + pMsg->msgData[2] = pGpioConfig->outputslewrate; + pMsg->msgData[3] = pGpioConfig->outputdriving; + pMsg->msgData[4] = pGpioConfig->direction; pMsg->msgData[5] = 0; } diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index 62f05e89da0e..f2510f50d1fe 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -638,8 +638,16 @@ struct smscore_config_gpio { #define SMS_GPIO_INPUTCHARACTERISTICS_SCHMITT 1 u8 inputcharacteristics; -#define SMS_GPIO_OUTPUTSLEWRATE_FAST 0 -#define SMS_GPIO_OUTPUTSLEWRATE_SLOW 1 + /* 10xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 +#define SMS_GPIO_OUTPUT_SLEW_WRATE_SLOW 1 + + /* 11xx */ +#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 +#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 +#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 +#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 + u8 outputslewrate; /* 10xx */ @@ -661,47 +669,6 @@ struct smscore_config_gpio { u8 outputdriving; }; -struct smscore_gpio_config { -#define SMS_GPIO_DIRECTION_INPUT 0 -#define SMS_GPIO_DIRECTION_OUTPUT 1 - u8 Direction; - -#define SMS_GPIO_PULL_UP_DOWN_NONE 0 -#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1 -#define SMS_GPIO_PULL_UP_DOWN_PULLUP 2 -#define SMS_GPIO_PULL_UP_DOWN_KEEPER 3 - u8 PullUpDown; - -#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL 0 -#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1 - u8 InputCharacteristics; - -#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW 1 /* 10xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST 0 /* 10xx */ - - -#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS 0 /* 11xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS 1 /* 11xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS 2 /* 11xx */ -#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS 3 /* 11xx */ - u8 OutputSlewRate; - -#define SMS_GPIO_OUTPUT_DRIVING_S_4mA 0 /* 10xx */ -#define SMS_GPIO_OUTPUT_DRIVING_S_8mA 1 /* 10xx */ -#define SMS_GPIO_OUTPUT_DRIVING_S_12mA 2 /* 10xx */ -#define SMS_GPIO_OUTPUT_DRIVING_S_16mA 3 /* 10xx */ - -#define SMS_GPIO_OUTPUT_DRIVING_1_5mA 0 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_2_8mA 1 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_4mA 2 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_7mA 3 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_10mA 4 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_11mA 5 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_14mA 6 /* 11xx */ -#define SMS_GPIO_OUTPUT_DRIVING_16mA 7 /* 11xx */ - u8 OutputDriving; -}; - extern void smscore_registry_setmode(char *devpath, int mode); extern int smscore_registry_getmode(char *devpath); @@ -750,7 +717,7 @@ int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level); /* new GPIO management */ extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, - struct smscore_gpio_config *pGpioConfig); + struct smscore_config_gpio *pGpioConfig); extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, u8 NewLevel); extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, -- cgit v1.2.3 From f251001c8086c8388aa7635b9fcd908b444e139c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 6 Mar 2013 07:16:19 -0300 Subject: [media] siano: update message macros Convert from #define into an enum and add the newer message macros as found on this patch from Doron Cohen: http://patchwork.linuxtv.org/patch/7882/ No messages got supressed. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.h | 374 +++++++++++++++++++++++++++----- 1 file changed, 321 insertions(+), 53 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index f2510f50d1fe..4a0a7639319d 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -194,59 +194,327 @@ struct smscore_device_t { #define SMS_MAX_PAYLOAD_SIZE 240 #define SMS_TUNE_TIMEOUT 500 -#define MSG_SMS_GPIO_CONFIG_REQ 507 -#define MSG_SMS_GPIO_CONFIG_RES 508 -#define MSG_SMS_GPIO_SET_LEVEL_REQ 509 -#define MSG_SMS_GPIO_SET_LEVEL_RES 510 -#define MSG_SMS_GPIO_GET_LEVEL_REQ 511 -#define MSG_SMS_GPIO_GET_LEVEL_RES 512 -#define MSG_SMS_RF_TUNE_REQ 561 -#define MSG_SMS_RF_TUNE_RES 562 -#define MSG_SMS_INIT_DEVICE_REQ 578 -#define MSG_SMS_INIT_DEVICE_RES 579 -#define MSG_SMS_ADD_PID_FILTER_REQ 601 -#define MSG_SMS_ADD_PID_FILTER_RES 602 -#define MSG_SMS_REMOVE_PID_FILTER_REQ 603 -#define MSG_SMS_REMOVE_PID_FILTER_RES 604 -#define MSG_SMS_DAB_CHANNEL 607 -#define MSG_SMS_GET_PID_FILTER_LIST_REQ 608 -#define MSG_SMS_GET_PID_FILTER_LIST_RES 609 -#define MSG_SMS_GET_STATISTICS_RES 616 -#define MSG_SMS_GET_STATISTICS_REQ 615 -#define MSG_SMS_HO_PER_SLICES_IND 630 -#define MSG_SMS_SET_ANTENNA_CONFIG_REQ 651 -#define MSG_SMS_SET_ANTENNA_CONFIG_RES 652 -#define MSG_SMS_SLEEP_RESUME_COMP_IND 655 -#define MSG_SMS_DATA_DOWNLOAD_REQ 660 -#define MSG_SMS_DATA_DOWNLOAD_RES 661 -#define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ 664 -#define MSG_SMS_SWDOWNLOAD_TRIGGER_RES 665 -#define MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ 666 -#define MSG_SMS_SWDOWNLOAD_BACKDOOR_RES 667 -#define MSG_SMS_GET_VERSION_EX_REQ 668 -#define MSG_SMS_GET_VERSION_EX_RES 669 -#define MSG_SMS_SET_CLOCK_OUTPUT_REQ 670 -#define MSG_SMS_I2C_SET_FREQ_REQ 685 -#define MSG_SMS_GENERIC_I2C_REQ 687 -#define MSG_SMS_GENERIC_I2C_RES 688 -#define MSG_SMS_DVBT_BDA_DATA 693 -#define MSG_SW_RELOAD_REQ 697 -#define MSG_SMS_DATA_MSG 699 -#define MSG_SW_RELOAD_START_REQ 702 -#define MSG_SW_RELOAD_START_RES 703 -#define MSG_SW_RELOAD_EXEC_REQ 704 -#define MSG_SW_RELOAD_EXEC_RES 705 -#define MSG_SMS_SPI_INT_LINE_SET_REQ 710 -#define MSG_SMS_GPIO_CONFIG_EX_REQ 712 -#define MSG_SMS_GPIO_CONFIG_EX_RES 713 -#define MSG_SMS_ISDBT_TUNE_REQ 776 -#define MSG_SMS_ISDBT_TUNE_RES 777 -#define MSG_SMS_TRANSMISSION_IND 782 -#define MSG_SMS_START_IR_REQ 800 -#define MSG_SMS_START_IR_RES 801 -#define MSG_SMS_IR_SAMPLES_IND 802 -#define MSG_SMS_SIGNAL_DETECTED_IND 827 -#define MSG_SMS_NO_SIGNAL_IND 828 +enum msg_types { + MSG_TYPE_BASE_VAL = 500, + MSG_SMS_GET_VERSION_REQ = 503, + MSG_SMS_GET_VERSION_RES = 504, + MSG_SMS_MULTI_BRIDGE_CFG = 505, + MSG_SMS_GPIO_CONFIG_REQ = 507, + MSG_SMS_GPIO_CONFIG_RES = 508, + MSG_SMS_GPIO_SET_LEVEL_REQ = 509, + MSG_SMS_GPIO_SET_LEVEL_RES = 510, + MSG_SMS_GPIO_GET_LEVEL_REQ = 511, + MSG_SMS_GPIO_GET_LEVEL_RES = 512, + MSG_SMS_EEPROM_BURN_IND = 513, + MSG_SMS_LOG_ENABLE_CHANGE_REQ = 514, + MSG_SMS_LOG_ENABLE_CHANGE_RES = 515, + MSG_SMS_SET_MAX_TX_MSG_LEN_REQ = 516, + MSG_SMS_SET_MAX_TX_MSG_LEN_RES = 517, + MSG_SMS_SPI_HALFDUPLEX_TOKEN_HOST_TO_DEVICE = 518, + MSG_SMS_SPI_HALFDUPLEX_TOKEN_DEVICE_TO_HOST = 519, + MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_REQ = 520, + MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_RES = 521, + MSG_SMS_BACKGROUND_SCAN_SIGNAL_DETECTED_IND = 522, + MSG_SMS_BACKGROUND_SCAN_NO_SIGNAL_IND = 523, + MSG_SMS_CONFIGURE_RF_SWITCH_REQ = 524, + MSG_SMS_CONFIGURE_RF_SWITCH_RES = 525, + MSG_SMS_MRC_PATH_DISCONNECT_REQ = 526, + MSG_SMS_MRC_PATH_DISCONNECT_RES = 527, + MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_REQ = 528, + MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_RES = 529, + MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_REQ = 530, + MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_RES = 531, + MSG_WR_REG_RFT_REQ = 533, + MSG_WR_REG_RFT_RES = 534, + MSG_RD_REG_RFT_REQ = 535, + MSG_RD_REG_RFT_RES = 536, + MSG_RD_REG_ALL_RFT_REQ = 537, + MSG_RD_REG_ALL_RFT_RES = 538, + MSG_HELP_INT = 539, + MSG_RUN_SCRIPT_INT = 540, + MSG_SMS_EWS_INBAND_REQ = 541, + MSG_SMS_EWS_INBAND_RES = 542, + MSG_SMS_RFS_SELECT_REQ = 543, + MSG_SMS_RFS_SELECT_RES = 544, + MSG_SMS_MB_GET_VER_REQ = 545, + MSG_SMS_MB_GET_VER_RES = 546, + MSG_SMS_MB_WRITE_CFGFILE_REQ = 547, + MSG_SMS_MB_WRITE_CFGFILE_RES = 548, + MSG_SMS_MB_READ_CFGFILE_REQ = 549, + MSG_SMS_MB_READ_CFGFILE_RES = 550, + MSG_SMS_RD_MEM_REQ = 552, + MSG_SMS_RD_MEM_RES = 553, + MSG_SMS_WR_MEM_REQ = 554, + MSG_SMS_WR_MEM_RES = 555, + MSG_SMS_UPDATE_MEM_REQ = 556, + MSG_SMS_UPDATE_MEM_RES = 557, + MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_REQ = 558, + MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_RES = 559, + MSG_SMS_RF_TUNE_REQ = 561, + MSG_SMS_RF_TUNE_RES = 562, + MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_REQ = 563, + MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_RES = 564, + MSG_SMS_ISDBT_SB_RECEPTION_REQ = 565, + MSG_SMS_ISDBT_SB_RECEPTION_RES = 566, + MSG_SMS_GENERIC_EPROM_WRITE_REQ = 567, + MSG_SMS_GENERIC_EPROM_WRITE_RES = 568, + MSG_SMS_GENERIC_EPROM_READ_REQ = 569, + MSG_SMS_GENERIC_EPROM_READ_RES = 570, + MSG_SMS_EEPROM_WRITE_REQ = 571, + MSG_SMS_EEPROM_WRITE_RES = 572, + MSG_SMS_CUSTOM_READ_REQ = 574, + MSG_SMS_CUSTOM_READ_RES = 575, + MSG_SMS_CUSTOM_WRITE_REQ = 576, + MSG_SMS_CUSTOM_WRITE_RES = 577, + MSG_SMS_INIT_DEVICE_REQ = 578, + MSG_SMS_INIT_DEVICE_RES = 579, + MSG_SMS_ATSC_SET_ALL_IP_REQ = 580, + MSG_SMS_ATSC_SET_ALL_IP_RES = 581, + MSG_SMS_ATSC_START_ENSEMBLE_REQ = 582, + MSG_SMS_ATSC_START_ENSEMBLE_RES = 583, + MSG_SMS_SET_OUTPUT_MODE_REQ = 584, + MSG_SMS_SET_OUTPUT_MODE_RES = 585, + MSG_SMS_ATSC_IP_FILTER_GET_LIST_REQ = 586, + MSG_SMS_ATSC_IP_FILTER_GET_LIST_RES = 587, + MSG_SMS_SUB_CHANNEL_START_REQ = 589, + MSG_SMS_SUB_CHANNEL_START_RES = 590, + MSG_SMS_SUB_CHANNEL_STOP_REQ = 591, + MSG_SMS_SUB_CHANNEL_STOP_RES = 592, + MSG_SMS_ATSC_IP_FILTER_ADD_REQ = 593, + MSG_SMS_ATSC_IP_FILTER_ADD_RES = 594, + MSG_SMS_ATSC_IP_FILTER_REMOVE_REQ = 595, + MSG_SMS_ATSC_IP_FILTER_REMOVE_RES = 596, + MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_REQ = 597, + MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_RES = 598, + MSG_SMS_WAIT_CMD = 599, + MSG_SMS_ADD_PID_FILTER_REQ = 601, + MSG_SMS_ADD_PID_FILTER_RES = 602, + MSG_SMS_REMOVE_PID_FILTER_REQ = 603, + MSG_SMS_REMOVE_PID_FILTER_RES = 604, + MSG_SMS_FAST_INFORMATION_CHANNEL_REQ = 605, + MSG_SMS_FAST_INFORMATION_CHANNEL_RES = 606, + MSG_SMS_DAB_CHANNEL = 607, + MSG_SMS_GET_PID_FILTER_LIST_REQ = 608, + MSG_SMS_GET_PID_FILTER_LIST_RES = 609, + MSG_SMS_POWER_DOWN_REQ = 610, + MSG_SMS_POWER_DOWN_RES = 611, + MSG_SMS_ATSC_SLT_EXIST_IND = 612, + MSG_SMS_ATSC_NO_SLT_IND = 613, + MSG_SMS_GET_STATISTICS_REQ = 615, + MSG_SMS_GET_STATISTICS_RES = 616, + MSG_SMS_SEND_DUMP = 617, + MSG_SMS_SCAN_START_REQ = 618, + MSG_SMS_SCAN_START_RES = 619, + MSG_SMS_SCAN_STOP_REQ = 620, + MSG_SMS_SCAN_STOP_RES = 621, + MSG_SMS_SCAN_PROGRESS_IND = 622, + MSG_SMS_SCAN_COMPLETE_IND = 623, + MSG_SMS_LOG_ITEM = 624, + MSG_SMS_DAB_SUBCHANNEL_RECONFIG_REQ = 628, + MSG_SMS_DAB_SUBCHANNEL_RECONFIG_RES = 629, + MSG_SMS_HO_PER_SLICES_IND = 630, + MSG_SMS_HO_INBAND_POWER_IND = 631, + MSG_SMS_MANUAL_DEMOD_REQ = 632, + MSG_SMS_HO_TUNE_ON_REQ = 636, + MSG_SMS_HO_TUNE_ON_RES = 637, + MSG_SMS_HO_TUNE_OFF_REQ = 638, + MSG_SMS_HO_TUNE_OFF_RES = 639, + MSG_SMS_HO_PEEK_FREQ_REQ = 640, + MSG_SMS_HO_PEEK_FREQ_RES = 641, + MSG_SMS_HO_PEEK_FREQ_IND = 642, + MSG_SMS_MB_ATTEN_SET_REQ = 643, + MSG_SMS_MB_ATTEN_SET_RES = 644, + MSG_SMS_ENABLE_STAT_IN_I2C_REQ = 649, + MSG_SMS_ENABLE_STAT_IN_I2C_RES = 650, + MSG_SMS_SET_ANTENNA_CONFIG_REQ = 651, + MSG_SMS_SET_ANTENNA_CONFIG_RES = 652, + MSG_SMS_GET_STATISTICS_EX_REQ = 653, + MSG_SMS_GET_STATISTICS_EX_RES = 654, + MSG_SMS_SLEEP_RESUME_COMP_IND = 655, + MSG_SMS_SWITCH_HOST_INTERFACE_REQ = 656, + MSG_SMS_SWITCH_HOST_INTERFACE_RES = 657, + MSG_SMS_DATA_DOWNLOAD_REQ = 660, + MSG_SMS_DATA_DOWNLOAD_RES = 661, + MSG_SMS_DATA_VALIDITY_REQ = 662, + MSG_SMS_DATA_VALIDITY_RES = 663, + MSG_SMS_SWDOWNLOAD_TRIGGER_REQ = 664, + MSG_SMS_SWDOWNLOAD_TRIGGER_RES = 665, + MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ = 666, + MSG_SMS_SWDOWNLOAD_BACKDOOR_RES = 667, + MSG_SMS_GET_VERSION_EX_REQ = 668, + MSG_SMS_GET_VERSION_EX_RES = 669, + MSG_SMS_CLOCK_OUTPUT_CONFIG_REQ = 670, + MSG_SMS_CLOCK_OUTPUT_CONFIG_RES = 671, + MSG_SMS_I2C_SET_FREQ_REQ = 685, + MSG_SMS_I2C_SET_FREQ_RES = 686, + MSG_SMS_GENERIC_I2C_REQ = 687, + MSG_SMS_GENERIC_I2C_RES = 688, + MSG_SMS_DVBT_BDA_DATA = 693, + MSG_SW_RELOAD_REQ = 697, + MSG_SMS_DATA_MSG = 699, + MSG_TABLE_UPLOAD_REQ = 700, + MSG_TABLE_UPLOAD_RES = 701, + MSG_SW_RELOAD_START_REQ = 702, + MSG_SW_RELOAD_START_RES = 703, + MSG_SW_RELOAD_EXEC_REQ = 704, + MSG_SW_RELOAD_EXEC_RES = 705, + MSG_SMS_SPI_INT_LINE_SET_REQ = 710, + MSG_SMS_SPI_INT_LINE_SET_RES = 711, + MSG_SMS_GPIO_CONFIG_EX_REQ = 712, + MSG_SMS_GPIO_CONFIG_EX_RES = 713, + MSG_SMS_WATCHDOG_ACT_REQ = 716, + MSG_SMS_WATCHDOG_ACT_RES = 717, + MSG_SMS_LOOPBACK_REQ = 718, + MSG_SMS_LOOPBACK_RES = 719, + MSG_SMS_RAW_CAPTURE_START_REQ = 720, + MSG_SMS_RAW_CAPTURE_START_RES = 721, + MSG_SMS_RAW_CAPTURE_ABORT_REQ = 722, + MSG_SMS_RAW_CAPTURE_ABORT_RES = 723, + MSG_SMS_RAW_CAPTURE_COMPLETE_IND = 728, + MSG_SMS_DATA_PUMP_IND = 729, + MSG_SMS_DATA_PUMP_REQ = 730, + MSG_SMS_DATA_PUMP_RES = 731, + MSG_SMS_FLASH_DL_REQ = 732, + MSG_SMS_EXEC_TEST_1_REQ = 734, + MSG_SMS_EXEC_TEST_1_RES = 735, + MSG_SMS_ENBALE_TS_INTERFACE_REQ = 736, + MSG_SMS_ENBALE_TS_INTERFACE_RES = 737, + MSG_SMS_SPI_SET_BUS_WIDTH_REQ = 738, + MSG_SMS_SPI_SET_BUS_WIDTH_RES = 739, + MSG_SMS_SEND_EMM_REQ = 740, + MSG_SMS_SEND_EMM_RES = 741, + MSG_SMS_DISABLE_TS_INTERFACE_REQ = 742, + MSG_SMS_DISABLE_TS_INTERFACE_RES = 743, + MSG_SMS_IS_BUF_FREE_REQ = 744, + MSG_SMS_IS_BUF_FREE_RES = 745, + MSG_SMS_EXT_ANTENNA_REQ = 746, + MSG_SMS_EXT_ANTENNA_RES = 747, + MSG_SMS_CMMB_GET_NET_OF_FREQ_REQ_OBSOLETE = 748, + MSG_SMS_CMMB_GET_NET_OF_FREQ_RES_OBSOLETE = 749, + MSG_SMS_BATTERY_LEVEL_REQ = 750, + MSG_SMS_BATTERY_LEVEL_RES = 751, + MSG_SMS_CMMB_INJECT_TABLE_REQ_OBSOLETE = 752, + MSG_SMS_CMMB_INJECT_TABLE_RES_OBSOLETE = 753, + MSG_SMS_FM_RADIO_BLOCK_IND = 754, + MSG_SMS_HOST_NOTIFICATION_IND = 755, + MSG_SMS_CMMB_GET_CONTROL_TABLE_REQ_OBSOLETE = 756, + MSG_SMS_CMMB_GET_CONTROL_TABLE_RES_OBSOLETE = 757, + MSG_SMS_CMMB_GET_NETWORKS_REQ = 760, + MSG_SMS_CMMB_GET_NETWORKS_RES = 761, + MSG_SMS_CMMB_START_SERVICE_REQ = 762, + MSG_SMS_CMMB_START_SERVICE_RES = 763, + MSG_SMS_CMMB_STOP_SERVICE_REQ = 764, + MSG_SMS_CMMB_STOP_SERVICE_RES = 765, + MSG_SMS_CMMB_ADD_CHANNEL_FILTER_REQ = 768, + MSG_SMS_CMMB_ADD_CHANNEL_FILTER_RES = 769, + MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_REQ = 770, + MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_RES = 771, + MSG_SMS_CMMB_START_CONTROL_INFO_REQ = 772, + MSG_SMS_CMMB_START_CONTROL_INFO_RES = 773, + MSG_SMS_CMMB_STOP_CONTROL_INFO_REQ = 774, + MSG_SMS_CMMB_STOP_CONTROL_INFO_RES = 775, + MSG_SMS_ISDBT_TUNE_REQ = 776, + MSG_SMS_ISDBT_TUNE_RES = 777, + MSG_SMS_TRANSMISSION_IND = 782, + MSG_SMS_PID_STATISTICS_IND = 783, + MSG_SMS_POWER_DOWN_IND = 784, + MSG_SMS_POWER_DOWN_CONF = 785, + MSG_SMS_POWER_UP_IND = 786, + MSG_SMS_POWER_UP_CONF = 787, + MSG_SMS_POWER_MODE_SET_REQ = 790, + MSG_SMS_POWER_MODE_SET_RES = 791, + MSG_SMS_DEBUG_HOST_EVENT_REQ = 792, + MSG_SMS_DEBUG_HOST_EVENT_RES = 793, + MSG_SMS_NEW_CRYSTAL_REQ = 794, + MSG_SMS_NEW_CRYSTAL_RES = 795, + MSG_SMS_CONFIG_SPI_REQ = 796, + MSG_SMS_CONFIG_SPI_RES = 797, + MSG_SMS_I2C_SHORT_STAT_IND = 798, + MSG_SMS_START_IR_REQ = 800, + MSG_SMS_START_IR_RES = 801, + MSG_SMS_IR_SAMPLES_IND = 802, + MSG_SMS_CMMB_CA_SERVICE_IND = 803, + MSG_SMS_SLAVE_DEVICE_DETECTED = 804, + MSG_SMS_INTERFACE_LOCK_IND = 805, + MSG_SMS_INTERFACE_UNLOCK_IND = 806, + MSG_SMS_SEND_ROSUM_BUFF_REQ = 810, + MSG_SMS_SEND_ROSUM_BUFF_RES = 811, + MSG_SMS_ROSUM_BUFF = 812, + MSG_SMS_SET_AES128_KEY_REQ = 815, + MSG_SMS_SET_AES128_KEY_RES = 816, + MSG_SMS_MBBMS_WRITE_REQ = 817, + MSG_SMS_MBBMS_WRITE_RES = 818, + MSG_SMS_MBBMS_READ_IND = 819, + MSG_SMS_IQ_STREAM_START_REQ = 820, + MSG_SMS_IQ_STREAM_START_RES = 821, + MSG_SMS_IQ_STREAM_STOP_REQ = 822, + MSG_SMS_IQ_STREAM_STOP_RES = 823, + MSG_SMS_IQ_STREAM_DATA_BLOCK = 824, + MSG_SMS_GET_EEPROM_VERSION_REQ = 825, + MSG_SMS_GET_EEPROM_VERSION_RES = 826, + MSG_SMS_SIGNAL_DETECTED_IND = 827, + MSG_SMS_NO_SIGNAL_IND = 828, + MSG_SMS_MRC_SHUTDOWN_SLAVE_REQ = 830, + MSG_SMS_MRC_SHUTDOWN_SLAVE_RES = 831, + MSG_SMS_MRC_BRINGUP_SLAVE_REQ = 832, + MSG_SMS_MRC_BRINGUP_SLAVE_RES = 833, + MSG_SMS_EXTERNAL_LNA_CTRL_REQ = 834, + MSG_SMS_EXTERNAL_LNA_CTRL_RES = 835, + MSG_SMS_SET_PERIODIC_STATISTICS_REQ = 836, + MSG_SMS_SET_PERIODIC_STATISTICS_RES = 837, + MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_REQ = 838, + MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_RES = 839, + LOCAL_TUNE = 850, + LOCAL_IFFT_H_ICI = 851, + MSG_RESYNC_REQ = 852, + MSG_SMS_CMMB_GET_MRC_STATISTICS_REQ = 853, + MSG_SMS_CMMB_GET_MRC_STATISTICS_RES = 854, + MSG_SMS_LOG_EX_ITEM = 855, + MSG_SMS_DEVICE_DATA_LOSS_IND = 856, + MSG_SMS_MRC_WATCHDOG_TRIGGERED_IND = 857, + MSG_SMS_USER_MSG_REQ = 858, + MSG_SMS_USER_MSG_RES = 859, + MSG_SMS_SMART_CARD_INIT_REQ = 860, + MSG_SMS_SMART_CARD_INIT_RES = 861, + MSG_SMS_SMART_CARD_WRITE_REQ = 862, + MSG_SMS_SMART_CARD_WRITE_RES = 863, + MSG_SMS_SMART_CARD_READ_IND = 864, + MSG_SMS_TSE_ENABLE_REQ = 866, + MSG_SMS_TSE_ENABLE_RES = 867, + MSG_SMS_CMMB_GET_SHORT_STATISTICS_REQ = 868, + MSG_SMS_CMMB_GET_SHORT_STATISTICS_RES = 869, + MSG_SMS_LED_CONFIG_REQ = 870, + MSG_SMS_LED_CONFIG_RES = 871, + MSG_PWM_ANTENNA_REQ = 872, + MSG_PWM_ANTENNA_RES = 873, + MSG_SMS_CMMB_SMD_SN_REQ = 874, + MSG_SMS_CMMB_SMD_SN_RES = 875, + MSG_SMS_CMMB_SET_CA_CW_REQ = 876, + MSG_SMS_CMMB_SET_CA_CW_RES = 877, + MSG_SMS_CMMB_SET_CA_SALT_REQ = 878, + MSG_SMS_CMMB_SET_CA_SALT_RES = 879, + MSG_SMS_NSCD_INIT_REQ = 880, + MSG_SMS_NSCD_INIT_RES = 881, + MSG_SMS_NSCD_PROCESS_SECTION_REQ = 882, + MSG_SMS_NSCD_PROCESS_SECTION_RES = 883, + MSG_SMS_DBD_CREATE_OBJECT_REQ = 884, + MSG_SMS_DBD_CREATE_OBJECT_RES = 885, + MSG_SMS_DBD_CONFIGURE_REQ = 886, + MSG_SMS_DBD_CONFIGURE_RES = 887, + MSG_SMS_DBD_SET_KEYS_REQ = 888, + MSG_SMS_DBD_SET_KEYS_RES = 889, + MSG_SMS_DBD_PROCESS_HEADER_REQ = 890, + MSG_SMS_DBD_PROCESS_HEADER_RES = 891, + MSG_SMS_DBD_PROCESS_DATA_REQ = 892, + MSG_SMS_DBD_PROCESS_DATA_RES = 893, + MSG_SMS_DBD_PROCESS_GET_DATA_REQ = 894, + MSG_SMS_DBD_PROCESS_GET_DATA_RES = 895, + MSG_SMS_NSCD_OPEN_SESSION_REQ = 896, + MSG_SMS_NSCD_OPEN_SESSION_RES = 897, + MSG_SMS_SEND_HOST_DATA_TO_DEMUX_REQ = 898, + MSG_SMS_SEND_HOST_DATA_TO_DEMUX_RES = 899, + MSG_LAST_MSG_TYPE = 900, +}; #define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \ (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \ -- cgit v1.2.3 From 4c3bdb5e2f5612ceb99ac17dbbe673b59a94d105 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Mar 2013 09:27:39 -0300 Subject: [media] siano: better debug send/receive messages Instead of printing a message for some random messages, print it for all sent/received ones. That helps a lot to debug what's going on. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 351 +++++++++++++++++++++++++++++++- drivers/media/common/siano/smscoreapi.h | 2 + drivers/media/common/siano/smsdvb.c | 10 +- drivers/media/usb/siano/smsusb.c | 9 + 4 files changed, 354 insertions(+), 18 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 804eb32fd8cc..bc15dcecb25d 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -63,6 +63,345 @@ struct smscore_client_t { onremove_t onremove_handler; }; +static char *siano_msgs[] = { + [MSG_TYPE_BASE_VAL - MSG_TYPE_BASE_VAL] = "MSG_TYPE_BASE_VAL", + [MSG_SMS_GET_VERSION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_REQ", + [MSG_SMS_GET_VERSION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_RES", + [MSG_SMS_MULTI_BRIDGE_CFG - MSG_TYPE_BASE_VAL] = "MSG_SMS_MULTI_BRIDGE_CFG", + [MSG_SMS_GPIO_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_REQ", + [MSG_SMS_GPIO_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_RES", + [MSG_SMS_GPIO_SET_LEVEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_SET_LEVEL_REQ", + [MSG_SMS_GPIO_SET_LEVEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_SET_LEVEL_RES", + [MSG_SMS_GPIO_GET_LEVEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_GET_LEVEL_REQ", + [MSG_SMS_GPIO_GET_LEVEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_GET_LEVEL_RES", + [MSG_SMS_EEPROM_BURN_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_EEPROM_BURN_IND", + [MSG_SMS_LOG_ENABLE_CHANGE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_ENABLE_CHANGE_REQ", + [MSG_SMS_LOG_ENABLE_CHANGE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_ENABLE_CHANGE_RES", + [MSG_SMS_SET_MAX_TX_MSG_LEN_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_MAX_TX_MSG_LEN_REQ", + [MSG_SMS_SET_MAX_TX_MSG_LEN_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_MAX_TX_MSG_LEN_RES", + [MSG_SMS_SPI_HALFDUPLEX_TOKEN_HOST_TO_DEVICE - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_HALFDUPLEX_TOKEN_HOST_TO_DEVICE", + [MSG_SMS_SPI_HALFDUPLEX_TOKEN_DEVICE_TO_HOST - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_HALFDUPLEX_TOKEN_DEVICE_TO_HOST", + [MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_REQ", + [MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_FLAG_CHANGE_RES", + [MSG_SMS_BACKGROUND_SCAN_SIGNAL_DETECTED_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_SIGNAL_DETECTED_IND", + [MSG_SMS_BACKGROUND_SCAN_NO_SIGNAL_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_BACKGROUND_SCAN_NO_SIGNAL_IND", + [MSG_SMS_CONFIGURE_RF_SWITCH_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIGURE_RF_SWITCH_REQ", + [MSG_SMS_CONFIGURE_RF_SWITCH_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIGURE_RF_SWITCH_RES", + [MSG_SMS_MRC_PATH_DISCONNECT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_PATH_DISCONNECT_REQ", + [MSG_SMS_MRC_PATH_DISCONNECT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_PATH_DISCONNECT_RES", + [MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_REQ", + [MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_1SEG_THROUGH_FULLSEG_RES", + [MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_REQ", + [MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RECEIVE_VHF_VIA_VHF_INPUT_RES", + [MSG_WR_REG_RFT_REQ - MSG_TYPE_BASE_VAL] = "MSG_WR_REG_RFT_REQ", + [MSG_WR_REG_RFT_RES - MSG_TYPE_BASE_VAL] = "MSG_WR_REG_RFT_RES", + [MSG_RD_REG_RFT_REQ - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_RFT_REQ", + [MSG_RD_REG_RFT_RES - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_RFT_RES", + [MSG_RD_REG_ALL_RFT_REQ - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_ALL_RFT_REQ", + [MSG_RD_REG_ALL_RFT_RES - MSG_TYPE_BASE_VAL] = "MSG_RD_REG_ALL_RFT_RES", + [MSG_HELP_INT - MSG_TYPE_BASE_VAL] = "MSG_HELP_INT", + [MSG_RUN_SCRIPT_INT - MSG_TYPE_BASE_VAL] = "MSG_RUN_SCRIPT_INT", + [MSG_SMS_EWS_INBAND_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EWS_INBAND_REQ", + [MSG_SMS_EWS_INBAND_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EWS_INBAND_RES", + [MSG_SMS_RFS_SELECT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RFS_SELECT_REQ", + [MSG_SMS_RFS_SELECT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RFS_SELECT_RES", + [MSG_SMS_MB_GET_VER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_GET_VER_REQ", + [MSG_SMS_MB_GET_VER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_GET_VER_RES", + [MSG_SMS_MB_WRITE_CFGFILE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_WRITE_CFGFILE_REQ", + [MSG_SMS_MB_WRITE_CFGFILE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_WRITE_CFGFILE_RES", + [MSG_SMS_MB_READ_CFGFILE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_READ_CFGFILE_REQ", + [MSG_SMS_MB_READ_CFGFILE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_READ_CFGFILE_RES", + [MSG_SMS_RD_MEM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RD_MEM_REQ", + [MSG_SMS_RD_MEM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RD_MEM_RES", + [MSG_SMS_WR_MEM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_WR_MEM_REQ", + [MSG_SMS_WR_MEM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_WR_MEM_RES", + [MSG_SMS_UPDATE_MEM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_UPDATE_MEM_REQ", + [MSG_SMS_UPDATE_MEM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_UPDATE_MEM_RES", + [MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_REQ", + [MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_FULL_PARAMS_SET_RES", + [MSG_SMS_RF_TUNE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RF_TUNE_REQ", + [MSG_SMS_RF_TUNE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RF_TUNE_RES", + [MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_REQ", + [MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_ENABLE_HIGH_MOBILITY_RES", + [MSG_SMS_ISDBT_SB_RECEPTION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_SB_RECEPTION_REQ", + [MSG_SMS_ISDBT_SB_RECEPTION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_SB_RECEPTION_RES", + [MSG_SMS_GENERIC_EPROM_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_WRITE_REQ", + [MSG_SMS_GENERIC_EPROM_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_WRITE_RES", + [MSG_SMS_GENERIC_EPROM_READ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_READ_REQ", + [MSG_SMS_GENERIC_EPROM_READ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_EPROM_READ_RES", + [MSG_SMS_EEPROM_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EEPROM_WRITE_REQ", + [MSG_SMS_EEPROM_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EEPROM_WRITE_RES", + [MSG_SMS_CUSTOM_READ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_READ_REQ", + [MSG_SMS_CUSTOM_READ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_READ_RES", + [MSG_SMS_CUSTOM_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_WRITE_REQ", + [MSG_SMS_CUSTOM_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CUSTOM_WRITE_RES", + [MSG_SMS_INIT_DEVICE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_INIT_DEVICE_REQ", + [MSG_SMS_INIT_DEVICE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_INIT_DEVICE_RES", + [MSG_SMS_ATSC_SET_ALL_IP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_SET_ALL_IP_REQ", + [MSG_SMS_ATSC_SET_ALL_IP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_SET_ALL_IP_RES", + [MSG_SMS_ATSC_START_ENSEMBLE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_START_ENSEMBLE_REQ", + [MSG_SMS_ATSC_START_ENSEMBLE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_START_ENSEMBLE_RES", + [MSG_SMS_SET_OUTPUT_MODE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_OUTPUT_MODE_REQ", + [MSG_SMS_SET_OUTPUT_MODE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_OUTPUT_MODE_RES", + [MSG_SMS_ATSC_IP_FILTER_GET_LIST_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_GET_LIST_REQ", + [MSG_SMS_ATSC_IP_FILTER_GET_LIST_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_GET_LIST_RES", + [MSG_SMS_SUB_CHANNEL_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_START_REQ", + [MSG_SMS_SUB_CHANNEL_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_START_RES", + [MSG_SMS_SUB_CHANNEL_STOP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_STOP_REQ", + [MSG_SMS_SUB_CHANNEL_STOP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SUB_CHANNEL_STOP_RES", + [MSG_SMS_ATSC_IP_FILTER_ADD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_ADD_REQ", + [MSG_SMS_ATSC_IP_FILTER_ADD_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_ADD_RES", + [MSG_SMS_ATSC_IP_FILTER_REMOVE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_REQ", + [MSG_SMS_ATSC_IP_FILTER_REMOVE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_RES", + [MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_REQ", + [MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_IP_FILTER_REMOVE_ALL_RES", + [MSG_SMS_WAIT_CMD - MSG_TYPE_BASE_VAL] = "MSG_SMS_WAIT_CMD", + [MSG_SMS_ADD_PID_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ADD_PID_FILTER_REQ", + [MSG_SMS_ADD_PID_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ADD_PID_FILTER_RES", + [MSG_SMS_REMOVE_PID_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_REMOVE_PID_FILTER_REQ", + [MSG_SMS_REMOVE_PID_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_REMOVE_PID_FILTER_RES", + [MSG_SMS_FAST_INFORMATION_CHANNEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_FAST_INFORMATION_CHANNEL_REQ", + [MSG_SMS_FAST_INFORMATION_CHANNEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_FAST_INFORMATION_CHANNEL_RES", + [MSG_SMS_DAB_CHANNEL - MSG_TYPE_BASE_VAL] = "MSG_SMS_DAB_CHANNEL", + [MSG_SMS_GET_PID_FILTER_LIST_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_PID_FILTER_LIST_REQ", + [MSG_SMS_GET_PID_FILTER_LIST_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_PID_FILTER_LIST_RES", + [MSG_SMS_POWER_DOWN_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_REQ", + [MSG_SMS_POWER_DOWN_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_RES", + [MSG_SMS_ATSC_SLT_EXIST_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_SLT_EXIST_IND", + [MSG_SMS_ATSC_NO_SLT_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_ATSC_NO_SLT_IND", + [MSG_SMS_GET_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_REQ", + [MSG_SMS_GET_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_RES", + [MSG_SMS_SEND_DUMP - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_DUMP", + [MSG_SMS_SCAN_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_START_REQ", + [MSG_SMS_SCAN_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_START_RES", + [MSG_SMS_SCAN_STOP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_STOP_REQ", + [MSG_SMS_SCAN_STOP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_STOP_RES", + [MSG_SMS_SCAN_PROGRESS_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_PROGRESS_IND", + [MSG_SMS_SCAN_COMPLETE_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SCAN_COMPLETE_IND", + [MSG_SMS_LOG_ITEM - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_ITEM", + [MSG_SMS_DAB_SUBCHANNEL_RECONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DAB_SUBCHANNEL_RECONFIG_REQ", + [MSG_SMS_DAB_SUBCHANNEL_RECONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DAB_SUBCHANNEL_RECONFIG_RES", + [MSG_SMS_HO_PER_SLICES_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PER_SLICES_IND", + [MSG_SMS_HO_INBAND_POWER_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_INBAND_POWER_IND", + [MSG_SMS_MANUAL_DEMOD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MANUAL_DEMOD_REQ", + [MSG_SMS_HO_TUNE_ON_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_ON_REQ", + [MSG_SMS_HO_TUNE_ON_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_ON_RES", + [MSG_SMS_HO_TUNE_OFF_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_OFF_REQ", + [MSG_SMS_HO_TUNE_OFF_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_TUNE_OFF_RES", + [MSG_SMS_HO_PEEK_FREQ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PEEK_FREQ_REQ", + [MSG_SMS_HO_PEEK_FREQ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PEEK_FREQ_RES", + [MSG_SMS_HO_PEEK_FREQ_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HO_PEEK_FREQ_IND", + [MSG_SMS_MB_ATTEN_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_ATTEN_SET_REQ", + [MSG_SMS_MB_ATTEN_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MB_ATTEN_SET_RES", + [MSG_SMS_ENABLE_STAT_IN_I2C_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENABLE_STAT_IN_I2C_REQ", + [MSG_SMS_ENABLE_STAT_IN_I2C_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENABLE_STAT_IN_I2C_RES", + [MSG_SMS_SET_ANTENNA_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_ANTENNA_CONFIG_REQ", + [MSG_SMS_SET_ANTENNA_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_ANTENNA_CONFIG_RES", + [MSG_SMS_GET_STATISTICS_EX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_EX_REQ", + [MSG_SMS_GET_STATISTICS_EX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_STATISTICS_EX_RES", + [MSG_SMS_SLEEP_RESUME_COMP_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SLEEP_RESUME_COMP_IND", + [MSG_SMS_SWITCH_HOST_INTERFACE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWITCH_HOST_INTERFACE_REQ", + [MSG_SMS_SWITCH_HOST_INTERFACE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWITCH_HOST_INTERFACE_RES", + [MSG_SMS_DATA_DOWNLOAD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_DOWNLOAD_REQ", + [MSG_SMS_DATA_DOWNLOAD_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_DOWNLOAD_RES", + [MSG_SMS_DATA_VALIDITY_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_VALIDITY_REQ", + [MSG_SMS_DATA_VALIDITY_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_VALIDITY_RES", + [MSG_SMS_SWDOWNLOAD_TRIGGER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_TRIGGER_REQ", + [MSG_SMS_SWDOWNLOAD_TRIGGER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_TRIGGER_RES", + [MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_BACKDOOR_REQ", + [MSG_SMS_SWDOWNLOAD_BACKDOOR_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SWDOWNLOAD_BACKDOOR_RES", + [MSG_SMS_GET_VERSION_EX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_EX_REQ", + [MSG_SMS_GET_VERSION_EX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_VERSION_EX_RES", + [MSG_SMS_CLOCK_OUTPUT_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CLOCK_OUTPUT_CONFIG_REQ", + [MSG_SMS_CLOCK_OUTPUT_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CLOCK_OUTPUT_CONFIG_RES", + [MSG_SMS_I2C_SET_FREQ_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_I2C_SET_FREQ_REQ", + [MSG_SMS_I2C_SET_FREQ_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_I2C_SET_FREQ_RES", + [MSG_SMS_GENERIC_I2C_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_I2C_REQ", + [MSG_SMS_GENERIC_I2C_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GENERIC_I2C_RES", + [MSG_SMS_DVBT_BDA_DATA - MSG_TYPE_BASE_VAL] = "MSG_SMS_DVBT_BDA_DATA", + [MSG_SW_RELOAD_REQ - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_REQ", + [MSG_SMS_DATA_MSG - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_MSG", + [MSG_TABLE_UPLOAD_REQ - MSG_TYPE_BASE_VAL] = "MSG_TABLE_UPLOAD_REQ", + [MSG_TABLE_UPLOAD_RES - MSG_TYPE_BASE_VAL] = "MSG_TABLE_UPLOAD_RES", + [MSG_SW_RELOAD_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_START_REQ", + [MSG_SW_RELOAD_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_START_RES", + [MSG_SW_RELOAD_EXEC_REQ - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_EXEC_REQ", + [MSG_SW_RELOAD_EXEC_RES - MSG_TYPE_BASE_VAL] = "MSG_SW_RELOAD_EXEC_RES", + [MSG_SMS_SPI_INT_LINE_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_INT_LINE_SET_REQ", + [MSG_SMS_SPI_INT_LINE_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_INT_LINE_SET_RES", + [MSG_SMS_GPIO_CONFIG_EX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_EX_REQ", + [MSG_SMS_GPIO_CONFIG_EX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GPIO_CONFIG_EX_RES", + [MSG_SMS_WATCHDOG_ACT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_WATCHDOG_ACT_REQ", + [MSG_SMS_WATCHDOG_ACT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_WATCHDOG_ACT_RES", + [MSG_SMS_LOOPBACK_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOOPBACK_REQ", + [MSG_SMS_LOOPBACK_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOOPBACK_RES", + [MSG_SMS_RAW_CAPTURE_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_START_REQ", + [MSG_SMS_RAW_CAPTURE_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_START_RES", + [MSG_SMS_RAW_CAPTURE_ABORT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_ABORT_REQ", + [MSG_SMS_RAW_CAPTURE_ABORT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_ABORT_RES", + [MSG_SMS_RAW_CAPTURE_COMPLETE_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_RAW_CAPTURE_COMPLETE_IND", + [MSG_SMS_DATA_PUMP_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_PUMP_IND", + [MSG_SMS_DATA_PUMP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_PUMP_REQ", + [MSG_SMS_DATA_PUMP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DATA_PUMP_RES", + [MSG_SMS_FLASH_DL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_FLASH_DL_REQ", + [MSG_SMS_EXEC_TEST_1_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXEC_TEST_1_REQ", + [MSG_SMS_EXEC_TEST_1_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXEC_TEST_1_RES", + [MSG_SMS_ENBALE_TS_INTERFACE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENBALE_TS_INTERFACE_REQ", + [MSG_SMS_ENBALE_TS_INTERFACE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ENBALE_TS_INTERFACE_RES", + [MSG_SMS_SPI_SET_BUS_WIDTH_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_SET_BUS_WIDTH_REQ", + [MSG_SMS_SPI_SET_BUS_WIDTH_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SPI_SET_BUS_WIDTH_RES", + [MSG_SMS_SEND_EMM_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_EMM_REQ", + [MSG_SMS_SEND_EMM_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_EMM_RES", + [MSG_SMS_DISABLE_TS_INTERFACE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DISABLE_TS_INTERFACE_REQ", + [MSG_SMS_DISABLE_TS_INTERFACE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DISABLE_TS_INTERFACE_RES", + [MSG_SMS_IS_BUF_FREE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_IS_BUF_FREE_REQ", + [MSG_SMS_IS_BUF_FREE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_IS_BUF_FREE_RES", + [MSG_SMS_EXT_ANTENNA_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXT_ANTENNA_REQ", + [MSG_SMS_EXT_ANTENNA_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXT_ANTENNA_RES", + [MSG_SMS_CMMB_GET_NET_OF_FREQ_REQ_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NET_OF_FREQ_REQ_OBSOLETE", + [MSG_SMS_CMMB_GET_NET_OF_FREQ_RES_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NET_OF_FREQ_RES_OBSOLETE", + [MSG_SMS_BATTERY_LEVEL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_BATTERY_LEVEL_REQ", + [MSG_SMS_BATTERY_LEVEL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_BATTERY_LEVEL_RES", + [MSG_SMS_CMMB_INJECT_TABLE_REQ_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_INJECT_TABLE_REQ_OBSOLETE", + [MSG_SMS_CMMB_INJECT_TABLE_RES_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_INJECT_TABLE_RES_OBSOLETE", + [MSG_SMS_FM_RADIO_BLOCK_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_FM_RADIO_BLOCK_IND", + [MSG_SMS_HOST_NOTIFICATION_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_HOST_NOTIFICATION_IND", + [MSG_SMS_CMMB_GET_CONTROL_TABLE_REQ_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_CONTROL_TABLE_REQ_OBSOLETE", + [MSG_SMS_CMMB_GET_CONTROL_TABLE_RES_OBSOLETE - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_CONTROL_TABLE_RES_OBSOLETE", + [MSG_SMS_CMMB_GET_NETWORKS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NETWORKS_REQ", + [MSG_SMS_CMMB_GET_NETWORKS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_NETWORKS_RES", + [MSG_SMS_CMMB_START_SERVICE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_SERVICE_REQ", + [MSG_SMS_CMMB_START_SERVICE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_SERVICE_RES", + [MSG_SMS_CMMB_STOP_SERVICE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_SERVICE_REQ", + [MSG_SMS_CMMB_STOP_SERVICE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_SERVICE_RES", + [MSG_SMS_CMMB_ADD_CHANNEL_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_ADD_CHANNEL_FILTER_REQ", + [MSG_SMS_CMMB_ADD_CHANNEL_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_ADD_CHANNEL_FILTER_RES", + [MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_REQ", + [MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_REMOVE_CHANNEL_FILTER_RES", + [MSG_SMS_CMMB_START_CONTROL_INFO_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_CONTROL_INFO_REQ", + [MSG_SMS_CMMB_START_CONTROL_INFO_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_START_CONTROL_INFO_RES", + [MSG_SMS_CMMB_STOP_CONTROL_INFO_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_CONTROL_INFO_REQ", + [MSG_SMS_CMMB_STOP_CONTROL_INFO_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_STOP_CONTROL_INFO_RES", + [MSG_SMS_ISDBT_TUNE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_TUNE_REQ", + [MSG_SMS_ISDBT_TUNE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_ISDBT_TUNE_RES", + [MSG_SMS_TRANSMISSION_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_TRANSMISSION_IND", + [MSG_SMS_PID_STATISTICS_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_PID_STATISTICS_IND", + [MSG_SMS_POWER_DOWN_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_IND", + [MSG_SMS_POWER_DOWN_CONF - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_DOWN_CONF", + [MSG_SMS_POWER_UP_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_UP_IND", + [MSG_SMS_POWER_UP_CONF - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_UP_CONF", + [MSG_SMS_POWER_MODE_SET_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_MODE_SET_REQ", + [MSG_SMS_POWER_MODE_SET_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_POWER_MODE_SET_RES", + [MSG_SMS_DEBUG_HOST_EVENT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DEBUG_HOST_EVENT_REQ", + [MSG_SMS_DEBUG_HOST_EVENT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DEBUG_HOST_EVENT_RES", + [MSG_SMS_NEW_CRYSTAL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NEW_CRYSTAL_REQ", + [MSG_SMS_NEW_CRYSTAL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NEW_CRYSTAL_RES", + [MSG_SMS_CONFIG_SPI_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIG_SPI_REQ", + [MSG_SMS_CONFIG_SPI_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CONFIG_SPI_RES", + [MSG_SMS_I2C_SHORT_STAT_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_I2C_SHORT_STAT_IND", + [MSG_SMS_START_IR_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_START_IR_REQ", + [MSG_SMS_START_IR_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_START_IR_RES", + [MSG_SMS_IR_SAMPLES_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_IR_SAMPLES_IND", + [MSG_SMS_CMMB_CA_SERVICE_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_CA_SERVICE_IND", + [MSG_SMS_SLAVE_DEVICE_DETECTED - MSG_TYPE_BASE_VAL] = "MSG_SMS_SLAVE_DEVICE_DETECTED", + [MSG_SMS_INTERFACE_LOCK_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_INTERFACE_LOCK_IND", + [MSG_SMS_INTERFACE_UNLOCK_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_INTERFACE_UNLOCK_IND", + [MSG_SMS_SEND_ROSUM_BUFF_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_ROSUM_BUFF_REQ", + [MSG_SMS_SEND_ROSUM_BUFF_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_ROSUM_BUFF_RES", + [MSG_SMS_ROSUM_BUFF - MSG_TYPE_BASE_VAL] = "MSG_SMS_ROSUM_BUFF", + [MSG_SMS_SET_AES128_KEY_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_AES128_KEY_REQ", + [MSG_SMS_SET_AES128_KEY_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_AES128_KEY_RES", + [MSG_SMS_MBBMS_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MBBMS_WRITE_REQ", + [MSG_SMS_MBBMS_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MBBMS_WRITE_RES", + [MSG_SMS_MBBMS_READ_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_MBBMS_READ_IND", + [MSG_SMS_IQ_STREAM_START_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_START_REQ", + [MSG_SMS_IQ_STREAM_START_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_START_RES", + [MSG_SMS_IQ_STREAM_STOP_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_STOP_REQ", + [MSG_SMS_IQ_STREAM_STOP_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_STOP_RES", + [MSG_SMS_IQ_STREAM_DATA_BLOCK - MSG_TYPE_BASE_VAL] = "MSG_SMS_IQ_STREAM_DATA_BLOCK", + [MSG_SMS_GET_EEPROM_VERSION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_EEPROM_VERSION_REQ", + [MSG_SMS_GET_EEPROM_VERSION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_GET_EEPROM_VERSION_RES", + [MSG_SMS_SIGNAL_DETECTED_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SIGNAL_DETECTED_IND", + [MSG_SMS_NO_SIGNAL_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_NO_SIGNAL_IND", + [MSG_SMS_MRC_SHUTDOWN_SLAVE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_SHUTDOWN_SLAVE_REQ", + [MSG_SMS_MRC_SHUTDOWN_SLAVE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_SHUTDOWN_SLAVE_RES", + [MSG_SMS_MRC_BRINGUP_SLAVE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_BRINGUP_SLAVE_REQ", + [MSG_SMS_MRC_BRINGUP_SLAVE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_BRINGUP_SLAVE_RES", + [MSG_SMS_EXTERNAL_LNA_CTRL_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXTERNAL_LNA_CTRL_REQ", + [MSG_SMS_EXTERNAL_LNA_CTRL_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_EXTERNAL_LNA_CTRL_RES", + [MSG_SMS_SET_PERIODIC_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_PERIODIC_STATISTICS_REQ", + [MSG_SMS_SET_PERIODIC_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SET_PERIODIC_STATISTICS_RES", + [MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_REQ", + [MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_AUTO_OUTPUT_TS0_RES", + [LOCAL_TUNE - MSG_TYPE_BASE_VAL] = "LOCAL_TUNE", + [LOCAL_IFFT_H_ICI - MSG_TYPE_BASE_VAL] = "LOCAL_IFFT_H_ICI", + [MSG_RESYNC_REQ - MSG_TYPE_BASE_VAL] = "MSG_RESYNC_REQ", + [MSG_SMS_CMMB_GET_MRC_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_MRC_STATISTICS_REQ", + [MSG_SMS_CMMB_GET_MRC_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_MRC_STATISTICS_RES", + [MSG_SMS_LOG_EX_ITEM - MSG_TYPE_BASE_VAL] = "MSG_SMS_LOG_EX_ITEM", + [MSG_SMS_DEVICE_DATA_LOSS_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_DEVICE_DATA_LOSS_IND", + [MSG_SMS_MRC_WATCHDOG_TRIGGERED_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_MRC_WATCHDOG_TRIGGERED_IND", + [MSG_SMS_USER_MSG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_USER_MSG_REQ", + [MSG_SMS_USER_MSG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_USER_MSG_RES", + [MSG_SMS_SMART_CARD_INIT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_INIT_REQ", + [MSG_SMS_SMART_CARD_INIT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_INIT_RES", + [MSG_SMS_SMART_CARD_WRITE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_WRITE_REQ", + [MSG_SMS_SMART_CARD_WRITE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_WRITE_RES", + [MSG_SMS_SMART_CARD_READ_IND - MSG_TYPE_BASE_VAL] = "MSG_SMS_SMART_CARD_READ_IND", + [MSG_SMS_TSE_ENABLE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_TSE_ENABLE_REQ", + [MSG_SMS_TSE_ENABLE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_TSE_ENABLE_RES", + [MSG_SMS_CMMB_GET_SHORT_STATISTICS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_SHORT_STATISTICS_REQ", + [MSG_SMS_CMMB_GET_SHORT_STATISTICS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_GET_SHORT_STATISTICS_RES", + [MSG_SMS_LED_CONFIG_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_LED_CONFIG_REQ", + [MSG_SMS_LED_CONFIG_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_LED_CONFIG_RES", + [MSG_PWM_ANTENNA_REQ - MSG_TYPE_BASE_VAL] = "MSG_PWM_ANTENNA_REQ", + [MSG_PWM_ANTENNA_RES - MSG_TYPE_BASE_VAL] = "MSG_PWM_ANTENNA_RES", + [MSG_SMS_CMMB_SMD_SN_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SMD_SN_REQ", + [MSG_SMS_CMMB_SMD_SN_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SMD_SN_RES", + [MSG_SMS_CMMB_SET_CA_CW_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_CW_REQ", + [MSG_SMS_CMMB_SET_CA_CW_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_CW_RES", + [MSG_SMS_CMMB_SET_CA_SALT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_SALT_REQ", + [MSG_SMS_CMMB_SET_CA_SALT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_CMMB_SET_CA_SALT_RES", + [MSG_SMS_NSCD_INIT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_INIT_REQ", + [MSG_SMS_NSCD_INIT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_INIT_RES", + [MSG_SMS_NSCD_PROCESS_SECTION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_PROCESS_SECTION_REQ", + [MSG_SMS_NSCD_PROCESS_SECTION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_PROCESS_SECTION_RES", + [MSG_SMS_DBD_CREATE_OBJECT_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CREATE_OBJECT_REQ", + [MSG_SMS_DBD_CREATE_OBJECT_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CREATE_OBJECT_RES", + [MSG_SMS_DBD_CONFIGURE_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CONFIGURE_REQ", + [MSG_SMS_DBD_CONFIGURE_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_CONFIGURE_RES", + [MSG_SMS_DBD_SET_KEYS_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_SET_KEYS_REQ", + [MSG_SMS_DBD_SET_KEYS_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_SET_KEYS_RES", + [MSG_SMS_DBD_PROCESS_HEADER_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_HEADER_REQ", + [MSG_SMS_DBD_PROCESS_HEADER_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_HEADER_RES", + [MSG_SMS_DBD_PROCESS_DATA_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_DATA_REQ", + [MSG_SMS_DBD_PROCESS_DATA_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_DATA_RES", + [MSG_SMS_DBD_PROCESS_GET_DATA_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_GET_DATA_REQ", + [MSG_SMS_DBD_PROCESS_GET_DATA_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_DBD_PROCESS_GET_DATA_RES", + [MSG_SMS_NSCD_OPEN_SESSION_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_OPEN_SESSION_REQ", + [MSG_SMS_NSCD_OPEN_SESSION_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_NSCD_OPEN_SESSION_RES", + [MSG_SMS_SEND_HOST_DATA_TO_DEMUX_REQ - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_HOST_DATA_TO_DEMUX_REQ", + [MSG_SMS_SEND_HOST_DATA_TO_DEMUX_RES - MSG_TYPE_BASE_VAL] = "MSG_SMS_SEND_HOST_DATA_TO_DEMUX_RES", + [MSG_LAST_MSG_TYPE - MSG_TYPE_BASE_VAL] = "MSG_LAST_MSG_TYPE", +}; + +char *smscore_translate_msg(enum msg_types msgtype) +{ + int i = msgtype - MSG_TYPE_BASE_VAL; + char *msg; + + if (i < 0 || i > ARRAY_SIZE(siano_msgs)) + return "Unknown msg type"; + + msg = siano_msgs[i]; + + if (!*msg) + return "Unknown msg type"; + + return msg; +} +EXPORT_SYMBOL_GPL(smscore_translate_msg); + void smscore_set_board_id(struct smscore_device_t *core, int id) { core->board_id = id; @@ -1012,8 +1351,7 @@ void smscore_onresponse(struct smscore_device_t *coredev, { struct SmsVersionRes_ST *ver = (struct SmsVersionRes_ST *) phdr; - sms_debug("MSG_SMS_GET_VERSION_EX_RES " - "id %d prots 0x%x ver %d.%d", + sms_debug("Firmware id %d prots 0x%x ver %d.%d", ver->FirmwareId, ver->SupportedProtocols, ver->RomVersionMajor, ver->RomVersionMinor); @@ -1025,39 +1363,33 @@ void smscore_onresponse(struct smscore_device_t *coredev, break; } case MSG_SMS_INIT_DEVICE_RES: - sms_debug("MSG_SMS_INIT_DEVICE_RES"); complete(&coredev->init_device_done); break; case MSG_SW_RELOAD_START_RES: - sms_debug("MSG_SW_RELOAD_START_RES"); complete(&coredev->reload_start_done); break; case MSG_SMS_DATA_DOWNLOAD_RES: complete(&coredev->data_download_done); break; case MSG_SW_RELOAD_EXEC_RES: - sms_debug("MSG_SW_RELOAD_EXEC_RES"); break; case MSG_SMS_SWDOWNLOAD_TRIGGER_RES: - sms_debug("MSG_SMS_SWDOWNLOAD_TRIGGER_RES"); complete(&coredev->trigger_done); break; case MSG_SMS_SLEEP_RESUME_COMP_IND: complete(&coredev->resume_done); break; case MSG_SMS_GPIO_CONFIG_EX_RES: - sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES"); complete(&coredev->gpio_configuration_done); break; case MSG_SMS_GPIO_SET_LEVEL_RES: - sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES"); complete(&coredev->gpio_set_level_done); break; case MSG_SMS_GPIO_GET_LEVEL_RES: { u32 *msgdata = (u32 *) phdr; coredev->gpio_get_res = msgdata[1]; - sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d", + sms_debug("gpio level %d", coredev->gpio_get_res); complete(&coredev->gpio_get_level_done); break; @@ -1075,6 +1407,7 @@ void smscore_onresponse(struct smscore_device_t *coredev, break; default: + sms_debug("message not handled.\n"); break; } smscore_putbuffer(coredev, cb); diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index 4a0a7639319d..0078fef095a7 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -937,6 +937,8 @@ struct smscore_config_gpio { u8 outputdriving; }; +char *smscore_translate_msg(enum msg_types msgtype); + extern void smscore_registry_setmode(char *devpath, int mode); extern int smscore_registry_getmode(char *devpath); diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index aa77e54a8fae..57f3560514ab 100644 --- a/drivers/media/common/siano/smsdvb.c +++ b/drivers/media/common/siano/smsdvb.c @@ -249,20 +249,16 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) break; case MSG_SMS_SIGNAL_DETECTED_IND: - sms_info("MSG_SMS_SIGNAL_DETECTED_IND"); client->sms_stat_dvb.TransmissionData.IsDemodLocked = true; is_status_update = true; break; case MSG_SMS_NO_SIGNAL_IND: - sms_info("MSG_SMS_NO_SIGNAL_IND"); client->sms_stat_dvb.TransmissionData.IsDemodLocked = false; is_status_update = true; break; case MSG_SMS_TRANSMISSION_IND: { - sms_info("MSG_SMS_TRANSMISSION_IND"); - pMsgData++; memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData, sizeof(struct TRANSMISSION_STATISTICS_S)); @@ -281,7 +277,6 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) &client->sms_stat_dvb.ReceptionData; struct SRVM_SIGNAL_STATUS_S SignalStatusData; - /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/ pMsgData++; SignalStatusData.result = pMsgData[0]; SignalStatusData.snr = pMsgData[1]; @@ -336,8 +331,6 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) struct RECEPTION_STATISTICS_S *pReceptionData = &client->sms_stat_dvb.ReceptionData; - sms_info("MSG_SMS_GET_STATISTICS_RES"); - is_status_update = true; switch (smscore_get_device_mode(client->coredev)) { @@ -360,8 +353,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) break; } default: - sms_info("Unhandled message %d", phdr->msgType); - + sms_info("message not handled"); } smscore_putbuffer(client->coredev, cb); diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index de2c10289eec..2050e4c415b1 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -106,6 +106,10 @@ static void smsusb_onresponse(struct urb *urb) } else surb->cb->offset = 0; + sms_debug("received %s(%d) size: %d", + smscore_translate_msg(phdr->msgType), + phdr->msgType, phdr->msgLength); + smscore_onresponse(dev->coredev, surb->cb); surb->cb = NULL; } else { @@ -181,8 +185,13 @@ static int smsusb_start_streaming(struct smsusb_device_t *dev) static int smsusb_sendrequest(void *context, void *buffer, size_t size) { struct smsusb_device_t *dev = (struct smsusb_device_t *) context; + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer; int dummy; + sms_debug("sending %s(%d) size: %d", + smscore_translate_msg(phdr->msgType), phdr->msgType, + phdr->msgLength); + smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer); return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), buffer, size, &dummy, 1000); -- cgit v1.2.3 From ab2b599ebfbdd4e311e796643d487722256418b6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 6 Mar 2013 07:37:47 -0300 Subject: [media] siano: add the remaining new defines from new driver Add the remaining new defines/enums from Doron Cohen's patch: http://patchwork.linuxtv.org/patch/7882/ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.h | 39 ++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index 0078fef095a7..fc451e206436 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -50,18 +50,31 @@ along with this program. If not, see . #define SMS_ALIGN_ADDRESS(addr) \ ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1)) +#define SMS_DEVICE_FAMILY1 0 #define SMS_DEVICE_FAMILY2 1 #define SMS_ROM_NO_RESPONSE 2 #define SMS_DEVICE_NOT_READY 0x8000000 enum sms_device_type_st { + SMS_UNKNOWN_TYPE = -1, SMS_STELLAR = 0, SMS_NOVA_A0, SMS_NOVA_B0, SMS_VEGA, + SMS_VENICE, + SMS_MING, + SMS_PELE, + SMS_RIO, + SMS_DENVER_1530, + SMS_DENVER_2160, SMS_NUM_OF_DEVICE_TYPES }; +enum sms_power_mode_st { + SMS_POWER_MODE_ACTIVE, + SMS_POWER_MODE_SUSPENDED +}; + struct smscore_device_t; struct smscore_client_t; struct smscore_buffer_t; @@ -176,18 +189,29 @@ struct smscore_device_t { #define SMS_ANTENNA_GPIO_0 1 #define SMS_ANTENNA_GPIO_1 0 -#define BW_8_MHZ 0 -#define BW_7_MHZ 1 -#define BW_6_MHZ 2 -#define BW_5_MHZ 3 -#define BW_ISDBT_1SEG 4 -#define BW_ISDBT_3SEG 5 +enum sms_bandwidth_mode { + BW_8_MHZ = 0, + BW_7_MHZ = 1, + BW_6_MHZ = 2, + BW_5_MHZ = 3, + BW_ISDBT_1SEG = 4, + BW_ISDBT_3SEG = 5, + BW_2_MHZ = 6, + BW_FM_RADIO = 7, + BW_ISDBT_13SEG = 8, + BW_1_5_MHZ = 15, + BW_UNKNOWN = 0xffff +}; + #define MSG_HDR_FLAG_SPLIT_MSG 4 #define MAX_GPIO_PIN_NUMBER 31 #define HIF_TASK 11 +#define HIF_TASK_SLAVE 22 +#define HIF_TASK_SLAVE2 33 +#define HIF_TASK_SLAVE3 44 #define SMS_HOST_LIB 150 #define DVBT_BDA_CONTROL_MSG_ID 201 @@ -545,6 +569,9 @@ enum SMS_DEVICE_MODE { DEVICE_MODE_ISDBT_BDA, DEVICE_MODE_CMMB, DEVICE_MODE_RAW_TUNER, + DEVICE_MODE_FM_RADIO, + DEVICE_MODE_FM_RADIO_BDA, + DEVICE_MODE_ATSC, DEVICE_MODE_MAX, }; -- cgit v1.2.3 From 3ba92d0b58c909d68c316b5f7989abbc7b62b3ad Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 6 Mar 2013 08:42:47 -0300 Subject: [media] siano: Properly initialize board information Board #0 is an existing one. Instead of initializing the driver with it, use a different value to detect if board is unknown. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index bc15dcecb25d..1dab4b64d395 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -723,6 +723,7 @@ int smscore_register_device(struct smsdevice_params_t *params, sms_info("allocated %d buffers", dev->num_buffers); dev->mode = DEVICE_MODE_NONE; + dev->board_id = SMS_BOARD_UNKNOWN; dev->context = params->context; dev->device = params->device; dev->setmode_handler = params->setmode_handler; -- cgit v1.2.3 From db30567a63db0094e03338462939031edf558cc8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 6 Mar 2013 08:33:44 -0300 Subject: [media] siano: add additional attributes to cards entries Those attributes will be used by the newer sms2xxx cards. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/sms-cards.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h index d8cdf756f7cf..9f1861aa71c9 100644 --- a/drivers/media/common/siano/sms-cards.h +++ b/drivers/media/common/siano/sms-cards.h @@ -79,6 +79,12 @@ struct sms_board { /* gpios */ int led_power, led_hi, led_lo, lna_ctrl, rf_switch; + + char intf_num; + int default_mode; + unsigned int mtu; + unsigned int crystal; + struct sms_antenna_config_ST *antenna_config; }; struct sms_board *sms_get_board(unsigned id); -- cgit v1.2.3 From 05f0ffbc487517a529c00119d0bfde33df509b52 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 6 Mar 2013 09:53:50 -0300 Subject: [media] siano: use USB endpoint descriptors for in/out endp Instead of using hardcoded descriptors, detect them from the USB descriptors. This patch is rebased form Doron Cohen's patch: http://patchwork.linuxtv.org/patch/7883/ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/siano/smsusb.c | 99 +++++++++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 26 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 2050e4c415b1..a31bf74a5957 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -35,16 +35,23 @@ module_param_named(debug, sms_dbg, int, 0644); MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); #define USB1_BUFFER_SIZE 0x1000 -#define USB2_BUFFER_SIZE 0x4000 +#define USB2_BUFFER_SIZE 0x2000 #define MAX_BUFFERS 50 #define MAX_URBS 10 struct smsusb_device_t; +enum smsusb_state { + SMSUSB_DISCONNECTED, + SMSUSB_SUSPENDED, + SMSUSB_ACTIVE +}; + struct smsusb_urb_t { + struct list_head entry; struct smscore_buffer_t *cb; - struct smsusb_device_t *dev; + struct smsusb_device_t *dev; struct urb urb; }; @@ -57,11 +64,23 @@ struct smsusb_device_t { int response_alignment; int buffer_size; + + unsigned char in_ep; + unsigned char out_ep; + enum smsusb_state state; }; static int smsusb_submit_urb(struct smsusb_device_t *dev, struct smsusb_urb_t *surb); +/** + * Completing URB's callback handler - top half (interrupt context) + * adds completing sms urb to the global surbs list and activtes the worker + * thread the surb + * IMPORTANT - blocking functions must not be called from here !!! + + * @param urb pointer to a completing urb object + */ static void smsusb_onresponse(struct urb *urb) { struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context; @@ -140,7 +159,7 @@ static int smsusb_submit_urb(struct smsusb_device_t *dev, usb_fill_bulk_urb( &surb->urb, dev->udev, - usb_rcvbulkpipe(dev->udev, 0x81), + usb_rcvbulkpipe(dev->udev, dev->in_ep), surb->cb->p, dev->buffer_size, smsusb_onresponse, @@ -192,6 +211,9 @@ static int smsusb_sendrequest(void *context, void *buffer, size_t size) smscore_translate_msg(phdr->msgType), phdr->msgType, phdr->msgLength); + if (dev->state != SMSUSB_ACTIVE) + return -ENOENT; + smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer); return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), buffer, size, &dummy, 1000); @@ -301,13 +323,15 @@ static void smsusb_term_device(struct usb_interface *intf) struct smsusb_device_t *dev = usb_get_intfdata(intf); if (dev) { + dev->state = SMSUSB_DISCONNECTED; + smsusb_stop_streaming(dev); /* unregister from smscore */ if (dev->coredev) smscore_unregister_device(dev->coredev); - sms_info("device %p destroyed", dev); + sms_info("device 0x%p destroyed", dev); kfree(dev); } @@ -330,6 +354,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) memset(¶ms, 0, sizeof(params)); usb_set_intfdata(intf, dev); dev->udev = interface_to_usbdev(intf); + dev->state = SMSUSB_DISCONNECTED; params.device_type = sms_get_board(board_id)->type; @@ -346,6 +371,8 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) case SMS_NOVA_A0: case SMS_NOVA_B0: case SMS_VEGA: + case SMS_VENICE: + case SMS_DENVER_1530: dev->buffer_size = USB2_BUFFER_SIZE; dev->response_alignment = le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) - @@ -355,6 +382,16 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) break; } + for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { + if (intf->cur_altsetting->endpoint[i].desc. bEndpointAddress & USB_DIR_IN) + dev->in_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress; + else + dev->out_ep = intf->cur_altsetting->endpoint[i].desc.bEndpointAddress; + } + + sms_info("in_ep = %02x, out_ep = %02x", + dev->in_ep, dev->out_ep); + params.device = &dev->udev->dev; params.buffer_size = dev->buffer_size; params.num_buffers = MAX_BUFFERS; @@ -386,6 +423,8 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) return rc; } + dev->state = SMSUSB_ACTIVE; + rc = smscore_start_device(dev->coredev); if (rc < 0) { sms_err("smscore_start_device(...) failed"); @@ -393,7 +432,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) return rc; } - sms_info("device %p created", dev); + sms_info("device 0x%p created", dev); return rc; } @@ -402,15 +441,23 @@ static int smsusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); - char devpath[32]; int i, rc; - rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81)); - rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02)); + sms_info("interface number %d", + intf->cur_altsetting->desc.bInterfaceNumber); - if (intf->num_altsetting > 0) { - rc = usb_set_interface( - udev, intf->cur_altsetting->desc.bInterfaceNumber, 0); + if (sms_get_board(id->driver_info)->intf_num != + intf->cur_altsetting->desc.bInterfaceNumber) { + sms_err("interface number is %d expecting %d", + sms_get_board(id->driver_info)->intf_num, + intf->cur_altsetting->desc.bInterfaceNumber); + return -ENODEV; + } + + if (intf->num_altsetting > 1) { + rc = usb_set_interface(udev, + intf->cur_altsetting->desc.bInterfaceNumber, + 0); if (rc < 0) { sms_err("usb_set_interface failed, rc %d", rc); return rc; @@ -419,27 +466,25 @@ static int smsusb_probe(struct usb_interface *intf, sms_info("smsusb_probe %d", intf->cur_altsetting->desc.bInterfaceNumber); - for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) + for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { sms_info("endpoint %d %02x %02x %d", i, intf->cur_altsetting->endpoint[i].desc.bEndpointAddress, intf->cur_altsetting->endpoint[i].desc.bmAttributes, intf->cur_altsetting->endpoint[i].desc.wMaxPacketSize); - + if (intf->cur_altsetting->endpoint[i].desc.bEndpointAddress & + USB_DIR_IN) + rc = usb_clear_halt(udev, usb_rcvbulkpipe(udev, + intf->cur_altsetting->endpoint[i].desc.bEndpointAddress)); + else + rc = usb_clear_halt(udev, usb_sndbulkpipe(udev, + intf->cur_altsetting->endpoint[i].desc.bEndpointAddress)); + } if ((udev->actconfig->desc.bNumInterfaces == 2) && (intf->cur_altsetting->desc.bInterfaceNumber == 0)) { sms_err("rom interface 0 is not used"); return -ENODEV; } - if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { - snprintf(devpath, sizeof(devpath), "usb\\%d-%s", - udev->bus->busnum, udev->devpath); - sms_info("stellar device was found."); - return smsusb1_load_firmware( - udev, smscore_registry_getmode(devpath), - id->driver_info); - } - rc = smsusb_init_device(intf, id->driver_info); sms_info("rc %d", rc); sms_board_load_modules(id->driver_info); @@ -454,7 +499,9 @@ static void smsusb_disconnect(struct usb_interface *intf) static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg) { struct smsusb_device_t *dev = usb_get_intfdata(intf); - printk(KERN_INFO "%s: Entering status %d.\n", __func__, msg.event); + printk(KERN_INFO "%s Entering status %d.\n", __func__, msg.event); + dev->state = SMSUSB_SUSPENDED; + /*smscore_set_power_mode(dev, SMS_POWER_MODE_SUSPENDED);*/ smsusb_stop_streaming(dev); return 0; } @@ -465,9 +512,9 @@ static int smsusb_resume(struct usb_interface *intf) struct smsusb_device_t *dev = usb_get_intfdata(intf); struct usb_device *udev = interface_to_usbdev(intf); - printk(KERN_INFO "%s: Entering.\n", __func__); - usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x81)); - usb_clear_halt(udev, usb_rcvbulkpipe(udev, 0x02)); + printk(KERN_INFO "%s Entering.\n", __func__); + usb_clear_halt(udev, usb_rcvbulkpipe(udev, dev->in_ep)); + usb_clear_halt(udev, usb_sndbulkpipe(udev, dev->out_ep)); for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) printk(KERN_INFO "endpoint %d %02x %02x %d\n", i, -- cgit v1.2.3 From 7333839505d568e0e69a6d02a3ee0f455b6c37a5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Mar 2013 09:56:27 -0300 Subject: [media] siano: store firmware version As there are some changes that seem to be firmware-dependent, we need to store the firmware version, as we don't want to break support for existing cards that use a legacy (and sometimes custom) firmware. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 2 ++ drivers/media/common/siano/smscoreapi.h | 1 + 2 files changed, 3 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 1dab4b64d395..7b5d81a30cdf 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1359,6 +1359,8 @@ void smscore_onresponse(struct smscore_device_t *coredev, coredev->mode = ver->FirmwareId == 255 ? DEVICE_MODE_NONE : ver->FirmwareId; coredev->modes_supported = ver->SupportedProtocols; + coredev->fw_version = ver->RomVersionMajor << 8 | + ver->RomVersionMinor; complete(&coredev->version_ex_done); break; diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index fc451e206436..f1440a55cb4d 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -178,6 +178,7 @@ struct smscore_device_t { /* Firmware */ u8 *fw_buf; u32 fw_buf_size; + u16 fw_version; /* Infrared (IR) */ struct ir_t ir; -- cgit v1.2.3 From 018b0c6f8acb5819591f3b43b51fc342af548c82 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 6 Mar 2013 12:15:08 -0300 Subject: [media] siano: make load firmware logic to work with newer firmwares There are new firmwares for sms2xxx devices. Change the firmware load logic to handle those newer firmwares and devices. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 348 ++++++++++++++++++++------------ drivers/media/common/siano/smscoreapi.h | 8 +- 2 files changed, 220 insertions(+), 136 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 7b5d81a30cdf..d489701c3842 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -683,6 +683,7 @@ int smscore_register_device(struct smsdevice_params_t *params, /* init completion events */ init_completion(&dev->version_ex_done); init_completion(&dev->data_download_done); + init_completion(&dev->data_validity_done); init_completion(&dev->trigger_done); init_completion(&dev->init_device_done); init_completion(&dev->reload_start_done); @@ -753,7 +754,13 @@ EXPORT_SYMBOL_GPL(smscore_register_device); static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, void *buffer, size_t size, struct completion *completion) { - int rc = coredev->sendrequest_handler(coredev->context, buffer, size); + int rc; + + if (completion == NULL) + return -EINVAL; + init_completion(completion); + + rc = coredev->sendrequest_handler(coredev->context, buffer, size); if (rc < 0) { sms_info("sendrequest returned error %d", rc); return rc; @@ -850,8 +857,9 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, void *buffer, size_t size) { struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer; - struct SmsMsgHdr_ST *msg; - u32 mem_address; + struct SmsMsgData_ST4 *msg; + u32 mem_address, calc_checksum = 0; + u32 i, *ptr; u8 *payload = firmware->Payload; int rc = 0; firmware->StartAddress = le32_to_cpu(firmware->StartAddress); @@ -874,34 +882,35 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, if (coredev->mode != DEVICE_MODE_NONE) { sms_debug("sending reload command."); - SMS_INIT_MSG(msg, MSG_SW_RELOAD_START_REQ, + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SW_RELOAD_START_REQ, sizeof(struct SmsMsgHdr_ST)); rc = smscore_sendrequest_and_wait(coredev, msg, - msg->msgLength, + msg->xMsgHeader.msgLength, &coredev->reload_start_done); + if (rc < 0) { + sms_err("device reload failed, rc %d", rc); + goto exit_fw_download; + } mem_address = *(u32 *) &payload[20]; } + for (i = 0, ptr = (u32 *)firmware->Payload; i < firmware->Length/4 ; + i++, ptr++) + calc_checksum += *ptr; + while (size && rc >= 0) { struct SmsDataDownload_ST *DataMsg = (struct SmsDataDownload_ST *) msg; int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE); - SMS_INIT_MSG(msg, MSG_SMS_DATA_DOWNLOAD_REQ, + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_DATA_DOWNLOAD_REQ, (u16)(sizeof(struct SmsMsgHdr_ST) + sizeof(u32) + payload_size)); DataMsg->MemAddr = mem_address; memcpy(DataMsg->Payload, payload, payload_size); - if ((coredev->device_flags & SMS_ROM_NO_RESPONSE) && - (coredev->mode == DEVICE_MODE_NONE)) - rc = coredev->sendrequest_handler( - coredev->context, DataMsg, - DataMsg->xMsgHeader.msgLength); - else - rc = smscore_sendrequest_and_wait( - coredev, DataMsg, + rc = smscore_sendrequest_and_wait(coredev, DataMsg, DataMsg->xMsgHeader.msgLength, &coredev->data_download_done); @@ -910,44 +919,65 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, mem_address += payload_size; } - if (rc >= 0) { - if (coredev->mode == DEVICE_MODE_NONE) { - struct SmsMsgData_ST *TriggerMsg = - (struct SmsMsgData_ST *) msg; - - SMS_INIT_MSG(msg, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, - sizeof(struct SmsMsgHdr_ST) + - sizeof(u32) * 5); - - TriggerMsg->msgData[0] = firmware->StartAddress; - /* Entry point */ - TriggerMsg->msgData[1] = 5; /* Priority */ - TriggerMsg->msgData[2] = 0x200; /* Stack size */ - TriggerMsg->msgData[3] = 0; /* Parameter */ - TriggerMsg->msgData[4] = 4; /* Task ID */ - - if (coredev->device_flags & SMS_ROM_NO_RESPONSE) { - rc = coredev->sendrequest_handler( - coredev->context, TriggerMsg, - TriggerMsg->xMsgHeader.msgLength); - msleep(100); - } else - rc = smscore_sendrequest_and_wait( - coredev, TriggerMsg, + if (rc < 0) + goto exit_fw_download; + + sms_err("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x", + calc_checksum); + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_DATA_VALIDITY_REQ, + sizeof(msg->xMsgHeader) + + sizeof(u32) * 3); + msg->msgData[0] = firmware->StartAddress; + /* Entry point */ + msg->msgData[1] = firmware->Length; + msg->msgData[2] = 0; /* Regular checksum*/ + smsendian_handle_tx_message(msg); + rc = smscore_sendrequest_and_wait(coredev, msg, + msg->xMsgHeader.msgLength, + &coredev->data_validity_done); + if (rc < 0) + goto exit_fw_download; + + if (coredev->mode == DEVICE_MODE_NONE) { + struct SmsMsgData_ST *TriggerMsg = + (struct SmsMsgData_ST *) msg; + + sms_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ"); + SMS_INIT_MSG(&msg->xMsgHeader, + MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, + sizeof(struct SmsMsgHdr_ST) + + sizeof(u32) * 5); + + TriggerMsg->msgData[0] = firmware->StartAddress; + /* Entry point */ + TriggerMsg->msgData[1] = 6; /* Priority */ + TriggerMsg->msgData[2] = 0x200; /* Stack size */ + TriggerMsg->msgData[3] = 0; /* Parameter */ + TriggerMsg->msgData[4] = 4; /* Task ID */ + + smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg); + rc = smscore_sendrequest_and_wait(coredev, TriggerMsg, TriggerMsg->xMsgHeader.msgLength, &coredev->trigger_done); - } else { - SMS_INIT_MSG(msg, MSG_SW_RELOAD_EXEC_REQ, - sizeof(struct SmsMsgHdr_ST)); - - rc = coredev->sendrequest_handler(coredev->context, - msg, msg->msgLength); - } - msleep(500); + } else { + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SW_RELOAD_EXEC_REQ, + sizeof(struct SmsMsgHdr_ST)); + smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg); + rc = coredev->sendrequest_handler(coredev->context, msg, + msg->xMsgHeader.msgLength); } - sms_debug("rc=%d, postload=%p ", rc, - coredev->postload_handler); + if (rc < 0) + goto exit_fw_download; + + /* + * backward compatibility - wait to device_ready_done for + * not more than 400 ms + */ + msleep(400); + +exit_fw_download: + sms_debug("rc=%d, postload=0x%p ", rc, coredev->postload_handler); kfree(msg); @@ -956,6 +986,10 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, rc; } + +static char *smscore_get_fw_filename(struct smscore_device_t *coredev, + int mode, int lookup); + /** * loads specified firmware into a buffer and calls device loadfirmware_handler * @@ -967,41 +1001,43 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, * @return 0 on success, <0 on error. */ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, - char *filename, + int mode, int lookup, loadfirmware_t loadfirmware_handler) { int rc = -ENOENT; + u8 *fw_buf; + u32 fw_buf_size; const struct firmware *fw; - u8 *fw_buffer; - if (loadfirmware_handler == NULL && !(coredev->device_flags & - SMS_DEVICE_FAMILY2)) + char *fw_filename = smscore_get_fw_filename(coredev, mode, lookup); + if (!strcmp(fw_filename, "none")) + return -ENOENT; + + if (loadfirmware_handler == NULL && !(coredev->device_flags + & SMS_DEVICE_FAMILY2)) return -EINVAL; - rc = request_firmware(&fw, filename, coredev->device); + rc = request_firmware(&fw, fw_filename, coredev->device); if (rc < 0) { - sms_info("failed to open \"%s\"", filename); + sms_info("failed to open \"%s\"", fw_filename); return rc; } - sms_info("read FW %s, size=%zd", filename, fw->size); - fw_buffer = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT), - GFP_KERNEL | GFP_DMA); - if (fw_buffer) { - memcpy(fw_buffer, fw->data, fw->size); - - rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ? - smscore_load_firmware_family2(coredev, - fw_buffer, - fw->size) : - loadfirmware_handler(coredev->context, - fw_buffer, fw->size); - - kfree(fw_buffer); - } else { + sms_info("read fw %s, buffer size=0x%zx", fw_filename, fw->size); + fw_buf = kmalloc(ALIGN(fw->size, SMS_ALLOC_ALIGNMENT), + GFP_KERNEL | GFP_DMA); + if (!fw_buf) { sms_info("failed to allocate firmware buffer"); - rc = -ENOMEM; + return -ENOMEM; } + memcpy(fw_buf, fw->data, fw->size); + fw_buf_size = fw->size; + + rc = (coredev->device_flags & SMS_DEVICE_FAMILY2) ? + smscore_load_firmware_family2(coredev, fw_buf, fw_buf_size) + : loadfirmware_handler(coredev->context, fw_buf, + fw_buf_size); + kfree(fw_buf); release_firmware(fw); return rc; @@ -1050,7 +1086,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev) sms_info("waiting for %d buffer(s)", coredev->num_buffers - num_buffers); + kmutex_unlock(&g_smscore_deviceslock); msleep(100); + kmutex_lock(&g_smscore_deviceslock); } sms_info("freed %d buffers", num_buffers); @@ -1107,30 +1145,73 @@ static int smscore_detect_mode(struct smscore_device_t *coredev) } static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = { - /*Stellar NOVA A0 Nova B0 VEGA*/ - /*DVBT*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, - /*DVBH*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, - /*TDMB*/ - {"none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none"}, - /*DABIP*/ - {"none", "none", "none", "none"}, - /*BDA*/ - {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"}, - /*ISDBT*/ - {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, - /*ISDBTBDA*/ - {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"}, - /*CMMB*/ - {"none", "none", "none", "cmmb_vega_12mhz.inp"} + /*Stellar, NOVA A0, Nova B0, VEGA, VENICE, MING, PELE, RIO, DENVER_1530, DENVER_2160 */ + /*DVBT*/ + { "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none", "none", "none", "none", "dvb_rio.inp", "none", "none" }, + /*DVBH*/ + { "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none", "none", "none", "none", "dvbh_rio.inp", "none", "none" }, + /*TDMB*/ + { "none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none", "none", "none", "none", "none", "none", "tdmb_denver.inp" }, + /*DABIP*/ + { "none", "none", "none", "none", "none", "none", "none", "none", "none", "none" }, + /*DVBT_BDA*/ + { "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none", "none", "none", "none", "dvb_rio.inp", "none", "none" }, + /*ISDBT*/ + { "none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none", "none", "none", "isdbt_pele.inp", "isdbt_rio.inp", "none", "none" }, + /*ISDBT_BDA*/ + { "none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none", "none", "none", "isdbt_pele.inp", "isdbt_rio.inp", "none", "none" }, + /*CMMB*/ + { "none", "none", "none", "cmmb_vega_12mhz.inp", "cmmb_venice_12mhz.inp", "cmmb_ming_app.inp", "none", "none", "none", "none" }, + /*RAW - not supported*/ + { "none", "none", "none", "none", "none", "none", "none", "none", "none", "none" }, + /*FM*/ + { "none", "none", "fm_radio.inp", "none", "none", "none", "none", "fm_radio_rio.inp", "none", "none" }, + /*FM_BDA*/ + { "none", "none", "fm_radio.inp", "none", "none", "none", "none", "fm_radio_rio.inp", "none", "none" }, + /*ATSC*/ + { "none", "none", "none", "none", "none", "none", "none", "none", "atsc_denver.inp", "none" } }; -static inline char *sms_get_fw_name(struct smscore_device_t *coredev, - int mode, enum sms_device_type_st type) +/** + * get firmware file name from one of the two mechanisms : sms_boards or + * smscore_fw_lkup. + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param mode requested mode of operation + * @param lookup if 1, always get the fw filename from smscore_fw_lkup + * table. if 0, try first to get from sms_boards + * + * @return 0 on success, <0 on error. + */ +static char *smscore_get_fw_filename(struct smscore_device_t *coredev, + int mode, int lookup) { - char **fw = sms_get_board(smscore_get_board_id(coredev))->fw; - return (fw && fw[mode]) ? fw[mode] : smscore_fw_lkup[mode][type]; + char **fw; + int board_id = smscore_get_board_id(coredev); + enum sms_device_type_st type = smscore_registry_gettype(coredev->devpath); + + if ((board_id == SMS_BOARD_UNKNOWN) || (lookup == 1)) { + sms_debug("trying to get fw name from lookup table mode %d type %d", + mode, type); + return smscore_fw_lkup[mode][type]; + } + + sms_debug("trying to get fw name from sms_boards board_id %d mode %d", + board_id, mode); + fw = sms_get_board(board_id)->fw; + if (fw == NULL) { + sms_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d", + mode, type); + return smscore_fw_lkup[mode][type]; + } + + if (fw[mode] == NULL) { + sms_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d", + mode, type); + return smscore_fw_lkup[mode][type]; + } + + return fw[mode]; } /** @@ -1145,9 +1226,7 @@ static inline char *sms_get_fw_name(struct smscore_device_t *coredev, */ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) { - void *buffer; int rc = 0; - enum sms_device_type_st type; sms_debug("set device mode to %d", mode); if (coredev->device_flags & SMS_DEVICE_FAMILY2) { @@ -1172,55 +1251,30 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) } if (!(coredev->modes_supported & (1 << mode))) { - char *fw_filename; - - type = smscore_registry_gettype(coredev->devpath); - fw_filename = sms_get_fw_name(coredev, mode, type); - rc = smscore_load_firmware_from_file(coredev, - fw_filename, NULL); - if (rc < 0) { - sms_warn("error %d loading firmware: %s, " - "trying again with default firmware", - rc, fw_filename); + mode, 0, NULL); - /* try again with the default firmware */ - fw_filename = smscore_fw_lkup[mode][type]; + /* + * try again with the default firmware - + * get the fw filename from look-up table + */ + if (rc < 0) { + sms_debug("error %d loading firmware, trying again with default firmware", + rc); rc = smscore_load_firmware_from_file(coredev, - fw_filename, NULL); - + mode, 1, + NULL); if (rc < 0) { - sms_warn("error %d loading " - "firmware: %s", rc, - fw_filename); + sms_debug("error %d loading firmware", + rc); return rc; } } - sms_log("firmware download success: %s", fw_filename); - } else - sms_info("mode %d supported by running " - "firmware", mode); - - buffer = kmalloc(sizeof(struct SmsMsgData_ST) + - SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); - if (buffer) { - struct SmsMsgData_ST *msg = - (struct SmsMsgData_ST *) - SMS_ALIGN_ADDRESS(buffer); - - SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, - sizeof(struct SmsMsgData_ST)); - msg->msgData[0] = mode; - - rc = smscore_sendrequest_and_wait( - coredev, msg, msg->xMsgHeader.msgLength, - &coredev->init_device_done); - - kfree(buffer); + if (rc >= 0) + sms_info("firmware download success"); } else { - sms_err("Could not allocate buffer for " - "init device message."); - rc = -ENOMEM; + sms_info("mode %d is already supported by running firmware", + mode); } } else { if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { @@ -1239,8 +1293,25 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) } if (rc >= 0) { + char *buffer; coredev->mode = mode; coredev->device_flags &= ~SMS_DEVICE_NOT_READY; + + buffer = kmalloc(sizeof(struct SmsMsgData_ST) + + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); + if (buffer) { + struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *) SMS_ALIGN_ADDRESS(buffer); + + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, + sizeof(struct SmsMsgData_ST)); + msg->msgData[0] = mode; + + rc = smscore_sendrequest_and_wait( + coredev, msg, msg->xMsgHeader.msgLength, + &coredev->init_device_done); + + kfree(buffer); + } } if (rc < 0) @@ -1371,6 +1442,15 @@ void smscore_onresponse(struct smscore_device_t *coredev, case MSG_SW_RELOAD_START_RES: complete(&coredev->reload_start_done); break; + case MSG_SMS_DATA_VALIDITY_RES: + { + struct SmsMsgData_ST *validity = (struct SmsMsgData_ST *) phdr; + + sms_err("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x", + validity->msgData[0]); + complete(&coredev->data_validity_done); + break; + } case MSG_SMS_DATA_DOWNLOAD_RES: complete(&coredev->data_download_done); break; diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index f1440a55cb4d..91db8536c2b0 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -162,6 +162,7 @@ struct smscore_device_t { /* host <--> device messages */ struct completion version_ex_done, data_download_done, trigger_done; + struct completion data_validity_done, device_ready_done; struct completion init_device_done, reload_start_done, resume_done; struct completion gpio_configuration_done, gpio_set_level_done; struct completion gpio_get_level_done, ir_init_done; @@ -594,6 +595,11 @@ struct SmsMsgData_ST2 { u32 msgData[2]; }; +struct SmsMsgData_ST4 { + struct SmsMsgHdr_ST xMsgHeader; + u32 msgData[4]; +}; + struct SmsDataDownload_ST { struct SmsMsgHdr_ST xMsgHeader; u32 MemAddr; @@ -998,8 +1004,6 @@ extern void smscore_onresponse(struct smscore_device_t *coredev, extern int smscore_get_common_buffer_size(struct smscore_device_t *coredev); extern int smscore_map_common_buffer(struct smscore_device_t *coredev, struct vm_area_struct *vma); -extern int smscore_get_fw_filename(struct smscore_device_t *coredev, - int mode, char *filename); extern int smscore_send_fw_file(struct smscore_device_t *coredev, u8 *ufwbuf, int size); -- cgit v1.2.3 From ab7bdb12984732e5ebac00d6a180431cbd4e0ce1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Mar 2013 06:54:14 -0300 Subject: [media] siano: report the choosed firmware in debug Don't keep in the dark: report the firmware file name after lookup. That helps to debug what's happening when a firmware is not found. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index d489701c3842..5034153ed09c 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1010,6 +1010,7 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, const struct firmware *fw; char *fw_filename = smscore_get_fw_filename(coredev, mode, lookup); + sms_debug("Firmware name: %s\n", fw_filename); if (!strcmp(fw_filename, "none")) return -ENOENT; -- cgit v1.2.3 From 1e19c21ec7b5e66228602f4d88d894e23db1e004 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Mar 2013 07:32:47 -0300 Subject: [media] siano: fix the debug message Instead of displaying this: [ 61.869415] smscore_load_firmware_family2: rc=0, postload=0x (null) Display, instead: [ 1348.441160] smscore_load_firmware_family2: rc=0 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 5034153ed09c..7302f950c6bd 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -977,13 +977,16 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, msleep(400); exit_fw_download: - sms_debug("rc=%d, postload=0x%p ", rc, coredev->postload_handler); - kfree(msg); - return ((rc >= 0) && coredev->postload_handler) ? - coredev->postload_handler(coredev->context) : - rc; + if (coredev->postload_handler) { + sms_debug("rc=%d, postload=0x%p", rc, coredev->postload_handler); + if (rc >= 0) + return coredev->postload_handler(coredev->context); + } + + sms_debug("rc=%d", rc); + return rc; } -- cgit v1.2.3 From 9e915e5bc8dfa3380c376a5e10f1abe8c17f324a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Mar 2013 11:35:00 -0300 Subject: [media] siano: always load smsdvb Without smsdvb, the driver actually does nothing, as it lacks the userspace API. While I wrote it independently, in order to make a sms2270 board I have here to work, this patch is functionally identical to this patch from Doron Cohen: http://patchwork.linuxtv.org/patch/7894/ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/sms-cards.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index b22b61dbc0e2..04bb04ca414f 100644 --- a/drivers/media/common/siano/sms-cards.c +++ b/drivers/media/common/siano/sms-cards.c @@ -293,19 +293,7 @@ EXPORT_SYMBOL_GPL(sms_board_lna_control); int sms_board_load_modules(int id) { - switch (id) { - case SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT: - case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A: - case SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B: - case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD: - case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2: - request_module("smsdvb"); - break; - default: - /* do nothing */ - break; - } + request_module("smsdvb"); return 0; } EXPORT_SYMBOL_GPL(sms_board_load_modules); -- cgit v1.2.3 From e5d218ee75787bbe5bbe6c570797443c877cd4e5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Mar 2013 11:38:57 -0300 Subject: [media] siano: cleanups at smscoreapi.c Some cleanups at smscoreapi. Most are just CodingStyle. Also, use kzalloc when allocating a new buffer, as it initializes the allocated space with zero. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 25 ++++++++++++++++--------- drivers/media/common/siano/smscoreapi.h | 1 - 2 files changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 7302f950c6bd..ba73293cf7d3 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -490,10 +490,10 @@ static enum sms_device_type_st smscore_registry_gettype(char *devpath) else sms_err("No registry found."); - return -1; + return -EINVAL; } -void smscore_registry_setmode(char *devpath, int mode) +static void smscore_registry_setmode(char *devpath, int mode) { struct smscore_registry_entry_t *entry; @@ -633,10 +633,11 @@ static struct smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, dma_addr_t common_buffer_phys) { - struct smscore_buffer_t *cb = - kmalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL); + struct smscore_buffer_t *cb; + + cb = kzalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL); if (!cb) { - sms_info("kmalloc(...) failed"); + sms_info("kzalloc(...) failed"); return NULL; } @@ -710,9 +711,10 @@ int smscore_register_device(struct smsdevice_params_t *params, for (buffer = dev->common_buffer; dev->num_buffers < params->num_buffers; dev->num_buffers++, buffer += params->buffer_size) { - struct smscore_buffer_t *cb = - smscore_createbuffer(buffer, dev->common_buffer, - dev->common_buffer_phys); + struct smscore_buffer_t *cb; + + cb = smscore_createbuffer(buffer, dev->common_buffer, + dev->common_buffer_phys); if (!cb) { smscore_unregister_device(dev); return -ENOMEM; @@ -1192,7 +1194,9 @@ static char *smscore_get_fw_filename(struct smscore_device_t *coredev, { char **fw; int board_id = smscore_get_board_id(coredev); - enum sms_device_type_st type = smscore_registry_gettype(coredev->devpath); + enum sms_device_type_st type; + + type = smscore_registry_gettype(coredev->devpath); if ((board_id == SMS_BOARD_UNKNOWN) || (lookup == 1)) { sms_debug("trying to get fw name from lookup table mode %d type %d", @@ -1320,6 +1324,9 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) if (rc < 0) sms_err("return error code %d.", rc); + else + sms_debug("Success setting device mode."); + return rc; } diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index 91db8536c2b0..8af94c434352 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -973,7 +973,6 @@ struct smscore_config_gpio { char *smscore_translate_msg(enum msg_types msgtype); -extern void smscore_registry_setmode(char *devpath, int mode); extern int smscore_registry_getmode(char *devpath); extern int smscore_register_hotplug(hotplug_t hotplug); -- cgit v1.2.3 From faab6820b3c11ca62fd2284d2e5174ccb0650b05 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Mar 2013 11:53:46 -0300 Subject: [media] siano: add some new messages to the smscoreapi Based on Doron Cohen's patch: http://patchwork.linuxtv.org/patch/7887/ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index ba73293cf7d3..67d0319dc013 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1429,7 +1429,23 @@ void smscore_onresponse(struct smscore_device_t *coredev, rc = client->onresponse_handler(client->context, cb); if (rc < 0) { + smsendian_handle_rx_message((struct SmsMsgData_ST *)phdr); + switch (phdr->msgType) { + case MSG_SMS_ISDBT_TUNE_RES: + break; + case MSG_SMS_RF_TUNE_RES: + break; + case MSG_SMS_SIGNAL_DETECTED_IND: + break; + case MSG_SMS_NO_SIGNAL_IND: + break; + case MSG_SMS_SPI_INT_LINE_SET_RES: + break; + case MSG_SMS_INTERFACE_LOCK_IND: + break; + case MSG_SMS_INTERFACE_UNLOCK_IND: + break; case MSG_SMS_GET_VERSION_EX_RES: { struct SmsVersionRes_ST *ver = -- cgit v1.2.3 From 76e41a655ae68b3e0468a3ef497a57415a77b54b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Mar 2013 16:32:33 -0300 Subject: [media] siano: use a separate completion for stats Instead of re-use tune_done also for stats, the better is to use a different completion. Also, it was noticed that sometimes, the driver answers with MSG_SMS_SIGNAL_DETECTED_IND for status request. Fix the code to also handle those other signal indicators. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index 57f3560514ab..f4fd6703c49e 100644 --- a/drivers/media/common/siano/smsdvb.c +++ b/drivers/media/common/siano/smsdvb.c @@ -48,6 +48,7 @@ struct smsdvb_client_t { fe_status_t fe_status; struct completion tune_done; + struct completion stats_done; struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb; int event_fe_state; @@ -349,7 +350,6 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) pReceptionData->ErrorTSPackets = 0; } - complete(&client->tune_done); break; } default: @@ -376,6 +376,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) client->fe_status = 0; sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK); } + complete(&client->stats_done); } return 0; @@ -471,7 +472,7 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) sizeof(struct SmsMsgHdr_ST), 0 }; rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); + &client->stats_done); return rc; } @@ -1002,6 +1003,7 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, client->coredev = coredev; init_completion(&client->tune_done); + init_completion(&client->stats_done); kmutex_lock(&g_smsdvb_clientslock); -- cgit v1.2.3 From a51fea4fdbf1c8151f55029c82f850cbd335ff29 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Mar 2013 16:34:06 -0300 Subject: [media] siano: add support for ISDB-T full-seg Fix the DVBv5 API handling for ISDB-T and add support for 13 segments. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb.c | 46 ++++++++++++++----------------------- 1 file changed, 17 insertions(+), 29 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index f4fd6703c49e..4900aa9e8b7a 100644 --- a/drivers/media/common/siano/smsdvb.c +++ b/drivers/media/common/siano/smsdvb.c @@ -652,6 +652,9 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct smsdvb_client_t *client = container_of(fe, struct smsdvb_client_t, frontend); + int board_id = smscore_get_board_id(client->coredev); + struct sms_board *board = sms_get_board(board_id); + enum sms_device_type_st type = board->type; struct { struct SmsMsgHdr_ST Msg; @@ -669,40 +672,25 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) if (c->isdbt_sb_segment_idx == -1) c->isdbt_sb_segment_idx = 0; - switch (c->isdbt_sb_segment_count) { - case 3: - Msg.Data[1] = BW_ISDBT_3SEG; - break; - case 1: - Msg.Data[1] = BW_ISDBT_1SEG; - break; - case 0: /* AUTO */ - switch (c->bandwidth_hz / 1000000) { - case 8: - case 7: - c->isdbt_sb_segment_count = 3; - Msg.Data[1] = BW_ISDBT_3SEG; - break; - case 6: - c->isdbt_sb_segment_count = 1; - Msg.Data[1] = BW_ISDBT_1SEG; - break; - default: /* Assumes 6 MHZ bw */ - c->isdbt_sb_segment_count = 1; - c->bandwidth_hz = 6000; - Msg.Data[1] = BW_ISDBT_1SEG; - break; - } - break; - default: - sms_info("Segment count %d not supported", c->isdbt_sb_segment_count); - return -EINVAL; - } + if (!c->isdbt_layer_enabled) + c->isdbt_layer_enabled = 7; Msg.Data[0] = c->frequency; + Msg.Data[1] = BW_ISDBT_1SEG; Msg.Data[2] = 12000000; Msg.Data[3] = c->isdbt_sb_segment_idx; + if (c->isdbt_partial_reception) { + if ((type == SMS_PELE || type == SMS_RIO) && + c->isdbt_sb_segment_count > 3) + Msg.Data[1] = BW_ISDBT_13SEG; + else if (c->isdbt_sb_segment_count > 1) + Msg.Data[1] = BW_ISDBT_3SEG; + } else if (type == SMS_PELE || type == SMS_RIO) + Msg.Data[1] = BW_ISDBT_13SEG; + + c->bandwidth_hz = 6000000; + sms_info("%s: freq %d segwidth %d segindex %d\n", __func__, c->frequency, c->isdbt_sb_segment_count, c->isdbt_sb_segment_idx); -- cgit v1.2.3 From 0c189fa69ed3d9c08d6f1db845c6fd174c92c429 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Mar 2013 16:34:53 -0300 Subject: [media] siano: add support for LNA on ISDB-T The very same code also exists for DVB-T. Add it for ISDB-T. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index 4900aa9e8b7a..864f53e7ca63 100644 --- a/drivers/media/common/siano/smsdvb.c +++ b/drivers/media/common/siano/smsdvb.c @@ -655,7 +655,7 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) int board_id = smscore_get_board_id(client->coredev); struct sms_board *board = sms_get_board(board_id); enum sms_device_type_st type = board->type; - + int ret; struct { struct SmsMsgHdr_ST Msg; u32 Data[4]; @@ -695,6 +695,23 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) c->frequency, c->isdbt_sb_segment_count, c->isdbt_sb_segment_idx); + /* Disable LNA, if any. An error is returned if no LNA is present */ + ret = sms_board_lna_control(client->coredev, 0); + if (ret == 0) { + fe_status_t status; + + /* tune with LNA off at first */ + ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->tune_done); + + smsdvb_read_status(fe, &status); + + if (status & FE_HAS_LOCK) + return ret; + + /* previous tune didn't lock - enable LNA and tune again */ + sms_board_lna_control(client->coredev, 1); + } return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), &client->tune_done); } -- cgit v1.2.3 From b4059095ab281b940b52a6a0e826de25eb50e3c7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Mar 2013 21:58:47 -0300 Subject: [media] siano: use the newer stats message for recent firmwares The old statistics request don't work with newer firmwares. Add a logic to use the newer stats if firmware major is 8. Note that I have only 2 devices here, one with firmware 2.1 (Hauppauge model 55009 Rev B1F7) and another one with firmware 8.1. We may need to adjust the firmware minimal version for the *_EX message variants, as we start finding firmware versions between 2.x and 8.x. This patch was based on Doron Cohen patch: http://patchwork.linuxtv.org/patch/7886/ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.h | 103 +++++++++++++++++++ drivers/media/common/siano/smsdvb.c | 177 ++++++++++++++++++++++++++++---- 2 files changed, 260 insertions(+), 20 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index 8af94c434352..7925c04e3edc 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -800,6 +800,66 @@ struct SMSHOSTLIB_STATISTICS_ISDBT_ST { u32 SmsToHostTxErrors; /* Total number of transmission errors. */ }; +struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST { + u32 StatisticsType; /* Enumerator identifying the type of the + * structure. Values are the same as + * SMSHOSTLIB_DEVICE_MODES_E + * + * This field MUST always be first in any + * statistics structure */ + + u32 FullSize; /* Total size of the structure returned by the modem. + * If the size requested by the host is smaller than + * FullSize, the struct will be truncated */ + + /* Common parameters */ + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + + /* Reception quality */ + s32 SNR; /* dB */ + s32 RSSI; /* dBm */ + s32 InBandPwr; /* In band power in dBM */ + s32 CarrierOffset; /* Carrier Offset in Hz */ + + /* Transmission parameters */ + u32 Frequency; /* Frequency in Hz */ + u32 Bandwidth; /* Bandwidth in MHz */ + u32 TransmissionMode; /* ISDB-T transmission mode */ + u32 ModemState; /* 0 - Acquisition, 1 - Locked */ + u32 GuardInterval; /* Guard Interval, 1 divided by value */ + u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */ + u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */ + u32 NumOfLayers; /* Number of ISDB-T layers in the network */ + + u32 SegmentNumber; /* Segment number for ISDB-Tsb */ + u32 TuneBW; /* Tuned bandwidth - BW_ISDBT_1SEG / BW_ISDBT_3SEG */ + + /* Per-layer information */ + /* Layers A, B and C */ + struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3]; + /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */ + + /* Interface information */ + u32 Reserved1; /* Was SmsToHostTxErrors - obsolete . */ + /* Proprietary information */ + u32 ExtAntenna; /* Obsolete field. */ + u32 ReceptionQuality; + u32 EwsAlertActive; /* Signals if EWS alert is currently on */ + u32 LNAOnOff; /* Internal LNA state: 0: OFF, 1: ON */ + + u32 RfAgcLevel; /* RF AGC Level [linear units], full gain = 65535 (20dB) */ + u32 BbAgcLevel; /* Baseband AGC level [linear units], full gain = 65535 (71.5dB) */ + u32 FwErrorsCounter; /* Application errors - should be always zero */ + u8 FwErrorsHistoryArr[8]; /* Last FW errors IDs - first is most recent, last is oldest */ + + s32 MRC_SNR; /* dB */ + u32 SNRFullRes; /* dB x 65536 */ + u32 Reserved4[4]; +}; + + struct PID_STATISTICS_DATA_S { struct PID_BURST_S { u32 size; @@ -880,6 +940,35 @@ struct RECEPTION_STATISTICS_S { s32 MRC_InBandPwr; /* In band power in dBM */ }; +struct RECEPTION_STATISTICS_EX_S { + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + + u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ + s32 SNR; /* dB */ + u32 BER; /* Post Viterbi BER [1E-5] */ + u32 BERErrorCount; /* Number of erronous SYNC bits. */ + u32 BERBitCount; /* Total number of SYNC bits. */ + u32 TS_PER; /* Transport stream PER, + 0xFFFFFFFF indicate N/A */ + u32 MFER; /* DVB-H frame error rate in percentage, + 0xFFFFFFFF indicate N/A, valid only for DVB-H */ + s32 RSSI; /* dBm */ + s32 InBandPwr; /* In band power in dBM */ + s32 CarrierOffset; /* Carrier Offset in bin/1024 */ + u32 ErrorTSPackets; /* Number of erroneous + transport-stream packets */ + u32 TotalTSPackets; /* Total number of transport-stream packets */ + + s32 RefDevPPM; + s32 FreqDevHz; + + s32 MRC_SNR; /* dB */ + s32 MRC_RSSI; /* dBm */ + s32 MRC_InBandPwr; /* In band power in dBM */ +}; + /* Statistics information returned as response for * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */ @@ -895,6 +984,20 @@ struct SMSHOSTLIB_STATISTICS_DVB_S { struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS]; }; +/* Statistics information returned as response for + * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */ +struct SMSHOSTLIB_STATISTICS_DVB_EX_S { + /* Reception */ + struct RECEPTION_STATISTICS_EX_S ReceptionData; + + /* Transmission parameters */ + struct TRANSMISSION_STATISTICS_S TransmissionData; + + /* Burst parameters, valid only for DVB-H */ +#define SRVM_MAX_PID_FILTERS 8 + struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS]; +}; + struct SRVM_SIGNAL_STATUS_S { u32 result; u32 snr; diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index 864f53e7ca63..dbb807e3a212 100644 --- a/drivers/media/common/siano/smsdvb.c +++ b/drivers/media/common/siano/smsdvb.c @@ -50,7 +50,7 @@ struct smsdvb_client_t { struct completion tune_done; struct completion stats_done; - struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb; + struct SMSHOSTLIB_STATISTICS_DVB_EX_S sms_stat_dvb; int event_fe_state; int event_unc_state; }; @@ -115,12 +115,10 @@ static void sms_board_dvb3_event(struct smsdvb_client_t *client, } } - -static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData, +static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_EX_S *pReceptionData, struct SMSHOSTLIB_STATISTICS_ST *p) { if (sms_dbg & 2) { - printk(KERN_DEBUG "Reserved = %d", p->Reserved); printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); @@ -132,6 +130,7 @@ static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionDat printk(KERN_DEBUG "RSSI = %d", p->RSSI); printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); + printk(KERN_DEBUG "ModemState = %d", p->ModemState); printk(KERN_DEBUG "Frequency = %d", p->Frequency); printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); @@ -163,17 +162,24 @@ static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionDat printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived); } + /* update reception data */ + pReceptionData->IsRfLocked = p->IsRfLocked; pReceptionData->IsDemodLocked = p->IsDemodLocked; - + pReceptionData->IsExternalLNAOn = p->IsExternalLNAOn; + pReceptionData->ModemState = p->ModemState; pReceptionData->SNR = p->SNR; pReceptionData->BER = p->BER; pReceptionData->BERErrorCount = p->BERErrorCount; + pReceptionData->BERBitCount = p->BERBitCount; + pReceptionData->RSSI = p->RSSI; + CORRECT_STAT_RSSI(*pReceptionData); pReceptionData->InBandPwr = p->InBandPwr; + pReceptionData->CarrierOffset = p->CarrierOffset; pReceptionData->ErrorTSPackets = p->ErrorTSPackets; + pReceptionData->TotalTSPackets = p->TotalTSPackets; }; - -static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData, +static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_EX_S *pReceptionData, struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) { int i; @@ -212,18 +218,100 @@ static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionD } } + /* update reception data */ + pReceptionData->IsRfLocked = p->IsRfLocked; pReceptionData->IsDemodLocked = p->IsDemodLocked; + pReceptionData->IsExternalLNAOn = p->IsExternalLNAOn; + pReceptionData->ModemState = p->ModemState; + pReceptionData->SNR = p->SNR; + pReceptionData->BER = p->LayerInfo[0].BER; + pReceptionData->BERErrorCount = p->LayerInfo[0].BERErrorCount; + pReceptionData->BERBitCount = p->LayerInfo[0].BERBitCount; + pReceptionData->RSSI = p->RSSI; + CORRECT_STAT_RSSI(*pReceptionData); + pReceptionData->InBandPwr = p->InBandPwr; + pReceptionData->CarrierOffset = p->CarrierOffset; + pReceptionData->ErrorTSPackets = p->LayerInfo[0].ErrorTSPackets; + pReceptionData->TotalTSPackets = p->LayerInfo[0].TotalTSPackets; + pReceptionData->MFER = 0; + + /* TS PER */ + if ((p->LayerInfo[0].TotalTSPackets + + p->LayerInfo[0].ErrorTSPackets) > 0) { + pReceptionData->TS_PER = (p->LayerInfo[0].ErrorTSPackets + * 100) / (p->LayerInfo[0].TotalTSPackets + + p->LayerInfo[0].ErrorTSPackets); + } else { + pReceptionData->TS_PER = 0; + } +} + +static void smsdvb_update_isdbt_stats_ex(struct RECEPTION_STATISTICS_EX_S *pReceptionData, + struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p) +{ + int i; + + if (sms_dbg & 2) { + printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); + printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); + printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); + printk(KERN_DEBUG "SNR = %d", p->SNR); + printk(KERN_DEBUG "RSSI = %d", p->RSSI); + printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); + printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); + printk(KERN_DEBUG "Frequency = %d", p->Frequency); + printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); + printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); + printk(KERN_DEBUG "ModemState = %d", p->ModemState); + printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); + printk(KERN_DEBUG "SystemType = %d", p->SystemType); + printk(KERN_DEBUG "PartialReception = %d", p->PartialReception); + printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers); + printk(KERN_DEBUG "SegmentNumber = %d", p->SegmentNumber); + printk(KERN_DEBUG "TuneBW = %d", p->TuneBW); + for (i = 0; i < 3; i++) { + printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate); + printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation); + printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER); + printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount); + printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount); + printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER); + printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER); + printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets); + printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets); + printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI); + printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments); + printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors); + } + } + + /* update reception data */ + pReceptionData->IsRfLocked = p->IsRfLocked; + pReceptionData->IsDemodLocked = p->IsDemodLocked; + pReceptionData->IsExternalLNAOn = p->IsExternalLNAOn; + pReceptionData->ModemState = p->ModemState; pReceptionData->SNR = p->SNR; + pReceptionData->BER = p->LayerInfo[0].BER; + pReceptionData->BERErrorCount = p->LayerInfo[0].BERErrorCount; + pReceptionData->BERBitCount = p->LayerInfo[0].BERBitCount; + pReceptionData->RSSI = p->RSSI; + CORRECT_STAT_RSSI(*pReceptionData); pReceptionData->InBandPwr = p->InBandPwr; - pReceptionData->ErrorTSPackets = 0; - pReceptionData->BER = 0; - pReceptionData->BERErrorCount = 0; - for (i = 0; i < 3; i++) { - pReceptionData->BER += p->LayerInfo[i].BER; - pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount; - pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets; + pReceptionData->CarrierOffset = p->CarrierOffset; + pReceptionData->ErrorTSPackets = p->LayerInfo[0].ErrorTSPackets; + pReceptionData->TotalTSPackets = p->LayerInfo[0].TotalTSPackets; + pReceptionData->MFER = 0; + + /* TS PER */ + if ((p->LayerInfo[0].TotalTSPackets + + p->LayerInfo[0].ErrorTSPackets) > 0) { + pReceptionData->TS_PER = (p->LayerInfo[0].ErrorTSPackets + * 100) / (p->LayerInfo[0].TotalTSPackets + + p->LayerInfo[0].ErrorTSPackets); + } else { + pReceptionData->TS_PER = 0; } } @@ -260,21 +348,29 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) break; case MSG_SMS_TRANSMISSION_IND: { + pMsgData++; memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData, sizeof(struct TRANSMISSION_STATISTICS_S)); +#if 1 + /* + * FIXME: newer driver doesn't have those fixes + * Are those firmware-specific stuff? + */ + /* Mo need to correct guard interval * (as opposed to old statistics message). */ CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData); CORRECT_STAT_TRANSMISSON_MODE( client->sms_stat_dvb.TransmissionData); +#endif is_status_update = true; break; } case MSG_SMS_HO_PER_SLICES_IND: { - struct RECEPTION_STATISTICS_S *pReceptionData = + struct RECEPTION_STATISTICS_EX_S *pReceptionData = &client->sms_stat_dvb.ReceptionData; struct SRVM_SIGNAL_STATUS_S SignalStatusData; @@ -329,7 +425,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt; struct SmsMsgStatisticsInfo_ST dvb; } *p = (void *) (phdr + 1); - struct RECEPTION_STATISTICS_S *pReceptionData = + struct RECEPTION_STATISTICS_EX_S *pReceptionData = &client->sms_stat_dvb.ReceptionData; is_status_update = true; @@ -352,6 +448,34 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) break; } + case MSG_SMS_GET_STATISTICS_EX_RES: { + union { + struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST isdbt; + struct SMSHOSTLIB_STATISTICS_ST dvb; + } *p = (void *) (phdr + 1); + struct RECEPTION_STATISTICS_EX_S *pReceptionData = + &client->sms_stat_dvb.ReceptionData; + + is_status_update = true; + + switch (smscore_get_device_mode(client->coredev)) { + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + smsdvb_update_isdbt_stats_ex(pReceptionData, &p->isdbt); + break; + default: + smsdvb_update_dvb_stats(pReceptionData, &p->dvb); + } + if (!pReceptionData->IsDemodLocked) { + pReceptionData->SNR = 0; + pReceptionData->BER = 0; + pReceptionData->BERErrorCount = 0; + pReceptionData->InBandPwr = 0; + pReceptionData->ErrorTSPackets = 0; + } + + break; + } default: sms_info("message not handled"); } @@ -466,10 +590,23 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) { int rc; - struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ, - DVBT_BDA_CONTROL_MSG_ID, - HIF_TASK, - sizeof(struct SmsMsgHdr_ST), 0 }; + struct SmsMsgHdr_ST Msg; + + + Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + Msg.msgDstId = HIF_TASK; + Msg.msgFlags = 0; + Msg.msgLength = sizeof(Msg); + + /* + * Check for firmware version, to avoid breaking for old cards + */ + if (client->coredev->fw_version >= 0x800) + Msg.msgType = MSG_SMS_GET_STATISTICS_EX_REQ; + else + Msg.msgType = MSG_SMS_GET_STATISTICS_REQ; + + smsendian_handle_tx_message((struct SmsMsgHdr_S *)&Msg); rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), &client->stats_done); -- cgit v1.2.3 From 347d8f1fa69f4dd021f1ca3d69e1527d95f185e0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 5 Mar 2013 22:35:44 -0300 Subject: [media] siano: add new devices to the Siano Driver This patch is based on Doron Cohen's patches: http://patchwork.linuxtv.org/patch/7881/ http://patchwork.linuxtv.org/patch/7888/ http://patchwork.linuxtv.org/patch/7883/ It basically merges the above patches, rebasing them to the macro definitions used upstream, with are different than the ones used by them internally. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/sms-cards.c | 65 ++++++++++++++++++++++++++++++++-- drivers/media/common/siano/sms-cards.h | 8 +++++ drivers/media/mmc/siano/smssdio.c | 10 ++++++ drivers/media/usb/siano/smsusb.c | 31 ++++++++++++++++ 4 files changed, 111 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 04bb04ca414f..bb6e558b8120 100644 --- a/drivers/media/common/siano/sms-cards.c +++ b/drivers/media/common/siano/sms-cards.c @@ -28,43 +28,53 @@ MODULE_PARM_DESC(cards_dbg, "set debug level (info=1, adv=2 (or-able))"); static struct sms_board sms_boards[] = { [SMS_BOARD_UNKNOWN] = { .name = "Unknown board", + .type = SMS_UNKNOWN_TYPE, + .default_mode = DEVICE_MODE_NONE, }, [SMS1XXX_BOARD_SIANO_STELLAR] = { .name = "Siano Stellar Digital Receiver", .type = SMS_STELLAR, + .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_SIANO_NOVA_A] = { .name = "Siano Nova A Digital Receiver", .type = SMS_NOVA_A0, + .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_SIANO_NOVA_B] = { .name = "Siano Nova B Digital Receiver", .type = SMS_NOVA_B0, + .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_SIANO_VEGA] = { .name = "Siano Vega Digital Receiver", .type = SMS_VEGA, + .default_mode = DEVICE_MODE_CMMB, }, [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = { .name = "Hauppauge Catamount", .type = SMS_STELLAR, .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw", + .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = { .name = "Hauppauge Okemo-A", .type = SMS_NOVA_A0, .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw", + .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = { .name = "Hauppauge Okemo-B", .type = SMS_NOVA_B0, .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw", + .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = { .name = "Hauppauge WinTV MiniStick", .type = SMS_NOVA_B0, .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw", .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .default_mode = DEVICE_MODE_DVBT_BDA, .rc_codes = RC_MAP_HAUPPAUGE, .board_cfg.leds_power = 26, .board_cfg.led0 = 27, @@ -78,6 +88,7 @@ static struct sms_board sms_boards[] = { .name = "Hauppauge WinTV MiniCard", .type = SMS_NOVA_B0, .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .default_mode = DEVICE_MODE_DVBT_BDA, .lna_ctrl = 29, .board_cfg.foreign_lna0_ctrl = 29, .rf_switch = 17, @@ -87,17 +98,64 @@ static struct sms_board sms_boards[] = { .name = "Hauppauge WinTV MiniCard", .type = SMS_NOVA_B0, .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .default_mode = DEVICE_MODE_DVBT_BDA, .lna_ctrl = -1, }, [SMS1XXX_BOARD_SIANO_NICE] = { - /* 11 */ .name = "Siano Nice Digital Receiver", .type = SMS_NOVA_B0, + .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_SIANO_VENICE] = { - /* 12 */ .name = "Siano Venice Digital Receiver", .type = SMS_VEGA, + .default_mode = DEVICE_MODE_CMMB, + }, + [SMS1XXX_BOARD_SIANO_STELLAR_ROM] = { + .name = "Siano Stellar Digital Receiver ROM", + .type = SMS_STELLAR, + .default_mode = DEVICE_MODE_DVBT_BDA, + .intf_num = 1, + }, + [SMS1XXX_BOARD_ZTE_DVB_DATA_CARD] = { + .name = "ZTE Data Card Digital Receiver", + .type = SMS_NOVA_B0, + .default_mode = DEVICE_MODE_DVBT_BDA, + .intf_num = 5, + .mtu = 15792, + }, + [SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD] = { + .name = "ONDA Data Card Digital Receiver", + .type = SMS_NOVA_B0, + .default_mode = DEVICE_MODE_DVBT_BDA, + .intf_num = 6, + .mtu = 15792, + }, + [SMS1XXX_BOARD_SIANO_MING] = { + .name = "Siano Ming Digital Receiver", + .type = SMS_MING, + .default_mode = DEVICE_MODE_CMMB, + }, + [SMS1XXX_BOARD_SIANO_PELE] = { + .name = "Siano Pele Digital Receiver", + .type = SMS_PELE, + .default_mode = DEVICE_MODE_ISDBT_BDA, + }, + [SMS1XXX_BOARD_SIANO_RIO] = { + .name = "Siano Rio Digital Receiver", + .type = SMS_RIO, + .default_mode = DEVICE_MODE_ISDBT_BDA, + }, + [SMS1XXX_BOARD_SIANO_DENVER_1530] = { + .name = "Siano Denver (ATSC-M/H) Digital Receiver", + .type = SMS_DENVER_1530, + .default_mode = DEVICE_MODE_ATSC, + .crystal = 2400, + }, + [SMS1XXX_BOARD_SIANO_DENVER_2160] = { + .name = "Siano Denver (TDMB) Digital Receiver", + .type = SMS_DENVER_2160, + .default_mode = DEVICE_MODE_DAB_TDMB, }, }; @@ -119,7 +177,8 @@ static inline void sms_gpio_assign_11xx_default_led_config( } int sms_board_event(struct smscore_device_t *coredev, - enum SMS_BOARD_EVENTS gevent) { + enum SMS_BOARD_EVENTS gevent) +{ struct smscore_config_gpio MyGpioConfig; sms_gpio_assign_11xx_default_led_config(&MyGpioConfig); diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h index 9f1861aa71c9..c63b544c49c5 100644 --- a/drivers/media/common/siano/sms-cards.h +++ b/drivers/media/common/siano/sms-cards.h @@ -37,6 +37,14 @@ #define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10 #define SMS1XXX_BOARD_SIANO_NICE 11 #define SMS1XXX_BOARD_SIANO_VENICE 12 +#define SMS1XXX_BOARD_SIANO_STELLAR_ROM 13 +#define SMS1XXX_BOARD_ZTE_DVB_DATA_CARD 14 +#define SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD 15 +#define SMS1XXX_BOARD_SIANO_MING 16 +#define SMS1XXX_BOARD_SIANO_PELE 17 +#define SMS1XXX_BOARD_SIANO_RIO 18 +#define SMS1XXX_BOARD_SIANO_DENVER_1530 19 +#define SMS1XXX_BOARD_SIANO_DENVER_2160 20 struct sms_board_gpio_cfg { int lna_vhf_exist; diff --git a/drivers/media/mmc/siano/smssdio.c b/drivers/media/mmc/siano/smssdio.c index 15d34935e00b..c96da47bece5 100644 --- a/drivers/media/mmc/siano/smssdio.c +++ b/drivers/media/mmc/siano/smssdio.c @@ -61,6 +61,16 @@ static const struct sdio_device_id smssdio_ids[] = { .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE), .driver_data = SMS1XXX_BOARD_SIANO_VEGA}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x302), + .driver_data = SMS1XXX_BOARD_SIANO_MING}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x500), + .driver_data = SMS1XXX_BOARD_SIANO_PELE}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x600), + .driver_data = SMS1XXX_BOARD_SIANO_RIO}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x700), + .driver_data = SMS1XXX_BOARD_SIANO_DENVER_2160}, + {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, 0x800), + .driver_data = SMS1XXX_BOARD_SIANO_DENVER_1530}, { /* end: all zeroes */ }, }; diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index a31bf74a5957..751c0d6d98b8 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -441,6 +441,7 @@ static int smsusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); + char devpath[32]; int i, rc; sms_info("interface number %d", @@ -485,6 +486,16 @@ static int smsusb_probe(struct usb_interface *intf, return -ENODEV; } + if (id->driver_info == SMS1XXX_BOARD_SIANO_STELLAR_ROM) { + sms_info("stellar device was found."); + snprintf(devpath, sizeof(devpath), "usb\\%d-%s", + udev->bus->busnum, udev->devpath); + sms_info("stellar device was found."); + return smsusb1_load_firmware( + udev, smscore_registry_getmode(devpath), + id->driver_info); + } + rc = smsusb_init_device(intf, id->driver_info); sms_info("rc %d", rc); sms_board_load_modules(id->driver_info); @@ -602,6 +613,26 @@ static const struct usb_device_id smsusb_id_table[] = { .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, { USB_DEVICE(0x2040, 0xf5a0), .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM }, + { USB_DEVICE(0x187f, 0x0202), + .driver_info = SMS1XXX_BOARD_SIANO_NICE }, + { USB_DEVICE(0x187f, 0x0301), + .driver_info = SMS1XXX_BOARD_SIANO_VENICE }, + { USB_DEVICE(0x187f, 0x0302), + .driver_info = SMS1XXX_BOARD_SIANO_VENICE }, + { USB_DEVICE(0x187f, 0x0310), + .driver_info = SMS1XXX_BOARD_SIANO_MING }, + { USB_DEVICE(0x187f, 0x0500), + .driver_info = SMS1XXX_BOARD_SIANO_PELE }, + { USB_DEVICE(0x187f, 0x0600), + .driver_info = SMS1XXX_BOARD_SIANO_RIO }, + { USB_DEVICE(0x187f, 0x0700), + .driver_info = SMS1XXX_BOARD_SIANO_DENVER_2160 }, + { USB_DEVICE(0x187f, 0x0800), + .driver_info = SMS1XXX_BOARD_SIANO_DENVER_1530 }, + { USB_DEVICE(0x19D2, 0x0086), + .driver_info = SMS1XXX_BOARD_ZTE_DVB_DATA_CARD }, + { USB_DEVICE(0x19D2, 0x0078), + .driver_info = SMS1XXX_BOARD_ONDA_MDTV_DATA_CARD }, { } /* Terminating entry */ }; -- cgit v1.2.3 From dfbf021c9e6c9de2296eae7b4e89148e7f68b28e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 8 Mar 2013 20:48:42 -0300 Subject: [media] siano: Configure board's mtu and xtal Backported from Doron Cohen's patch: http://patchwork.linuxtv.org/patch/7889/ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 56 +++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 67d0319dc013..6b53367f74dc 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -824,6 +824,57 @@ static int smscore_init_ir(struct smscore_device_t *coredev) return 0; } +/** + * configures device features according to board configuration structure. + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * + * @return 0 on success, <0 on error. + */ +int smscore_configure_board(struct smscore_device_t *coredev) +{ + struct sms_board *board; + + board = sms_get_board(coredev->board_id); + if (!board) { + sms_err("no board configuration exist."); + return -EINVAL; + } + + if (board->mtu) { + struct SmsMsgData_ST MtuMsg; + sms_debug("set max transmit unit %d", board->mtu); + + MtuMsg.xMsgHeader.msgSrcId = 0; + MtuMsg.xMsgHeader.msgDstId = HIF_TASK; + MtuMsg.xMsgHeader.msgFlags = 0; + MtuMsg.xMsgHeader.msgType = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ; + MtuMsg.xMsgHeader.msgLength = sizeof(MtuMsg); + MtuMsg.msgData[0] = board->mtu; + + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&MtuMsg); + coredev->sendrequest_handler(coredev->context, &MtuMsg, + sizeof(MtuMsg)); + } + + if (board->crystal) { + struct SmsMsgData_ST CrysMsg; + sms_debug("set crystal value %d", board->crystal); + + SMS_INIT_MSG(&CrysMsg.xMsgHeader, + MSG_SMS_NEW_CRYSTAL_REQ, + sizeof(CrysMsg)); + CrysMsg.msgData[0] = board->crystal; + + smsendian_handle_tx_message((struct SmsMsgHdr_S *)&CrysMsg); + coredev->sendrequest_handler(coredev->context, &CrysMsg, + sizeof(CrysMsg)); + } + + return 0; +} + /** * sets initial device mode and notifies client hotplugs that device is ready * @@ -840,6 +891,11 @@ int smscore_start_device(struct smscore_device_t *coredev) sms_info("set device mode faile , rc %d", rc); return rc; } + rc = smscore_configure_board(coredev); + if (rc < 0) { + sms_info("configure board failed , rc %d", rc); + return rc; + } kmutex_lock(&g_smscore_deviceslock); -- cgit v1.2.3 From fe802fd92d6abd1fce2ae8d03a073807d25e9453 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Mar 2013 10:24:38 -0300 Subject: [media] siano: call MSG_SMS_INIT_DEVICE_REQ Newer firmwares seem to require an init device message. Apply such change from Doron Cohen's patch: http://patchwork.linuxtv.org/patch/7889/ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 43 ++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 6b53367f74dc..9379ea7f8152 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1278,6 +1278,42 @@ static char *smscore_get_fw_filename(struct smscore_device_t *coredev, return fw[mode]; } +/** + * send init device request and wait for response + * + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param mode requested mode of operation + * + * @return 0 on success, <0 on error. + */ +int smscore_init_device(struct smscore_device_t *coredev, int mode) +{ + void *buffer; + struct SmsMsgData_ST *msg; + int rc = 0; + + buffer = kmalloc(sizeof(struct SmsMsgData_ST) + + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); + if (!buffer) { + sms_err("Could not allocate buffer for init device message."); + return -ENOMEM; + } + + msg = (struct SmsMsgData_ST *)SMS_ALIGN_ADDRESS(buffer); + SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, + sizeof(struct SmsMsgData_ST)); + msg->msgData[0] = mode; + + smsendian_handle_tx_message((struct SmsMsgHdr_ST *)msg); + rc = smscore_sendrequest_and_wait(coredev, msg, + msg->xMsgHeader. msgLength, + &coredev->init_device_done); + + kfree(buffer); + return rc; +} + /** * calls device handler to change mode of operation * NOTE: stellar/usb may disconnect when changing mode @@ -1340,8 +1376,13 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) sms_info("mode %d is already supported by running firmware", mode); } + if (coredev->fw_version >= 0x800) { + rc = smscore_init_device(coredev, mode); + if (rc < 0) + sms_err("device init failed, rc %d.", rc); + } } else { - if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { + if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_MAX) { sms_err("invalid mode specified %d", mode); return -EINVAL; } -- cgit v1.2.3 From 80ccb51a0f970ab0935a8be70b677ecbcdf74e3e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Mar 2013 11:34:56 -0300 Subject: [media] siano: simplify message endianness logic Currently, every time a message is sent or received, the endiannes need to be fixed on big endian machines. This is currently done on every call to the send API, and on every msg reception logic. Instead of doing that, move it to the send/receive functions. That simplifies the logic and avoids the risk of forgetting to fix it somewhere. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 14 -------------- drivers/media/common/siano/smsdvb.c | 8 -------- drivers/media/mmc/siano/smssdio.c | 3 +++ drivers/media/usb/siano/smsusb.c | 9 ++++++--- 4 files changed, 9 insertions(+), 25 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 9379ea7f8152..8c576a6e3829 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -37,7 +37,6 @@ #include "smscoreapi.h" #include "sms-cards.h" #include "smsir.h" -#include "smsendian.h" static int sms_dbg; module_param_named(debug, sms_dbg, int, 0644); @@ -807,8 +806,6 @@ static int smscore_init_ir(struct smscore_device_t *coredev) msg->msgData[0] = coredev->ir.controller; msg->msgData[1] = coredev->ir.timeout; - smsendian_handle_tx_message( - (struct SmsMsgHdr_ST2 *)msg); rc = smscore_sendrequest_and_wait(coredev, msg, msg->xMsgHeader. msgLength, &coredev->ir_init_done); @@ -853,7 +850,6 @@ int smscore_configure_board(struct smscore_device_t *coredev) MtuMsg.xMsgHeader.msgLength = sizeof(MtuMsg); MtuMsg.msgData[0] = board->mtu; - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&MtuMsg); coredev->sendrequest_handler(coredev->context, &MtuMsg, sizeof(MtuMsg)); } @@ -867,7 +863,6 @@ int smscore_configure_board(struct smscore_device_t *coredev) sizeof(CrysMsg)); CrysMsg.msgData[0] = board->crystal; - smsendian_handle_tx_message((struct SmsMsgHdr_S *)&CrysMsg); coredev->sendrequest_handler(coredev->context, &CrysMsg, sizeof(CrysMsg)); } @@ -989,7 +984,6 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, /* Entry point */ msg->msgData[1] = firmware->Length; msg->msgData[2] = 0; /* Regular checksum*/ - smsendian_handle_tx_message(msg); rc = smscore_sendrequest_and_wait(coredev, msg, msg->xMsgHeader.msgLength, &coredev->data_validity_done); @@ -1013,14 +1007,12 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, TriggerMsg->msgData[3] = 0; /* Parameter */ TriggerMsg->msgData[4] = 4; /* Task ID */ - smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg); rc = smscore_sendrequest_and_wait(coredev, TriggerMsg, TriggerMsg->xMsgHeader.msgLength, &coredev->trigger_done); } else { SMS_INIT_MSG(&msg->xMsgHeader, MSG_SW_RELOAD_EXEC_REQ, sizeof(struct SmsMsgHdr_ST)); - smsendian_handle_tx_message((struct SmsMsgHdr_S *)msg); rc = coredev->sendrequest_handler(coredev->context, msg, msg->xMsgHeader.msgLength); } @@ -1305,7 +1297,6 @@ int smscore_init_device(struct smscore_device_t *coredev, int mode) sizeof(struct SmsMsgData_ST)); msg->msgData[0] = mode; - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)msg); rc = smscore_sendrequest_and_wait(coredev, msg, msg->xMsgHeader. msgLength, &coredev->init_device_done); @@ -1526,8 +1517,6 @@ void smscore_onresponse(struct smscore_device_t *coredev, rc = client->onresponse_handler(client->context, cb); if (rc < 0) { - smsendian_handle_rx_message((struct SmsMsgData_ST *)phdr); - switch (phdr->msgType) { case MSG_SMS_ISDBT_TUNE_RES: break; @@ -2008,7 +1997,6 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, pMsg->msgData[5] = 0; } - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, &coredev->gpio_configuration_done); @@ -2058,7 +2046,6 @@ int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, pMsg->msgData[1] = NewLevel; /* Send message to SMS */ - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, &coredev->gpio_set_level_done); @@ -2107,7 +2094,6 @@ int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, pMsg->msgData[1] = 0; /* Send message to SMS */ - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg); rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, &coredev->gpio_get_level_done); diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index dbb807e3a212..6335574e9342 100644 --- a/drivers/media/common/siano/smsdvb.c +++ b/drivers/media/common/siano/smsdvb.c @@ -29,7 +29,6 @@ along with this program. If not, see . #include "dvb_frontend.h" #include "smscoreapi.h" -#include "smsendian.h" #include "sms-cards.h" DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -324,8 +323,6 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/ bool is_status_update = false; - smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr); - switch (phdr->msgType) { case MSG_SMS_DVBT_BDA_DATA: dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1), @@ -545,7 +542,6 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed) PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); PidMsg.msgData[0] = feed->pid; - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); return smsclient_sendrequest(client->smsclient, &PidMsg, sizeof(PidMsg)); } @@ -566,7 +562,6 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed) PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); PidMsg.msgData[0] = feed->pid; - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg); return smsclient_sendrequest(client->smsclient, &PidMsg, sizeof(PidMsg)); } @@ -577,7 +572,6 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, { int rc; - smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer); rc = smsclient_sendrequest(client->smsclient, buffer, size); if (rc < 0) return rc; @@ -606,8 +600,6 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) else Msg.msgType = MSG_SMS_GET_STATISTICS_REQ; - smsendian_handle_tx_message((struct SmsMsgHdr_S *)&Msg); - rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), &client->stats_done); diff --git a/drivers/media/mmc/siano/smssdio.c b/drivers/media/mmc/siano/smssdio.c index c96da47bece5..8834c435acae 100644 --- a/drivers/media/mmc/siano/smssdio.c +++ b/drivers/media/mmc/siano/smssdio.c @@ -43,6 +43,7 @@ #include "smscoreapi.h" #include "sms-cards.h" +#include "smsendian.h" /* Registers */ @@ -97,6 +98,7 @@ static int smssdio_sendrequest(void *context, void *buffer, size_t size) sdio_claim_host(smsdev->func); + smsendian_handle_tx_message((struct SmsMsgData_ST *) buffer); while (size >= smsdev->func->cur_blksize) { ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA, buffer, smsdev->func->cur_blksize); @@ -231,6 +233,7 @@ static void smssdio_interrupt(struct sdio_func *func) cb->size = hdr->msgLength; cb->offset = 0; + smsendian_handle_rx_message((struct SmsMsgData_ST *) cb->p); smscore_onresponse(smsdev->coredev, cb); } diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 751c0d6d98b8..acd3d1e82e03 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -129,6 +129,8 @@ static void smsusb_onresponse(struct urb *urb) smscore_translate_msg(phdr->msgType), phdr->msgType, phdr->msgLength); + smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr); + smscore_onresponse(dev->coredev, surb->cb); surb->cb = NULL; } else { @@ -207,13 +209,14 @@ static int smsusb_sendrequest(void *context, void *buffer, size_t size) struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer; int dummy; + if (dev->state != SMSUSB_ACTIVE) + return -ENOENT; + sms_debug("sending %s(%d) size: %d", smscore_translate_msg(phdr->msgType), phdr->msgType, phdr->msgLength); - if (dev->state != SMSUSB_ACTIVE) - return -ENOENT; - + smsendian_handle_tx_message((struct SmsMsgData_ST *) phdr); smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer); return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), buffer, size, &dummy, 1000); -- cgit v1.2.3 From eab0fa0f04317c7bb50f87d6b410d8ad6e2c2888 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Mar 2013 12:05:58 -0300 Subject: [media] siano: split get_frontend into per-std functions Instead of handling both DVB-T and ISDB-T at the same get_frontend function, break it intow one function per-delivery system. That makes the code clearer as we start to add support for DVBv5 statistics, and for ISDB-T get frontend stuff. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb.c | 229 +++++++++++++++++++----------------- 1 file changed, 124 insertions(+), 105 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index 6335574e9342..1d6b8dfa0808 100644 --- a/drivers/media/common/siano/smsdvb.c +++ b/drivers/media/common/siano/smsdvb.c @@ -863,131 +863,150 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe) } } -static int smsdvb_get_frontend(struct dvb_frontend *fe) +static int smsdvb_get_frontend_dvb(struct dvb_frontend *fe) { struct dtv_frontend_properties *fep = &fe->dtv_property_cache; struct smsdvb_client_t *client = container_of(fe, struct smsdvb_client_t, frontend); - struct smscore_device_t *coredev = client->coredev; struct TRANSMISSION_STATISTICS_S *td = &client->sms_stat_dvb.TransmissionData; - switch (smscore_get_device_mode(coredev)) { - case DEVICE_MODE_DVBT: - case DEVICE_MODE_DVBT_BDA: - fep->frequency = td->Frequency; - - switch (td->Bandwidth) { - case 6: - fep->bandwidth_hz = 6000000; - break; - case 7: - fep->bandwidth_hz = 7000000; - break; - case 8: - fep->bandwidth_hz = 8000000; - break; - } + fep->frequency = td->Frequency; - switch (td->TransmissionMode) { - case 2: - fep->transmission_mode = TRANSMISSION_MODE_2K; - break; - case 8: - fep->transmission_mode = TRANSMISSION_MODE_8K; - } + switch (td->Bandwidth) { + case 6: + fep->bandwidth_hz = 6000000; + break; + case 7: + fep->bandwidth_hz = 7000000; + break; + case 8: + fep->bandwidth_hz = 8000000; + break; + } - switch (td->GuardInterval) { - case 0: - fep->guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - fep->guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - fep->guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - fep->guard_interval = GUARD_INTERVAL_1_4; - break; - } + switch (td->TransmissionMode) { + case 2: + fep->transmission_mode = TRANSMISSION_MODE_2K; + break; + case 8: + fep->transmission_mode = TRANSMISSION_MODE_8K; + } - switch (td->CodeRate) { - case 0: - fep->code_rate_HP = FEC_1_2; - break; - case 1: - fep->code_rate_HP = FEC_2_3; - break; - case 2: - fep->code_rate_HP = FEC_3_4; - break; - case 3: - fep->code_rate_HP = FEC_5_6; - break; - case 4: - fep->code_rate_HP = FEC_7_8; - break; - } + switch (td->GuardInterval) { + case 0: + fep->guard_interval = GUARD_INTERVAL_1_32; + break; + case 1: + fep->guard_interval = GUARD_INTERVAL_1_16; + break; + case 2: + fep->guard_interval = GUARD_INTERVAL_1_8; + break; + case 3: + fep->guard_interval = GUARD_INTERVAL_1_4; + break; + } - switch (td->LPCodeRate) { - case 0: - fep->code_rate_LP = FEC_1_2; - break; - case 1: - fep->code_rate_LP = FEC_2_3; - break; - case 2: - fep->code_rate_LP = FEC_3_4; - break; - case 3: - fep->code_rate_LP = FEC_5_6; - break; - case 4: - fep->code_rate_LP = FEC_7_8; - break; - } + switch (td->CodeRate) { + case 0: + fep->code_rate_HP = FEC_1_2; + break; + case 1: + fep->code_rate_HP = FEC_2_3; + break; + case 2: + fep->code_rate_HP = FEC_3_4; + break; + case 3: + fep->code_rate_HP = FEC_5_6; + break; + case 4: + fep->code_rate_HP = FEC_7_8; + break; + } - switch (td->Constellation) { - case 0: - fep->modulation = QPSK; - break; - case 1: - fep->modulation = QAM_16; - break; - case 2: - fep->modulation = QAM_64; - break; - } + switch (td->LPCodeRate) { + case 0: + fep->code_rate_LP = FEC_1_2; + break; + case 1: + fep->code_rate_LP = FEC_2_3; + break; + case 2: + fep->code_rate_LP = FEC_3_4; + break; + case 3: + fep->code_rate_LP = FEC_5_6; + break; + case 4: + fep->code_rate_LP = FEC_7_8; + break; + } - switch (td->Hierarchy) { - case 0: - fep->hierarchy = HIERARCHY_NONE; - break; - case 1: - fep->hierarchy = HIERARCHY_1; - break; - case 2: - fep->hierarchy = HIERARCHY_2; - break; - case 3: - fep->hierarchy = HIERARCHY_4; - break; - } + switch (td->Constellation) { + case 0: + fep->modulation = QPSK; + break; + case 1: + fep->modulation = QAM_16; + break; + case 2: + fep->modulation = QAM_64; + break; + } - fep->inversion = INVERSION_AUTO; + switch (td->Hierarchy) { + case 0: + fep->hierarchy = HIERARCHY_NONE; break; + case 1: + fep->hierarchy = HIERARCHY_1; + break; + case 2: + fep->hierarchy = HIERARCHY_2; + break; + case 3: + fep->hierarchy = HIERARCHY_4; + break; + } + + fep->inversion = INVERSION_AUTO; + + return 0; +} + +static int smsdvb_get_frontend_isdb(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *fep = &fe->dtv_property_cache; + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + struct TRANSMISSION_STATISTICS_S *td = + &client->sms_stat_dvb.TransmissionData; + + fep->frequency = td->Frequency; + fep->bandwidth_hz = 6000000; + /* todo: retrive the other parameters */ + + return 0; +} + +static int smsdvb_get_frontend(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + struct smscore_device_t *coredev = client->coredev; + + switch (smscore_get_device_mode(coredev)) { + case DEVICE_MODE_DVBT: + case DEVICE_MODE_DVBT_BDA: + return smsdvb_get_frontend_dvb(fe); case DEVICE_MODE_ISDBT: case DEVICE_MODE_ISDBT_BDA: - fep->frequency = td->Frequency; - fep->bandwidth_hz = 6000000; - /* todo: retrive the other parameters */ - break; + return smsdvb_get_frontend_isdb(fe); default: return -EINVAL; } - - return 0; } static int smsdvb_init(struct dvb_frontend *fe) -- cgit v1.2.3 From ff702eb8d9c8ca293e7f0343dd38b718d58815b0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Mar 2013 15:54:46 -0300 Subject: [media] siano: split debug logic from the status update routine It is confusing to merge both status updates with debug stuff. Also, it is a better idea to move those status updates to debugfs, instead of doing a large amount of printk's like that. So, break them into a separate block of routines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb.c | 250 +++++++++++++++++++----------------- 1 file changed, 135 insertions(+), 115 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index 1d6b8dfa0808..04544f591df5 100644 --- a/drivers/media/common/siano/smsdvb.c +++ b/drivers/media/common/siano/smsdvb.c @@ -61,6 +61,136 @@ static int sms_dbg; module_param_named(debug, sms_dbg, int, 0644); MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); +static void smsdvb_print_dvb_stats(struct SMSHOSTLIB_STATISTICS_ST *p) +{ + if (!(sms_dbg & 2)) + return; + + printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); + printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); + printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); + printk(KERN_DEBUG "SNR = %d", p->SNR); + printk(KERN_DEBUG "BER = %d", p->BER); + printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC); + printk(KERN_DEBUG "TS_PER = %d", p->TS_PER); + printk(KERN_DEBUG "MFER = %d", p->MFER); + printk(KERN_DEBUG "RSSI = %d", p->RSSI); + printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); + printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); + printk(KERN_DEBUG "ModemState = %d", p->ModemState); + printk(KERN_DEBUG "Frequency = %d", p->Frequency); + printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); + printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); + printk(KERN_DEBUG "ModemState = %d", p->ModemState); + printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); + printk(KERN_DEBUG "CodeRate = %d", p->CodeRate); + printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate); + printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy); + printk(KERN_DEBUG "Constellation = %d", p->Constellation); + printk(KERN_DEBUG "BurstSize = %d", p->BurstSize); + printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration); + printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime); + printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime); + printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows); + printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols); + printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols); + printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets); + printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets); + printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs); + printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs); + printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs); + printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount); + printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount); + printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); + printk(KERN_DEBUG "PreBER = %d", p->PreBER); + printk(KERN_DEBUG "CellId = %d", p->CellId); + printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP); + printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP); + printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived); +} + +static void smsdvb_print_isdb_stats(struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) +{ + int i; + + if (!(sms_dbg & 2)) + return; + + printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); + printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); + printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); + printk(KERN_DEBUG "SNR = %d", p->SNR); + printk(KERN_DEBUG "RSSI = %d", p->RSSI); + printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); + printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); + printk(KERN_DEBUG "Frequency = %d", p->Frequency); + printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); + printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); + printk(KERN_DEBUG "ModemState = %d", p->ModemState); + printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); + printk(KERN_DEBUG "SystemType = %d", p->SystemType); + printk(KERN_DEBUG "PartialReception = %d", p->PartialReception); + printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers); + printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); + + for (i = 0; i < 3; i++) { + printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate); + printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation); + printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER); + printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount); + printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount); + printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER); + printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER); + printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets); + printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets); + printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI); + printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments); + printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors); + } +} + +static void +smsdvb_print_isdb_stats_ex(struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p) +{ + int i; + + if (!(sms_dbg & 2)) + return; + + printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); + printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); + printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); + printk(KERN_DEBUG "SNR = %d", p->SNR); + printk(KERN_DEBUG "RSSI = %d", p->RSSI); + printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); + printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); + printk(KERN_DEBUG "Frequency = %d", p->Frequency); + printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); + printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); + printk(KERN_DEBUG "ModemState = %d", p->ModemState); + printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); + printk(KERN_DEBUG "SystemType = %d", p->SystemType); + printk(KERN_DEBUG "PartialReception = %d", p->PartialReception); + printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers); + printk(KERN_DEBUG "SegmentNumber = %d", p->SegmentNumber); + printk(KERN_DEBUG "TuneBW = %d", p->TuneBW); + + for (i = 0; i < 3; i++) { + printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate); + printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation); + printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER); + printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount); + printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount); + printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER); + printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER); + printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets); + printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets); + printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI); + printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments); + printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors); + } +} + /* Events that may come from DVB v3 adapter */ static void sms_board_dvb3_event(struct smsdvb_client_t *client, enum SMS_DVB3_EVENTS event) { @@ -115,51 +245,9 @@ static void sms_board_dvb3_event(struct smsdvb_client_t *client, } static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_EX_S *pReceptionData, - struct SMSHOSTLIB_STATISTICS_ST *p) + struct SMSHOSTLIB_STATISTICS_ST *p) { - if (sms_dbg & 2) { - printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); - printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); - printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); - printk(KERN_DEBUG "SNR = %d", p->SNR); - printk(KERN_DEBUG "BER = %d", p->BER); - printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC); - printk(KERN_DEBUG "TS_PER = %d", p->TS_PER); - printk(KERN_DEBUG "MFER = %d", p->MFER); - printk(KERN_DEBUG "RSSI = %d", p->RSSI); - printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); - printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); - printk(KERN_DEBUG "ModemState = %d", p->ModemState); - printk(KERN_DEBUG "Frequency = %d", p->Frequency); - printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); - printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); - printk(KERN_DEBUG "ModemState = %d", p->ModemState); - printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); - printk(KERN_DEBUG "CodeRate = %d", p->CodeRate); - printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate); - printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy); - printk(KERN_DEBUG "Constellation = %d", p->Constellation); - printk(KERN_DEBUG "BurstSize = %d", p->BurstSize); - printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration); - printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime); - printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime); - printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows); - printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols); - printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols); - printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets); - printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets); - printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs); - printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs); - printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs); - printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount); - printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount); - printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); - printk(KERN_DEBUG "PreBER = %d", p->PreBER); - printk(KERN_DEBUG "CellId = %d", p->CellId); - printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP); - printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP); - printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived); - } + smsdvb_print_dvb_stats(p); /* update reception data */ pReceptionData->IsRfLocked = p->IsRfLocked; @@ -179,43 +267,9 @@ static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_EX_S *pReception }; static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_EX_S *pReceptionData, - struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) + struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) { - int i; - - if (sms_dbg & 2) { - printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); - printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); - printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); - printk(KERN_DEBUG "SNR = %d", p->SNR); - printk(KERN_DEBUG "RSSI = %d", p->RSSI); - printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); - printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); - printk(KERN_DEBUG "Frequency = %d", p->Frequency); - printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); - printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); - printk(KERN_DEBUG "ModemState = %d", p->ModemState); - printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); - printk(KERN_DEBUG "SystemType = %d", p->SystemType); - printk(KERN_DEBUG "PartialReception = %d", p->PartialReception); - printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers); - printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); - - for (i = 0; i < 3; i++) { - printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate); - printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation); - printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER); - printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount); - printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount); - printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER); - printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER); - printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets); - printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets); - printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI); - printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments); - printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors); - } - } + smsdvb_print_isdb_stats(p); /* update reception data */ pReceptionData->IsRfLocked = p->IsRfLocked; @@ -249,41 +303,7 @@ static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_EX_S *pRecepti static void smsdvb_update_isdbt_stats_ex(struct RECEPTION_STATISTICS_EX_S *pReceptionData, struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p) { - int i; - - if (sms_dbg & 2) { - printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); - printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); - printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); - printk(KERN_DEBUG "SNR = %d", p->SNR); - printk(KERN_DEBUG "RSSI = %d", p->RSSI); - printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); - printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); - printk(KERN_DEBUG "Frequency = %d", p->Frequency); - printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); - printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); - printk(KERN_DEBUG "ModemState = %d", p->ModemState); - printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); - printk(KERN_DEBUG "SystemType = %d", p->SystemType); - printk(KERN_DEBUG "PartialReception = %d", p->PartialReception); - printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers); - printk(KERN_DEBUG "SegmentNumber = %d", p->SegmentNumber); - printk(KERN_DEBUG "TuneBW = %d", p->TuneBW); - for (i = 0; i < 3; i++) { - printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate); - printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation); - printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER); - printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount); - printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount); - printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER); - printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER); - printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets); - printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets); - printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI); - printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments); - printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors); - } - } + smsdvb_print_isdb_stats_ex(p); /* update reception data */ pReceptionData->IsRfLocked = p->IsRfLocked; -- cgit v1.2.3 From d42f1cb25334bbcddf213a00bb67083414027933 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Mar 2013 19:26:28 -0300 Subject: [media] siano: Convert it to report DVBv5 stats While this frontend provides a nice set of statistics, the way it is currently reported to userspace is poor. Worse than that, instead of using quality indicators that range from 0 to 65535, as expected by userspace, most indicators range from 0 to 100. Improve it by using DVBv5 statistics API. The legacy indicators are still reported using the very same old way, but they're now using a proper range (0 to 65535 for quality indicadors; 0.1 dB for SNR). Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb.c | 826 ++++++++++++++++++++---------------- 1 file changed, 468 insertions(+), 358 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index 04544f591df5..a5f52721154c 100644 --- a/drivers/media/common/siano/smsdvb.c +++ b/drivers/media/common/siano/smsdvb.c @@ -49,7 +49,10 @@ struct smsdvb_client_t { struct completion tune_done; struct completion stats_done; - struct SMSHOSTLIB_STATISTICS_DVB_EX_S sms_stat_dvb; + int last_per; + + int legacy_ber, legacy_per; + int event_fe_state; int event_unc_state; }; @@ -61,6 +64,82 @@ static int sms_dbg; module_param_named(debug, sms_dbg, int, 0644); MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); +/* + * This struct is a mix of RECEPTION_STATISTICS_EX_S and SRVM_SIGNAL_STATUS_S. + * It was obtained by comparing the way it was filled by the original code + */ +struct RECEPTION_STATISTICS_PER_SLICES_S { + u32 result; + u32 snr; + s32 inBandPower; + u32 tsPackets; + u32 etsPackets; + u32 constellation; + u32 hpCode; + u32 tpsSrvIndLP; + u32 tpsSrvIndHP; + u32 cellId; + u32 reason; + u32 requestId; + u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ + + u32 BER; /* Post Viterbi BER [1E-5] */ + s32 RSSI; /* dBm */ + s32 CarrierOffset; /* Carrier Offset in bin/1024 */ + + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + + u32 BERBitCount; /* Total number of SYNC bits. */ + u32 BERErrorCount; /* Number of erronous SYNC bits. */ + + s32 MRC_SNR; /* dB */ + s32 MRC_InBandPwr; /* In band power in dBM */ + s32 MRC_RSSI; /* dBm */ +}; + +u32 sms_to_bw_table[] = { + [BW_8_MHZ] = 8000000, + [BW_7_MHZ] = 7000000, + [BW_6_MHZ] = 6000000, + [BW_5_MHZ] = 5000000, + [BW_2_MHZ] = 2000000, + [BW_1_5_MHZ] = 1500000, + [BW_ISDBT_1SEG] = 6000000, + [BW_ISDBT_3SEG] = 6000000, + [BW_ISDBT_13SEG] = 6000000, +}; + +u32 sms_to_guard_interval_table[] = { + [0] = GUARD_INTERVAL_1_32, + [1] = GUARD_INTERVAL_1_16, + [2] = GUARD_INTERVAL_1_8, + [3] = GUARD_INTERVAL_1_4, +}; + +u32 sms_to_code_rate_table[] = { + [0] = FEC_1_2, + [1] = FEC_2_3, + [2] = FEC_3_4, + [3] = FEC_5_6, + [4] = FEC_7_8, +}; + + +u32 sms_to_hierarchy_table[] = { + [0] = HIERARCHY_NONE, + [1] = HIERARCHY_1, + [2] = HIERARCHY_2, + [3] = HIERARCHY_4, +}; + +u32 sms_to_modulation_table[] = { + [0] = QPSK, + [1] = QAM_16, + [2] = QAM_64, + [3] = DQPSK, +}; + static void smsdvb_print_dvb_stats(struct SMSHOSTLIB_STATISTICS_ST *p) { if (!(sms_dbg & 2)) @@ -244,93 +323,350 @@ static void sms_board_dvb3_event(struct smsdvb_client_t *client, } } -static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_EX_S *pReceptionData, +static void smsdvb_stats_not_ready(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + struct smscore_device_t *coredev = client->coredev; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int i, n_layers; + + switch (smscore_get_device_mode(coredev)) { + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + n_layers = 4; + default: + n_layers = 1; + } + + /* Fill the length of each status counter */ + + /* Only global stats */ + c->strength.len = 1; + c->cnr.len = 1; + + /* Per-layer stats */ + c->post_bit_error.len = n_layers; + c->post_bit_count.len = n_layers; + c->block_error.len = n_layers; + c->block_count.len = n_layers; + + /* Signal is always available */ + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + c->strength.stat[0].uvalue = 0; + + /* Put all of them at FE_SCALE_NOT_AVAILABLE */ + for (i = 0; i < n_layers; i++) { + c->cnr.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + } +} + +static inline int sms_to_mode(u32 mode) +{ + switch (mode) { + case 2: + return TRANSMISSION_MODE_2K; + case 4: + return TRANSMISSION_MODE_4K; + case 8: + return TRANSMISSION_MODE_8K; + } + return TRANSMISSION_MODE_AUTO; +} + +static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked) +{ + if (is_demod_locked) + return FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_LOCK; + + if (is_rf_locked) + return FE_HAS_SIGNAL | FE_HAS_CARRIER; + + return 0; +} + + +#define convert_from_table(value, table, defval) ({ \ + u32 __ret; \ + if (value < ARRAY_SIZE(table)) \ + __ret = table[value]; \ + else \ + __ret = defval; \ + __ret; \ +}) + +#define sms_to_bw(value) \ + convert_from_table(value, sms_to_bw_table, 0); + +#define sms_to_guard_interval(value) \ + convert_from_table(value, sms_to_guard_interval_table, \ + GUARD_INTERVAL_AUTO); + +#define sms_to_code_rate(value) \ + convert_from_table(value, sms_to_code_rate_table, \ + FEC_NONE); + +#define sms_to_hierarchy(value) \ + convert_from_table(value, sms_to_hierarchy_table, \ + FEC_NONE); + +#define sms_to_modulation(value) \ + convert_from_table(value, sms_to_modulation_table, \ + FEC_NONE); + +static void smsdvb_update_tx_params(struct smsdvb_client_t *client, + struct TRANSMISSION_STATISTICS_S *p) +{ + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + c->frequency = p->Frequency; + client->fe_status = sms_to_status(p->IsDemodLocked, 0); + c->bandwidth_hz = sms_to_bw(p->Bandwidth); + c->transmission_mode = sms_to_mode(p->TransmissionMode); + c->guard_interval = sms_to_guard_interval(p->GuardInterval); + c->code_rate_HP = sms_to_code_rate(p->CodeRate); + c->code_rate_LP = sms_to_code_rate(p->LPCodeRate); + c->hierarchy = sms_to_hierarchy(p->Hierarchy); + c->modulation = sms_to_modulation(p->Constellation); +} + +static void smsdvb_update_per_slices(struct smsdvb_client_t *client, + struct RECEPTION_STATISTICS_PER_SLICES_S *p) +{ + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked); + c->modulation = sms_to_modulation(p->constellation); + + /* TS PER */ + client->last_per = c->block_error.stat[0].uvalue; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += p->etsPackets; + c->block_count.stat[0].uvalue += p->etsPackets + p->tsPackets; + + /* BER */ + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += p->BERErrorCount; + c->post_bit_count.stat[0].uvalue += p->BERBitCount; + + /* Legacy PER/BER */ + client->legacy_per = (p->etsPackets * 65535) / + (p->tsPackets + p->etsPackets); + + /* Signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->RSSI * 1000; + + /* Carrier to Noise ratio, in DB */ + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = p->snr * 1000; +} + +static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client, struct SMSHOSTLIB_STATISTICS_ST *p) { + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + smsdvb_print_dvb_stats(p); + client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked); + + /* Update DVB modulation parameters */ + c->frequency = p->Frequency; + client->fe_status = sms_to_status(p->IsDemodLocked, 0); + c->bandwidth_hz = sms_to_bw(p->Bandwidth); + c->transmission_mode = sms_to_mode(p->TransmissionMode); + c->guard_interval = sms_to_guard_interval(p->GuardInterval); + c->code_rate_HP = sms_to_code_rate(p->CodeRate); + c->code_rate_LP = sms_to_code_rate(p->LPCodeRate); + c->hierarchy = sms_to_hierarchy(p->Hierarchy); + c->modulation = sms_to_modulation(p->Constellation); + /* update reception data */ - pReceptionData->IsRfLocked = p->IsRfLocked; - pReceptionData->IsDemodLocked = p->IsDemodLocked; - pReceptionData->IsExternalLNAOn = p->IsExternalLNAOn; - pReceptionData->ModemState = p->ModemState; - pReceptionData->SNR = p->SNR; - pReceptionData->BER = p->BER; - pReceptionData->BERErrorCount = p->BERErrorCount; - pReceptionData->BERBitCount = p->BERBitCount; - pReceptionData->RSSI = p->RSSI; - CORRECT_STAT_RSSI(*pReceptionData); - pReceptionData->InBandPwr = p->InBandPwr; - pReceptionData->CarrierOffset = p->CarrierOffset; - pReceptionData->ErrorTSPackets = p->ErrorTSPackets; - pReceptionData->TotalTSPackets = p->TotalTSPackets; + c->lna = p->IsExternalLNAOn ? 1 : 0; + + /* Carrier to Noise ratio, in DB */ + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = p->SNR * 1000; + + /* Signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->RSSI * 1000; + + /* TS PER */ + client->last_per = c->block_error.stat[0].uvalue; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += p->ErrorTSPackets; + c->block_count.stat[0].uvalue += p->TotalTSPackets; + + /* BER */ + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += p->BERErrorCount; + c->post_bit_count.stat[0].uvalue += p->BERBitCount; + + /* Legacy PER/BER */ + client->legacy_ber = p->BER; }; -static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_EX_S *pReceptionData, +static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) { + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr; + int i, n_layers; + smsdvb_print_isdb_stats(p); + /* Update ISDB-T transmission parameters */ + c->frequency = p->Frequency; + client->fe_status = sms_to_status(p->IsDemodLocked, 0); + c->bandwidth_hz = sms_to_bw(p->Bandwidth); + c->transmission_mode = sms_to_mode(p->TransmissionMode); + c->guard_interval = sms_to_guard_interval(p->GuardInterval); + c->isdbt_partial_reception = p->PartialReception ? 1 : 0; + n_layers = p->NumOfLayers; + if (n_layers < 1) + n_layers = 1; + if (n_layers > 3) + n_layers = 3; + c->isdbt_layer_enabled = 0; + /* update reception data */ - pReceptionData->IsRfLocked = p->IsRfLocked; - pReceptionData->IsDemodLocked = p->IsDemodLocked; - pReceptionData->IsExternalLNAOn = p->IsExternalLNAOn; - pReceptionData->ModemState = p->ModemState; - pReceptionData->SNR = p->SNR; - pReceptionData->BER = p->LayerInfo[0].BER; - pReceptionData->BERErrorCount = p->LayerInfo[0].BERErrorCount; - pReceptionData->BERBitCount = p->LayerInfo[0].BERBitCount; - pReceptionData->RSSI = p->RSSI; - CORRECT_STAT_RSSI(*pReceptionData); - pReceptionData->InBandPwr = p->InBandPwr; - - pReceptionData->CarrierOffset = p->CarrierOffset; - pReceptionData->ErrorTSPackets = p->LayerInfo[0].ErrorTSPackets; - pReceptionData->TotalTSPackets = p->LayerInfo[0].TotalTSPackets; - pReceptionData->MFER = 0; + c->lna = p->IsExternalLNAOn ? 1 : 0; - /* TS PER */ - if ((p->LayerInfo[0].TotalTSPackets + - p->LayerInfo[0].ErrorTSPackets) > 0) { - pReceptionData->TS_PER = (p->LayerInfo[0].ErrorTSPackets - * 100) / (p->LayerInfo[0].TotalTSPackets - + p->LayerInfo[0].ErrorTSPackets); - } else { - pReceptionData->TS_PER = 0; + /* Carrier to Noise ratio, in DB */ + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = p->SNR * 1000; + + /* Signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->RSSI * 1000; + + client->last_per = c->block_error.stat[0].uvalue; + + /* Clears global counters, as the code below will sum it again */ + c->block_error.stat[0].uvalue = 0; + c->block_count.stat[0].uvalue = 0; + c->post_bit_error.stat[0].uvalue = 0; + c->post_bit_count.stat[0].uvalue = 0; + + for (i = 0; i < n_layers; i++) { + lr = &p->LayerInfo[i]; + + /* Update per-layer transmission parameters */ + if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) { + c->isdbt_layer_enabled |= 1 << i; + c->layer[i].segment_count = lr->NumberOfSegments; + } else { + continue; + } + c->layer[i].modulation = sms_to_modulation(lr->Constellation); + + /* TS PER */ + c->block_error.stat[i].scale = FE_SCALE_COUNTER; + c->block_count.stat[i].scale = FE_SCALE_COUNTER; + c->block_error.stat[i].uvalue += lr->ErrorTSPackets; + c->block_count.stat[i].uvalue += lr->TotalTSPackets; + + /* Update global PER counter */ + c->block_error.stat[0].uvalue += lr->ErrorTSPackets; + c->block_count.stat[0].uvalue += lr->TotalTSPackets; + + /* BER */ + c->post_bit_error.stat[i].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[i].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[i].uvalue += lr->BERErrorCount; + c->post_bit_count.stat[i].uvalue += lr->BERBitCount; + + /* Update global BER counter */ + c->post_bit_error.stat[0].uvalue += lr->BERErrorCount; + c->post_bit_count.stat[0].uvalue += lr->BERBitCount; } } -static void smsdvb_update_isdbt_stats_ex(struct RECEPTION_STATISTICS_EX_S *pReceptionData, - struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p) +static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, + struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p) { + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr; + int i, n_layers; + smsdvb_print_isdb_stats_ex(p); + /* Update ISDB-T transmission parameters */ + c->frequency = p->Frequency; + client->fe_status = sms_to_status(p->IsDemodLocked, 0); + c->bandwidth_hz = sms_to_bw(p->Bandwidth); + c->transmission_mode = sms_to_mode(p->TransmissionMode); + c->guard_interval = sms_to_guard_interval(p->GuardInterval); + c->isdbt_partial_reception = p->PartialReception ? 1 : 0; + n_layers = p->NumOfLayers; + if (n_layers < 1) + n_layers = 1; + if (n_layers > 3) + n_layers = 3; + c->isdbt_layer_enabled = 0; + /* update reception data */ - pReceptionData->IsRfLocked = p->IsRfLocked; - pReceptionData->IsDemodLocked = p->IsDemodLocked; - pReceptionData->IsExternalLNAOn = p->IsExternalLNAOn; - pReceptionData->ModemState = p->ModemState; - pReceptionData->SNR = p->SNR; - pReceptionData->BER = p->LayerInfo[0].BER; - pReceptionData->BERErrorCount = p->LayerInfo[0].BERErrorCount; - pReceptionData->BERBitCount = p->LayerInfo[0].BERBitCount; - pReceptionData->RSSI = p->RSSI; - CORRECT_STAT_RSSI(*pReceptionData); - pReceptionData->InBandPwr = p->InBandPwr; - - pReceptionData->CarrierOffset = p->CarrierOffset; - pReceptionData->ErrorTSPackets = p->LayerInfo[0].ErrorTSPackets; - pReceptionData->TotalTSPackets = p->LayerInfo[0].TotalTSPackets; - pReceptionData->MFER = 0; + c->lna = p->IsExternalLNAOn ? 1 : 0; - /* TS PER */ - if ((p->LayerInfo[0].TotalTSPackets + - p->LayerInfo[0].ErrorTSPackets) > 0) { - pReceptionData->TS_PER = (p->LayerInfo[0].ErrorTSPackets - * 100) / (p->LayerInfo[0].TotalTSPackets - + p->LayerInfo[0].ErrorTSPackets); - } else { - pReceptionData->TS_PER = 0; + /* Carrier to Noise ratio, in DB */ + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = p->SNR * 1000; + + /* Signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->RSSI * 1000; + + client->last_per = c->block_error.stat[0].uvalue; + + /* Clears global counters, as the code below will sum it again */ + c->block_error.stat[0].uvalue = 0; + c->block_count.stat[0].uvalue = 0; + c->post_bit_error.stat[0].uvalue = 0; + c->post_bit_count.stat[0].uvalue = 0; + + for (i = 0; i < n_layers; i++) { + lr = &p->LayerInfo[i]; + + /* Update per-layer transmission parameters */ + if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) { + c->isdbt_layer_enabled |= 1 << i; + c->layer[i].segment_count = lr->NumberOfSegments; + } else { + continue; + } + c->layer[i].modulation = sms_to_modulation(lr->Constellation); + + /* TS PER */ + c->block_error.stat[i].scale = FE_SCALE_COUNTER; + c->block_count.stat[i].scale = FE_SCALE_COUNTER; + c->block_error.stat[i].uvalue += lr->ErrorTSPackets; + c->block_count.stat[i].uvalue += lr->TotalTSPackets; + + /* Update global PER counter */ + c->block_error.stat[0].uvalue += lr->ErrorTSPackets; + c->block_count.stat[0].uvalue += lr->TotalTSPackets; + + /* BER */ + c->post_bit_error.stat[i].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[i].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[i].uvalue += lr->BERErrorCount; + c->post_bit_count.stat[i].uvalue += lr->BERBitCount; + + /* Update global BER counter */ + c->post_bit_error.stat[0].uvalue += lr->BERErrorCount; + c->post_bit_count.stat[0].uvalue += lr->BERBitCount; } } @@ -339,13 +675,14 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) struct smsdvb_client_t *client = (struct smsdvb_client_t *) context; struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p) + cb->offset); - u32 *pMsgData = (u32 *) phdr + 1; - /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/ + void *p = phdr + 1; + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; bool is_status_update = false; switch (phdr->msgType) { case MSG_SMS_DVBT_BDA_DATA: - dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1), + dvb_dmx_swfilter(&client->demux, p, cb->size - sizeof(struct SmsMsgHdr_ST)); break; @@ -355,166 +692,64 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) break; case MSG_SMS_SIGNAL_DETECTED_IND: - client->sms_stat_dvb.TransmissionData.IsDemodLocked = true; + client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_LOCK; + is_status_update = true; break; case MSG_SMS_NO_SIGNAL_IND: - client->sms_stat_dvb.TransmissionData.IsDemodLocked = false; + client->fe_status = 0; + is_status_update = true; break; - case MSG_SMS_TRANSMISSION_IND: { - - pMsgData++; - memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData, - sizeof(struct TRANSMISSION_STATISTICS_S)); + case MSG_SMS_TRANSMISSION_IND: + smsdvb_update_tx_params(client, p); -#if 1 - /* - * FIXME: newer driver doesn't have those fixes - * Are those firmware-specific stuff? - */ - - /* Mo need to correct guard interval - * (as opposed to old statistics message). - */ - CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData); - CORRECT_STAT_TRANSMISSON_MODE( - client->sms_stat_dvb.TransmissionData); -#endif is_status_update = true; break; - } - case MSG_SMS_HO_PER_SLICES_IND: { - struct RECEPTION_STATISTICS_EX_S *pReceptionData = - &client->sms_stat_dvb.ReceptionData; - struct SRVM_SIGNAL_STATUS_S SignalStatusData; - - pMsgData++; - SignalStatusData.result = pMsgData[0]; - SignalStatusData.snr = pMsgData[1]; - SignalStatusData.inBandPower = (s32) pMsgData[2]; - SignalStatusData.tsPackets = pMsgData[3]; - SignalStatusData.etsPackets = pMsgData[4]; - SignalStatusData.constellation = pMsgData[5]; - SignalStatusData.hpCode = pMsgData[6]; - SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03; - SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03; - SignalStatusData.cellId = pMsgData[9] & 0xFFFF; - SignalStatusData.reason = pMsgData[10]; - SignalStatusData.requestId = pMsgData[11]; - pReceptionData->IsRfLocked = pMsgData[16]; - pReceptionData->IsDemodLocked = pMsgData[17]; - pReceptionData->ModemState = pMsgData[12]; - pReceptionData->SNR = pMsgData[1]; - pReceptionData->BER = pMsgData[13]; - pReceptionData->RSSI = pMsgData[14]; - CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData); - - pReceptionData->InBandPwr = (s32) pMsgData[2]; - pReceptionData->CarrierOffset = (s32) pMsgData[15]; - pReceptionData->TotalTSPackets = pMsgData[3]; - pReceptionData->ErrorTSPackets = pMsgData[4]; - /* TS PER */ - if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets) - > 0) { - pReceptionData->TS_PER = (SignalStatusData.etsPackets - * 100) / (SignalStatusData.tsPackets - + SignalStatusData.etsPackets); - } else { - pReceptionData->TS_PER = 0; - } - - pReceptionData->BERBitCount = pMsgData[18]; - pReceptionData->BERErrorCount = pMsgData[19]; - - pReceptionData->MRC_SNR = pMsgData[20]; - pReceptionData->MRC_InBandPwr = pMsgData[21]; - pReceptionData->MRC_RSSI = pMsgData[22]; + case MSG_SMS_HO_PER_SLICES_IND: + smsdvb_update_per_slices(client, p); is_status_update = true; break; - } - case MSG_SMS_GET_STATISTICS_RES: { - union { - struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt; - struct SmsMsgStatisticsInfo_ST dvb; - } *p = (void *) (phdr + 1); - struct RECEPTION_STATISTICS_EX_S *pReceptionData = - &client->sms_stat_dvb.ReceptionData; - - is_status_update = true; + case MSG_SMS_GET_STATISTICS_RES: switch (smscore_get_device_mode(client->coredev)) { case DEVICE_MODE_ISDBT: case DEVICE_MODE_ISDBT_BDA: - smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt); + smsdvb_update_isdbt_stats(client, p); break; default: - smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat); - } - if (!pReceptionData->IsDemodLocked) { - pReceptionData->SNR = 0; - pReceptionData->BER = 0; - pReceptionData->BERErrorCount = 0; - pReceptionData->InBandPwr = 0; - pReceptionData->ErrorTSPackets = 0; + smsdvb_update_dvb_stats(client, p); } + is_status_update = true; break; - } - case MSG_SMS_GET_STATISTICS_EX_RES: { - union { - struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST isdbt; - struct SMSHOSTLIB_STATISTICS_ST dvb; - } *p = (void *) (phdr + 1); - struct RECEPTION_STATISTICS_EX_S *pReceptionData = - &client->sms_stat_dvb.ReceptionData; + /* Only for ISDB-T */ + case MSG_SMS_GET_STATISTICS_EX_RES: + smsdvb_update_isdbt_stats_ex(client, p); is_status_update = true; - - switch (smscore_get_device_mode(client->coredev)) { - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - smsdvb_update_isdbt_stats_ex(pReceptionData, &p->isdbt); - break; - default: - smsdvb_update_dvb_stats(pReceptionData, &p->dvb); - } - if (!pReceptionData->IsDemodLocked) { - pReceptionData->SNR = 0; - pReceptionData->BER = 0; - pReceptionData->BERErrorCount = 0; - pReceptionData->InBandPwr = 0; - pReceptionData->ErrorTSPackets = 0; - } - break; - } default: sms_info("message not handled"); } smscore_putbuffer(client->coredev, cb); if (is_status_update) { - if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) { - client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER - | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK; + if (client->fe_status == FE_HAS_LOCK) { sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK); - if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets - == 0) + if (client->last_per == c->block_error.stat[0].uvalue) sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK); else - sms_board_dvb3_event(client, - DVB3_EVENT_UNC_ERR); - + sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR); } else { - if (client->sms_stat_dvb.ReceptionData.IsRfLocked) - client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER; - else - client->fe_status = 0; + smsdvb_stats_not_ready(fe); + sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK); } complete(&client->stats_done); @@ -612,13 +847,20 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) Msg.msgFlags = 0; Msg.msgLength = sizeof(Msg); - /* - * Check for firmware version, to avoid breaking for old cards - */ - if (client->coredev->fw_version >= 0x800) - Msg.msgType = MSG_SMS_GET_STATISTICS_EX_REQ; - else + switch (smscore_get_device_mode(client->coredev)) { + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + /* + * Check for firmware version, to avoid breaking for old cards + */ + if (client->coredev->fw_version >= 0x800) + Msg.msgType = MSG_SMS_GET_STATISTICS_EX_REQ; + else + Msg.msgType = MSG_SMS_GET_STATISTICS_REQ; + break; + default: Msg.msgType = MSG_SMS_GET_STATISTICS_REQ; + } rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), &client->stats_done); @@ -628,12 +870,12 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) static inline int led_feedback(struct smsdvb_client_t *client) { - if (client->fe_status & FE_HAS_LOCK) - return sms_board_led_feedback(client->coredev, - (client->sms_stat_dvb.ReceptionData.BER - == 0) ? SMS_LED_HI : SMS_LED_LO); - else + if (!(client->fe_status & FE_HAS_LOCK)) return sms_board_led_feedback(client->coredev, SMS_LED_OFF); + + return sms_board_led_feedback(client->coredev, + (client->legacy_ber == 0) ? + SMS_LED_HI : SMS_LED_LO); } static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat) @@ -655,11 +897,12 @@ static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber) { int rc; struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); rc = smsdvb_send_statistics_request(client); - *ber = client->sms_stat_dvb.ReceptionData.BER; + *ber = client->legacy_ber; led_feedback(client); @@ -668,21 +911,21 @@ static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber) static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int rc; - + s32 power = (s32) c->strength.stat[0].uvalue; struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); rc = smsdvb_send_statistics_request(client); - if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95) + if (power < -95) *strength = 0; - else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29) - *strength = 100; + else if (power > -29) + *strength = 65535; else - *strength = - (client->sms_stat_dvb.ReceptionData.InBandPwr - + 95) * 3 / 2; + *strength = (power + 95) * 65535 / 66; led_feedback(client); @@ -691,13 +934,16 @@ static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength) static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int rc; struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); rc = smsdvb_send_statistics_request(client); - *snr = client->sms_stat_dvb.ReceptionData.SNR; + /* Preferred scale for SNR with legacy API: 0.1 dB */ + *snr = c->cnr.stat[0].svalue / 100; led_feedback(client); @@ -707,12 +953,14 @@ static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr) static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { int rc; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); rc = smsdvb_send_statistics_request(client); - *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets; + *ucblocks = c->block_error.stat[0].uvalue; led_feedback(client); @@ -743,7 +991,7 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) int ret; - client->fe_status = FE_HAS_SIGNAL; + client->fe_status = 0; client->event_fe_state = -1; client->event_unc_state = -1; fe->dtv_property_cache.delivery_system = SYS_DVBT; @@ -871,6 +1119,8 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe) container_of(fe, struct smsdvb_client_t, frontend); struct smscore_device_t *coredev = client->coredev; + smsdvb_stats_not_ready(fe); + switch (smscore_get_device_mode(coredev)) { case DEVICE_MODE_DVBT: case DEVICE_MODE_DVBT_BDA: @@ -883,150 +1133,10 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe) } } -static int smsdvb_get_frontend_dvb(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *fep = &fe->dtv_property_cache; - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - struct TRANSMISSION_STATISTICS_S *td = - &client->sms_stat_dvb.TransmissionData; - - fep->frequency = td->Frequency; - - switch (td->Bandwidth) { - case 6: - fep->bandwidth_hz = 6000000; - break; - case 7: - fep->bandwidth_hz = 7000000; - break; - case 8: - fep->bandwidth_hz = 8000000; - break; - } - - switch (td->TransmissionMode) { - case 2: - fep->transmission_mode = TRANSMISSION_MODE_2K; - break; - case 8: - fep->transmission_mode = TRANSMISSION_MODE_8K; - } - - switch (td->GuardInterval) { - case 0: - fep->guard_interval = GUARD_INTERVAL_1_32; - break; - case 1: - fep->guard_interval = GUARD_INTERVAL_1_16; - break; - case 2: - fep->guard_interval = GUARD_INTERVAL_1_8; - break; - case 3: - fep->guard_interval = GUARD_INTERVAL_1_4; - break; - } - - switch (td->CodeRate) { - case 0: - fep->code_rate_HP = FEC_1_2; - break; - case 1: - fep->code_rate_HP = FEC_2_3; - break; - case 2: - fep->code_rate_HP = FEC_3_4; - break; - case 3: - fep->code_rate_HP = FEC_5_6; - break; - case 4: - fep->code_rate_HP = FEC_7_8; - break; - } - - switch (td->LPCodeRate) { - case 0: - fep->code_rate_LP = FEC_1_2; - break; - case 1: - fep->code_rate_LP = FEC_2_3; - break; - case 2: - fep->code_rate_LP = FEC_3_4; - break; - case 3: - fep->code_rate_LP = FEC_5_6; - break; - case 4: - fep->code_rate_LP = FEC_7_8; - break; - } - - switch (td->Constellation) { - case 0: - fep->modulation = QPSK; - break; - case 1: - fep->modulation = QAM_16; - break; - case 2: - fep->modulation = QAM_64; - break; - } - - switch (td->Hierarchy) { - case 0: - fep->hierarchy = HIERARCHY_NONE; - break; - case 1: - fep->hierarchy = HIERARCHY_1; - break; - case 2: - fep->hierarchy = HIERARCHY_2; - break; - case 3: - fep->hierarchy = HIERARCHY_4; - break; - } - - fep->inversion = INVERSION_AUTO; - - return 0; -} - -static int smsdvb_get_frontend_isdb(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *fep = &fe->dtv_property_cache; - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - struct TRANSMISSION_STATISTICS_S *td = - &client->sms_stat_dvb.TransmissionData; - - fep->frequency = td->Frequency; - fep->bandwidth_hz = 6000000; - /* todo: retrive the other parameters */ - - return 0; -} - +/* Nothing to do here, as stats are automatically updated */ static int smsdvb_get_frontend(struct dvb_frontend *fe) { - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - struct smscore_device_t *coredev = client->coredev; - - switch (smscore_get_device_mode(coredev)) { - case DEVICE_MODE_DVBT: - case DEVICE_MODE_DVBT_BDA: - return smsdvb_get_frontend_dvb(fe); - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - return smsdvb_get_frontend_isdb(fe); - default: - return -EINVAL; - } + return 0; } static int smsdvb_init(struct dvb_frontend *fe) -- cgit v1.2.3 From c02272f9b9c71c5fe6c0cb3874ec153ff2e842ef Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Mar 2013 23:01:48 -0300 Subject: [media] siano: fix start of statistics It seems that the first u32 after the header for some stats are used by something not documented. The stats struct starts after it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index a5f52721154c..70ea3e9b4ac6 100644 --- a/drivers/media/common/siano/smsdvb.c +++ b/drivers/media/common/siano/smsdvb.c @@ -724,7 +724,8 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) smsdvb_update_isdbt_stats(client, p); break; default: - smsdvb_update_dvb_stats(client, p); + /* Skip SmsMsgStatisticsInfo_ST:RequestResult field */ + smsdvb_update_dvb_stats(client, p + sizeof(u32)); } is_status_update = true; @@ -732,7 +733,8 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) /* Only for ISDB-T */ case MSG_SMS_GET_STATISTICS_EX_RES: - smsdvb_update_isdbt_stats_ex(client, p); + /* Skip SmsMsgStatisticsInfo_ST:RequestResult field? */ + smsdvb_update_isdbt_stats_ex(client, p + sizeof(u32)); is_status_update = true; break; default: -- cgit v1.2.3 From 3f6b87cff66bb8507aefd62559c516dd7c8f822a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 9 Mar 2013 22:33:06 -0300 Subject: [media] siano: allow showing the complete statistics via debugfs Outputs the result of the statistics responses via debugfs. That can help to track bugs at the stats filling. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb.c | 464 +++++++++++++++++++++++++++--------- 1 file changed, 355 insertions(+), 109 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index 70ea3e9b4ac6..aeadd8a42775 100644 --- a/drivers/media/common/siano/smsdvb.c +++ b/drivers/media/common/siano/smsdvb.c @@ -22,6 +22,7 @@ along with this program. If not, see . #include #include #include +#include #include "dmxdev.h" #include "dvbdev.h" @@ -55,6 +56,13 @@ struct smsdvb_client_t { int event_fe_state; int event_unc_state; + + /* Stats debugfs data */ + struct dentry *debugfs; + char *stats_data; + atomic_t stats_count; + bool stats_was_read; + wait_queue_head_t stats_queue; }; static struct list_head g_smsdvb_clients; @@ -140,134 +148,358 @@ u32 sms_to_modulation_table[] = { [3] = DQPSK, }; -static void smsdvb_print_dvb_stats(struct SMSHOSTLIB_STATISTICS_ST *p) +static struct dentry *smsdvb_debugfs; + +static void smsdvb_print_dvb_stats(struct smsdvb_client_t *client, + struct SMSHOSTLIB_STATISTICS_ST *p) { - if (!(sms_dbg & 2)) + int n = 0; + char *buf; + + if (!client->stats_data || atomic_read(&client->stats_count)) return; - printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); - printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); - printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); - printk(KERN_DEBUG "SNR = %d", p->SNR); - printk(KERN_DEBUG "BER = %d", p->BER); - printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC); - printk(KERN_DEBUG "TS_PER = %d", p->TS_PER); - printk(KERN_DEBUG "MFER = %d", p->MFER); - printk(KERN_DEBUG "RSSI = %d", p->RSSI); - printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); - printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); - printk(KERN_DEBUG "ModemState = %d", p->ModemState); - printk(KERN_DEBUG "Frequency = %d", p->Frequency); - printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); - printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); - printk(KERN_DEBUG "ModemState = %d", p->ModemState); - printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); - printk(KERN_DEBUG "CodeRate = %d", p->CodeRate); - printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate); - printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy); - printk(KERN_DEBUG "Constellation = %d", p->Constellation); - printk(KERN_DEBUG "BurstSize = %d", p->BurstSize); - printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration); - printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime); - printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime); - printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows); - printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols); - printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols); - printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets); - printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets); - printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs); - printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs); - printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs); - printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount); - printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount); - printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); - printk(KERN_DEBUG "PreBER = %d", p->PreBER); - printk(KERN_DEBUG "CellId = %d", p->CellId); - printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP); - printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP); - printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived); + buf = client->stats_data; + + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsRfLocked = %d\n", p->IsRfLocked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsDemodLocked = %d\n", p->IsDemodLocked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsExternalLNAOn = %d\n", p->IsExternalLNAOn); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SNR = %d\n", p->SNR); + n += snprintf(&buf[n], PAGE_SIZE - n, + "BER = %d\n", p->BER); + n += snprintf(&buf[n], PAGE_SIZE - n, + "FIB_CRC = %d\n", p->FIB_CRC); + n += snprintf(&buf[n], PAGE_SIZE - n, + "TS_PER = %d\n", p->TS_PER); + n += snprintf(&buf[n], PAGE_SIZE - n, + "MFER = %d\n", p->MFER); + n += snprintf(&buf[n], PAGE_SIZE - n, + "RSSI = %d\n", p->RSSI); + n += snprintf(&buf[n], PAGE_SIZE - n, + "InBandPwr = %d\n", p->InBandPwr); + n += snprintf(&buf[n], PAGE_SIZE - n, + "CarrierOffset = %d\n", p->CarrierOffset); + n += snprintf(&buf[n], PAGE_SIZE - n, + "ModemState = %d\n", p->ModemState); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Frequency = %d\n", p->Frequency); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Bandwidth = %d\n", p->Bandwidth); + n += snprintf(&buf[n], PAGE_SIZE - n, + "TransmissionMode = %d\n", p->TransmissionMode); + n += snprintf(&buf[n], PAGE_SIZE - n, + "ModemState = %d\n", p->ModemState); + n += snprintf(&buf[n], PAGE_SIZE - n, + "GuardInterval = %d\n", p->GuardInterval); + n += snprintf(&buf[n], PAGE_SIZE - n, + "CodeRate = %d\n", p->CodeRate); + n += snprintf(&buf[n], PAGE_SIZE - n, + "LPCodeRate = %d\n", p->LPCodeRate); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Hierarchy = %d\n", p->Hierarchy); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Constellation = %d\n", p->Constellation); + n += snprintf(&buf[n], PAGE_SIZE - n, + "BurstSize = %d\n", p->BurstSize); + n += snprintf(&buf[n], PAGE_SIZE - n, + "BurstDuration = %d\n", p->BurstDuration); + n += snprintf(&buf[n], PAGE_SIZE - n, + "BurstCycleTime = %d\n", p->BurstCycleTime); + n += snprintf(&buf[n], PAGE_SIZE - n, + "CalculatedBurstCycleTime = %d\n", + p->CalculatedBurstCycleTime); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfRows = %d\n", p->NumOfRows); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfPaddCols = %d\n", p->NumOfPaddCols); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfPunctCols = %d\n", p->NumOfPunctCols); + n += snprintf(&buf[n], PAGE_SIZE - n, + "ErrorTSPackets = %d\n", p->ErrorTSPackets); + n += snprintf(&buf[n], PAGE_SIZE - n, + "TotalTSPackets = %d\n", p->TotalTSPackets); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfValidMpeTlbs = %d\n", p->NumOfValidMpeTlbs); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfInvalidMpeTlbs = %d\n", p->NumOfInvalidMpeTlbs); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfCorrectedMpeTlbs = %d\n", p->NumOfCorrectedMpeTlbs); + n += snprintf(&buf[n], PAGE_SIZE - n, + "BERErrorCount = %d\n", p->BERErrorCount); + n += snprintf(&buf[n], PAGE_SIZE - n, + "BERBitCount = %d\n", p->BERBitCount); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SmsToHostTxErrors = %d\n", p->SmsToHostTxErrors); + n += snprintf(&buf[n], PAGE_SIZE - n, + "PreBER = %d\n", p->PreBER); + n += snprintf(&buf[n], PAGE_SIZE - n, + "CellId = %d\n", p->CellId); + n += snprintf(&buf[n], PAGE_SIZE - n, + "DvbhSrvIndHP = %d\n", p->DvbhSrvIndHP); + n += snprintf(&buf[n], PAGE_SIZE - n, + "DvbhSrvIndLP = %d\n", p->DvbhSrvIndLP); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumMPEReceived = %d\n", p->NumMPEReceived); + + atomic_set(&client->stats_count, n); + wake_up(&client->stats_queue); } -static void smsdvb_print_isdb_stats(struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) +static void smsdvb_print_isdb_stats(struct smsdvb_client_t *client, + struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) { - int i; + int i, n = 0; + char *buf; - if (!(sms_dbg & 2)) + if (!client->stats_data || atomic_read(&client->stats_count)) return; - printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); - printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); - printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); - printk(KERN_DEBUG "SNR = %d", p->SNR); - printk(KERN_DEBUG "RSSI = %d", p->RSSI); - printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); - printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); - printk(KERN_DEBUG "Frequency = %d", p->Frequency); - printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); - printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); - printk(KERN_DEBUG "ModemState = %d", p->ModemState); - printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); - printk(KERN_DEBUG "SystemType = %d", p->SystemType); - printk(KERN_DEBUG "PartialReception = %d", p->PartialReception); - printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers); - printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors); + buf = client->stats_data; + + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsRfLocked = %d\t\t", p->IsRfLocked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsDemodLocked = %d\t", p->IsDemodLocked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsExternalLNAOn = %d\n", p->IsExternalLNAOn); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SNR = %d dB\t\t", p->SNR); + n += snprintf(&buf[n], PAGE_SIZE - n, + "RSSI = %d dBm\t\t", p->RSSI); + n += snprintf(&buf[n], PAGE_SIZE - n, + "InBandPwr = %d dBm\n", p->InBandPwr); + n += snprintf(&buf[n], PAGE_SIZE - n, + "CarrierOffset = %d\t", p->CarrierOffset); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Bandwidth = %d\t\t", p->Bandwidth); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Frequency = %d Hz\n", p->Frequency); + n += snprintf(&buf[n], PAGE_SIZE - n, + "TransmissionMode = %d\t", p->TransmissionMode); + n += snprintf(&buf[n], PAGE_SIZE - n, + "ModemState = %d\t\t", p->ModemState); + n += snprintf(&buf[n], PAGE_SIZE - n, + "GuardInterval = %d\n", p->GuardInterval); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SystemType = %d\t\t", p->SystemType); + n += snprintf(&buf[n], PAGE_SIZE - n, + "PartialReception = %d\t", p->PartialReception); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfLayers = %d\n", p->NumOfLayers); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SmsToHostTxErrors = %d\n", p->SmsToHostTxErrors); for (i = 0; i < 3; i++) { - printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate); - printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation); - printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER); - printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount); - printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount); - printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER); - printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER); - printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets); - printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets); - printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI); - printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments); - printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors); + if (p->LayerInfo[i].NumberOfSegments < 1 || + p->LayerInfo[i].NumberOfSegments > 13) + continue; + + n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tCodeRate = %d\t", + p->LayerInfo[i].CodeRate); + n += snprintf(&buf[n], PAGE_SIZE - n, "Constellation = %d\n", + p->LayerInfo[i].Constellation); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tBER = %-5d\t", + p->LayerInfo[i].BER); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tBERErrorCount = %-5d\t", + p->LayerInfo[i].BERErrorCount); + n += snprintf(&buf[n], PAGE_SIZE - n, "BERBitCount = %-5d\n", + p->LayerInfo[i].BERBitCount); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tPreBER = %-5d\t", + p->LayerInfo[i].PreBER); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tTS_PER = %-5d\n", + p->LayerInfo[i].TS_PER); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tErrorTSPackets = %-5d\t", + p->LayerInfo[i].ErrorTSPackets); + n += snprintf(&buf[n], PAGE_SIZE - n, "TotalTSPackets = %-5d\t", + p->LayerInfo[i].TotalTSPackets); + n += snprintf(&buf[n], PAGE_SIZE - n, "TILdepthI = %d\n", + p->LayerInfo[i].TILdepthI); + n += snprintf(&buf[n], PAGE_SIZE - n, + "\tNumberOfSegments = %d\t", + p->LayerInfo[i].NumberOfSegments); + n += snprintf(&buf[n], PAGE_SIZE - n, "TMCCErrors = %d\n", + p->LayerInfo[i].TMCCErrors); } + + atomic_set(&client->stats_count, n); + wake_up(&client->stats_queue); } static void -smsdvb_print_isdb_stats_ex(struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p) +smsdvb_print_isdb_stats_ex(struct smsdvb_client_t *client, + struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p) { - int i; + int i, n = 0; + char *buf; - if (!(sms_dbg & 2)) + if (!client->stats_data || atomic_read(&client->stats_count)) return; - printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked); - printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked); - printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn); - printk(KERN_DEBUG "SNR = %d", p->SNR); - printk(KERN_DEBUG "RSSI = %d", p->RSSI); - printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr); - printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset); - printk(KERN_DEBUG "Frequency = %d", p->Frequency); - printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth); - printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode); - printk(KERN_DEBUG "ModemState = %d", p->ModemState); - printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval); - printk(KERN_DEBUG "SystemType = %d", p->SystemType); - printk(KERN_DEBUG "PartialReception = %d", p->PartialReception); - printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers); - printk(KERN_DEBUG "SegmentNumber = %d", p->SegmentNumber); - printk(KERN_DEBUG "TuneBW = %d", p->TuneBW); + buf = client->stats_data; + + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsRfLocked = %d\t\t", p->IsRfLocked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsDemodLocked = %d\t", p->IsDemodLocked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsExternalLNAOn = %d\n", p->IsExternalLNAOn); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SNR = %d dB\t\t", p->SNR); + n += snprintf(&buf[n], PAGE_SIZE - n, + "RSSI = %d dBm\t\t", p->RSSI); + n += snprintf(&buf[n], PAGE_SIZE - n, + "InBandPwr = %d dBm\n", p->InBandPwr); + n += snprintf(&buf[n], PAGE_SIZE - n, + "CarrierOffset = %d\t", p->CarrierOffset); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Bandwidth = %d\t\t", p->Bandwidth); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Frequency = %d Hz\n", p->Frequency); + n += snprintf(&buf[n], PAGE_SIZE - n, + "TransmissionMode = %d\t", p->TransmissionMode); + n += snprintf(&buf[n], PAGE_SIZE - n, + "ModemState = %d\t\t", p->ModemState); + n += snprintf(&buf[n], PAGE_SIZE - n, + "GuardInterval = %d\n", p->GuardInterval); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SystemType = %d\t\t", p->SystemType); + n += snprintf(&buf[n], PAGE_SIZE - n, + "PartialReception = %d\t", p->PartialReception); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfLayers = %d\n", p->NumOfLayers); + n += snprintf(&buf[n], PAGE_SIZE - n, "SegmentNumber = %d\t", + p->SegmentNumber); + n += snprintf(&buf[n], PAGE_SIZE - n, "TuneBW = %d\n", + p->TuneBW); for (i = 0; i < 3; i++) { - printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate); - printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation); - printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER); - printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount); - printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount); - printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER); - printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER); - printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets); - printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets); - printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI); - printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments); - printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors); + if (p->LayerInfo[i].NumberOfSegments < 1 || + p->LayerInfo[i].NumberOfSegments > 13) + continue; + + n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tCodeRate = %d\t", + p->LayerInfo[i].CodeRate); + n += snprintf(&buf[n], PAGE_SIZE - n, "Constellation = %d\n", + p->LayerInfo[i].Constellation); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tBER = %-5d\t", + p->LayerInfo[i].BER); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tBERErrorCount = %-5d\t", + p->LayerInfo[i].BERErrorCount); + n += snprintf(&buf[n], PAGE_SIZE - n, "BERBitCount = %-5d\n", + p->LayerInfo[i].BERBitCount); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tPreBER = %-5d\t", + p->LayerInfo[i].PreBER); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tTS_PER = %-5d\n", + p->LayerInfo[i].TS_PER); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tErrorTSPackets = %-5d\t", + p->LayerInfo[i].ErrorTSPackets); + n += snprintf(&buf[n], PAGE_SIZE - n, "TotalTSPackets = %-5d\t", + p->LayerInfo[i].TotalTSPackets); + n += snprintf(&buf[n], PAGE_SIZE - n, "TILdepthI = %d\n", + p->LayerInfo[i].TILdepthI); + n += snprintf(&buf[n], PAGE_SIZE - n, + "\tNumberOfSegments = %d\t", + p->LayerInfo[i].NumberOfSegments); + n += snprintf(&buf[n], PAGE_SIZE - n, "TMCCErrors = %d\n", + p->LayerInfo[i].TMCCErrors); + } + + atomic_set(&client->stats_count, n); + wake_up(&client->stats_queue); +} + +static int smsdvb_stats_open(struct inode *inode, struct file *file) +{ + struct smsdvb_client_t *client = inode->i_private; + + atomic_set(&client->stats_count, 0); + client->stats_was_read = false; + + init_waitqueue_head(&client->stats_queue); + + client->stats_data = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (client->stats_data == NULL) + return -ENOMEM; + + file->private_data = client; + + return 0; +} + +static ssize_t smsdvb_stats_read(struct file *file, char __user *user_buf, + size_t nbytes, loff_t *ppos) +{ + struct smsdvb_client_t *client = file->private_data; + + if (!client->stats_data || client->stats_was_read) + return 0; + + wait_event_interruptible(client->stats_queue, + atomic_read(&client->stats_count)); + + return simple_read_from_buffer(user_buf, nbytes, ppos, + client->stats_data, + atomic_read(&client->stats_count)); + + client->stats_was_read = true; +} + +static int smsdvb_stats_release(struct inode *inode, struct file *file) +{ + struct smsdvb_client_t *client = file->private_data; + + kfree(client->stats_data); + client->stats_data = NULL; + + return 0; +} + +static const struct file_operations debugfs_stats_ops = { + .open = smsdvb_stats_open, + .read = smsdvb_stats_read, + .release = smsdvb_stats_release, + .llseek = generic_file_llseek, +}; + +static int create_stats_debugfs(struct smsdvb_client_t *client) +{ + struct smscore_device_t *coredev = client->coredev; + struct dentry *d; + + if (!smsdvb_debugfs) + return -ENODEV; + + client->debugfs = debugfs_create_dir(coredev->devpath, smsdvb_debugfs); + if (IS_ERR_OR_NULL(client->debugfs)) { + sms_info("Unable to create debugfs %s directory.\n", + coredev->devpath); + return -ENODEV; } + + d = debugfs_create_file("stats", S_IRUGO | S_IWUSR, client->debugfs, + client, &debugfs_stats_ops); + if (!d) { + debugfs_remove(client->debugfs); + return -ENOMEM; + } + + return 0; +} + +static void release_stats_debugfs(struct smsdvb_client_t *client) +{ + if (!client->debugfs) + return; + + debugfs_remove_recursive(client->debugfs); + + client->debugfs = NULL; } /* Events that may come from DVB v3 adapter */ @@ -476,7 +708,7 @@ static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client, struct dvb_frontend *fe = &client->frontend; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - smsdvb_print_dvb_stats(p); + smsdvb_print_dvb_stats(client, p); client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked); @@ -526,7 +758,7 @@ static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr; int i, n_layers; - smsdvb_print_isdb_stats(p); + smsdvb_print_isdb_stats(client, p); /* Update ISDB-T transmission parameters */ c->frequency = p->Frequency; @@ -602,7 +834,7 @@ static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr; int i, n_layers; - smsdvb_print_isdb_stats_ex(p); + smsdvb_print_isdb_stats_ex(client, p); /* Update ISDB-T transmission parameters */ c->frequency = p->Frequency; @@ -766,6 +998,7 @@ static void smsdvb_unregister_client(struct smsdvb_client_t *client) list_del(&client->entry); + release_stats_debugfs(client); smscore_unregister_client(client->smsclient); dvb_unregister_frontend(&client->frontend); dvb_dmxdev_release(&client->dmxdev); @@ -1303,6 +1536,9 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, sms_info("success"); sms_board_setup(coredev); + if (create_stats_debugfs(client) < 0) + sms_info("failed to create debugfs node"); + return 0; client_error: @@ -1325,10 +1561,17 @@ adapter_error: static int __init smsdvb_module_init(void) { int rc; + struct dentry *d; INIT_LIST_HEAD(&g_smsdvb_clients); kmutex_init(&g_smsdvb_clientslock); + d = debugfs_create_dir("smsdvb", usb_debug_root); + if (IS_ERR_OR_NULL(d)) + sms_err("Couldn't create sysfs node for smsdvb"); + else + smsdvb_debugfs = d; + rc = smscore_register_hotplug(smsdvb_hotplug); sms_debug(""); @@ -1346,6 +1589,9 @@ static void __exit smsdvb_module_exit(void) smsdvb_unregister_client( (struct smsdvb_client_t *) g_smsdvb_clients.next); + if (smsdvb_debugfs) + debugfs_remove_recursive(smsdvb_debugfs); + kmutex_unlock(&g_smsdvb_clientslock); } -- cgit v1.2.3 From 503efe5cfc9fb9f67a6659c4ab39174b442876f3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 10 Mar 2013 09:04:44 -0300 Subject: [media] siano: split debugfs code into a separate file To avoid mixing two different things at the same place, move the debugfs code into a separate file. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/Kconfig | 12 + drivers/media/common/siano/Makefile | 5 + drivers/media/common/siano/smscoreapi.h | 6 + drivers/media/common/siano/smsdvb-debugfs.c | 503 +++++++++ drivers/media/common/siano/smsdvb-main.c | 1184 ++++++++++++++++++++ drivers/media/common/siano/smsdvb.c | 1603 --------------------------- drivers/media/common/siano/smsdvb.h | 124 +++ drivers/media/usb/siano/smsusb.c | 2 + 8 files changed, 1836 insertions(+), 1603 deletions(-) create mode 100644 drivers/media/common/siano/smsdvb-debugfs.c create mode 100644 drivers/media/common/siano/smsdvb-main.c delete mode 100644 drivers/media/common/siano/smsdvb.c create mode 100644 drivers/media/common/siano/smsdvb.h (limited to 'drivers/media') diff --git a/drivers/media/common/siano/Kconfig b/drivers/media/common/siano/Kconfig index 68f0f604678e..f3f5ec44e685 100644 --- a/drivers/media/common/siano/Kconfig +++ b/drivers/media/common/siano/Kconfig @@ -17,3 +17,15 @@ config SMS_SIANO_RC default y ---help--- Choose Y to select Remote Controller support for Siano driver. + +config SMS_SIANO_DEBUGFS + bool "Enable debugfs for smsdvb" + depends on SMS_SIANO_MDTV + depends on DEBUG_FS + depends on SMS_USB_DRV + ---help--- + Choose Y to enable visualizing a dump of the frontend + statistics response packets via debugfs. Currently, works + only with Siano USB devices. + + Useful only for developers. In doubt, say N. diff --git a/drivers/media/common/siano/Makefile b/drivers/media/common/siano/Makefile index 81b1e985bea5..4c0567f106b2 100644 --- a/drivers/media/common/siano/Makefile +++ b/drivers/media/common/siano/Makefile @@ -1,4 +1,5 @@ smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o +smsdvb-objs := smsdvb-main.o obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o @@ -6,6 +7,10 @@ ifeq ($(CONFIG_SMS_SIANO_RC),y) smsmdtv-objs += smsir.o endif +ifeq ($(CONFIG_SMS_SIANO_DEBUGFS),y) + smsdvb-objs += smsdvb-debugfs.o +endif + ccflags-y += -Idrivers/media/dvb-core ccflags-y += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index 7925c04e3edc..53b81cbc1bda 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -184,6 +184,12 @@ struct smscore_device_t { /* Infrared (IR) */ struct ir_t ir; + /* + * Identify if device is USB or not. + * Used by smsdvb-sysfs to know the root node for debugfs + */ + bool is_usb_device; + int led_state; }; diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c new file mode 100644 index 000000000000..4d5dd471e2e1 --- /dev/null +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -0,0 +1,503 @@ +/*********************************************************************** + * + * Copyright(c) 2013 Mauro Carvalho Chehab + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + ***********************************************************************/ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" + +#include "smscoreapi.h" + +#include "smsdvb.h" + +static struct dentry *smsdvb_debugfs_usb_root; + +struct smsdvb_debugfs { + struct kref refcount; + spinlock_t lock; + + char stats_data[PAGE_SIZE]; + unsigned stats_count; + bool stats_was_read; + + wait_queue_head_t stats_queue; +}; + +void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data, + struct SMSHOSTLIB_STATISTICS_ST *p) +{ + int n = 0; + char *buf; + + spin_lock(&debug_data->lock); + if (debug_data->stats_count) { + spin_unlock(&debug_data->lock); + return; + } + + buf = debug_data->stats_data; + + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsRfLocked = %d\n", p->IsRfLocked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsDemodLocked = %d\n", p->IsDemodLocked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsExternalLNAOn = %d\n", p->IsExternalLNAOn); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SNR = %d\n", p->SNR); + n += snprintf(&buf[n], PAGE_SIZE - n, + "BER = %d\n", p->BER); + n += snprintf(&buf[n], PAGE_SIZE - n, + "FIB_CRC = %d\n", p->FIB_CRC); + n += snprintf(&buf[n], PAGE_SIZE - n, + "TS_PER = %d\n", p->TS_PER); + n += snprintf(&buf[n], PAGE_SIZE - n, + "MFER = %d\n", p->MFER); + n += snprintf(&buf[n], PAGE_SIZE - n, + "RSSI = %d\n", p->RSSI); + n += snprintf(&buf[n], PAGE_SIZE - n, + "InBandPwr = %d\n", p->InBandPwr); + n += snprintf(&buf[n], PAGE_SIZE - n, + "CarrierOffset = %d\n", p->CarrierOffset); + n += snprintf(&buf[n], PAGE_SIZE - n, + "ModemState = %d\n", p->ModemState); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Frequency = %d\n", p->Frequency); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Bandwidth = %d\n", p->Bandwidth); + n += snprintf(&buf[n], PAGE_SIZE - n, + "TransmissionMode = %d\n", p->TransmissionMode); + n += snprintf(&buf[n], PAGE_SIZE - n, + "ModemState = %d\n", p->ModemState); + n += snprintf(&buf[n], PAGE_SIZE - n, + "GuardInterval = %d\n", p->GuardInterval); + n += snprintf(&buf[n], PAGE_SIZE - n, + "CodeRate = %d\n", p->CodeRate); + n += snprintf(&buf[n], PAGE_SIZE - n, + "LPCodeRate = %d\n", p->LPCodeRate); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Hierarchy = %d\n", p->Hierarchy); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Constellation = %d\n", p->Constellation); + n += snprintf(&buf[n], PAGE_SIZE - n, + "BurstSize = %d\n", p->BurstSize); + n += snprintf(&buf[n], PAGE_SIZE - n, + "BurstDuration = %d\n", p->BurstDuration); + n += snprintf(&buf[n], PAGE_SIZE - n, + "BurstCycleTime = %d\n", p->BurstCycleTime); + n += snprintf(&buf[n], PAGE_SIZE - n, + "CalculatedBurstCycleTime = %d\n", + p->CalculatedBurstCycleTime); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfRows = %d\n", p->NumOfRows); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfPaddCols = %d\n", p->NumOfPaddCols); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfPunctCols = %d\n", p->NumOfPunctCols); + n += snprintf(&buf[n], PAGE_SIZE - n, + "ErrorTSPackets = %d\n", p->ErrorTSPackets); + n += snprintf(&buf[n], PAGE_SIZE - n, + "TotalTSPackets = %d\n", p->TotalTSPackets); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfValidMpeTlbs = %d\n", p->NumOfValidMpeTlbs); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfInvalidMpeTlbs = %d\n", p->NumOfInvalidMpeTlbs); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfCorrectedMpeTlbs = %d\n", p->NumOfCorrectedMpeTlbs); + n += snprintf(&buf[n], PAGE_SIZE - n, + "BERErrorCount = %d\n", p->BERErrorCount); + n += snprintf(&buf[n], PAGE_SIZE - n, + "BERBitCount = %d\n", p->BERBitCount); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SmsToHostTxErrors = %d\n", p->SmsToHostTxErrors); + n += snprintf(&buf[n], PAGE_SIZE - n, + "PreBER = %d\n", p->PreBER); + n += snprintf(&buf[n], PAGE_SIZE - n, + "CellId = %d\n", p->CellId); + n += snprintf(&buf[n], PAGE_SIZE - n, + "DvbhSrvIndHP = %d\n", p->DvbhSrvIndHP); + n += snprintf(&buf[n], PAGE_SIZE - n, + "DvbhSrvIndLP = %d\n", p->DvbhSrvIndLP); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumMPEReceived = %d\n", p->NumMPEReceived); + + debug_data->stats_count = n; + spin_unlock(&debug_data->lock); + wake_up(&debug_data->stats_queue); +} + +void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data, + struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) +{ + int i, n = 0; + char *buf; + + spin_lock(&debug_data->lock); + if (debug_data->stats_count) { + spin_unlock(&debug_data->lock); + return; + } + + buf = debug_data->stats_data; + + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsRfLocked = %d\t\t", p->IsRfLocked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsDemodLocked = %d\t", p->IsDemodLocked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsExternalLNAOn = %d\n", p->IsExternalLNAOn); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SNR = %d dB\t\t", p->SNR); + n += snprintf(&buf[n], PAGE_SIZE - n, + "RSSI = %d dBm\t\t", p->RSSI); + n += snprintf(&buf[n], PAGE_SIZE - n, + "InBandPwr = %d dBm\n", p->InBandPwr); + n += snprintf(&buf[n], PAGE_SIZE - n, + "CarrierOffset = %d\t", p->CarrierOffset); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Bandwidth = %d\t\t", p->Bandwidth); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Frequency = %d Hz\n", p->Frequency); + n += snprintf(&buf[n], PAGE_SIZE - n, + "TransmissionMode = %d\t", p->TransmissionMode); + n += snprintf(&buf[n], PAGE_SIZE - n, + "ModemState = %d\t\t", p->ModemState); + n += snprintf(&buf[n], PAGE_SIZE - n, + "GuardInterval = %d\n", p->GuardInterval); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SystemType = %d\t\t", p->SystemType); + n += snprintf(&buf[n], PAGE_SIZE - n, + "PartialReception = %d\t", p->PartialReception); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfLayers = %d\n", p->NumOfLayers); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SmsToHostTxErrors = %d\n", p->SmsToHostTxErrors); + + for (i = 0; i < 3; i++) { + if (p->LayerInfo[i].NumberOfSegments < 1 || + p->LayerInfo[i].NumberOfSegments > 13) + continue; + + n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tCodeRate = %d\t", + p->LayerInfo[i].CodeRate); + n += snprintf(&buf[n], PAGE_SIZE - n, "Constellation = %d\n", + p->LayerInfo[i].Constellation); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tBER = %-5d\t", + p->LayerInfo[i].BER); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tBERErrorCount = %-5d\t", + p->LayerInfo[i].BERErrorCount); + n += snprintf(&buf[n], PAGE_SIZE - n, "BERBitCount = %-5d\n", + p->LayerInfo[i].BERBitCount); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tPreBER = %-5d\t", + p->LayerInfo[i].PreBER); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tTS_PER = %-5d\n", + p->LayerInfo[i].TS_PER); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tErrorTSPackets = %-5d\t", + p->LayerInfo[i].ErrorTSPackets); + n += snprintf(&buf[n], PAGE_SIZE - n, "TotalTSPackets = %-5d\t", + p->LayerInfo[i].TotalTSPackets); + n += snprintf(&buf[n], PAGE_SIZE - n, "TILdepthI = %d\n", + p->LayerInfo[i].TILdepthI); + n += snprintf(&buf[n], PAGE_SIZE - n, + "\tNumberOfSegments = %d\t", + p->LayerInfo[i].NumberOfSegments); + n += snprintf(&buf[n], PAGE_SIZE - n, "TMCCErrors = %d\n", + p->LayerInfo[i].TMCCErrors); + } + + debug_data->stats_count = n; + spin_unlock(&debug_data->lock); + wake_up(&debug_data->stats_queue); +} + +void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data, + struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p) +{ + int i, n = 0; + char *buf; + + spin_lock(&debug_data->lock); + if (debug_data->stats_count) { + spin_unlock(&debug_data->lock); + return; + } + + buf = debug_data->stats_data; + + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsRfLocked = %d\t\t", p->IsRfLocked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsDemodLocked = %d\t", p->IsDemodLocked); + n += snprintf(&buf[n], PAGE_SIZE - n, + "IsExternalLNAOn = %d\n", p->IsExternalLNAOn); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SNR = %d dB\t\t", p->SNR); + n += snprintf(&buf[n], PAGE_SIZE - n, + "RSSI = %d dBm\t\t", p->RSSI); + n += snprintf(&buf[n], PAGE_SIZE - n, + "InBandPwr = %d dBm\n", p->InBandPwr); + n += snprintf(&buf[n], PAGE_SIZE - n, + "CarrierOffset = %d\t", p->CarrierOffset); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Bandwidth = %d\t\t", p->Bandwidth); + n += snprintf(&buf[n], PAGE_SIZE - n, + "Frequency = %d Hz\n", p->Frequency); + n += snprintf(&buf[n], PAGE_SIZE - n, + "TransmissionMode = %d\t", p->TransmissionMode); + n += snprintf(&buf[n], PAGE_SIZE - n, + "ModemState = %d\t\t", p->ModemState); + n += snprintf(&buf[n], PAGE_SIZE - n, + "GuardInterval = %d\n", p->GuardInterval); + n += snprintf(&buf[n], PAGE_SIZE - n, + "SystemType = %d\t\t", p->SystemType); + n += snprintf(&buf[n], PAGE_SIZE - n, + "PartialReception = %d\t", p->PartialReception); + n += snprintf(&buf[n], PAGE_SIZE - n, + "NumOfLayers = %d\n", p->NumOfLayers); + n += snprintf(&buf[n], PAGE_SIZE - n, "SegmentNumber = %d\t", + p->SegmentNumber); + n += snprintf(&buf[n], PAGE_SIZE - n, "TuneBW = %d\n", + p->TuneBW); + + for (i = 0; i < 3; i++) { + if (p->LayerInfo[i].NumberOfSegments < 1 || + p->LayerInfo[i].NumberOfSegments > 13) + continue; + + n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tCodeRate = %d\t", + p->LayerInfo[i].CodeRate); + n += snprintf(&buf[n], PAGE_SIZE - n, "Constellation = %d\n", + p->LayerInfo[i].Constellation); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tBER = %-5d\t", + p->LayerInfo[i].BER); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tBERErrorCount = %-5d\t", + p->LayerInfo[i].BERErrorCount); + n += snprintf(&buf[n], PAGE_SIZE - n, "BERBitCount = %-5d\n", + p->LayerInfo[i].BERBitCount); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tPreBER = %-5d\t", + p->LayerInfo[i].PreBER); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tTS_PER = %-5d\n", + p->LayerInfo[i].TS_PER); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tErrorTSPackets = %-5d\t", + p->LayerInfo[i].ErrorTSPackets); + n += snprintf(&buf[n], PAGE_SIZE - n, "TotalTSPackets = %-5d\t", + p->LayerInfo[i].TotalTSPackets); + n += snprintf(&buf[n], PAGE_SIZE - n, "TILdepthI = %d\n", + p->LayerInfo[i].TILdepthI); + n += snprintf(&buf[n], PAGE_SIZE - n, + "\tNumberOfSegments = %d\t", + p->LayerInfo[i].NumberOfSegments); + n += snprintf(&buf[n], PAGE_SIZE - n, "TMCCErrors = %d\n", + p->LayerInfo[i].TMCCErrors); + } + + + debug_data->stats_count = n; + spin_unlock(&debug_data->lock); + + wake_up(&debug_data->stats_queue); +} + +static int smsdvb_stats_open(struct inode *inode, struct file *file) +{ + struct smsdvb_client_t *client = inode->i_private; + struct smsdvb_debugfs *debug_data = client->debug_data; + + kref_get(&debug_data->refcount); + + spin_lock(&debug_data->lock); + debug_data->stats_count = 0; + debug_data->stats_was_read = false; + spin_unlock(&debug_data->lock); + + file->private_data = debug_data; + + return 0; +} + +static int smsdvb_stats_wait_read(struct smsdvb_debugfs *debug_data) +{ + int rc = 1; + + spin_lock(&debug_data->lock); + + if (debug_data->stats_was_read) + goto exit; + + rc = debug_data->stats_count; + +exit: + spin_unlock(&debug_data->lock); + return rc; +} + +static ssize_t smsdvb_stats_read(struct file *file, char __user *user_buf, + size_t nbytes, loff_t *ppos) +{ + int rc = 0; + struct smsdvb_debugfs *debug_data = file->private_data; + + rc = wait_event_interruptible(debug_data->stats_queue, + smsdvb_stats_wait_read(debug_data)); + if (rc < 0) + return rc; + + rc = simple_read_from_buffer(user_buf, nbytes, ppos, + debug_data->stats_data, + debug_data->stats_count); + spin_lock(&debug_data->lock); + debug_data->stats_was_read = true; + spin_unlock(&debug_data->lock); + + return rc; +} + +static void smsdvb_debugfs_data_release(struct kref *ref) +{ + struct smsdvb_debugfs *debug_data; + + debug_data = container_of(ref, struct smsdvb_debugfs, refcount); + kfree(debug_data); +} + +static int smsdvb_stats_release(struct inode *inode, struct file *file) +{ + struct smsdvb_debugfs *debug_data = file->private_data; + + spin_lock(&debug_data->lock); + debug_data->stats_was_read = true; + spin_unlock(&debug_data->lock); + wake_up_interruptible_sync(&debug_data->stats_queue); + + kref_put(&debug_data->refcount, smsdvb_debugfs_data_release); + file->private_data = NULL; + + return 0; +} + +static const struct file_operations debugfs_stats_ops = { + .open = smsdvb_stats_open, + .read = smsdvb_stats_read, + .release = smsdvb_stats_release, + .llseek = generic_file_llseek, +}; + +/* + * Functions used by smsdvb, in order to create the interfaces + */ + +int smsdvb_debugfs_create(struct smsdvb_client_t *client) +{ + struct smscore_device_t *coredev = client->coredev; + struct dentry *d; + struct smsdvb_debugfs *debug_data; + + if (!smsdvb_debugfs_usb_root || !coredev->is_usb_device) + return -ENODEV; + + client->debugfs = debugfs_create_dir(coredev->devpath, + smsdvb_debugfs_usb_root); + if (IS_ERR_OR_NULL(client->debugfs)) { + pr_info("Unable to create debugfs %s directory.\n", + coredev->devpath); + return -ENODEV; + } + + d = debugfs_create_file("stats", S_IRUGO | S_IWUSR, client->debugfs, + client, &debugfs_stats_ops); + if (!d) { + debugfs_remove(client->debugfs); + return -ENOMEM; + } + + debug_data = kzalloc(sizeof(*client->debug_data), GFP_KERNEL); + if (!debug_data) + return -ENOMEM; + + client->debug_data = debug_data; + client->prt_dvb_stats = smsdvb_print_dvb_stats; + client->prt_isdb_stats = smsdvb_print_isdb_stats; + client->prt_isdb_stats_ex = smsdvb_print_isdb_stats_ex; + + init_waitqueue_head(&debug_data->stats_queue); + spin_lock_init(&debug_data->lock); + kref_init(&debug_data->refcount); + + return 0; +} + +void smsdvb_debugfs_release(struct smsdvb_client_t *client) +{ + if (!client->debugfs) + return; + +printk("%s\n", __func__); + + client->prt_dvb_stats = NULL; + client->prt_isdb_stats = NULL; + client->prt_isdb_stats_ex = NULL; + + debugfs_remove_recursive(client->debugfs); + kref_put(&client->debug_data->refcount, smsdvb_debugfs_data_release); + + client->debug_data = NULL; + client->debugfs = NULL; +} + +int smsdvb_debugfs_register(void) +{ + struct dentry *d; + + /* + * FIXME: This was written to debug Siano USB devices. So, it creates + * the debugfs node under /usb. + * A similar logic would be needed for Siano sdio devices, but, in that + * case, usb_debug_root is not a good choice. + * + * Perhaps the right fix here would be to create another sysfs root + * node for sdio-based boards, but this may need some logic at sdio + * subsystem. + */ + d = debugfs_create_dir("smsdvb", usb_debug_root); + if (IS_ERR_OR_NULL(d)) { + sms_err("Couldn't create sysfs node for smsdvb"); + return PTR_ERR(d); + } else { + smsdvb_debugfs_usb_root = d; + } + return 0; +} + +void smsdvb_debugfs_unregister(void) +{ + if (smsdvb_debugfs_usb_root) + debugfs_remove_recursive(smsdvb_debugfs_usb_root); + smsdvb_debugfs_usb_root = NULL; +} diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c new file mode 100644 index 000000000000..c14f10d5d6c0 --- /dev/null +++ b/drivers/media/common/siano/smsdvb-main.c @@ -0,0 +1,1184 @@ +/**************************************************************** + +Siano Mobile Silicon, Inc. +MDTV receiver kernel modules. +Copyright (C) 2006-2008, Uri Shkolnik + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + + This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +****************************************************************/ + +#include +#include +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" + +#include "smscoreapi.h" +#include "sms-cards.h" + +#include "smsdvb.h" + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +static struct list_head g_smsdvb_clients; +static struct mutex g_smsdvb_clientslock; + +static int sms_dbg; +module_param_named(debug, sms_dbg, int, 0644); +MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); + + +u32 sms_to_bw_table[] = { + [BW_8_MHZ] = 8000000, + [BW_7_MHZ] = 7000000, + [BW_6_MHZ] = 6000000, + [BW_5_MHZ] = 5000000, + [BW_2_MHZ] = 2000000, + [BW_1_5_MHZ] = 1500000, + [BW_ISDBT_1SEG] = 6000000, + [BW_ISDBT_3SEG] = 6000000, + [BW_ISDBT_13SEG] = 6000000, +}; + +u32 sms_to_guard_interval_table[] = { + [0] = GUARD_INTERVAL_1_32, + [1] = GUARD_INTERVAL_1_16, + [2] = GUARD_INTERVAL_1_8, + [3] = GUARD_INTERVAL_1_4, +}; + +u32 sms_to_code_rate_table[] = { + [0] = FEC_1_2, + [1] = FEC_2_3, + [2] = FEC_3_4, + [3] = FEC_5_6, + [4] = FEC_7_8, +}; + + +u32 sms_to_hierarchy_table[] = { + [0] = HIERARCHY_NONE, + [1] = HIERARCHY_1, + [2] = HIERARCHY_2, + [3] = HIERARCHY_4, +}; + +u32 sms_to_modulation_table[] = { + [0] = QPSK, + [1] = QAM_16, + [2] = QAM_64, + [3] = DQPSK, +}; + + +/* Events that may come from DVB v3 adapter */ +static void sms_board_dvb3_event(struct smsdvb_client_t *client, + enum SMS_DVB3_EVENTS event) { + + struct smscore_device_t *coredev = client->coredev; + switch (event) { + case DVB3_EVENT_INIT: + sms_debug("DVB3_EVENT_INIT"); + sms_board_event(coredev, BOARD_EVENT_BIND); + break; + case DVB3_EVENT_SLEEP: + sms_debug("DVB3_EVENT_SLEEP"); + sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND); + break; + case DVB3_EVENT_HOTPLUG: + sms_debug("DVB3_EVENT_HOTPLUG"); + sms_board_event(coredev, BOARD_EVENT_POWER_INIT); + break; + case DVB3_EVENT_FE_LOCK: + if (client->event_fe_state != DVB3_EVENT_FE_LOCK) { + client->event_fe_state = DVB3_EVENT_FE_LOCK; + sms_debug("DVB3_EVENT_FE_LOCK"); + sms_board_event(coredev, BOARD_EVENT_FE_LOCK); + } + break; + case DVB3_EVENT_FE_UNLOCK: + if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) { + client->event_fe_state = DVB3_EVENT_FE_UNLOCK; + sms_debug("DVB3_EVENT_FE_UNLOCK"); + sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK); + } + break; + case DVB3_EVENT_UNC_OK: + if (client->event_unc_state != DVB3_EVENT_UNC_OK) { + client->event_unc_state = DVB3_EVENT_UNC_OK; + sms_debug("DVB3_EVENT_UNC_OK"); + sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK); + } + break; + case DVB3_EVENT_UNC_ERR: + if (client->event_unc_state != DVB3_EVENT_UNC_ERR) { + client->event_unc_state = DVB3_EVENT_UNC_ERR; + sms_debug("DVB3_EVENT_UNC_ERR"); + sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS); + } + break; + + default: + sms_err("Unknown dvb3 api event"); + break; + } +} + +static void smsdvb_stats_not_ready(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + struct smscore_device_t *coredev = client->coredev; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int i, n_layers; + + switch (smscore_get_device_mode(coredev)) { + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + n_layers = 4; + default: + n_layers = 1; + } + + /* Fill the length of each status counter */ + + /* Only global stats */ + c->strength.len = 1; + c->cnr.len = 1; + + /* Per-layer stats */ + c->post_bit_error.len = n_layers; + c->post_bit_count.len = n_layers; + c->block_error.len = n_layers; + c->block_count.len = n_layers; + + /* Signal is always available */ + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + c->strength.stat[0].uvalue = 0; + + /* Put all of them at FE_SCALE_NOT_AVAILABLE */ + for (i = 0; i < n_layers; i++) { + c->cnr.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + } +} + +static inline int sms_to_mode(u32 mode) +{ + switch (mode) { + case 2: + return TRANSMISSION_MODE_2K; + case 4: + return TRANSMISSION_MODE_4K; + case 8: + return TRANSMISSION_MODE_8K; + } + return TRANSMISSION_MODE_AUTO; +} + +static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked) +{ + if (is_demod_locked) + return FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_LOCK; + + if (is_rf_locked) + return FE_HAS_SIGNAL | FE_HAS_CARRIER; + + return 0; +} + + +#define convert_from_table(value, table, defval) ({ \ + u32 __ret; \ + if (value < ARRAY_SIZE(table)) \ + __ret = table[value]; \ + else \ + __ret = defval; \ + __ret; \ +}) + +#define sms_to_bw(value) \ + convert_from_table(value, sms_to_bw_table, 0); + +#define sms_to_guard_interval(value) \ + convert_from_table(value, sms_to_guard_interval_table, \ + GUARD_INTERVAL_AUTO); + +#define sms_to_code_rate(value) \ + convert_from_table(value, sms_to_code_rate_table, \ + FEC_NONE); + +#define sms_to_hierarchy(value) \ + convert_from_table(value, sms_to_hierarchy_table, \ + FEC_NONE); + +#define sms_to_modulation(value) \ + convert_from_table(value, sms_to_modulation_table, \ + FEC_NONE); + +static void smsdvb_update_tx_params(struct smsdvb_client_t *client, + struct TRANSMISSION_STATISTICS_S *p) +{ + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + c->frequency = p->Frequency; + client->fe_status = sms_to_status(p->IsDemodLocked, 0); + c->bandwidth_hz = sms_to_bw(p->Bandwidth); + c->transmission_mode = sms_to_mode(p->TransmissionMode); + c->guard_interval = sms_to_guard_interval(p->GuardInterval); + c->code_rate_HP = sms_to_code_rate(p->CodeRate); + c->code_rate_LP = sms_to_code_rate(p->LPCodeRate); + c->hierarchy = sms_to_hierarchy(p->Hierarchy); + c->modulation = sms_to_modulation(p->Constellation); +} + +static void smsdvb_update_per_slices(struct smsdvb_client_t *client, + struct RECEPTION_STATISTICS_PER_SLICES_S *p) +{ + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked); + c->modulation = sms_to_modulation(p->constellation); + + /* TS PER */ + client->last_per = c->block_error.stat[0].uvalue; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += p->etsPackets; + c->block_count.stat[0].uvalue += p->etsPackets + p->tsPackets; + + /* BER */ + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += p->BERErrorCount; + c->post_bit_count.stat[0].uvalue += p->BERBitCount; + + /* Legacy PER/BER */ + client->legacy_per = (p->etsPackets * 65535) / + (p->tsPackets + p->etsPackets); + + /* Signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->RSSI * 1000; + + /* Carrier to Noise ratio, in DB */ + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = p->snr * 1000; +} + +static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client, + struct SMSHOSTLIB_STATISTICS_ST *p) +{ + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + if (client->prt_dvb_stats) + client->prt_dvb_stats(client->debug_data, p); + + client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked); + + /* Update DVB modulation parameters */ + c->frequency = p->Frequency; + client->fe_status = sms_to_status(p->IsDemodLocked, 0); + c->bandwidth_hz = sms_to_bw(p->Bandwidth); + c->transmission_mode = sms_to_mode(p->TransmissionMode); + c->guard_interval = sms_to_guard_interval(p->GuardInterval); + c->code_rate_HP = sms_to_code_rate(p->CodeRate); + c->code_rate_LP = sms_to_code_rate(p->LPCodeRate); + c->hierarchy = sms_to_hierarchy(p->Hierarchy); + c->modulation = sms_to_modulation(p->Constellation); + + /* update reception data */ + c->lna = p->IsExternalLNAOn ? 1 : 0; + + /* Carrier to Noise ratio, in DB */ + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = p->SNR * 1000; + + /* Signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->RSSI * 1000; + + /* TS PER */ + client->last_per = c->block_error.stat[0].uvalue; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += p->ErrorTSPackets; + c->block_count.stat[0].uvalue += p->TotalTSPackets; + + /* BER */ + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += p->BERErrorCount; + c->post_bit_count.stat[0].uvalue += p->BERBitCount; + + /* Legacy PER/BER */ + client->legacy_ber = p->BER; +}; + +static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, + struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) +{ + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr; + int i, n_layers; + + if (client->prt_isdb_stats) + client->prt_isdb_stats(client->debug_data, p); + + /* Update ISDB-T transmission parameters */ + c->frequency = p->Frequency; + client->fe_status = sms_to_status(p->IsDemodLocked, 0); + c->bandwidth_hz = sms_to_bw(p->Bandwidth); + c->transmission_mode = sms_to_mode(p->TransmissionMode); + c->guard_interval = sms_to_guard_interval(p->GuardInterval); + c->isdbt_partial_reception = p->PartialReception ? 1 : 0; + n_layers = p->NumOfLayers; + if (n_layers < 1) + n_layers = 1; + if (n_layers > 3) + n_layers = 3; + c->isdbt_layer_enabled = 0; + + /* update reception data */ + c->lna = p->IsExternalLNAOn ? 1 : 0; + + /* Carrier to Noise ratio, in DB */ + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = p->SNR * 1000; + + /* Signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->RSSI * 1000; + + client->last_per = c->block_error.stat[0].uvalue; + + /* Clears global counters, as the code below will sum it again */ + c->block_error.stat[0].uvalue = 0; + c->block_count.stat[0].uvalue = 0; + c->post_bit_error.stat[0].uvalue = 0; + c->post_bit_count.stat[0].uvalue = 0; + + for (i = 0; i < n_layers; i++) { + lr = &p->LayerInfo[i]; + + /* Update per-layer transmission parameters */ + if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) { + c->isdbt_layer_enabled |= 1 << i; + c->layer[i].segment_count = lr->NumberOfSegments; + } else { + continue; + } + c->layer[i].modulation = sms_to_modulation(lr->Constellation); + + /* TS PER */ + c->block_error.stat[i].scale = FE_SCALE_COUNTER; + c->block_count.stat[i].scale = FE_SCALE_COUNTER; + c->block_error.stat[i].uvalue += lr->ErrorTSPackets; + c->block_count.stat[i].uvalue += lr->TotalTSPackets; + + /* Update global PER counter */ + c->block_error.stat[0].uvalue += lr->ErrorTSPackets; + c->block_count.stat[0].uvalue += lr->TotalTSPackets; + + /* BER */ + c->post_bit_error.stat[i].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[i].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[i].uvalue += lr->BERErrorCount; + c->post_bit_count.stat[i].uvalue += lr->BERBitCount; + + /* Update global BER counter */ + c->post_bit_error.stat[0].uvalue += lr->BERErrorCount; + c->post_bit_count.stat[0].uvalue += lr->BERBitCount; + } +} + +static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, + struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p) +{ + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr; + int i, n_layers; + + if (client->prt_isdb_stats_ex) + client->prt_isdb_stats_ex(client->debug_data, p); + + /* Update ISDB-T transmission parameters */ + c->frequency = p->Frequency; + client->fe_status = sms_to_status(p->IsDemodLocked, 0); + c->bandwidth_hz = sms_to_bw(p->Bandwidth); + c->transmission_mode = sms_to_mode(p->TransmissionMode); + c->guard_interval = sms_to_guard_interval(p->GuardInterval); + c->isdbt_partial_reception = p->PartialReception ? 1 : 0; + n_layers = p->NumOfLayers; + if (n_layers < 1) + n_layers = 1; + if (n_layers > 3) + n_layers = 3; + c->isdbt_layer_enabled = 0; + + /* update reception data */ + c->lna = p->IsExternalLNAOn ? 1 : 0; + + /* Carrier to Noise ratio, in DB */ + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = p->SNR * 1000; + + /* Signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->RSSI * 1000; + + client->last_per = c->block_error.stat[0].uvalue; + + /* Clears global counters, as the code below will sum it again */ + c->block_error.stat[0].uvalue = 0; + c->block_count.stat[0].uvalue = 0; + c->post_bit_error.stat[0].uvalue = 0; + c->post_bit_count.stat[0].uvalue = 0; + + for (i = 0; i < n_layers; i++) { + lr = &p->LayerInfo[i]; + + /* Update per-layer transmission parameters */ + if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) { + c->isdbt_layer_enabled |= 1 << i; + c->layer[i].segment_count = lr->NumberOfSegments; + } else { + continue; + } + c->layer[i].modulation = sms_to_modulation(lr->Constellation); + + /* TS PER */ + c->block_error.stat[i].scale = FE_SCALE_COUNTER; + c->block_count.stat[i].scale = FE_SCALE_COUNTER; + c->block_error.stat[i].uvalue += lr->ErrorTSPackets; + c->block_count.stat[i].uvalue += lr->TotalTSPackets; + + /* Update global PER counter */ + c->block_error.stat[0].uvalue += lr->ErrorTSPackets; + c->block_count.stat[0].uvalue += lr->TotalTSPackets; + + /* BER */ + c->post_bit_error.stat[i].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[i].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[i].uvalue += lr->BERErrorCount; + c->post_bit_count.stat[i].uvalue += lr->BERBitCount; + + /* Update global BER counter */ + c->post_bit_error.stat[0].uvalue += lr->BERErrorCount; + c->post_bit_count.stat[0].uvalue += lr->BERBitCount; + } +} + +static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) +{ + struct smsdvb_client_t *client = (struct smsdvb_client_t *) context; + struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p) + + cb->offset); + void *p = phdr + 1; + struct dvb_frontend *fe = &client->frontend; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + bool is_status_update = false; + + switch (phdr->msgType) { + case MSG_SMS_DVBT_BDA_DATA: + dvb_dmx_swfilter(&client->demux, p, + cb->size - sizeof(struct SmsMsgHdr_ST)); + break; + + case MSG_SMS_RF_TUNE_RES: + case MSG_SMS_ISDBT_TUNE_RES: + complete(&client->tune_done); + break; + + case MSG_SMS_SIGNAL_DETECTED_IND: + client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_LOCK; + + is_status_update = true; + break; + + case MSG_SMS_NO_SIGNAL_IND: + client->fe_status = 0; + + is_status_update = true; + break; + + case MSG_SMS_TRANSMISSION_IND: + smsdvb_update_tx_params(client, p); + + is_status_update = true; + break; + + case MSG_SMS_HO_PER_SLICES_IND: + smsdvb_update_per_slices(client, p); + + is_status_update = true; + break; + + case MSG_SMS_GET_STATISTICS_RES: + switch (smscore_get_device_mode(client->coredev)) { + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + smsdvb_update_isdbt_stats(client, p); + break; + default: + /* Skip SmsMsgStatisticsInfo_ST:RequestResult field */ + smsdvb_update_dvb_stats(client, p + sizeof(u32)); + } + + is_status_update = true; + break; + + /* Only for ISDB-T */ + case MSG_SMS_GET_STATISTICS_EX_RES: + /* Skip SmsMsgStatisticsInfo_ST:RequestResult field? */ + smsdvb_update_isdbt_stats_ex(client, p + sizeof(u32)); + is_status_update = true; + break; + default: + sms_info("message not handled"); + } + smscore_putbuffer(client->coredev, cb); + + if (is_status_update) { + if (client->fe_status == FE_HAS_LOCK) { + sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK); + if (client->last_per == c->block_error.stat[0].uvalue) + sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK); + else + sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR); + } else { + smsdvb_stats_not_ready(fe); + + sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK); + } + complete(&client->stats_done); + } + + return 0; +} + +static void smsdvb_unregister_client(struct smsdvb_client_t *client) +{ + /* must be called under clientslock */ + + list_del(&client->entry); + + smsdvb_debugfs_release(client); + smscore_unregister_client(client->smsclient); + dvb_unregister_frontend(&client->frontend); + dvb_dmxdev_release(&client->dmxdev); + dvb_dmx_release(&client->demux); + dvb_unregister_adapter(&client->adapter); + kfree(client); +} + +static void smsdvb_onremove(void *context) +{ + kmutex_lock(&g_smsdvb_clientslock); + + smsdvb_unregister_client((struct smsdvb_client_t *) context); + + kmutex_unlock(&g_smsdvb_clientslock); +} + +static int smsdvb_start_feed(struct dvb_demux_feed *feed) +{ + struct smsdvb_client_t *client = + container_of(feed->demux, struct smsdvb_client_t, demux); + struct SmsMsgData_ST PidMsg; + + sms_debug("add pid %d(%x)", + feed->pid, feed->pid); + + PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + PidMsg.xMsgHeader.msgDstId = HIF_TASK; + PidMsg.xMsgHeader.msgFlags = 0; + PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ; + PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); + PidMsg.msgData[0] = feed->pid; + + return smsclient_sendrequest(client->smsclient, + &PidMsg, sizeof(PidMsg)); +} + +static int smsdvb_stop_feed(struct dvb_demux_feed *feed) +{ + struct smsdvb_client_t *client = + container_of(feed->demux, struct smsdvb_client_t, demux); + struct SmsMsgData_ST PidMsg; + + sms_debug("remove pid %d(%x)", + feed->pid, feed->pid); + + PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + PidMsg.xMsgHeader.msgDstId = HIF_TASK; + PidMsg.xMsgHeader.msgFlags = 0; + PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ; + PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); + PidMsg.msgData[0] = feed->pid; + + return smsclient_sendrequest(client->smsclient, + &PidMsg, sizeof(PidMsg)); +} + +static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, + void *buffer, size_t size, + struct completion *completion) +{ + int rc; + + rc = smsclient_sendrequest(client->smsclient, buffer, size); + if (rc < 0) + return rc; + + return wait_for_completion_timeout(completion, + msecs_to_jiffies(2000)) ? + 0 : -ETIME; +} + +static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) +{ + int rc; + struct SmsMsgHdr_ST Msg; + + + Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + Msg.msgDstId = HIF_TASK; + Msg.msgFlags = 0; + Msg.msgLength = sizeof(Msg); + + switch (smscore_get_device_mode(client->coredev)) { + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + /* + * Check for firmware version, to avoid breaking for old cards + */ + if (client->coredev->fw_version >= 0x800) + Msg.msgType = MSG_SMS_GET_STATISTICS_EX_REQ; + else + Msg.msgType = MSG_SMS_GET_STATISTICS_REQ; + break; + default: + Msg.msgType = MSG_SMS_GET_STATISTICS_REQ; + } + + rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->stats_done); + + return rc; +} + +static inline int led_feedback(struct smsdvb_client_t *client) +{ + if (!(client->fe_status & FE_HAS_LOCK)) + return sms_board_led_feedback(client->coredev, SMS_LED_OFF); + + return sms_board_led_feedback(client->coredev, + (client->legacy_ber == 0) ? + SMS_LED_HI : SMS_LED_LO); +} + +static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat) +{ + int rc; + struct smsdvb_client_t *client; + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + *stat = client->fe_status; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + int rc; + struct smsdvb_client_t *client; + + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + *ber = client->legacy_ber; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int rc; + s32 power = (s32) c->strength.stat[0].uvalue; + struct smsdvb_client_t *client; + + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + if (power < -95) + *strength = 0; + else if (power > -29) + *strength = 65535; + else + *strength = (power + 95) * 65535 / 66; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int rc; + struct smsdvb_client_t *client; + + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + /* Preferred scale for SNR with legacy API: 0.1 dB */ + *snr = c->cnr.stat[0].svalue / 100; + + led_feedback(client); + + return rc; +} + +static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + int rc; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct smsdvb_client_t *client; + + client = container_of(fe, struct smsdvb_client_t, frontend); + + rc = smsdvb_send_statistics_request(client); + + *ucblocks = c->block_error.stat[0].uvalue; + + led_feedback(client); + + return rc; +} + +static int smsdvb_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *tune) +{ + sms_debug(""); + + tune->min_delay_ms = 400; + tune->step_size = 250000; + tune->max_drift = 0; + return 0; +} + +static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + struct { + struct SmsMsgHdr_ST Msg; + u32 Data[3]; + } Msg; + + int ret; + + client->fe_status = 0; + client->event_fe_state = -1; + client->event_unc_state = -1; + fe->dtv_property_cache.delivery_system = SYS_DVBT; + + Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + Msg.Msg.msgDstId = HIF_TASK; + Msg.Msg.msgFlags = 0; + Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ; + Msg.Msg.msgLength = sizeof(Msg); + Msg.Data[0] = c->frequency; + Msg.Data[2] = 12000000; + + sms_info("%s: freq %d band %d", __func__, c->frequency, + c->bandwidth_hz); + + switch (c->bandwidth_hz / 1000000) { + case 8: + Msg.Data[1] = BW_8_MHZ; + break; + case 7: + Msg.Data[1] = BW_7_MHZ; + break; + case 6: + Msg.Data[1] = BW_6_MHZ; + break; + case 0: + return -EOPNOTSUPP; + default: + return -EINVAL; + } + /* Disable LNA, if any. An error is returned if no LNA is present */ + ret = sms_board_lna_control(client->coredev, 0); + if (ret == 0) { + fe_status_t status; + + /* tune with LNA off at first */ + ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->tune_done); + + smsdvb_read_status(fe, &status); + + if (status & FE_HAS_LOCK) + return ret; + + /* previous tune didn't lock - enable LNA and tune again */ + sms_board_lna_control(client->coredev, 1); + } + + return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->tune_done); +} + +static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + int board_id = smscore_get_board_id(client->coredev); + struct sms_board *board = sms_get_board(board_id); + enum sms_device_type_st type = board->type; + int ret; + + struct { + struct SmsMsgHdr_ST Msg; + u32 Data[4]; + } Msg; + + fe->dtv_property_cache.delivery_system = SYS_ISDBT; + + Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; + Msg.Msg.msgDstId = HIF_TASK; + Msg.Msg.msgFlags = 0; + Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ; + Msg.Msg.msgLength = sizeof(Msg); + + if (c->isdbt_sb_segment_idx == -1) + c->isdbt_sb_segment_idx = 0; + + if (!c->isdbt_layer_enabled) + c->isdbt_layer_enabled = 7; + + Msg.Data[0] = c->frequency; + Msg.Data[1] = BW_ISDBT_1SEG; + Msg.Data[2] = 12000000; + Msg.Data[3] = c->isdbt_sb_segment_idx; + + if (c->isdbt_partial_reception) { + if ((type == SMS_PELE || type == SMS_RIO) && + c->isdbt_sb_segment_count > 3) + Msg.Data[1] = BW_ISDBT_13SEG; + else if (c->isdbt_sb_segment_count > 1) + Msg.Data[1] = BW_ISDBT_3SEG; + } else if (type == SMS_PELE || type == SMS_RIO) + Msg.Data[1] = BW_ISDBT_13SEG; + + c->bandwidth_hz = 6000000; + + sms_info("%s: freq %d segwidth %d segindex %d\n", __func__, + c->frequency, c->isdbt_sb_segment_count, + c->isdbt_sb_segment_idx); + + /* Disable LNA, if any. An error is returned if no LNA is present */ + ret = sms_board_lna_control(client->coredev, 0); + if (ret == 0) { + fe_status_t status; + + /* tune with LNA off at first */ + ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->tune_done); + + smsdvb_read_status(fe, &status); + + if (status & FE_HAS_LOCK) + return ret; + + /* previous tune didn't lock - enable LNA and tune again */ + sms_board_lna_control(client->coredev, 1); + } + return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + &client->tune_done); +} + +static int smsdvb_set_frontend(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + struct smscore_device_t *coredev = client->coredev; + + smsdvb_stats_not_ready(fe); + + switch (smscore_get_device_mode(coredev)) { + case DEVICE_MODE_DVBT: + case DEVICE_MODE_DVBT_BDA: + return smsdvb_dvbt_set_frontend(fe); + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + return smsdvb_isdbt_set_frontend(fe); + default: + return -EINVAL; + } +} + +/* Nothing to do here, as stats are automatically updated */ +static int smsdvb_get_frontend(struct dvb_frontend *fe) +{ + return 0; +} + +static int smsdvb_init(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + sms_board_power(client->coredev, 1); + + sms_board_dvb3_event(client, DVB3_EVENT_INIT); + return 0; +} + +static int smsdvb_sleep(struct dvb_frontend *fe) +{ + struct smsdvb_client_t *client = + container_of(fe, struct smsdvb_client_t, frontend); + + sms_board_led_feedback(client->coredev, SMS_LED_OFF); + sms_board_power(client->coredev, 0); + + sms_board_dvb3_event(client, DVB3_EVENT_SLEEP); + + return 0; +} + +static void smsdvb_release(struct dvb_frontend *fe) +{ + /* do nothing */ +} + +static struct dvb_frontend_ops smsdvb_fe_ops = { + .info = { + .name = "Siano Mobile Digital MDTV Receiver", + .frequency_min = 44250000, + .frequency_max = 867250000, + .frequency_stepsize = 250000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = smsdvb_release, + + .set_frontend = smsdvb_set_frontend, + .get_frontend = smsdvb_get_frontend, + .get_tune_settings = smsdvb_get_tune_settings, + + .read_status = smsdvb_read_status, + .read_ber = smsdvb_read_ber, + .read_signal_strength = smsdvb_read_signal_strength, + .read_snr = smsdvb_read_snr, + .read_ucblocks = smsdvb_read_ucblocks, + + .init = smsdvb_init, + .sleep = smsdvb_sleep, +}; + +static int smsdvb_hotplug(struct smscore_device_t *coredev, + struct device *device, int arrival) +{ + struct smsclient_params_t params; + struct smsdvb_client_t *client; + int rc; + + /* device removal handled by onremove callback */ + if (!arrival) + return 0; + client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL); + if (!client) { + sms_err("kmalloc() failed"); + return -ENOMEM; + } + + /* register dvb adapter */ + rc = dvb_register_adapter(&client->adapter, + sms_get_board( + smscore_get_board_id(coredev))->name, + THIS_MODULE, device, adapter_nr); + if (rc < 0) { + sms_err("dvb_register_adapter() failed %d", rc); + goto adapter_error; + } + + /* init dvb demux */ + client->demux.dmx.capabilities = DMX_TS_FILTERING; + client->demux.filternum = 32; /* todo: nova ??? */ + client->demux.feednum = 32; + client->demux.start_feed = smsdvb_start_feed; + client->demux.stop_feed = smsdvb_stop_feed; + + rc = dvb_dmx_init(&client->demux); + if (rc < 0) { + sms_err("dvb_dmx_init failed %d", rc); + goto dvbdmx_error; + } + + /* init dmxdev */ + client->dmxdev.filternum = 32; + client->dmxdev.demux = &client->demux.dmx; + client->dmxdev.capabilities = 0; + + rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter); + if (rc < 0) { + sms_err("dvb_dmxdev_init failed %d", rc); + goto dmxdev_error; + } + + /* init and register frontend */ + memcpy(&client->frontend.ops, &smsdvb_fe_ops, + sizeof(struct dvb_frontend_ops)); + + switch (smscore_get_device_mode(coredev)) { + case DEVICE_MODE_DVBT: + case DEVICE_MODE_DVBT_BDA: + client->frontend.ops.delsys[0] = SYS_DVBT; + break; + case DEVICE_MODE_ISDBT: + case DEVICE_MODE_ISDBT_BDA: + client->frontend.ops.delsys[0] = SYS_ISDBT; + break; + } + + rc = dvb_register_frontend(&client->adapter, &client->frontend); + if (rc < 0) { + sms_err("frontend registration failed %d", rc); + goto frontend_error; + } + + params.initial_id = 1; + params.data_type = MSG_SMS_DVBT_BDA_DATA; + params.onresponse_handler = smsdvb_onresponse; + params.onremove_handler = smsdvb_onremove; + params.context = client; + + rc = smscore_register_client(coredev, ¶ms, &client->smsclient); + if (rc < 0) { + sms_err("smscore_register_client() failed %d", rc); + goto client_error; + } + + client->coredev = coredev; + + init_completion(&client->tune_done); + init_completion(&client->stats_done); + + kmutex_lock(&g_smsdvb_clientslock); + + list_add(&client->entry, &g_smsdvb_clients); + + kmutex_unlock(&g_smsdvb_clientslock); + + client->event_fe_state = -1; + client->event_unc_state = -1; + sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG); + + sms_info("success"); + sms_board_setup(coredev); + + if (smsdvb_debugfs_create(client) < 0) + sms_info("failed to create debugfs node"); + + return 0; + +client_error: + dvb_unregister_frontend(&client->frontend); + +frontend_error: + dvb_dmxdev_release(&client->dmxdev); + +dmxdev_error: + dvb_dmx_release(&client->demux); + +dvbdmx_error: + dvb_unregister_adapter(&client->adapter); + +adapter_error: + kfree(client); + return rc; +} + +static int __init smsdvb_module_init(void) +{ + int rc; + + INIT_LIST_HEAD(&g_smsdvb_clients); + kmutex_init(&g_smsdvb_clientslock); + + smsdvb_debugfs_register(); + + rc = smscore_register_hotplug(smsdvb_hotplug); + + sms_debug(""); + + return rc; +} + +static void __exit smsdvb_module_exit(void) +{ + smscore_unregister_hotplug(smsdvb_hotplug); + + kmutex_lock(&g_smsdvb_clientslock); + + while (!list_empty(&g_smsdvb_clients)) + smsdvb_unregister_client((struct smsdvb_client_t *)g_smsdvb_clients.next); + + smsdvb_debugfs_unregister(); + + kmutex_unlock(&g_smsdvb_clientslock); +} + +module_init(smsdvb_module_init); +module_exit(smsdvb_module_exit); + +MODULE_DESCRIPTION("SMS DVB subsystem adaptation module"); +MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c deleted file mode 100644 index aeadd8a42775..000000000000 --- a/drivers/media/common/siano/smsdvb.c +++ /dev/null @@ -1,1603 +0,0 @@ -/**************************************************************** - -Siano Mobile Silicon, Inc. -MDTV receiver kernel modules. -Copyright (C) 2006-2008, Uri Shkolnik - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 2 of the License, or -(at your option) any later version. - - This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - -****************************************************************/ - -#include -#include -#include -#include - -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" - -#include "smscoreapi.h" -#include "sms-cards.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -struct smsdvb_client_t { - struct list_head entry; - - struct smscore_device_t *coredev; - struct smscore_client_t *smsclient; - - struct dvb_adapter adapter; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dvb_frontend frontend; - - fe_status_t fe_status; - - struct completion tune_done; - struct completion stats_done; - - int last_per; - - int legacy_ber, legacy_per; - - int event_fe_state; - int event_unc_state; - - /* Stats debugfs data */ - struct dentry *debugfs; - char *stats_data; - atomic_t stats_count; - bool stats_was_read; - wait_queue_head_t stats_queue; -}; - -static struct list_head g_smsdvb_clients; -static struct mutex g_smsdvb_clientslock; - -static int sms_dbg; -module_param_named(debug, sms_dbg, int, 0644); -MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); - -/* - * This struct is a mix of RECEPTION_STATISTICS_EX_S and SRVM_SIGNAL_STATUS_S. - * It was obtained by comparing the way it was filled by the original code - */ -struct RECEPTION_STATISTICS_PER_SLICES_S { - u32 result; - u32 snr; - s32 inBandPower; - u32 tsPackets; - u32 etsPackets; - u32 constellation; - u32 hpCode; - u32 tpsSrvIndLP; - u32 tpsSrvIndHP; - u32 cellId; - u32 reason; - u32 requestId; - u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ - - u32 BER; /* Post Viterbi BER [1E-5] */ - s32 RSSI; /* dBm */ - s32 CarrierOffset; /* Carrier Offset in bin/1024 */ - - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - - u32 BERBitCount; /* Total number of SYNC bits. */ - u32 BERErrorCount; /* Number of erronous SYNC bits. */ - - s32 MRC_SNR; /* dB */ - s32 MRC_InBandPwr; /* In band power in dBM */ - s32 MRC_RSSI; /* dBm */ -}; - -u32 sms_to_bw_table[] = { - [BW_8_MHZ] = 8000000, - [BW_7_MHZ] = 7000000, - [BW_6_MHZ] = 6000000, - [BW_5_MHZ] = 5000000, - [BW_2_MHZ] = 2000000, - [BW_1_5_MHZ] = 1500000, - [BW_ISDBT_1SEG] = 6000000, - [BW_ISDBT_3SEG] = 6000000, - [BW_ISDBT_13SEG] = 6000000, -}; - -u32 sms_to_guard_interval_table[] = { - [0] = GUARD_INTERVAL_1_32, - [1] = GUARD_INTERVAL_1_16, - [2] = GUARD_INTERVAL_1_8, - [3] = GUARD_INTERVAL_1_4, -}; - -u32 sms_to_code_rate_table[] = { - [0] = FEC_1_2, - [1] = FEC_2_3, - [2] = FEC_3_4, - [3] = FEC_5_6, - [4] = FEC_7_8, -}; - - -u32 sms_to_hierarchy_table[] = { - [0] = HIERARCHY_NONE, - [1] = HIERARCHY_1, - [2] = HIERARCHY_2, - [3] = HIERARCHY_4, -}; - -u32 sms_to_modulation_table[] = { - [0] = QPSK, - [1] = QAM_16, - [2] = QAM_64, - [3] = DQPSK, -}; - -static struct dentry *smsdvb_debugfs; - -static void smsdvb_print_dvb_stats(struct smsdvb_client_t *client, - struct SMSHOSTLIB_STATISTICS_ST *p) -{ - int n = 0; - char *buf; - - if (!client->stats_data || atomic_read(&client->stats_count)) - return; - - buf = client->stats_data; - - n += snprintf(&buf[n], PAGE_SIZE - n, - "IsRfLocked = %d\n", p->IsRfLocked); - n += snprintf(&buf[n], PAGE_SIZE - n, - "IsDemodLocked = %d\n", p->IsDemodLocked); - n += snprintf(&buf[n], PAGE_SIZE - n, - "IsExternalLNAOn = %d\n", p->IsExternalLNAOn); - n += snprintf(&buf[n], PAGE_SIZE - n, - "SNR = %d\n", p->SNR); - n += snprintf(&buf[n], PAGE_SIZE - n, - "BER = %d\n", p->BER); - n += snprintf(&buf[n], PAGE_SIZE - n, - "FIB_CRC = %d\n", p->FIB_CRC); - n += snprintf(&buf[n], PAGE_SIZE - n, - "TS_PER = %d\n", p->TS_PER); - n += snprintf(&buf[n], PAGE_SIZE - n, - "MFER = %d\n", p->MFER); - n += snprintf(&buf[n], PAGE_SIZE - n, - "RSSI = %d\n", p->RSSI); - n += snprintf(&buf[n], PAGE_SIZE - n, - "InBandPwr = %d\n", p->InBandPwr); - n += snprintf(&buf[n], PAGE_SIZE - n, - "CarrierOffset = %d\n", p->CarrierOffset); - n += snprintf(&buf[n], PAGE_SIZE - n, - "ModemState = %d\n", p->ModemState); - n += snprintf(&buf[n], PAGE_SIZE - n, - "Frequency = %d\n", p->Frequency); - n += snprintf(&buf[n], PAGE_SIZE - n, - "Bandwidth = %d\n", p->Bandwidth); - n += snprintf(&buf[n], PAGE_SIZE - n, - "TransmissionMode = %d\n", p->TransmissionMode); - n += snprintf(&buf[n], PAGE_SIZE - n, - "ModemState = %d\n", p->ModemState); - n += snprintf(&buf[n], PAGE_SIZE - n, - "GuardInterval = %d\n", p->GuardInterval); - n += snprintf(&buf[n], PAGE_SIZE - n, - "CodeRate = %d\n", p->CodeRate); - n += snprintf(&buf[n], PAGE_SIZE - n, - "LPCodeRate = %d\n", p->LPCodeRate); - n += snprintf(&buf[n], PAGE_SIZE - n, - "Hierarchy = %d\n", p->Hierarchy); - n += snprintf(&buf[n], PAGE_SIZE - n, - "Constellation = %d\n", p->Constellation); - n += snprintf(&buf[n], PAGE_SIZE - n, - "BurstSize = %d\n", p->BurstSize); - n += snprintf(&buf[n], PAGE_SIZE - n, - "BurstDuration = %d\n", p->BurstDuration); - n += snprintf(&buf[n], PAGE_SIZE - n, - "BurstCycleTime = %d\n", p->BurstCycleTime); - n += snprintf(&buf[n], PAGE_SIZE - n, - "CalculatedBurstCycleTime = %d\n", - p->CalculatedBurstCycleTime); - n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfRows = %d\n", p->NumOfRows); - n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfPaddCols = %d\n", p->NumOfPaddCols); - n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfPunctCols = %d\n", p->NumOfPunctCols); - n += snprintf(&buf[n], PAGE_SIZE - n, - "ErrorTSPackets = %d\n", p->ErrorTSPackets); - n += snprintf(&buf[n], PAGE_SIZE - n, - "TotalTSPackets = %d\n", p->TotalTSPackets); - n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfValidMpeTlbs = %d\n", p->NumOfValidMpeTlbs); - n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfInvalidMpeTlbs = %d\n", p->NumOfInvalidMpeTlbs); - n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfCorrectedMpeTlbs = %d\n", p->NumOfCorrectedMpeTlbs); - n += snprintf(&buf[n], PAGE_SIZE - n, - "BERErrorCount = %d\n", p->BERErrorCount); - n += snprintf(&buf[n], PAGE_SIZE - n, - "BERBitCount = %d\n", p->BERBitCount); - n += snprintf(&buf[n], PAGE_SIZE - n, - "SmsToHostTxErrors = %d\n", p->SmsToHostTxErrors); - n += snprintf(&buf[n], PAGE_SIZE - n, - "PreBER = %d\n", p->PreBER); - n += snprintf(&buf[n], PAGE_SIZE - n, - "CellId = %d\n", p->CellId); - n += snprintf(&buf[n], PAGE_SIZE - n, - "DvbhSrvIndHP = %d\n", p->DvbhSrvIndHP); - n += snprintf(&buf[n], PAGE_SIZE - n, - "DvbhSrvIndLP = %d\n", p->DvbhSrvIndLP); - n += snprintf(&buf[n], PAGE_SIZE - n, - "NumMPEReceived = %d\n", p->NumMPEReceived); - - atomic_set(&client->stats_count, n); - wake_up(&client->stats_queue); -} - -static void smsdvb_print_isdb_stats(struct smsdvb_client_t *client, - struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) -{ - int i, n = 0; - char *buf; - - if (!client->stats_data || atomic_read(&client->stats_count)) - return; - - buf = client->stats_data; - - n += snprintf(&buf[n], PAGE_SIZE - n, - "IsRfLocked = %d\t\t", p->IsRfLocked); - n += snprintf(&buf[n], PAGE_SIZE - n, - "IsDemodLocked = %d\t", p->IsDemodLocked); - n += snprintf(&buf[n], PAGE_SIZE - n, - "IsExternalLNAOn = %d\n", p->IsExternalLNAOn); - n += snprintf(&buf[n], PAGE_SIZE - n, - "SNR = %d dB\t\t", p->SNR); - n += snprintf(&buf[n], PAGE_SIZE - n, - "RSSI = %d dBm\t\t", p->RSSI); - n += snprintf(&buf[n], PAGE_SIZE - n, - "InBandPwr = %d dBm\n", p->InBandPwr); - n += snprintf(&buf[n], PAGE_SIZE - n, - "CarrierOffset = %d\t", p->CarrierOffset); - n += snprintf(&buf[n], PAGE_SIZE - n, - "Bandwidth = %d\t\t", p->Bandwidth); - n += snprintf(&buf[n], PAGE_SIZE - n, - "Frequency = %d Hz\n", p->Frequency); - n += snprintf(&buf[n], PAGE_SIZE - n, - "TransmissionMode = %d\t", p->TransmissionMode); - n += snprintf(&buf[n], PAGE_SIZE - n, - "ModemState = %d\t\t", p->ModemState); - n += snprintf(&buf[n], PAGE_SIZE - n, - "GuardInterval = %d\n", p->GuardInterval); - n += snprintf(&buf[n], PAGE_SIZE - n, - "SystemType = %d\t\t", p->SystemType); - n += snprintf(&buf[n], PAGE_SIZE - n, - "PartialReception = %d\t", p->PartialReception); - n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfLayers = %d\n", p->NumOfLayers); - n += snprintf(&buf[n], PAGE_SIZE - n, - "SmsToHostTxErrors = %d\n", p->SmsToHostTxErrors); - - for (i = 0; i < 3; i++) { - if (p->LayerInfo[i].NumberOfSegments < 1 || - p->LayerInfo[i].NumberOfSegments > 13) - continue; - - n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tCodeRate = %d\t", - p->LayerInfo[i].CodeRate); - n += snprintf(&buf[n], PAGE_SIZE - n, "Constellation = %d\n", - p->LayerInfo[i].Constellation); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tBER = %-5d\t", - p->LayerInfo[i].BER); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tBERErrorCount = %-5d\t", - p->LayerInfo[i].BERErrorCount); - n += snprintf(&buf[n], PAGE_SIZE - n, "BERBitCount = %-5d\n", - p->LayerInfo[i].BERBitCount); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tPreBER = %-5d\t", - p->LayerInfo[i].PreBER); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tTS_PER = %-5d\n", - p->LayerInfo[i].TS_PER); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tErrorTSPackets = %-5d\t", - p->LayerInfo[i].ErrorTSPackets); - n += snprintf(&buf[n], PAGE_SIZE - n, "TotalTSPackets = %-5d\t", - p->LayerInfo[i].TotalTSPackets); - n += snprintf(&buf[n], PAGE_SIZE - n, "TILdepthI = %d\n", - p->LayerInfo[i].TILdepthI); - n += snprintf(&buf[n], PAGE_SIZE - n, - "\tNumberOfSegments = %d\t", - p->LayerInfo[i].NumberOfSegments); - n += snprintf(&buf[n], PAGE_SIZE - n, "TMCCErrors = %d\n", - p->LayerInfo[i].TMCCErrors); - } - - atomic_set(&client->stats_count, n); - wake_up(&client->stats_queue); -} - -static void -smsdvb_print_isdb_stats_ex(struct smsdvb_client_t *client, - struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p) -{ - int i, n = 0; - char *buf; - - if (!client->stats_data || atomic_read(&client->stats_count)) - return; - - buf = client->stats_data; - - n += snprintf(&buf[n], PAGE_SIZE - n, - "IsRfLocked = %d\t\t", p->IsRfLocked); - n += snprintf(&buf[n], PAGE_SIZE - n, - "IsDemodLocked = %d\t", p->IsDemodLocked); - n += snprintf(&buf[n], PAGE_SIZE - n, - "IsExternalLNAOn = %d\n", p->IsExternalLNAOn); - n += snprintf(&buf[n], PAGE_SIZE - n, - "SNR = %d dB\t\t", p->SNR); - n += snprintf(&buf[n], PAGE_SIZE - n, - "RSSI = %d dBm\t\t", p->RSSI); - n += snprintf(&buf[n], PAGE_SIZE - n, - "InBandPwr = %d dBm\n", p->InBandPwr); - n += snprintf(&buf[n], PAGE_SIZE - n, - "CarrierOffset = %d\t", p->CarrierOffset); - n += snprintf(&buf[n], PAGE_SIZE - n, - "Bandwidth = %d\t\t", p->Bandwidth); - n += snprintf(&buf[n], PAGE_SIZE - n, - "Frequency = %d Hz\n", p->Frequency); - n += snprintf(&buf[n], PAGE_SIZE - n, - "TransmissionMode = %d\t", p->TransmissionMode); - n += snprintf(&buf[n], PAGE_SIZE - n, - "ModemState = %d\t\t", p->ModemState); - n += snprintf(&buf[n], PAGE_SIZE - n, - "GuardInterval = %d\n", p->GuardInterval); - n += snprintf(&buf[n], PAGE_SIZE - n, - "SystemType = %d\t\t", p->SystemType); - n += snprintf(&buf[n], PAGE_SIZE - n, - "PartialReception = %d\t", p->PartialReception); - n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfLayers = %d\n", p->NumOfLayers); - n += snprintf(&buf[n], PAGE_SIZE - n, "SegmentNumber = %d\t", - p->SegmentNumber); - n += snprintf(&buf[n], PAGE_SIZE - n, "TuneBW = %d\n", - p->TuneBW); - - for (i = 0; i < 3; i++) { - if (p->LayerInfo[i].NumberOfSegments < 1 || - p->LayerInfo[i].NumberOfSegments > 13) - continue; - - n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tCodeRate = %d\t", - p->LayerInfo[i].CodeRate); - n += snprintf(&buf[n], PAGE_SIZE - n, "Constellation = %d\n", - p->LayerInfo[i].Constellation); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tBER = %-5d\t", - p->LayerInfo[i].BER); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tBERErrorCount = %-5d\t", - p->LayerInfo[i].BERErrorCount); - n += snprintf(&buf[n], PAGE_SIZE - n, "BERBitCount = %-5d\n", - p->LayerInfo[i].BERBitCount); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tPreBER = %-5d\t", - p->LayerInfo[i].PreBER); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tTS_PER = %-5d\n", - p->LayerInfo[i].TS_PER); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tErrorTSPackets = %-5d\t", - p->LayerInfo[i].ErrorTSPackets); - n += snprintf(&buf[n], PAGE_SIZE - n, "TotalTSPackets = %-5d\t", - p->LayerInfo[i].TotalTSPackets); - n += snprintf(&buf[n], PAGE_SIZE - n, "TILdepthI = %d\n", - p->LayerInfo[i].TILdepthI); - n += snprintf(&buf[n], PAGE_SIZE - n, - "\tNumberOfSegments = %d\t", - p->LayerInfo[i].NumberOfSegments); - n += snprintf(&buf[n], PAGE_SIZE - n, "TMCCErrors = %d\n", - p->LayerInfo[i].TMCCErrors); - } - - atomic_set(&client->stats_count, n); - wake_up(&client->stats_queue); -} - -static int smsdvb_stats_open(struct inode *inode, struct file *file) -{ - struct smsdvb_client_t *client = inode->i_private; - - atomic_set(&client->stats_count, 0); - client->stats_was_read = false; - - init_waitqueue_head(&client->stats_queue); - - client->stats_data = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (client->stats_data == NULL) - return -ENOMEM; - - file->private_data = client; - - return 0; -} - -static ssize_t smsdvb_stats_read(struct file *file, char __user *user_buf, - size_t nbytes, loff_t *ppos) -{ - struct smsdvb_client_t *client = file->private_data; - - if (!client->stats_data || client->stats_was_read) - return 0; - - wait_event_interruptible(client->stats_queue, - atomic_read(&client->stats_count)); - - return simple_read_from_buffer(user_buf, nbytes, ppos, - client->stats_data, - atomic_read(&client->stats_count)); - - client->stats_was_read = true; -} - -static int smsdvb_stats_release(struct inode *inode, struct file *file) -{ - struct smsdvb_client_t *client = file->private_data; - - kfree(client->stats_data); - client->stats_data = NULL; - - return 0; -} - -static const struct file_operations debugfs_stats_ops = { - .open = smsdvb_stats_open, - .read = smsdvb_stats_read, - .release = smsdvb_stats_release, - .llseek = generic_file_llseek, -}; - -static int create_stats_debugfs(struct smsdvb_client_t *client) -{ - struct smscore_device_t *coredev = client->coredev; - struct dentry *d; - - if (!smsdvb_debugfs) - return -ENODEV; - - client->debugfs = debugfs_create_dir(coredev->devpath, smsdvb_debugfs); - if (IS_ERR_OR_NULL(client->debugfs)) { - sms_info("Unable to create debugfs %s directory.\n", - coredev->devpath); - return -ENODEV; - } - - d = debugfs_create_file("stats", S_IRUGO | S_IWUSR, client->debugfs, - client, &debugfs_stats_ops); - if (!d) { - debugfs_remove(client->debugfs); - return -ENOMEM; - } - - return 0; -} - -static void release_stats_debugfs(struct smsdvb_client_t *client) -{ - if (!client->debugfs) - return; - - debugfs_remove_recursive(client->debugfs); - - client->debugfs = NULL; -} - -/* Events that may come from DVB v3 adapter */ -static void sms_board_dvb3_event(struct smsdvb_client_t *client, - enum SMS_DVB3_EVENTS event) { - - struct smscore_device_t *coredev = client->coredev; - switch (event) { - case DVB3_EVENT_INIT: - sms_debug("DVB3_EVENT_INIT"); - sms_board_event(coredev, BOARD_EVENT_BIND); - break; - case DVB3_EVENT_SLEEP: - sms_debug("DVB3_EVENT_SLEEP"); - sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND); - break; - case DVB3_EVENT_HOTPLUG: - sms_debug("DVB3_EVENT_HOTPLUG"); - sms_board_event(coredev, BOARD_EVENT_POWER_INIT); - break; - case DVB3_EVENT_FE_LOCK: - if (client->event_fe_state != DVB3_EVENT_FE_LOCK) { - client->event_fe_state = DVB3_EVENT_FE_LOCK; - sms_debug("DVB3_EVENT_FE_LOCK"); - sms_board_event(coredev, BOARD_EVENT_FE_LOCK); - } - break; - case DVB3_EVENT_FE_UNLOCK: - if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) { - client->event_fe_state = DVB3_EVENT_FE_UNLOCK; - sms_debug("DVB3_EVENT_FE_UNLOCK"); - sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK); - } - break; - case DVB3_EVENT_UNC_OK: - if (client->event_unc_state != DVB3_EVENT_UNC_OK) { - client->event_unc_state = DVB3_EVENT_UNC_OK; - sms_debug("DVB3_EVENT_UNC_OK"); - sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK); - } - break; - case DVB3_EVENT_UNC_ERR: - if (client->event_unc_state != DVB3_EVENT_UNC_ERR) { - client->event_unc_state = DVB3_EVENT_UNC_ERR; - sms_debug("DVB3_EVENT_UNC_ERR"); - sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS); - } - break; - - default: - sms_err("Unknown dvb3 api event"); - break; - } -} - -static void smsdvb_stats_not_ready(struct dvb_frontend *fe) -{ - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - struct smscore_device_t *coredev = client->coredev; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int i, n_layers; - - switch (smscore_get_device_mode(coredev)) { - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - n_layers = 4; - default: - n_layers = 1; - } - - /* Fill the length of each status counter */ - - /* Only global stats */ - c->strength.len = 1; - c->cnr.len = 1; - - /* Per-layer stats */ - c->post_bit_error.len = n_layers; - c->post_bit_count.len = n_layers; - c->block_error.len = n_layers; - c->block_count.len = n_layers; - - /* Signal is always available */ - c->strength.stat[0].scale = FE_SCALE_RELATIVE; - c->strength.stat[0].uvalue = 0; - - /* Put all of them at FE_SCALE_NOT_AVAILABLE */ - for (i = 0; i < n_layers; i++) { - c->cnr.stat[i].scale = FE_SCALE_NOT_AVAILABLE; - c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; - c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; - c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; - c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; - } -} - -static inline int sms_to_mode(u32 mode) -{ - switch (mode) { - case 2: - return TRANSMISSION_MODE_2K; - case 4: - return TRANSMISSION_MODE_4K; - case 8: - return TRANSMISSION_MODE_8K; - } - return TRANSMISSION_MODE_AUTO; -} - -static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked) -{ - if (is_demod_locked) - return FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_LOCK; - - if (is_rf_locked) - return FE_HAS_SIGNAL | FE_HAS_CARRIER; - - return 0; -} - - -#define convert_from_table(value, table, defval) ({ \ - u32 __ret; \ - if (value < ARRAY_SIZE(table)) \ - __ret = table[value]; \ - else \ - __ret = defval; \ - __ret; \ -}) - -#define sms_to_bw(value) \ - convert_from_table(value, sms_to_bw_table, 0); - -#define sms_to_guard_interval(value) \ - convert_from_table(value, sms_to_guard_interval_table, \ - GUARD_INTERVAL_AUTO); - -#define sms_to_code_rate(value) \ - convert_from_table(value, sms_to_code_rate_table, \ - FEC_NONE); - -#define sms_to_hierarchy(value) \ - convert_from_table(value, sms_to_hierarchy_table, \ - FEC_NONE); - -#define sms_to_modulation(value) \ - convert_from_table(value, sms_to_modulation_table, \ - FEC_NONE); - -static void smsdvb_update_tx_params(struct smsdvb_client_t *client, - struct TRANSMISSION_STATISTICS_S *p) -{ - struct dvb_frontend *fe = &client->frontend; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - - c->frequency = p->Frequency; - client->fe_status = sms_to_status(p->IsDemodLocked, 0); - c->bandwidth_hz = sms_to_bw(p->Bandwidth); - c->transmission_mode = sms_to_mode(p->TransmissionMode); - c->guard_interval = sms_to_guard_interval(p->GuardInterval); - c->code_rate_HP = sms_to_code_rate(p->CodeRate); - c->code_rate_LP = sms_to_code_rate(p->LPCodeRate); - c->hierarchy = sms_to_hierarchy(p->Hierarchy); - c->modulation = sms_to_modulation(p->Constellation); -} - -static void smsdvb_update_per_slices(struct smsdvb_client_t *client, - struct RECEPTION_STATISTICS_PER_SLICES_S *p) -{ - struct dvb_frontend *fe = &client->frontend; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - - client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked); - c->modulation = sms_to_modulation(p->constellation); - - /* TS PER */ - client->last_per = c->block_error.stat[0].uvalue; - c->block_error.stat[0].scale = FE_SCALE_COUNTER; - c->block_count.stat[0].scale = FE_SCALE_COUNTER; - c->block_error.stat[0].uvalue += p->etsPackets; - c->block_count.stat[0].uvalue += p->etsPackets + p->tsPackets; - - /* BER */ - c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; - c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[0].uvalue += p->BERErrorCount; - c->post_bit_count.stat[0].uvalue += p->BERBitCount; - - /* Legacy PER/BER */ - client->legacy_per = (p->etsPackets * 65535) / - (p->tsPackets + p->etsPackets); - - /* Signal Strength, in DBm */ - c->strength.stat[0].uvalue = p->RSSI * 1000; - - /* Carrier to Noise ratio, in DB */ - c->cnr.stat[0].scale = FE_SCALE_DECIBEL; - c->cnr.stat[0].svalue = p->snr * 1000; -} - -static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client, - struct SMSHOSTLIB_STATISTICS_ST *p) -{ - struct dvb_frontend *fe = &client->frontend; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - - smsdvb_print_dvb_stats(client, p); - - client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked); - - /* Update DVB modulation parameters */ - c->frequency = p->Frequency; - client->fe_status = sms_to_status(p->IsDemodLocked, 0); - c->bandwidth_hz = sms_to_bw(p->Bandwidth); - c->transmission_mode = sms_to_mode(p->TransmissionMode); - c->guard_interval = sms_to_guard_interval(p->GuardInterval); - c->code_rate_HP = sms_to_code_rate(p->CodeRate); - c->code_rate_LP = sms_to_code_rate(p->LPCodeRate); - c->hierarchy = sms_to_hierarchy(p->Hierarchy); - c->modulation = sms_to_modulation(p->Constellation); - - /* update reception data */ - c->lna = p->IsExternalLNAOn ? 1 : 0; - - /* Carrier to Noise ratio, in DB */ - c->cnr.stat[0].scale = FE_SCALE_DECIBEL; - c->cnr.stat[0].svalue = p->SNR * 1000; - - /* Signal Strength, in DBm */ - c->strength.stat[0].uvalue = p->RSSI * 1000; - - /* TS PER */ - client->last_per = c->block_error.stat[0].uvalue; - c->block_error.stat[0].scale = FE_SCALE_COUNTER; - c->block_count.stat[0].scale = FE_SCALE_COUNTER; - c->block_error.stat[0].uvalue += p->ErrorTSPackets; - c->block_count.stat[0].uvalue += p->TotalTSPackets; - - /* BER */ - c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; - c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[0].uvalue += p->BERErrorCount; - c->post_bit_count.stat[0].uvalue += p->BERBitCount; - - /* Legacy PER/BER */ - client->legacy_ber = p->BER; -}; - -static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, - struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) -{ - struct dvb_frontend *fe = &client->frontend; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr; - int i, n_layers; - - smsdvb_print_isdb_stats(client, p); - - /* Update ISDB-T transmission parameters */ - c->frequency = p->Frequency; - client->fe_status = sms_to_status(p->IsDemodLocked, 0); - c->bandwidth_hz = sms_to_bw(p->Bandwidth); - c->transmission_mode = sms_to_mode(p->TransmissionMode); - c->guard_interval = sms_to_guard_interval(p->GuardInterval); - c->isdbt_partial_reception = p->PartialReception ? 1 : 0; - n_layers = p->NumOfLayers; - if (n_layers < 1) - n_layers = 1; - if (n_layers > 3) - n_layers = 3; - c->isdbt_layer_enabled = 0; - - /* update reception data */ - c->lna = p->IsExternalLNAOn ? 1 : 0; - - /* Carrier to Noise ratio, in DB */ - c->cnr.stat[0].scale = FE_SCALE_DECIBEL; - c->cnr.stat[0].svalue = p->SNR * 1000; - - /* Signal Strength, in DBm */ - c->strength.stat[0].uvalue = p->RSSI * 1000; - - client->last_per = c->block_error.stat[0].uvalue; - - /* Clears global counters, as the code below will sum it again */ - c->block_error.stat[0].uvalue = 0; - c->block_count.stat[0].uvalue = 0; - c->post_bit_error.stat[0].uvalue = 0; - c->post_bit_count.stat[0].uvalue = 0; - - for (i = 0; i < n_layers; i++) { - lr = &p->LayerInfo[i]; - - /* Update per-layer transmission parameters */ - if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) { - c->isdbt_layer_enabled |= 1 << i; - c->layer[i].segment_count = lr->NumberOfSegments; - } else { - continue; - } - c->layer[i].modulation = sms_to_modulation(lr->Constellation); - - /* TS PER */ - c->block_error.stat[i].scale = FE_SCALE_COUNTER; - c->block_count.stat[i].scale = FE_SCALE_COUNTER; - c->block_error.stat[i].uvalue += lr->ErrorTSPackets; - c->block_count.stat[i].uvalue += lr->TotalTSPackets; - - /* Update global PER counter */ - c->block_error.stat[0].uvalue += lr->ErrorTSPackets; - c->block_count.stat[0].uvalue += lr->TotalTSPackets; - - /* BER */ - c->post_bit_error.stat[i].scale = FE_SCALE_COUNTER; - c->post_bit_count.stat[i].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[i].uvalue += lr->BERErrorCount; - c->post_bit_count.stat[i].uvalue += lr->BERBitCount; - - /* Update global BER counter */ - c->post_bit_error.stat[0].uvalue += lr->BERErrorCount; - c->post_bit_count.stat[0].uvalue += lr->BERBitCount; - } -} - -static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, - struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p) -{ - struct dvb_frontend *fe = &client->frontend; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr; - int i, n_layers; - - smsdvb_print_isdb_stats_ex(client, p); - - /* Update ISDB-T transmission parameters */ - c->frequency = p->Frequency; - client->fe_status = sms_to_status(p->IsDemodLocked, 0); - c->bandwidth_hz = sms_to_bw(p->Bandwidth); - c->transmission_mode = sms_to_mode(p->TransmissionMode); - c->guard_interval = sms_to_guard_interval(p->GuardInterval); - c->isdbt_partial_reception = p->PartialReception ? 1 : 0; - n_layers = p->NumOfLayers; - if (n_layers < 1) - n_layers = 1; - if (n_layers > 3) - n_layers = 3; - c->isdbt_layer_enabled = 0; - - /* update reception data */ - c->lna = p->IsExternalLNAOn ? 1 : 0; - - /* Carrier to Noise ratio, in DB */ - c->cnr.stat[0].scale = FE_SCALE_DECIBEL; - c->cnr.stat[0].svalue = p->SNR * 1000; - - /* Signal Strength, in DBm */ - c->strength.stat[0].uvalue = p->RSSI * 1000; - - client->last_per = c->block_error.stat[0].uvalue; - - /* Clears global counters, as the code below will sum it again */ - c->block_error.stat[0].uvalue = 0; - c->block_count.stat[0].uvalue = 0; - c->post_bit_error.stat[0].uvalue = 0; - c->post_bit_count.stat[0].uvalue = 0; - - for (i = 0; i < n_layers; i++) { - lr = &p->LayerInfo[i]; - - /* Update per-layer transmission parameters */ - if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) { - c->isdbt_layer_enabled |= 1 << i; - c->layer[i].segment_count = lr->NumberOfSegments; - } else { - continue; - } - c->layer[i].modulation = sms_to_modulation(lr->Constellation); - - /* TS PER */ - c->block_error.stat[i].scale = FE_SCALE_COUNTER; - c->block_count.stat[i].scale = FE_SCALE_COUNTER; - c->block_error.stat[i].uvalue += lr->ErrorTSPackets; - c->block_count.stat[i].uvalue += lr->TotalTSPackets; - - /* Update global PER counter */ - c->block_error.stat[0].uvalue += lr->ErrorTSPackets; - c->block_count.stat[0].uvalue += lr->TotalTSPackets; - - /* BER */ - c->post_bit_error.stat[i].scale = FE_SCALE_COUNTER; - c->post_bit_count.stat[i].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[i].uvalue += lr->BERErrorCount; - c->post_bit_count.stat[i].uvalue += lr->BERBitCount; - - /* Update global BER counter */ - c->post_bit_error.stat[0].uvalue += lr->BERErrorCount; - c->post_bit_count.stat[0].uvalue += lr->BERBitCount; - } -} - -static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) -{ - struct smsdvb_client_t *client = (struct smsdvb_client_t *) context; - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p) - + cb->offset); - void *p = phdr + 1; - struct dvb_frontend *fe = &client->frontend; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - bool is_status_update = false; - - switch (phdr->msgType) { - case MSG_SMS_DVBT_BDA_DATA: - dvb_dmx_swfilter(&client->demux, p, - cb->size - sizeof(struct SmsMsgHdr_ST)); - break; - - case MSG_SMS_RF_TUNE_RES: - case MSG_SMS_ISDBT_TUNE_RES: - complete(&client->tune_done); - break; - - case MSG_SMS_SIGNAL_DETECTED_IND: - client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | - FE_HAS_LOCK; - - is_status_update = true; - break; - - case MSG_SMS_NO_SIGNAL_IND: - client->fe_status = 0; - - is_status_update = true; - break; - - case MSG_SMS_TRANSMISSION_IND: - smsdvb_update_tx_params(client, p); - - is_status_update = true; - break; - - case MSG_SMS_HO_PER_SLICES_IND: - smsdvb_update_per_slices(client, p); - - is_status_update = true; - break; - - case MSG_SMS_GET_STATISTICS_RES: - switch (smscore_get_device_mode(client->coredev)) { - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - smsdvb_update_isdbt_stats(client, p); - break; - default: - /* Skip SmsMsgStatisticsInfo_ST:RequestResult field */ - smsdvb_update_dvb_stats(client, p + sizeof(u32)); - } - - is_status_update = true; - break; - - /* Only for ISDB-T */ - case MSG_SMS_GET_STATISTICS_EX_RES: - /* Skip SmsMsgStatisticsInfo_ST:RequestResult field? */ - smsdvb_update_isdbt_stats_ex(client, p + sizeof(u32)); - is_status_update = true; - break; - default: - sms_info("message not handled"); - } - smscore_putbuffer(client->coredev, cb); - - if (is_status_update) { - if (client->fe_status == FE_HAS_LOCK) { - sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK); - if (client->last_per == c->block_error.stat[0].uvalue) - sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK); - else - sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR); - } else { - smsdvb_stats_not_ready(fe); - - sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK); - } - complete(&client->stats_done); - } - - return 0; -} - -static void smsdvb_unregister_client(struct smsdvb_client_t *client) -{ - /* must be called under clientslock */ - - list_del(&client->entry); - - release_stats_debugfs(client); - smscore_unregister_client(client->smsclient); - dvb_unregister_frontend(&client->frontend); - dvb_dmxdev_release(&client->dmxdev); - dvb_dmx_release(&client->demux); - dvb_unregister_adapter(&client->adapter); - kfree(client); -} - -static void smsdvb_onremove(void *context) -{ - kmutex_lock(&g_smsdvb_clientslock); - - smsdvb_unregister_client((struct smsdvb_client_t *) context); - - kmutex_unlock(&g_smsdvb_clientslock); -} - -static int smsdvb_start_feed(struct dvb_demux_feed *feed) -{ - struct smsdvb_client_t *client = - container_of(feed->demux, struct smsdvb_client_t, demux); - struct SmsMsgData_ST PidMsg; - - sms_debug("add pid %d(%x)", - feed->pid, feed->pid); - - PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - PidMsg.xMsgHeader.msgDstId = HIF_TASK; - PidMsg.xMsgHeader.msgFlags = 0; - PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ; - PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); - PidMsg.msgData[0] = feed->pid; - - return smsclient_sendrequest(client->smsclient, - &PidMsg, sizeof(PidMsg)); -} - -static int smsdvb_stop_feed(struct dvb_demux_feed *feed) -{ - struct smsdvb_client_t *client = - container_of(feed->demux, struct smsdvb_client_t, demux); - struct SmsMsgData_ST PidMsg; - - sms_debug("remove pid %d(%x)", - feed->pid, feed->pid); - - PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - PidMsg.xMsgHeader.msgDstId = HIF_TASK; - PidMsg.xMsgHeader.msgFlags = 0; - PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ; - PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); - PidMsg.msgData[0] = feed->pid; - - return smsclient_sendrequest(client->smsclient, - &PidMsg, sizeof(PidMsg)); -} - -static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, - void *buffer, size_t size, - struct completion *completion) -{ - int rc; - - rc = smsclient_sendrequest(client->smsclient, buffer, size); - if (rc < 0) - return rc; - - return wait_for_completion_timeout(completion, - msecs_to_jiffies(2000)) ? - 0 : -ETIME; -} - -static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) -{ - int rc; - struct SmsMsgHdr_ST Msg; - - - Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - Msg.msgDstId = HIF_TASK; - Msg.msgFlags = 0; - Msg.msgLength = sizeof(Msg); - - switch (smscore_get_device_mode(client->coredev)) { - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - /* - * Check for firmware version, to avoid breaking for old cards - */ - if (client->coredev->fw_version >= 0x800) - Msg.msgType = MSG_SMS_GET_STATISTICS_EX_REQ; - else - Msg.msgType = MSG_SMS_GET_STATISTICS_REQ; - break; - default: - Msg.msgType = MSG_SMS_GET_STATISTICS_REQ; - } - - rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->stats_done); - - return rc; -} - -static inline int led_feedback(struct smsdvb_client_t *client) -{ - if (!(client->fe_status & FE_HAS_LOCK)) - return sms_board_led_feedback(client->coredev, SMS_LED_OFF); - - return sms_board_led_feedback(client->coredev, - (client->legacy_ber == 0) ? - SMS_LED_HI : SMS_LED_LO); -} - -static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat) -{ - int rc; - struct smsdvb_client_t *client; - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *stat = client->fe_status; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - int rc; - struct smsdvb_client_t *client; - - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *ber = client->legacy_ber; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int rc; - s32 power = (s32) c->strength.stat[0].uvalue; - struct smsdvb_client_t *client; - - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - if (power < -95) - *strength = 0; - else if (power > -29) - *strength = 65535; - else - *strength = (power + 95) * 65535 / 66; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int rc; - struct smsdvb_client_t *client; - - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - /* Preferred scale for SNR with legacy API: 0.1 dB */ - *snr = c->cnr.stat[0].svalue / 100; - - led_feedback(client); - - return rc; -} - -static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) -{ - int rc; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct smsdvb_client_t *client; - - client = container_of(fe, struct smsdvb_client_t, frontend); - - rc = smsdvb_send_statistics_request(client); - - *ucblocks = c->block_error.stat[0].uvalue; - - led_feedback(client); - - return rc; -} - -static int smsdvb_get_tune_settings(struct dvb_frontend *fe, - struct dvb_frontend_tune_settings *tune) -{ - sms_debug(""); - - tune->min_delay_ms = 400; - tune->step_size = 250000; - tune->max_drift = 0; - return 0; -} - -static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - struct { - struct SmsMsgHdr_ST Msg; - u32 Data[3]; - } Msg; - - int ret; - - client->fe_status = 0; - client->event_fe_state = -1; - client->event_unc_state = -1; - fe->dtv_property_cache.delivery_system = SYS_DVBT; - - Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - Msg.Msg.msgDstId = HIF_TASK; - Msg.Msg.msgFlags = 0; - Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ; - Msg.Msg.msgLength = sizeof(Msg); - Msg.Data[0] = c->frequency; - Msg.Data[2] = 12000000; - - sms_info("%s: freq %d band %d", __func__, c->frequency, - c->bandwidth_hz); - - switch (c->bandwidth_hz / 1000000) { - case 8: - Msg.Data[1] = BW_8_MHZ; - break; - case 7: - Msg.Data[1] = BW_7_MHZ; - break; - case 6: - Msg.Data[1] = BW_6_MHZ; - break; - case 0: - return -EOPNOTSUPP; - default: - return -EINVAL; - } - /* Disable LNA, if any. An error is returned if no LNA is present */ - ret = sms_board_lna_control(client->coredev, 0); - if (ret == 0) { - fe_status_t status; - - /* tune with LNA off at first */ - ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); - - smsdvb_read_status(fe, &status); - - if (status & FE_HAS_LOCK) - return ret; - - /* previous tune didn't lock - enable LNA and tune again */ - sms_board_lna_control(client->coredev, 1); - } - - return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); -} - -static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - int board_id = smscore_get_board_id(client->coredev); - struct sms_board *board = sms_get_board(board_id); - enum sms_device_type_st type = board->type; - int ret; - struct { - struct SmsMsgHdr_ST Msg; - u32 Data[4]; - } Msg; - - fe->dtv_property_cache.delivery_system = SYS_ISDBT; - - Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - Msg.Msg.msgDstId = HIF_TASK; - Msg.Msg.msgFlags = 0; - Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ; - Msg.Msg.msgLength = sizeof(Msg); - - if (c->isdbt_sb_segment_idx == -1) - c->isdbt_sb_segment_idx = 0; - - if (!c->isdbt_layer_enabled) - c->isdbt_layer_enabled = 7; - - Msg.Data[0] = c->frequency; - Msg.Data[1] = BW_ISDBT_1SEG; - Msg.Data[2] = 12000000; - Msg.Data[3] = c->isdbt_sb_segment_idx; - - if (c->isdbt_partial_reception) { - if ((type == SMS_PELE || type == SMS_RIO) && - c->isdbt_sb_segment_count > 3) - Msg.Data[1] = BW_ISDBT_13SEG; - else if (c->isdbt_sb_segment_count > 1) - Msg.Data[1] = BW_ISDBT_3SEG; - } else if (type == SMS_PELE || type == SMS_RIO) - Msg.Data[1] = BW_ISDBT_13SEG; - - c->bandwidth_hz = 6000000; - - sms_info("%s: freq %d segwidth %d segindex %d\n", __func__, - c->frequency, c->isdbt_sb_segment_count, - c->isdbt_sb_segment_idx); - - /* Disable LNA, if any. An error is returned if no LNA is present */ - ret = sms_board_lna_control(client->coredev, 0); - if (ret == 0) { - fe_status_t status; - - /* tune with LNA off at first */ - ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); - - smsdvb_read_status(fe, &status); - - if (status & FE_HAS_LOCK) - return ret; - - /* previous tune didn't lock - enable LNA and tune again */ - sms_board_lna_control(client->coredev, 1); - } - return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), - &client->tune_done); -} - -static int smsdvb_set_frontend(struct dvb_frontend *fe) -{ - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - struct smscore_device_t *coredev = client->coredev; - - smsdvb_stats_not_ready(fe); - - switch (smscore_get_device_mode(coredev)) { - case DEVICE_MODE_DVBT: - case DEVICE_MODE_DVBT_BDA: - return smsdvb_dvbt_set_frontend(fe); - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - return smsdvb_isdbt_set_frontend(fe); - default: - return -EINVAL; - } -} - -/* Nothing to do here, as stats are automatically updated */ -static int smsdvb_get_frontend(struct dvb_frontend *fe) -{ - return 0; -} - -static int smsdvb_init(struct dvb_frontend *fe) -{ - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - sms_board_power(client->coredev, 1); - - sms_board_dvb3_event(client, DVB3_EVENT_INIT); - return 0; -} - -static int smsdvb_sleep(struct dvb_frontend *fe) -{ - struct smsdvb_client_t *client = - container_of(fe, struct smsdvb_client_t, frontend); - - sms_board_led_feedback(client->coredev, SMS_LED_OFF); - sms_board_power(client->coredev, 0); - - sms_board_dvb3_event(client, DVB3_EVENT_SLEEP); - - return 0; -} - -static void smsdvb_release(struct dvb_frontend *fe) -{ - /* do nothing */ -} - -static struct dvb_frontend_ops smsdvb_fe_ops = { - .info = { - .name = "Siano Mobile Digital MDTV Receiver", - .frequency_min = 44250000, - .frequency_max = 867250000, - .frequency_stepsize = 250000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_RECOVER | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = smsdvb_release, - - .set_frontend = smsdvb_set_frontend, - .get_frontend = smsdvb_get_frontend, - .get_tune_settings = smsdvb_get_tune_settings, - - .read_status = smsdvb_read_status, - .read_ber = smsdvb_read_ber, - .read_signal_strength = smsdvb_read_signal_strength, - .read_snr = smsdvb_read_snr, - .read_ucblocks = smsdvb_read_ucblocks, - - .init = smsdvb_init, - .sleep = smsdvb_sleep, -}; - -static int smsdvb_hotplug(struct smscore_device_t *coredev, - struct device *device, int arrival) -{ - struct smsclient_params_t params; - struct smsdvb_client_t *client; - int rc; - - /* device removal handled by onremove callback */ - if (!arrival) - return 0; - client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL); - if (!client) { - sms_err("kmalloc() failed"); - return -ENOMEM; - } - - /* register dvb adapter */ - rc = dvb_register_adapter(&client->adapter, - sms_get_board( - smscore_get_board_id(coredev))->name, - THIS_MODULE, device, adapter_nr); - if (rc < 0) { - sms_err("dvb_register_adapter() failed %d", rc); - goto adapter_error; - } - - /* init dvb demux */ - client->demux.dmx.capabilities = DMX_TS_FILTERING; - client->demux.filternum = 32; /* todo: nova ??? */ - client->demux.feednum = 32; - client->demux.start_feed = smsdvb_start_feed; - client->demux.stop_feed = smsdvb_stop_feed; - - rc = dvb_dmx_init(&client->demux); - if (rc < 0) { - sms_err("dvb_dmx_init failed %d", rc); - goto dvbdmx_error; - } - - /* init dmxdev */ - client->dmxdev.filternum = 32; - client->dmxdev.demux = &client->demux.dmx; - client->dmxdev.capabilities = 0; - - rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter); - if (rc < 0) { - sms_err("dvb_dmxdev_init failed %d", rc); - goto dmxdev_error; - } - - /* init and register frontend */ - memcpy(&client->frontend.ops, &smsdvb_fe_ops, - sizeof(struct dvb_frontend_ops)); - - switch (smscore_get_device_mode(coredev)) { - case DEVICE_MODE_DVBT: - case DEVICE_MODE_DVBT_BDA: - client->frontend.ops.delsys[0] = SYS_DVBT; - break; - case DEVICE_MODE_ISDBT: - case DEVICE_MODE_ISDBT_BDA: - client->frontend.ops.delsys[0] = SYS_ISDBT; - break; - } - - rc = dvb_register_frontend(&client->adapter, &client->frontend); - if (rc < 0) { - sms_err("frontend registration failed %d", rc); - goto frontend_error; - } - - params.initial_id = 1; - params.data_type = MSG_SMS_DVBT_BDA_DATA; - params.onresponse_handler = smsdvb_onresponse; - params.onremove_handler = smsdvb_onremove; - params.context = client; - - rc = smscore_register_client(coredev, ¶ms, &client->smsclient); - if (rc < 0) { - sms_err("smscore_register_client() failed %d", rc); - goto client_error; - } - - client->coredev = coredev; - - init_completion(&client->tune_done); - init_completion(&client->stats_done); - - kmutex_lock(&g_smsdvb_clientslock); - - list_add(&client->entry, &g_smsdvb_clients); - - kmutex_unlock(&g_smsdvb_clientslock); - - client->event_fe_state = -1; - client->event_unc_state = -1; - sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG); - - sms_info("success"); - sms_board_setup(coredev); - - if (create_stats_debugfs(client) < 0) - sms_info("failed to create debugfs node"); - - return 0; - -client_error: - dvb_unregister_frontend(&client->frontend); - -frontend_error: - dvb_dmxdev_release(&client->dmxdev); - -dmxdev_error: - dvb_dmx_release(&client->demux); - -dvbdmx_error: - dvb_unregister_adapter(&client->adapter); - -adapter_error: - kfree(client); - return rc; -} - -static int __init smsdvb_module_init(void) -{ - int rc; - struct dentry *d; - - INIT_LIST_HEAD(&g_smsdvb_clients); - kmutex_init(&g_smsdvb_clientslock); - - d = debugfs_create_dir("smsdvb", usb_debug_root); - if (IS_ERR_OR_NULL(d)) - sms_err("Couldn't create sysfs node for smsdvb"); - else - smsdvb_debugfs = d; - - rc = smscore_register_hotplug(smsdvb_hotplug); - - sms_debug(""); - - return rc; -} - -static void __exit smsdvb_module_exit(void) -{ - smscore_unregister_hotplug(smsdvb_hotplug); - - kmutex_lock(&g_smsdvb_clientslock); - - while (!list_empty(&g_smsdvb_clients)) - smsdvb_unregister_client( - (struct smsdvb_client_t *) g_smsdvb_clients.next); - - if (smsdvb_debugfs) - debugfs_remove_recursive(smsdvb_debugfs); - - kmutex_unlock(&g_smsdvb_clientslock); -} - -module_init(smsdvb_module_init); -module_exit(smsdvb_module_exit); - -MODULE_DESCRIPTION("SMS DVB subsystem adaptation module"); -MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/siano/smsdvb.h b/drivers/media/common/siano/smsdvb.h new file mode 100644 index 000000000000..09982bcf2535 --- /dev/null +++ b/drivers/media/common/siano/smsdvb.h @@ -0,0 +1,124 @@ +/*********************************************************************** + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + ***********************************************************************/ + +struct smsdvb_debugfs; +struct smsdvb_client_t; + +typedef void (*sms_prt_dvb_stats_t)(struct smsdvb_debugfs *debug_data, + struct SMSHOSTLIB_STATISTICS_ST *p); + +typedef void (*sms_prt_isdb_stats_t)(struct smsdvb_debugfs *debug_data, + struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p); + +typedef void (*sms_prt_isdb_stats_ex_t) + (struct smsdvb_debugfs *debug_data, + struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p); + + +struct smsdvb_client_t { + struct list_head entry; + + struct smscore_device_t *coredev; + struct smscore_client_t *smsclient; + + struct dvb_adapter adapter; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dvb_frontend frontend; + + fe_status_t fe_status; + + struct completion tune_done; + struct completion stats_done; + + int last_per; + + int legacy_ber, legacy_per; + + int event_fe_state; + int event_unc_state; + + /* Stats debugfs data */ + struct dentry *debugfs; + + struct smsdvb_debugfs *debug_data; + + sms_prt_dvb_stats_t prt_dvb_stats; + sms_prt_isdb_stats_t prt_isdb_stats; + sms_prt_isdb_stats_ex_t prt_isdb_stats_ex; +}; + +/* + * This struct is a mix of RECEPTION_STATISTICS_EX_S and SRVM_SIGNAL_STATUS_S. + * It was obtained by comparing the way it was filled by the original code + */ +struct RECEPTION_STATISTICS_PER_SLICES_S { + u32 result; + u32 snr; + s32 inBandPower; + u32 tsPackets; + u32 etsPackets; + u32 constellation; + u32 hpCode; + u32 tpsSrvIndLP; + u32 tpsSrvIndHP; + u32 cellId; + u32 reason; + u32 requestId; + u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ + + u32 BER; /* Post Viterbi BER [1E-5] */ + s32 RSSI; /* dBm */ + s32 CarrierOffset; /* Carrier Offset in bin/1024 */ + + u32 IsRfLocked; /* 0 - not locked, 1 - locked */ + u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + + u32 BERBitCount; /* Total number of SYNC bits. */ + u32 BERErrorCount; /* Number of erronous SYNC bits. */ + + s32 MRC_SNR; /* dB */ + s32 MRC_InBandPwr; /* In band power in dBM */ + s32 MRC_RSSI; /* dBm */ +}; + +/* From smsdvb-debugfs.c */ +#ifdef CONFIG_SMS_SIANO_DEBUGFS + +int smsdvb_debugfs_create(struct smsdvb_client_t *client); +void smsdvb_debugfs_release(struct smsdvb_client_t *client); +int smsdvb_debugfs_register(void); +void smsdvb_debugfs_unregister(void); + +#else + +static inline int smsdvb_debugfs_create(struct smsdvb_client_t *client) +{ + return 0; +} + +static inline void smsdvb_debugfs_release(struct smsdvb_client_t *client) {} + +static inline int smsdvb_debugfs_register(void) +{ + return 0; +}; + +static inline void smsdvb_debugfs_unregister(void) {}; + +#endif + diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index acd3d1e82e03..def5e41405a4 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -412,6 +412,8 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) smscore_set_board_id(dev->coredev, board_id); + dev->coredev->is_usb_device = true; + /* initialize urbs */ for (i = 0; i < MAX_URBS; i++) { dev->surbs[i].dev = dev; -- cgit v1.2.3 From 4cce1f4eb29765def538e7c975dac73346a0d306 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 16 Mar 2013 14:32:25 -0300 Subject: [media] siano: add two missing fields to ISDB-T stats debugfs Those fields help to identify the version of the ISDB stats. Useful while debuging the driver. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb-debugfs.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index 4d5dd471e2e1..59c7323f98d4 100644 --- a/drivers/media/common/siano/smsdvb-debugfs.c +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -165,6 +165,11 @@ void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data, buf = debug_data->stats_data; + n += snprintf(&buf[n], PAGE_SIZE - n, + "StatisticsType = %d\t", p->StatisticsType); + n += snprintf(&buf[n], PAGE_SIZE - n, + "FullSize = %d\n", p->FullSize); + n += snprintf(&buf[n], PAGE_SIZE - n, "IsRfLocked = %d\t\t", p->IsRfLocked); n += snprintf(&buf[n], PAGE_SIZE - n, @@ -250,6 +255,11 @@ void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data, buf = debug_data->stats_data; + n += snprintf(&buf[n], PAGE_SIZE - n, + "StatisticsType = %d\t", p->StatisticsType); + n += snprintf(&buf[n], PAGE_SIZE - n, + "FullSize = %d\n", p->FullSize); + n += snprintf(&buf[n], PAGE_SIZE - n, "IsRfLocked = %d\t\t", p->IsRfLocked); n += snprintf(&buf[n], PAGE_SIZE - n, -- cgit v1.2.3 From a9b9fbdf0a6a65359cd97254a282526822de5257 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 10 Mar 2013 10:51:25 -0300 Subject: [media] siano: don't request statistics too fast As each DVBv3 call may generate an stats overhead, prevent doing it too fast. This is specially useful if a burst of get stats DVBv3 call is sent. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb-main.c | 5 +++++ drivers/media/common/siano/smsdvb.h | 2 ++ 2 files changed, 7 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index c14f10d5d6c0..4242005082ed 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -663,6 +663,11 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) int rc; struct SmsMsgHdr_ST Msg; + /* Don't request stats too fast */ + if (client->get_stats_jiffies && + (!time_after(jiffies, client->get_stats_jiffies))) + return 0; + client->get_stats_jiffies = jiffies + msecs_to_jiffies(100); Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; Msg.msgDstId = HIF_TASK; diff --git a/drivers/media/common/siano/smsdvb.h b/drivers/media/common/siano/smsdvb.h index 09982bcf2535..34220696d87d 100644 --- a/drivers/media/common/siano/smsdvb.h +++ b/drivers/media/common/siano/smsdvb.h @@ -52,6 +52,8 @@ struct smsdvb_client_t { int event_fe_state; int event_unc_state; + unsigned long get_stats_jiffies; + /* Stats debugfs data */ struct dentry *debugfs; -- cgit v1.2.3 From f5de95e2467b7b6b968e6c67489425265dd2a1c2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 10 Mar 2013 12:06:30 -0300 Subject: [media] siano: fix signal strength and CNR stats measurements There are a number of small issues with the stats refactoring: - InBandPwr better represents the signal strength; - Don't zero signal strength /cnr if no lock; - Fix signal strength/cnr scale; - Don't need to fill PER/BER if not locked, as the code will disable those stats anyway. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb-main.c | 57 ++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 22 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index 4242005082ed..90f6e894e593 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -155,11 +155,11 @@ static void smsdvb_stats_not_ready(struct dvb_frontend *fe) n_layers = 1; } - /* Fill the length of each status counter */ - - /* Only global stats */ + /* Global stats */ c->strength.len = 1; c->cnr.len = 1; + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; /* Per-layer stats */ c->post_bit_error.len = n_layers; @@ -167,13 +167,11 @@ static void smsdvb_stats_not_ready(struct dvb_frontend *fe) c->block_error.len = n_layers; c->block_count.len = n_layers; - /* Signal is always available */ - c->strength.stat[0].scale = FE_SCALE_RELATIVE; - c->strength.stat[0].uvalue = 0; - - /* Put all of them at FE_SCALE_NOT_AVAILABLE */ + /* + * Put all of them at FE_SCALE_NOT_AVAILABLE. They're dynamically + * changed when the stats become available. + */ for (i = 0; i < n_layers; i++) { - c->cnr.stat[i].scale = FE_SCALE_NOT_AVAILABLE; c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; @@ -261,6 +259,16 @@ static void smsdvb_update_per_slices(struct smsdvb_client_t *client, client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked); c->modulation = sms_to_modulation(p->constellation); + /* Signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->inBandPower * 1000; + + /* Carrier to Noise ratio, in DB */ + c->cnr.stat[0].svalue = p->snr * 1000; + + /* PER/BER requires demod lock */ + if (!p->IsDemodLocked) + return; + /* TS PER */ client->last_per = c->block_error.stat[0].uvalue; c->block_error.stat[0].scale = FE_SCALE_COUNTER; @@ -277,13 +285,6 @@ static void smsdvb_update_per_slices(struct smsdvb_client_t *client, /* Legacy PER/BER */ client->legacy_per = (p->etsPackets * 65535) / (p->tsPackets + p->etsPackets); - - /* Signal Strength, in DBm */ - c->strength.stat[0].uvalue = p->RSSI * 1000; - - /* Carrier to Noise ratio, in DB */ - c->cnr.stat[0].scale = FE_SCALE_DECIBEL; - c->cnr.stat[0].svalue = p->snr * 1000; } static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client, @@ -312,11 +313,14 @@ static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client, c->lna = p->IsExternalLNAOn ? 1 : 0; /* Carrier to Noise ratio, in DB */ - c->cnr.stat[0].scale = FE_SCALE_DECIBEL; c->cnr.stat[0].svalue = p->SNR * 1000; /* Signal Strength, in DBm */ - c->strength.stat[0].uvalue = p->RSSI * 1000; + c->strength.stat[0].uvalue = p->InBandPwr * 1000; + + /* PER/BER requires demod lock */ + if (!p->IsDemodLocked) + return; /* TS PER */ client->last_per = c->block_error.stat[0].uvalue; @@ -364,11 +368,14 @@ static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, c->lna = p->IsExternalLNAOn ? 1 : 0; /* Carrier to Noise ratio, in DB */ - c->cnr.stat[0].scale = FE_SCALE_DECIBEL; c->cnr.stat[0].svalue = p->SNR * 1000; /* Signal Strength, in DBm */ - c->strength.stat[0].uvalue = p->RSSI * 1000; + c->strength.stat[0].uvalue = p->InBandPwr * 1000; + + /* PER/BER and per-layer stats require demod lock */ + if (!p->IsDemodLocked) + return; client->last_per = c->block_error.stat[0].uvalue; @@ -441,11 +448,14 @@ static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, c->lna = p->IsExternalLNAOn ? 1 : 0; /* Carrier to Noise ratio, in DB */ - c->cnr.stat[0].scale = FE_SCALE_DECIBEL; c->cnr.stat[0].svalue = p->SNR * 1000; /* Signal Strength, in DBm */ - c->strength.stat[0].uvalue = p->RSSI * 1000; + c->strength.stat[0].uvalue = p->InBandPwr * 1000; + + /* PER/BER and per-layer stats require demod lock */ + if (!p->IsDemodLocked) + return; client->last_per = c->block_error.stat[0].uvalue; @@ -943,11 +953,14 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) static int smsdvb_set_frontend(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct smsdvb_client_t *client = container_of(fe, struct smsdvb_client_t, frontend); struct smscore_device_t *coredev = client->coredev; smsdvb_stats_not_ready(fe); + c->strength.stat[0].uvalue = 0; + c->cnr.stat[0].uvalue = 0; switch (smscore_get_device_mode(coredev)) { case DEVICE_MODE_DVBT: -- cgit v1.2.3 From 9671045f4ce7a9e5eedc669a6921aeec26bd095e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 10 Mar 2013 13:38:41 -0300 Subject: [media] siano: fix PER/BER report on DVBv5 The check for lock logic is broken. Due to that, no PER/BER stats will ever be showed, and the DVBV3 events will be wrong. Also, the per-layer PER/BER stats for ISDB-T are filled with the wrong index. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb-main.c | 46 ++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index 90f6e894e593..632a250a42cf 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -382,8 +382,12 @@ static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, /* Clears global counters, as the code below will sum it again */ c->block_error.stat[0].uvalue = 0; c->block_count.stat[0].uvalue = 0; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; c->post_bit_error.stat[0].uvalue = 0; c->post_bit_count.stat[0].uvalue = 0; + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; for (i = 0; i < n_layers; i++) { lr = &p->LayerInfo[i]; @@ -398,20 +402,20 @@ static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, c->layer[i].modulation = sms_to_modulation(lr->Constellation); /* TS PER */ - c->block_error.stat[i].scale = FE_SCALE_COUNTER; - c->block_count.stat[i].scale = FE_SCALE_COUNTER; - c->block_error.stat[i].uvalue += lr->ErrorTSPackets; - c->block_count.stat[i].uvalue += lr->TotalTSPackets; + c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER; + c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER; + c->block_error.stat[i + 1].uvalue += lr->ErrorTSPackets; + c->block_count.stat[i + 1].uvalue += lr->TotalTSPackets; /* Update global PER counter */ c->block_error.stat[0].uvalue += lr->ErrorTSPackets; c->block_count.stat[0].uvalue += lr->TotalTSPackets; /* BER */ - c->post_bit_error.stat[i].scale = FE_SCALE_COUNTER; - c->post_bit_count.stat[i].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[i].uvalue += lr->BERErrorCount; - c->post_bit_count.stat[i].uvalue += lr->BERBitCount; + c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[i + 1].uvalue += lr->BERErrorCount; + c->post_bit_count.stat[i + 1].uvalue += lr->BERBitCount; /* Update global BER counter */ c->post_bit_error.stat[0].uvalue += lr->BERErrorCount; @@ -462,9 +466,17 @@ static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, /* Clears global counters, as the code below will sum it again */ c->block_error.stat[0].uvalue = 0; c->block_count.stat[0].uvalue = 0; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; c->post_bit_error.stat[0].uvalue = 0; c->post_bit_count.stat[0].uvalue = 0; + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.len = n_layers + 1; + c->post_bit_count.len = n_layers + 1; + c->block_error.len = n_layers + 1; + c->block_count.len = n_layers + 1; for (i = 0; i < n_layers; i++) { lr = &p->LayerInfo[i]; @@ -478,20 +490,20 @@ static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, c->layer[i].modulation = sms_to_modulation(lr->Constellation); /* TS PER */ - c->block_error.stat[i].scale = FE_SCALE_COUNTER; - c->block_count.stat[i].scale = FE_SCALE_COUNTER; - c->block_error.stat[i].uvalue += lr->ErrorTSPackets; - c->block_count.stat[i].uvalue += lr->TotalTSPackets; + c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER; + c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER; + c->block_error.stat[i + 1].uvalue += lr->ErrorTSPackets; + c->block_count.stat[i + 1].uvalue += lr->TotalTSPackets; /* Update global PER counter */ c->block_error.stat[0].uvalue += lr->ErrorTSPackets; c->block_count.stat[0].uvalue += lr->TotalTSPackets; /* BER */ - c->post_bit_error.stat[i].scale = FE_SCALE_COUNTER; - c->post_bit_count.stat[i].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[i].uvalue += lr->BERErrorCount; - c->post_bit_count.stat[i].uvalue += lr->BERBitCount; + c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[i + 1].uvalue += lr->BERErrorCount; + c->post_bit_count.stat[i + 1].uvalue += lr->BERBitCount; /* Update global BER counter */ c->post_bit_error.stat[0].uvalue += lr->BERErrorCount; @@ -572,7 +584,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) smscore_putbuffer(client->coredev, cb); if (is_status_update) { - if (client->fe_status == FE_HAS_LOCK) { + if (client->fe_status & FE_HAS_LOCK) { sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK); if (client->last_per == c->block_error.stat[0].uvalue) sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK); -- cgit v1.2.3 From 5c3b87435b291efb260aec37fdbe397859e550c5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 10 Mar 2013 19:21:13 -0300 Subject: [media] siano: Fix bandwidth report It was expected that the bandwidth would be following the defines at smscoreapi.h. However, this doesn't work. Instead, this field brings just the bandwidth in MHz. Convert it to Hertz. It should be noticed that, on ISDB, using the _EX request, the field TuneBW seems to show the value that matches the bandwidth code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb-main.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index 632a250a42cf..d83896bb98fd 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -43,18 +43,6 @@ module_param_named(debug, sms_dbg, int, 0644); MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))"); -u32 sms_to_bw_table[] = { - [BW_8_MHZ] = 8000000, - [BW_7_MHZ] = 7000000, - [BW_6_MHZ] = 6000000, - [BW_5_MHZ] = 5000000, - [BW_2_MHZ] = 2000000, - [BW_1_5_MHZ] = 1500000, - [BW_ISDBT_1SEG] = 6000000, - [BW_ISDBT_3SEG] = 6000000, - [BW_ISDBT_13SEG] = 6000000, -}; - u32 sms_to_guard_interval_table[] = { [0] = GUARD_INTERVAL_1_32, [1] = GUARD_INTERVAL_1_16, @@ -204,6 +192,10 @@ static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked) return 0; } +static inline u32 sms_to_bw(u32 value) +{ + return value * 1000000; +} #define convert_from_table(value, table, defval) ({ \ u32 __ret; \ @@ -214,9 +206,6 @@ static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked) __ret; \ }) -#define sms_to_bw(value) \ - convert_from_table(value, sms_to_bw_table, 0); - #define sms_to_guard_interval(value) \ convert_from_table(value, sms_to_guard_interval_table, \ GUARD_INTERVAL_AUTO); -- cgit v1.2.3 From e1b2ac4d1e6bb214823c42bb807a6cc5f21aa223 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 15 Mar 2013 07:22:08 -0300 Subject: [media] siano: Only feed DVB data when there's a feed Right now, the driver sends DVB data even before tunning. It was noticed that this may lead into some mistakes at DVB decode, as the PIDs from wrong channels may be associated with another frequency, as they may already be inside the PID buffers. So, prevent it by not feeding DVB demux with data while there's no feed or while the device is not tuned. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb-main.c | 18 +++++++++++++++--- drivers/media/common/siano/smsdvb.h | 3 +++ 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index d83896bb98fd..4393c688d0ad 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -512,8 +512,13 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) switch (phdr->msgType) { case MSG_SMS_DVBT_BDA_DATA: - dvb_dmx_swfilter(&client->demux, p, - cb->size - sizeof(struct SmsMsgHdr_ST)); + /* + * Only feed data to dvb demux if are there any feed listening + * to it and if the device has tuned + */ + if (client->feed_users && client->has_tuned) + dvb_dmx_swfilter(&client->demux, p, + cb->size - sizeof(struct SmsMsgHdr_ST)); break; case MSG_SMS_RF_TUNE_RES: @@ -579,9 +584,10 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK); else sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR); + client->has_tuned = true; } else { smsdvb_stats_not_ready(fe); - + client->has_tuned = false; sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK); } complete(&client->stats_done); @@ -623,6 +629,8 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed) sms_debug("add pid %d(%x)", feed->pid, feed->pid); + client->feed_users++; + PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; PidMsg.xMsgHeader.msgDstId = HIF_TASK; PidMsg.xMsgHeader.msgFlags = 0; @@ -643,6 +651,8 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed) sms_debug("remove pid %d(%x)", feed->pid, feed->pid); + client->feed_users--; + PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; PidMsg.xMsgHeader.msgDstId = HIF_TASK; PidMsg.xMsgHeader.msgFlags = 0; @@ -963,6 +973,8 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe) c->strength.stat[0].uvalue = 0; c->cnr.stat[0].uvalue = 0; + client->has_tuned = false; + switch (smscore_get_device_mode(coredev)) { case DEVICE_MODE_DVBT: case DEVICE_MODE_DVBT_BDA: diff --git a/drivers/media/common/siano/smsdvb.h b/drivers/media/common/siano/smsdvb.h index 34220696d87d..63cdd755521e 100644 --- a/drivers/media/common/siano/smsdvb.h +++ b/drivers/media/common/siano/smsdvb.h @@ -54,6 +54,9 @@ struct smsdvb_client_t { unsigned long get_stats_jiffies; + int feed_users; + bool has_tuned; + /* Stats debugfs data */ struct dentry *debugfs; -- cgit v1.2.3 From 773adad14135999380a4652b4ba01c5694827870 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 16 Mar 2013 21:05:30 -0300 Subject: [media] siano: fix status report with old firmware and ISDB-T This seems to be ever broken. That's the status report with Firmware 2.1, before adding support for sms2270 is: [22273.787218] smsdvb_onresponse: MSG_SMS_GET_STATISTICS_RES [22273.792592] IsRfLocked = 1 [22273.792592] IsDemodLocked = 1 ... [22273.792598] TransmissionMode = -64 ... (all unshown fields are filled with zeros) Of course, transmission mode being a negative number is wrong. So, we need to take a deeper look on it. With the debugfs patches applied, it is possible to see that, instead of filling StatisticsType with 5, and FullSize with the size of the payload (this is what happens with sms2270 and firmware 8.1), those fields are also initialized with zero: StatisticsType = 0 FullSize = 0 IsRfLocked = 1 IsDemodLocked = 1 IsExternalLNAOn = 0 SNR = 0 dB RSSI = 0 dBm InBandPwr = 0 dBm CarrierOffset = 0 Bandwidth = 0 Frequency = 0 Hz TransmissionMode = -64 ModemState = 0 GuardInterval = 0 SystemType = 0 PartialReception = 0 NumOfLayers = 0 SmsToHostTxErrors = 0 The data under "TransmissionMode" varies according with the signal, and it is negative. It also matches the value for InBandPwr when the tuner is on DVB-T (ok, signal doesn't lock, but the power level should be about the same with the antena fixed, and measured at about the same time). So, there's a very high chance that, when StatisticsType is zero, the signal strength is at the same position as Transmission Mode. So, discard all other parameters, and provide only signal/rf lock and signal strength if StatisticsType is 0, for ISDB-T. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb-main.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index 4393c688d0ad..c53cb4e8d0c6 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -339,9 +339,21 @@ static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, if (client->prt_isdb_stats) client->prt_isdb_stats(client->debug_data, p); + client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked); + + /* + * Firmware 2.1 seems to report only lock status and + * Signal strength. The signal strength indicator is at the + * wrong field. + */ + if (p->StatisticsType == 0) { + c->strength.stat[0].uvalue = ((s32)p->TransmissionMode) * 1000; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + /* Update ISDB-T transmission parameters */ c->frequency = p->Frequency; - client->fe_status = sms_to_status(p->IsDemodLocked, 0); c->bandwidth_hz = sms_to_bw(p->Bandwidth); c->transmission_mode = sms_to_mode(p->TransmissionMode); c->guard_interval = sms_to_guard_interval(p->GuardInterval); -- cgit v1.2.3 From 6a28bd94f4d068b6de65517e52f52b6840603d0a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 17 Mar 2013 10:27:44 -0300 Subject: [media] siano: add support for .poll on debugfs Implement poll() method for debugfs and be sure that the debug_data won't be freed on ir or on read(). With this change, poll() will return POLLIN if either data was filled or if data was read. That allows read() to return 0 to indicate EOF in the latter case. As poll() is now provided, fix support for non-block mode. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb-debugfs.c | 77 ++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 18 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index 59c7323f98d4..0219be36c289 100644 --- a/drivers/media/common/siano/smsdvb-debugfs.c +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -352,6 +352,14 @@ static int smsdvb_stats_open(struct inode *inode, struct file *file) return 0; } +static void smsdvb_debugfs_data_release(struct kref *ref) +{ + struct smsdvb_debugfs *debug_data; + + debug_data = container_of(ref, struct smsdvb_debugfs, refcount); + kfree(debug_data); +} + static int smsdvb_stats_wait_read(struct smsdvb_debugfs *debug_data) { int rc = 1; @@ -368,33 +376,65 @@ exit: return rc; } -static ssize_t smsdvb_stats_read(struct file *file, char __user *user_buf, - size_t nbytes, loff_t *ppos) +static unsigned int smsdvb_stats_poll(struct file *file, poll_table *wait) { - int rc = 0; struct smsdvb_debugfs *debug_data = file->private_data; + int rc; - rc = wait_event_interruptible(debug_data->stats_queue, - smsdvb_stats_wait_read(debug_data)); - if (rc < 0) - return rc; + kref_get(&debug_data->refcount); - rc = simple_read_from_buffer(user_buf, nbytes, ppos, - debug_data->stats_data, - debug_data->stats_count); - spin_lock(&debug_data->lock); - debug_data->stats_was_read = true; - spin_unlock(&debug_data->lock); + poll_wait(file, &debug_data->stats_queue, wait); + + rc = smsdvb_stats_wait_read(debug_data); + if (rc > 0) + rc = POLLIN | POLLRDNORM; + + kref_put(&debug_data->refcount, smsdvb_debugfs_data_release); return rc; } -static void smsdvb_debugfs_data_release(struct kref *ref) +static ssize_t smsdvb_stats_read(struct file *file, char __user *user_buf, + size_t nbytes, loff_t *ppos) { - struct smsdvb_debugfs *debug_data; + int rc = 0, len; + struct smsdvb_debugfs *debug_data = file->private_data; - debug_data = container_of(ref, struct smsdvb_debugfs, refcount); - kfree(debug_data); + kref_get(&debug_data->refcount); + + if (file->f_flags & O_NONBLOCK) { + rc = smsdvb_stats_wait_read(debug_data); + if (!rc) { + rc = -EWOULDBLOCK; + goto ret; + } + } else { + rc = wait_event_interruptible(debug_data->stats_queue, + smsdvb_stats_wait_read(debug_data)); + if (rc < 0) + goto ret; + } + + if (debug_data->stats_was_read) { + rc = 0; /* EOF */ + goto ret; + } + + len = debug_data->stats_count - *ppos; + if (len >= 0) + rc = simple_read_from_buffer(user_buf, nbytes, ppos, + debug_data->stats_data, len); + else + rc = 0; + + if (*ppos >= debug_data->stats_count) { + spin_lock(&debug_data->lock); + debug_data->stats_was_read = true; + spin_unlock(&debug_data->lock); + } +ret: + kref_put(&debug_data->refcount, smsdvb_debugfs_data_release); + return rc; } static int smsdvb_stats_release(struct inode *inode, struct file *file) @@ -402,7 +442,7 @@ static int smsdvb_stats_release(struct inode *inode, struct file *file) struct smsdvb_debugfs *debug_data = file->private_data; spin_lock(&debug_data->lock); - debug_data->stats_was_read = true; + debug_data->stats_was_read = true; /* return EOF to read() */ spin_unlock(&debug_data->lock); wake_up_interruptible_sync(&debug_data->stats_queue); @@ -414,6 +454,7 @@ static int smsdvb_stats_release(struct inode *inode, struct file *file) static const struct file_operations debugfs_stats_ops = { .open = smsdvb_stats_open, + .poll = smsdvb_stats_poll, .read = smsdvb_stats_read, .release = smsdvb_stats_release, .llseek = generic_file_llseek, -- cgit v1.2.3 From 5ac14b60118071631bb0e2e50527c7528675648c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Mar 2013 09:50:17 -0300 Subject: [media] siano: simplify firmware lookup logic There are two ways to specify firmware for siano devices: a per-device ID and a per-device type. The per-device type logic is currently made by a 11x9 string table, sparsely filled. It is very hard to read the table at the source code, as there are too much "none" filling there ("none" there is a way to tell NULL). Instead of using such problematic table, convert it into an easy to read table, where the unused values will be defaulted to NULL. While here, also simplifies a little bit the logic and print a message if an user-selected mode doesn't exist. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 91 +++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 37 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 8c576a6e3829..9b2f2b42bfbb 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1063,9 +1063,11 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, const struct firmware *fw; char *fw_filename = smscore_get_fw_filename(coredev, mode, lookup); - sms_debug("Firmware name: %s\n", fw_filename); - if (!strcmp(fw_filename, "none")) + if (!fw_filename) { + sms_info("mode %d not supported on this device", mode); return -ENOENT; + } + sms_debug("Firmware name: %s", fw_filename); if (loadfirmware_handler == NULL && !(coredev->device_flags & SMS_DEVICE_FAMILY2)) @@ -1198,32 +1200,53 @@ static int smscore_detect_mode(struct smscore_device_t *coredev) return rc; } -static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = { - /*Stellar, NOVA A0, Nova B0, VEGA, VENICE, MING, PELE, RIO, DENVER_1530, DENVER_2160 */ - /*DVBT*/ - { "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none", "none", "none", "none", "dvb_rio.inp", "none", "none" }, - /*DVBH*/ - { "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none", "none", "none", "none", "dvbh_rio.inp", "none", "none" }, - /*TDMB*/ - { "none", "tdmb_nova_12mhz.inp", "tdmb_nova_12mhz_b0.inp", "none", "none", "none", "none", "none", "none", "tdmb_denver.inp" }, - /*DABIP*/ - { "none", "none", "none", "none", "none", "none", "none", "none", "none", "none" }, - /*DVBT_BDA*/ - { "none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none", "none", "none", "none", "dvb_rio.inp", "none", "none" }, - /*ISDBT*/ - { "none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none", "none", "none", "isdbt_pele.inp", "isdbt_rio.inp", "none", "none" }, - /*ISDBT_BDA*/ - { "none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none", "none", "none", "isdbt_pele.inp", "isdbt_rio.inp", "none", "none" }, - /*CMMB*/ - { "none", "none", "none", "cmmb_vega_12mhz.inp", "cmmb_venice_12mhz.inp", "cmmb_ming_app.inp", "none", "none", "none", "none" }, - /*RAW - not supported*/ - { "none", "none", "none", "none", "none", "none", "none", "none", "none", "none" }, - /*FM*/ - { "none", "none", "fm_radio.inp", "none", "none", "none", "none", "fm_radio_rio.inp", "none", "none" }, - /*FM_BDA*/ - { "none", "none", "fm_radio.inp", "none", "none", "none", "none", "fm_radio_rio.inp", "none", "none" }, - /*ATSC*/ - { "none", "none", "none", "none", "none", "none", "none", "none", "atsc_denver.inp", "none" } +static char *smscore_fw_lkup[][DEVICE_MODE_MAX] = { + [SMS_NOVA_A0] = { + [DEVICE_MODE_DVBT] = "dvb_nova_12mhz.inp", + [DEVICE_MODE_DVBH] = "dvb_nova_12mhz.inp", + [DEVICE_MODE_DAB_TDMB] = "tdmb_nova_12mhz.inp", + [DEVICE_MODE_DVBT_BDA] = "dvb_nova_12mhz.inp", + [DEVICE_MODE_ISDBT] = "isdbt_nova_12mhz.inp", + [DEVICE_MODE_ISDBT_BDA] = "isdbt_nova_12mhz.inp", + }, + [SMS_NOVA_B0] = { + [DEVICE_MODE_DVBT] = "dvb_nova_12mhz_b0.inp", + [DEVICE_MODE_DVBH] = "dvb_nova_12mhz_b0.inp", + [DEVICE_MODE_DAB_TDMB] = "tdmb_nova_12mhz_b0.inp", + [DEVICE_MODE_DVBT_BDA] = "dvb_nova_12mhz_b0.inp", + [DEVICE_MODE_ISDBT] = "isdbt_nova_12mhz_b0.inp", + [DEVICE_MODE_ISDBT_BDA] = "isdbt_nova_12mhz_b0.inp", + [DEVICE_MODE_FM_RADIO] = "fm_radio.inp", + [DEVICE_MODE_FM_RADIO_BDA] = "fm_radio.inp", + }, + [SMS_VEGA] = { + [DEVICE_MODE_CMMB] = "cmmb_vega_12mhz.inp", + }, + [SMS_VENICE] = { + [DEVICE_MODE_CMMB] = "cmmb_venice_12mhz.inp", + }, + [SMS_MING] = { + [DEVICE_MODE_CMMB] = "cmmb_ming_app.inp", + }, + [SMS_PELE] = { + [DEVICE_MODE_ISDBT] = "isdbt_pele.inp", + [DEVICE_MODE_ISDBT_BDA] = "isdbt_pele.inp", + }, + [SMS_RIO] = { + [DEVICE_MODE_DVBT] = "dvb_rio.inp", + [DEVICE_MODE_DVBH] = "dvbh_rio.inp", + [DEVICE_MODE_DVBT_BDA] = "dvb_rio.inp", + [DEVICE_MODE_ISDBT] = "isdbt_rio.inp", + [DEVICE_MODE_ISDBT_BDA] = "isdbt_rio.inp", + [DEVICE_MODE_FM_RADIO] = "fm_radio_rio.inp", + [DEVICE_MODE_FM_RADIO_BDA] = "fm_radio_rio.inp", + }, + [SMS_DENVER_1530] = { + [DEVICE_MODE_ATSC] = "atsc_denver.inp", + }, + [SMS_DENVER_2160] = { + [DEVICE_MODE_DAB_TDMB] = "tdmb_denver.inp", + }, }; /** @@ -1249,22 +1272,16 @@ static char *smscore_get_fw_filename(struct smscore_device_t *coredev, if ((board_id == SMS_BOARD_UNKNOWN) || (lookup == 1)) { sms_debug("trying to get fw name from lookup table mode %d type %d", mode, type); - return smscore_fw_lkup[mode][type]; + return smscore_fw_lkup[type][mode]; } sms_debug("trying to get fw name from sms_boards board_id %d mode %d", board_id, mode); fw = sms_get_board(board_id)->fw; - if (fw == NULL) { - sms_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d", - mode, type); - return smscore_fw_lkup[mode][type]; - } - - if (fw[mode] == NULL) { + if (!fw || !fw[mode]) { sms_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d", mode, type); - return smscore_fw_lkup[mode][type]; + return smscore_fw_lkup[type][mode]; } return fw[mode]; -- cgit v1.2.3 From 9711a8a600a12d2895c18f31be1fc5b3c4d9b209 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 7 Mar 2013 11:40:45 -0300 Subject: [media] siano: honour per-card default mode Instead of using a global default_mode, passed via modprobe parameter, use the one defined inside the cards struct. That will prevent the need of manually specify it for each board, except, of course, if the user wants to do something different, on boards that accept multiple types. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 9b2f2b42bfbb..44040a60cd77 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -434,7 +434,7 @@ static struct mutex g_smscore_deviceslock; static struct list_head g_smscore_registry; static struct mutex g_smscore_registrylock; -static int default_mode = 4; +static int default_mode = DEVICE_MODE_NONE; module_param(default_mode, int, 0644); MODULE_PARM_DESC(default_mode, "default firmware id (device mode)"); @@ -880,8 +880,15 @@ int smscore_configure_board(struct smscore_device_t *coredev) */ int smscore_start_device(struct smscore_device_t *coredev) { - int rc = smscore_set_device_mode( - coredev, smscore_registry_getmode(coredev->devpath)); + int rc; + int board_id = smscore_get_board_id(coredev); + int mode = smscore_registry_getmode(coredev->devpath); + + /* Device is initialized as DEVICE_MODE_NONE */ + if (board_id != SMS_BOARD_UNKNOWN && mode == DEVICE_MODE_NONE) + mode = sms_get_board(board_id)->default_mode; + + rc = smscore_set_device_mode(coredev, mode); if (rc < 0) { sms_info("set device mode faile , rc %d", rc); return rc; @@ -1269,6 +1276,12 @@ static char *smscore_get_fw_filename(struct smscore_device_t *coredev, type = smscore_registry_gettype(coredev->devpath); + /* Prevent looking outside the smscore_fw_lkup table */ + if (type <= SMS_UNKNOWN_TYPE || type >= SMS_NUM_OF_DEVICE_TYPES) + return NULL; + if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) + return NULL; + if ((board_id == SMS_BOARD_UNKNOWN) || (lookup == 1)) { sms_debug("trying to get fw name from lookup table mode %d type %d", mode, type); @@ -1338,7 +1351,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) sms_debug("set device mode to %d", mode); if (coredev->device_flags & SMS_DEVICE_FAMILY2) { - if (mode < DEVICE_MODE_DVBT || mode >= DEVICE_MODE_RAW_TUNER) { + if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) { sms_err("invalid mode specified %d", mode); return -EINVAL; } @@ -1390,7 +1403,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) sms_err("device init failed, rc %d.", rc); } } else { - if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_MAX) { + if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) { sms_err("invalid mode specified %d", mode); return -EINVAL; } -- cgit v1.2.3 From e584f9d61ea0aefa81ddd3faf53100536ba4057e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Mar 2013 12:00:23 -0300 Subject: [media] siano: remove the bogus firmware lookup code There is an special lookup code that is called when SMS_BOARD_UNKNOWN. The logic there is bogus and will cause an oops, as .type is SMS_UNKNOWN_TYPE (-1). As the code would do: return smscore_fw_lkup[type][mode]; That would mean that it would try to go past the smscore_fw_lkup table. So, just remove that bogus code, simplifying the logic. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 44040a60cd77..d57df9170ae1 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1048,7 +1048,7 @@ exit_fw_download: static char *smscore_get_fw_filename(struct smscore_device_t *coredev, - int mode, int lookup); + int mode); /** * loads specified firmware into a buffer and calls device loadfirmware_handler @@ -1061,7 +1061,7 @@ static char *smscore_get_fw_filename(struct smscore_device_t *coredev, * @return 0 on success, <0 on error. */ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, - int mode, int lookup, + int mode, loadfirmware_t loadfirmware_handler) { int rc = -ENOENT; @@ -1069,7 +1069,7 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, u32 fw_buf_size; const struct firmware *fw; - char *fw_filename = smscore_get_fw_filename(coredev, mode, lookup); + char *fw_filename = smscore_get_fw_filename(coredev, mode); if (!fw_filename) { sms_info("mode %d not supported on this device", mode); return -ENOENT; @@ -1268,7 +1268,7 @@ static char *smscore_fw_lkup[][DEVICE_MODE_MAX] = { * @return 0 on success, <0 on error. */ static char *smscore_get_fw_filename(struct smscore_device_t *coredev, - int mode, int lookup) + int mode) { char **fw; int board_id = smscore_get_board_id(coredev); @@ -1282,12 +1282,6 @@ static char *smscore_get_fw_filename(struct smscore_device_t *coredev, if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) return NULL; - if ((board_id == SMS_BOARD_UNKNOWN) || (lookup == 1)) { - sms_debug("trying to get fw name from lookup table mode %d type %d", - mode, type); - return smscore_fw_lkup[type][mode]; - } - sms_debug("trying to get fw name from sms_boards board_id %d mode %d", board_id, mode); fw = sms_get_board(board_id)->fw; @@ -1373,24 +1367,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) if (!(coredev->modes_supported & (1 << mode))) { rc = smscore_load_firmware_from_file(coredev, - mode, 0, NULL); - - /* - * try again with the default firmware - - * get the fw filename from look-up table - */ - if (rc < 0) { - sms_debug("error %d loading firmware, trying again with default firmware", - rc); - rc = smscore_load_firmware_from_file(coredev, - mode, 1, - NULL); - if (rc < 0) { - sms_debug("error %d loading firmware", - rc); - return rc; - } - } + mode, NULL); if (rc >= 0) sms_info("firmware download success"); } else { -- cgit v1.2.3 From 2a7643159d0faf839529f5001737b996d53760d9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Mar 2013 12:06:08 -0300 Subject: [media] siano: reorder smscore_get_fw_filename() function Put this function earlier in the code, to avoid the need of defining a function stub. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 172 ++++++++++++++++---------------- 1 file changed, 84 insertions(+), 88 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index d57df9170ae1..c04d8267adba 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1046,9 +1046,92 @@ exit_fw_download: return rc; } +static char *smscore_fw_lkup[][DEVICE_MODE_MAX] = { + [SMS_NOVA_A0] = { + [DEVICE_MODE_DVBT] = "dvb_nova_12mhz.inp", + [DEVICE_MODE_DVBH] = "dvb_nova_12mhz.inp", + [DEVICE_MODE_DAB_TDMB] = "tdmb_nova_12mhz.inp", + [DEVICE_MODE_DVBT_BDA] = "dvb_nova_12mhz.inp", + [DEVICE_MODE_ISDBT] = "isdbt_nova_12mhz.inp", + [DEVICE_MODE_ISDBT_BDA] = "isdbt_nova_12mhz.inp", + }, + [SMS_NOVA_B0] = { + [DEVICE_MODE_DVBT] = "dvb_nova_12mhz_b0.inp", + [DEVICE_MODE_DVBH] = "dvb_nova_12mhz_b0.inp", + [DEVICE_MODE_DAB_TDMB] = "tdmb_nova_12mhz_b0.inp", + [DEVICE_MODE_DVBT_BDA] = "dvb_nova_12mhz_b0.inp", + [DEVICE_MODE_ISDBT] = "isdbt_nova_12mhz_b0.inp", + [DEVICE_MODE_ISDBT_BDA] = "isdbt_nova_12mhz_b0.inp", + [DEVICE_MODE_FM_RADIO] = "fm_radio.inp", + [DEVICE_MODE_FM_RADIO_BDA] = "fm_radio.inp", + }, + [SMS_VEGA] = { + [DEVICE_MODE_CMMB] = "cmmb_vega_12mhz.inp", + }, + [SMS_VENICE] = { + [DEVICE_MODE_CMMB] = "cmmb_venice_12mhz.inp", + }, + [SMS_MING] = { + [DEVICE_MODE_CMMB] = "cmmb_ming_app.inp", + }, + [SMS_PELE] = { + [DEVICE_MODE_ISDBT] = "isdbt_pele.inp", + [DEVICE_MODE_ISDBT_BDA] = "isdbt_pele.inp", + }, + [SMS_RIO] = { + [DEVICE_MODE_DVBT] = "dvb_rio.inp", + [DEVICE_MODE_DVBH] = "dvbh_rio.inp", + [DEVICE_MODE_DVBT_BDA] = "dvb_rio.inp", + [DEVICE_MODE_ISDBT] = "isdbt_rio.inp", + [DEVICE_MODE_ISDBT_BDA] = "isdbt_rio.inp", + [DEVICE_MODE_FM_RADIO] = "fm_radio_rio.inp", + [DEVICE_MODE_FM_RADIO_BDA] = "fm_radio_rio.inp", + }, + [SMS_DENVER_1530] = { + [DEVICE_MODE_ATSC] = "atsc_denver.inp", + }, + [SMS_DENVER_2160] = { + [DEVICE_MODE_DAB_TDMB] = "tdmb_denver.inp", + }, +}; +/** + * get firmware file name from one of the two mechanisms : sms_boards or + * smscore_fw_lkup. + * @param coredev pointer to a coredev object returned by + * smscore_register_device + * @param mode requested mode of operation + * @param lookup if 1, always get the fw filename from smscore_fw_lkup + * table. if 0, try first to get from sms_boards + * + * @return 0 on success, <0 on error. + */ static char *smscore_get_fw_filename(struct smscore_device_t *coredev, - int mode); + int mode) +{ + char **fw; + int board_id = smscore_get_board_id(coredev); + enum sms_device_type_st type; + + type = smscore_registry_gettype(coredev->devpath); + + /* Prevent looking outside the smscore_fw_lkup table */ + if (type <= SMS_UNKNOWN_TYPE || type >= SMS_NUM_OF_DEVICE_TYPES) + return NULL; + if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) + return NULL; + + sms_debug("trying to get fw name from sms_boards board_id %d mode %d", + board_id, mode); + fw = sms_get_board(board_id)->fw; + if (!fw || !fw[mode]) { + sms_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d", + mode, type); + return smscore_fw_lkup[type][mode]; + } + + return fw[mode]; +} /** * loads specified firmware into a buffer and calls device loadfirmware_handler @@ -1207,93 +1290,6 @@ static int smscore_detect_mode(struct smscore_device_t *coredev) return rc; } -static char *smscore_fw_lkup[][DEVICE_MODE_MAX] = { - [SMS_NOVA_A0] = { - [DEVICE_MODE_DVBT] = "dvb_nova_12mhz.inp", - [DEVICE_MODE_DVBH] = "dvb_nova_12mhz.inp", - [DEVICE_MODE_DAB_TDMB] = "tdmb_nova_12mhz.inp", - [DEVICE_MODE_DVBT_BDA] = "dvb_nova_12mhz.inp", - [DEVICE_MODE_ISDBT] = "isdbt_nova_12mhz.inp", - [DEVICE_MODE_ISDBT_BDA] = "isdbt_nova_12mhz.inp", - }, - [SMS_NOVA_B0] = { - [DEVICE_MODE_DVBT] = "dvb_nova_12mhz_b0.inp", - [DEVICE_MODE_DVBH] = "dvb_nova_12mhz_b0.inp", - [DEVICE_MODE_DAB_TDMB] = "tdmb_nova_12mhz_b0.inp", - [DEVICE_MODE_DVBT_BDA] = "dvb_nova_12mhz_b0.inp", - [DEVICE_MODE_ISDBT] = "isdbt_nova_12mhz_b0.inp", - [DEVICE_MODE_ISDBT_BDA] = "isdbt_nova_12mhz_b0.inp", - [DEVICE_MODE_FM_RADIO] = "fm_radio.inp", - [DEVICE_MODE_FM_RADIO_BDA] = "fm_radio.inp", - }, - [SMS_VEGA] = { - [DEVICE_MODE_CMMB] = "cmmb_vega_12mhz.inp", - }, - [SMS_VENICE] = { - [DEVICE_MODE_CMMB] = "cmmb_venice_12mhz.inp", - }, - [SMS_MING] = { - [DEVICE_MODE_CMMB] = "cmmb_ming_app.inp", - }, - [SMS_PELE] = { - [DEVICE_MODE_ISDBT] = "isdbt_pele.inp", - [DEVICE_MODE_ISDBT_BDA] = "isdbt_pele.inp", - }, - [SMS_RIO] = { - [DEVICE_MODE_DVBT] = "dvb_rio.inp", - [DEVICE_MODE_DVBH] = "dvbh_rio.inp", - [DEVICE_MODE_DVBT_BDA] = "dvb_rio.inp", - [DEVICE_MODE_ISDBT] = "isdbt_rio.inp", - [DEVICE_MODE_ISDBT_BDA] = "isdbt_rio.inp", - [DEVICE_MODE_FM_RADIO] = "fm_radio_rio.inp", - [DEVICE_MODE_FM_RADIO_BDA] = "fm_radio_rio.inp", - }, - [SMS_DENVER_1530] = { - [DEVICE_MODE_ATSC] = "atsc_denver.inp", - }, - [SMS_DENVER_2160] = { - [DEVICE_MODE_DAB_TDMB] = "tdmb_denver.inp", - }, -}; - -/** - * get firmware file name from one of the two mechanisms : sms_boards or - * smscore_fw_lkup. - * @param coredev pointer to a coredev object returned by - * smscore_register_device - * @param mode requested mode of operation - * @param lookup if 1, always get the fw filename from smscore_fw_lkup - * table. if 0, try first to get from sms_boards - * - * @return 0 on success, <0 on error. - */ -static char *smscore_get_fw_filename(struct smscore_device_t *coredev, - int mode) -{ - char **fw; - int board_id = smscore_get_board_id(coredev); - enum sms_device_type_st type; - - type = smscore_registry_gettype(coredev->devpath); - - /* Prevent looking outside the smscore_fw_lkup table */ - if (type <= SMS_UNKNOWN_TYPE || type >= SMS_NUM_OF_DEVICE_TYPES) - return NULL; - if (mode <= DEVICE_MODE_NONE || mode >= DEVICE_MODE_MAX) - return NULL; - - sms_debug("trying to get fw name from sms_boards board_id %d mode %d", - board_id, mode); - fw = sms_get_board(board_id)->fw; - if (!fw || !fw[mode]) { - sms_debug("cannot find fw name in sms_boards, getting from lookup table mode %d type %d", - mode, type); - return smscore_fw_lkup[type][mode]; - } - - return fw[mode]; -} - /** * send init device request and wait for response * -- cgit v1.2.3 From 07bb6bdddfa09f01024e5caeb2bab8836b8de13e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Mar 2013 12:59:50 -0300 Subject: [media] siano: remove a bogus printk line The logic that detects the types of sms devices is bogus. It returns [ 4645.187790] smsusb_init_device: line: 372: Unspecified sms device type! For several devices, including the one I have (SMS_RIO). In a matter of fact, the right thing to do there is to print an error only if the device is really unknown (SMS_UNKNOWN_TYPE). Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/siano/smsusb.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index def5e41405a4..01a0f39a7cec 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -368,14 +368,10 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) params.setmode_handler = smsusb1_setmode; params.detectmode_handler = smsusb1_detectmode; break; - default: + case SMS_UNKNOWN_TYPE: sms_err("Unspecified sms device type!"); /* fall-thru */ - case SMS_NOVA_A0: - case SMS_NOVA_B0: - case SMS_VEGA: - case SMS_VENICE: - case SMS_DENVER_1530: + default: dev->buffer_size = USB2_BUFFER_SIZE; dev->response_alignment = le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) - -- cgit v1.2.3 From 98c3f94e6db3b4df21336b41c646366ea417527c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Mar 2013 13:06:28 -0300 Subject: [media] siano: remove doubled new line sms_debug() and sms_info() already adds a '\n' at the printed strings. No need to add more. That helps to cleanup stuff like: [ 4868.205648] smscore_onresponse: message not handled. [ 4868.205898] smscore_onresponse: message not handled. and: [ 5467.959769] smscore_onresponse: data rate 143069 bytes/secs While here, provides the message name, when the message is not handled by the smsmdtv core. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 6 ++++-- drivers/media/common/siano/smsdvb-main.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index c04d8267adba..92eea545ed4e 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1495,7 +1495,7 @@ void smscore_onresponse(struct smscore_device_t *coredev, last_sample_time = time_now; if (time_now - last_sample_time > 10000) { - sms_debug("\ndata rate %d bytes/secs", + sms_debug("data rate %d bytes/secs", (int)((data_total * 1000) / (time_now - last_sample_time))); @@ -1606,7 +1606,9 @@ void smscore_onresponse(struct smscore_device_t *coredev, break; default: - sms_debug("message not handled.\n"); + sms_debug("message %s(%d) not handled.", + smscore_translate_msg(phdr->msgType), + phdr->msgType); break; } smscore_putbuffer(coredev, cb); diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index c53cb4e8d0c6..a2882f5cfdd0 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -949,7 +949,7 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) c->bandwidth_hz = 6000000; - sms_info("%s: freq %d segwidth %d segindex %d\n", __func__, + sms_info("%s: freq %d segwidth %d segindex %d", __func__, c->frequency, c->isdbt_sb_segment_count, c->isdbt_sb_segment_idx); -- cgit v1.2.3 From d8a18e88c952f155b953d4b164818940ae8686a4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Mar 2013 13:12:29 -0300 Subject: [media] siano: Remove bogus complain about MSG_SMS_DVBT_BDA_DATA When the driver is tuned into chanel, and it is removed/reinserted, the message stream data may be arriving during device probe: [ 5680.162004] smscore_set_device_mode: set device mode to 6 [ 5680.162267] smscore_onresponse: message MSG_SMS_DVBT_BDA_DATA(693) not handled. [ 5680.162391] smscore_onresponse: message MSG_SMS_DVBT_BDA_DATA(693) not handled. [ 5680.162641] smscore_onresponse: message MSG_SMS_DVBT_BDA_DATA(693) not handled. [ 5680.162891] smscore_onresponse: message MSG_SMS_DVBT_BDA_DATA(693) not handled. [ 5680.163016] smscore_onresponse: message MSG_SMS_DVBT_BDA_DATA(693) not handled. [ 5680.163266] smscore_onresponse: message MSG_SMS_DVBT_BDA_DATA(693) not handled. [ 5680.163516] smscore_onresponse: message MSG_SMS_DVBT_BDA_DATA(693) not handled. [ 5680.163640] smscore_onresponse: message MSG_SMS_DVBT_BDA_DATA(693) not handled. [ 5680.163891] smscore_onresponse: message MSG_SMS_DVBT_BDA_DATA(693) not handled. [ 5680.164016] smscore_onresponse: message MSG_SMS_DVBT_BDA_DATA(693) not handled. [ 5680.164265] smscore_onresponse: message MSG_SMS_DVBT_BDA_DATA(693) not handled. [ 5680.164515] smscore_onresponse: message MSG_SMS_DVBT_BDA_DATA(693) not handled. [ 5680.164519] smscore_onresponse: Firmware id 6 prots 0x40 ver 8.1 [ 5680.164766] smscore_onresponse: message MSG_SMS_DVBT_BDA_DATA(693) not handled. [ 5680.166018] smscore_onresponse: message MSG_SMS_DVBT_BDA_DATA(693) not handled. [ 5680.166438] DVB: registering new adapter (Siano Rio Digital Receiver) Instead of complaining, just silently discard those messages, instead of complaining. A proper fix is to put the device on suspend/power down mode when the module is removed. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 92eea545ed4e..b5e40aa9651a 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1605,6 +1605,15 @@ void smscore_onresponse(struct smscore_device_t *coredev, - sizeof(struct SmsMsgHdr_ST)); break; + case MSG_SMS_DVBT_BDA_DATA: + /* + * It can be received here, if the frontend is + * tuned into a valid channel and the proper firmware + * is loaded. That happens when the module got removed + * and re-inserted, without powering the device off + */ + break; + default: sms_debug("message %s(%d) not handled.", smscore_translate_msg(phdr->msgType), -- cgit v1.2.3 From 11ad03a5630fbf109615ce17da1a031b9950f3f9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Mar 2013 17:02:54 -0300 Subject: [media] siano: use defines for firmware names There are too many firmwares there. As we need to add MODULE_FIMWARE() macros, the better is to define their names on just one place and use the macros for both cards/device type tables and MODULE_FIRMWARE(). Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/sms-cards.c | 14 ++++----- drivers/media/common/siano/smscoreapi.c | 56 ++++++++++++++++----------------- drivers/media/common/siano/smscoreapi.h | 24 ++++++++++++++ 3 files changed, 59 insertions(+), 35 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index bb6e558b8120..6680134d2336 100644 --- a/drivers/media/common/siano/sms-cards.c +++ b/drivers/media/common/siano/sms-cards.c @@ -54,26 +54,26 @@ static struct sms_board sms_boards[] = { [SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT] = { .name = "Hauppauge Catamount", .type = SMS_STELLAR, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw", + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_STELLAR, .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_A] = { .name = "Hauppauge Okemo-A", .type = SMS_NOVA_A0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw", + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_NOVA_A, .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_HAUPPAUGE_OKEMO_B] = { .name = "Hauppauge Okemo-B", .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw", + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_NOVA_B, .default_mode = DEVICE_MODE_DVBT_BDA, }, [SMS1XXX_BOARD_HAUPPAUGE_WINDHAM] = { .name = "Hauppauge WinTV MiniStick", .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw", - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .fw[DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_HCW_55XXX, + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX, .default_mode = DEVICE_MODE_DVBT_BDA, .rc_codes = RC_MAP_HAUPPAUGE, .board_cfg.leds_power = 26, @@ -87,7 +87,7 @@ static struct sms_board sms_boards[] = { [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD] = { .name = "Hauppauge WinTV MiniCard", .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX, .default_mode = DEVICE_MODE_DVBT_BDA, .lna_ctrl = 29, .board_cfg.foreign_lna0_ctrl = 29, @@ -97,7 +97,7 @@ static struct sms_board sms_boards[] = { [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = { .name = "Hauppauge WinTV MiniCard", .type = SMS_NOVA_B0, - .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw", + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX, .default_mode = DEVICE_MODE_DVBT_BDA, .lna_ctrl = -1, }, diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index b5e40aa9651a..b7aa63f9d9f6 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1048,50 +1048,50 @@ exit_fw_download: static char *smscore_fw_lkup[][DEVICE_MODE_MAX] = { [SMS_NOVA_A0] = { - [DEVICE_MODE_DVBT] = "dvb_nova_12mhz.inp", - [DEVICE_MODE_DVBH] = "dvb_nova_12mhz.inp", - [DEVICE_MODE_DAB_TDMB] = "tdmb_nova_12mhz.inp", - [DEVICE_MODE_DVBT_BDA] = "dvb_nova_12mhz.inp", - [DEVICE_MODE_ISDBT] = "isdbt_nova_12mhz.inp", - [DEVICE_MODE_ISDBT_BDA] = "isdbt_nova_12mhz.inp", + [DEVICE_MODE_DVBT] = SMS_FW_DVB_NOVA_12MHZ, + [DEVICE_MODE_DVBH] = SMS_FW_DVB_NOVA_12MHZ, + [DEVICE_MODE_DAB_TDMB] = SMS_FW_TDMB_NOVA_12MHZ, + [DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ, + [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_NOVA_12MHZ, + [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_NOVA_12MHZ, }, [SMS_NOVA_B0] = { - [DEVICE_MODE_DVBT] = "dvb_nova_12mhz_b0.inp", - [DEVICE_MODE_DVBH] = "dvb_nova_12mhz_b0.inp", - [DEVICE_MODE_DAB_TDMB] = "tdmb_nova_12mhz_b0.inp", - [DEVICE_MODE_DVBT_BDA] = "dvb_nova_12mhz_b0.inp", - [DEVICE_MODE_ISDBT] = "isdbt_nova_12mhz_b0.inp", - [DEVICE_MODE_ISDBT_BDA] = "isdbt_nova_12mhz_b0.inp", - [DEVICE_MODE_FM_RADIO] = "fm_radio.inp", - [DEVICE_MODE_FM_RADIO_BDA] = "fm_radio.inp", + [DEVICE_MODE_DVBT] = SMS_FW_DVB_NOVA_12MHZ_B0, + [DEVICE_MODE_DVBH] = SMS_FW_DVB_NOVA_12MHZ_B0, + [DEVICE_MODE_DAB_TDMB] = SMS_FW_TDMB_NOVA_12MHZ_B0, + [DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ_B0, + [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_NOVA_12MHZ_B0, + [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_NOVA_12MHZ_B0, + [DEVICE_MODE_FM_RADIO] = SMS_FW_FM_RADIO, + [DEVICE_MODE_FM_RADIO_BDA] = SMS_FW_FM_RADIO, }, [SMS_VEGA] = { - [DEVICE_MODE_CMMB] = "cmmb_vega_12mhz.inp", + [DEVICE_MODE_CMMB] = SMS_FW_CMMB_VEGA_12MHZ, }, [SMS_VENICE] = { - [DEVICE_MODE_CMMB] = "cmmb_venice_12mhz.inp", + [DEVICE_MODE_CMMB] = SMS_FW_CMMB_VENICE_12MHZ, }, [SMS_MING] = { - [DEVICE_MODE_CMMB] = "cmmb_ming_app.inp", + [DEVICE_MODE_CMMB] = SMS_FW_CMMB_MING_APP, }, [SMS_PELE] = { - [DEVICE_MODE_ISDBT] = "isdbt_pele.inp", - [DEVICE_MODE_ISDBT_BDA] = "isdbt_pele.inp", + [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_PELE, + [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_PELE, }, [SMS_RIO] = { - [DEVICE_MODE_DVBT] = "dvb_rio.inp", - [DEVICE_MODE_DVBH] = "dvbh_rio.inp", - [DEVICE_MODE_DVBT_BDA] = "dvb_rio.inp", - [DEVICE_MODE_ISDBT] = "isdbt_rio.inp", - [DEVICE_MODE_ISDBT_BDA] = "isdbt_rio.inp", - [DEVICE_MODE_FM_RADIO] = "fm_radio_rio.inp", - [DEVICE_MODE_FM_RADIO_BDA] = "fm_radio_rio.inp", + [DEVICE_MODE_DVBT] = SMS_FW_DVB_RIO, + [DEVICE_MODE_DVBH] = SMS_FW_DVBH_RIO, + [DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_RIO, + [DEVICE_MODE_ISDBT] = SMS_FW_ISDBT_RIO, + [DEVICE_MODE_ISDBT_BDA] = SMS_FW_ISDBT_RIO, + [DEVICE_MODE_FM_RADIO] = SMS_FW_FM_RADIO_RIO, + [DEVICE_MODE_FM_RADIO_BDA] = SMS_FW_FM_RADIO_RIO, }, [SMS_DENVER_1530] = { - [DEVICE_MODE_ATSC] = "atsc_denver.inp", + [DEVICE_MODE_ATSC] = SMS_FW_ATSC_DENVER, }, [SMS_DENVER_2160] = { - [DEVICE_MODE_DAB_TDMB] = "tdmb_denver.inp", + [DEVICE_MODE_DAB_TDMB] = SMS_FW_TDMB_DENVER, }, }; diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index 53b81cbc1bda..a9672e04c64f 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -44,6 +44,30 @@ along with this program. If not, see . #define min(a, b) (((a) < (b)) ? (a) : (b)) #endif +/* Define the firmware names used by the driver */ +#define SMS_FW_ATSC_DENVER "atsc_denver.inp" +#define SMS_FW_CMMB_MING_APP "cmmb_ming_app.inp" +#define SMS_FW_CMMB_VEGA_12MHZ "cmmb_vega_12mhz.inp" +#define SMS_FW_CMMB_VENICE_12MHZ "cmmb_venice_12mhz.inp" +#define SMS_FW_DVBH_RIO "dvbh_rio.inp" +#define SMS_FW_DVB_NOVA_12MHZ_B0 "dvb_nova_12mhz_b0.inp" +#define SMS_FW_DVB_NOVA_12MHZ "dvb_nova_12mhz.inp" +#define SMS_FW_DVB_RIO "dvb_rio.inp" +#define SMS_FW_FM_RADIO "fm_radio.inp" +#define SMS_FW_FM_RADIO_RIO "fm_radio_rio.inp" +#define SMS_FW_DVBT_HCW_55XXX "sms1xxx-hcw-55xxx-dvbt-02.fw" +#define SMS_FW_ISDBT_HCW_55XXX "sms1xxx-hcw-55xxx-isdbt-02.fw" +#define SMS_FW_ISDBT_NOVA_12MHZ_B0 "isdbt_nova_12mhz_b0.inp" +#define SMS_FW_ISDBT_NOVA_12MHZ "isdbt_nova_12mhz.inp" +#define SMS_FW_ISDBT_PELE "isdbt_pele.inp" +#define SMS_FW_ISDBT_RIO "isdbt_rio.inp" +#define SMS_FW_DVBT_NOVA_A "sms1xxx-nova-a-dvbt-01.fw" +#define SMS_FW_DVBT_NOVA_B "sms1xxx-nova-b-dvbt-01.fw" +#define SMS_FW_DVBT_STELLAR "sms1xxx-stellar-dvbt-01.fw" +#define SMS_FW_TDMB_DENVER "tdmb_denver.inp" +#define SMS_FW_TDMB_NOVA_12MHZ_B0 "tdmb_nova_12mhz_b0.inp" +#define SMS_FW_TDMB_NOVA_12MHZ "tdmb_nova_12mhz.inp" + #define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS (10000) #define SMS_ALLOC_ALIGNMENT 128 #define SMS_DMA_ALIGNMENT 16 -- cgit v1.2.3 From c8b8fdb39dabef67307df884212401c20877d9d2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Mar 2013 17:46:53 -0300 Subject: [media] siano: add MODULE_FIRMWARE() macros This driver can use several firmwares. Provide such info at module firmware metadata. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 24 ++++++++++++++++++++++++ drivers/media/common/siano/smscoreapi.h | 6 +++++- 2 files changed, 29 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index b7aa63f9d9f6..5006d1ce2806 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -2174,3 +2174,27 @@ module_exit(smscore_module_exit); MODULE_DESCRIPTION("Siano MDTV Core module"); MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)"); MODULE_LICENSE("GPL"); + +/* This should match what's defined at smscoreapi.h */ +MODULE_FIRMWARE(SMS_FW_ATSC_DENVER); +MODULE_FIRMWARE(SMS_FW_CMMB_MING_APP); +MODULE_FIRMWARE(SMS_FW_CMMB_VEGA_12MHZ); +MODULE_FIRMWARE(SMS_FW_CMMB_VENICE_12MHZ); +MODULE_FIRMWARE(SMS_FW_DVBH_RIO); +MODULE_FIRMWARE(SMS_FW_DVB_NOVA_12MHZ_B0); +MODULE_FIRMWARE(SMS_FW_DVB_NOVA_12MHZ); +MODULE_FIRMWARE(SMS_FW_DVB_RIO); +MODULE_FIRMWARE(SMS_FW_FM_RADIO); +MODULE_FIRMWARE(SMS_FW_FM_RADIO_RIO); +MODULE_FIRMWARE(SMS_FW_DVBT_HCW_55XXX); +MODULE_FIRMWARE(SMS_FW_ISDBT_HCW_55XXX); +MODULE_FIRMWARE(SMS_FW_ISDBT_NOVA_12MHZ_B0); +MODULE_FIRMWARE(SMS_FW_ISDBT_NOVA_12MHZ); +MODULE_FIRMWARE(SMS_FW_ISDBT_PELE); +MODULE_FIRMWARE(SMS_FW_ISDBT_RIO); +MODULE_FIRMWARE(SMS_FW_DVBT_NOVA_A); +MODULE_FIRMWARE(SMS_FW_DVBT_NOVA_B); +MODULE_FIRMWARE(SMS_FW_DVBT_STELLAR); +MODULE_FIRMWARE(SMS_FW_TDMB_DENVER); +MODULE_FIRMWARE(SMS_FW_TDMB_NOVA_12MHZ_B0); +MODULE_FIRMWARE(SMS_FW_TDMB_NOVA_12MHZ); diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index a9672e04c64f..bb742469d40a 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -44,7 +44,11 @@ along with this program. If not, see . #define min(a, b) (((a) < (b)) ? (a) : (b)) #endif -/* Define the firmware names used by the driver */ +/* + * Define the firmware names used by the driver. + * Those should match what's used at smscoreapi.c and sms-cards.c + * including the MODULE_FIRMWARE() macros at the end of smscoreapi.c + */ #define SMS_FW_ATSC_DENVER "atsc_denver.inp" #define SMS_FW_CMMB_MING_APP "cmmb_ming_app.inp" #define SMS_FW_CMMB_VEGA_12MHZ "cmmb_vega_12mhz.inp" -- cgit v1.2.3 From dfef84fc135832ad5c270758b6834fcb4bf448fc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Mar 2013 08:49:43 -0300 Subject: [media] siano: get rid of CammelCase from smscoreapi.h It is almost impossible to see a compliant with checkpatch.pl on those Siano drivers, as there are simply too much violations on it. So, now that a big change was done, the better is to cleanup the checkpatch compliants. Let's first replace all CammelCase symbols found at smscoreapi.h using camel_case namespace. That removed 144 checkpatch.pl compliants on this file. Of course, the other files need to be fixed accordingly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/sms-cards.c | 12 +- drivers/media/common/siano/smscoreapi.c | 336 +++++++++++----------- drivers/media/common/siano/smscoreapi.h | 420 ++++++++++++++-------------- drivers/media/common/siano/smsdvb-debugfs.c | 230 +++++++-------- drivers/media/common/siano/smsdvb-main.c | 250 ++++++++--------- drivers/media/common/siano/smsdvb.h | 32 +-- drivers/media/common/siano/smsendian.c | 30 +- drivers/media/mmc/siano/smssdio.c | 18 +- drivers/media/usb/siano/smsusb.c | 40 +-- 9 files changed, 684 insertions(+), 684 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 6680134d2336..9bd7aa1f43ec 100644 --- a/drivers/media/common/siano/sms-cards.c +++ b/drivers/media/common/siano/sms-cards.c @@ -167,13 +167,13 @@ struct sms_board *sms_get_board(unsigned id) } EXPORT_SYMBOL_GPL(sms_get_board); static inline void sms_gpio_assign_11xx_default_led_config( - struct smscore_config_gpio *pGpioConfig) { - pGpioConfig->direction = SMS_GPIO_DIRECTION_OUTPUT; - pGpioConfig->inputcharacteristics = + struct smscore_config_gpio *p_gpio_config) { + p_gpio_config->direction = SMS_GPIO_DIRECTION_OUTPUT; + p_gpio_config->inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL; - pGpioConfig->outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA; - pGpioConfig->outputslewrate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS; - pGpioConfig->pullupdown = SMS_GPIO_PULLUPDOWN_NONE; + p_gpio_config->outputdriving = SMS_GPIO_OUTPUTDRIVING_4mA; + p_gpio_config->outputslewrate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS; + p_gpio_config->pullupdown = SMS_GPIO_PULLUPDOWN_NONE; } int sms_board_event(struct smscore_device_t *coredev, diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 5006d1ce2806..e5fa4056adb3 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -792,22 +792,22 @@ static int smscore_init_ir(struct smscore_device_t *coredev) if (rc != 0) sms_err("Error initialization DTV IR sub-module"); else { - buffer = kmalloc(sizeof(struct SmsMsgData_ST2) + + buffer = kmalloc(sizeof(struct sms_msg_data2) + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); if (buffer) { - struct SmsMsgData_ST2 *msg = - (struct SmsMsgData_ST2 *) + struct sms_msg_data2 *msg = + (struct sms_msg_data2 *) SMS_ALIGN_ADDRESS(buffer); - SMS_INIT_MSG(&msg->xMsgHeader, + SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_START_IR_REQ, - sizeof(struct SmsMsgData_ST2)); + sizeof(struct sms_msg_data2)); msg->msgData[0] = coredev->ir.controller; msg->msgData[1] = coredev->ir.timeout; rc = smscore_sendrequest_and_wait(coredev, msg, - msg->xMsgHeader. msgLength, + msg->x_msg_header. msg_length, &coredev->ir_init_done); kfree(buffer); @@ -840,14 +840,14 @@ int smscore_configure_board(struct smscore_device_t *coredev) } if (board->mtu) { - struct SmsMsgData_ST MtuMsg; + struct sms_msg_data MtuMsg; sms_debug("set max transmit unit %d", board->mtu); - MtuMsg.xMsgHeader.msgSrcId = 0; - MtuMsg.xMsgHeader.msgDstId = HIF_TASK; - MtuMsg.xMsgHeader.msgFlags = 0; - MtuMsg.xMsgHeader.msgType = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ; - MtuMsg.xMsgHeader.msgLength = sizeof(MtuMsg); + MtuMsg.x_msg_header.msg_src_id = 0; + MtuMsg.x_msg_header.msg_dst_id = HIF_TASK; + MtuMsg.x_msg_header.msg_flags = 0; + MtuMsg.x_msg_header.msg_type = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ; + MtuMsg.x_msg_header.msg_length = sizeof(MtuMsg); MtuMsg.msgData[0] = board->mtu; coredev->sendrequest_handler(coredev->context, &MtuMsg, @@ -855,10 +855,10 @@ int smscore_configure_board(struct smscore_device_t *coredev) } if (board->crystal) { - struct SmsMsgData_ST CrysMsg; + struct sms_msg_data CrysMsg; sms_debug("set crystal value %d", board->crystal); - SMS_INIT_MSG(&CrysMsg.xMsgHeader, + SMS_INIT_MSG(&CrysMsg.x_msg_header, MSG_SMS_NEW_CRYSTAL_REQ, sizeof(CrysMsg)); CrysMsg.msgData[0] = board->crystal; @@ -916,19 +916,19 @@ EXPORT_SYMBOL_GPL(smscore_start_device); static int smscore_load_firmware_family2(struct smscore_device_t *coredev, void *buffer, size_t size) { - struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer; - struct SmsMsgData_ST4 *msg; + struct sms_firmware *firmware = (struct sms_firmware *) buffer; + struct sms_msg_data4 *msg; u32 mem_address, calc_checksum = 0; u32 i, *ptr; - u8 *payload = firmware->Payload; + u8 *payload = firmware->payload; int rc = 0; - firmware->StartAddress = le32_to_cpu(firmware->StartAddress); - firmware->Length = le32_to_cpu(firmware->Length); + firmware->start_address = le32_to_cpu(firmware->start_address); + firmware->length = le32_to_cpu(firmware->length); - mem_address = firmware->StartAddress; + mem_address = firmware->start_address; sms_info("loading FW to addr 0x%x size %d", - mem_address, firmware->Length); + mem_address, firmware->length); if (coredev->preload_handler) { rc = coredev->preload_handler(coredev->context); if (rc < 0) @@ -942,10 +942,10 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, if (coredev->mode != DEVICE_MODE_NONE) { sms_debug("sending reload command."); - SMS_INIT_MSG(&msg->xMsgHeader, MSG_SW_RELOAD_START_REQ, - sizeof(struct SmsMsgHdr_ST)); + SMS_INIT_MSG(&msg->x_msg_header, MSG_SW_RELOAD_START_REQ, + sizeof(struct sms_msg_hdr)); rc = smscore_sendrequest_and_wait(coredev, msg, - msg->xMsgHeader.msgLength, + msg->x_msg_header.msg_length, &coredev->reload_start_done); if (rc < 0) { sms_err("device reload failed, rc %d", rc); @@ -954,24 +954,24 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, mem_address = *(u32 *) &payload[20]; } - for (i = 0, ptr = (u32 *)firmware->Payload; i < firmware->Length/4 ; + for (i = 0, ptr = (u32 *)firmware->payload; i < firmware->length/4 ; i++, ptr++) calc_checksum += *ptr; while (size && rc >= 0) { - struct SmsDataDownload_ST *DataMsg = - (struct SmsDataDownload_ST *) msg; + struct sms_data_download *DataMsg = + (struct sms_data_download *) msg; int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE); - SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_DATA_DOWNLOAD_REQ, - (u16)(sizeof(struct SmsMsgHdr_ST) + + SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_DATA_DOWNLOAD_REQ, + (u16)(sizeof(struct sms_msg_hdr) + sizeof(u32) + payload_size)); - DataMsg->MemAddr = mem_address; - memcpy(DataMsg->Payload, payload, payload_size); + DataMsg->mem_addr = mem_address; + memcpy(DataMsg->payload, payload, payload_size); rc = smscore_sendrequest_and_wait(coredev, DataMsg, - DataMsg->xMsgHeader.msgLength, + DataMsg->x_msg_header.msg_length, &coredev->data_download_done); payload += payload_size; @@ -984,30 +984,30 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, sms_err("sending MSG_SMS_DATA_VALIDITY_REQ expecting 0x%x", calc_checksum); - SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_DATA_VALIDITY_REQ, - sizeof(msg->xMsgHeader) + + SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_DATA_VALIDITY_REQ, + sizeof(msg->x_msg_header) + sizeof(u32) * 3); - msg->msgData[0] = firmware->StartAddress; + msg->msgData[0] = firmware->start_address; /* Entry point */ - msg->msgData[1] = firmware->Length; + msg->msgData[1] = firmware->length; msg->msgData[2] = 0; /* Regular checksum*/ rc = smscore_sendrequest_and_wait(coredev, msg, - msg->xMsgHeader.msgLength, + msg->x_msg_header.msg_length, &coredev->data_validity_done); if (rc < 0) goto exit_fw_download; if (coredev->mode == DEVICE_MODE_NONE) { - struct SmsMsgData_ST *TriggerMsg = - (struct SmsMsgData_ST *) msg; + struct sms_msg_data *TriggerMsg = + (struct sms_msg_data *) msg; sms_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ"); - SMS_INIT_MSG(&msg->xMsgHeader, + SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_SWDOWNLOAD_TRIGGER_REQ, - sizeof(struct SmsMsgHdr_ST) + + sizeof(struct sms_msg_hdr) + sizeof(u32) * 5); - TriggerMsg->msgData[0] = firmware->StartAddress; + TriggerMsg->msgData[0] = firmware->start_address; /* Entry point */ TriggerMsg->msgData[1] = 6; /* Priority */ TriggerMsg->msgData[2] = 0x200; /* Stack size */ @@ -1015,13 +1015,13 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, TriggerMsg->msgData[4] = 4; /* Task ID */ rc = smscore_sendrequest_and_wait(coredev, TriggerMsg, - TriggerMsg->xMsgHeader.msgLength, + TriggerMsg->x_msg_header.msg_length, &coredev->trigger_done); } else { - SMS_INIT_MSG(&msg->xMsgHeader, MSG_SW_RELOAD_EXEC_REQ, - sizeof(struct SmsMsgHdr_ST)); + SMS_INIT_MSG(&msg->x_msg_header, MSG_SW_RELOAD_EXEC_REQ, + sizeof(struct sms_msg_hdr)); rc = coredev->sendrequest_handler(coredev->context, msg, - msg->xMsgHeader.msgLength); + msg->x_msg_header.msg_length); } if (rc < 0) @@ -1256,19 +1256,19 @@ EXPORT_SYMBOL_GPL(smscore_unregister_device); static int smscore_detect_mode(struct smscore_device_t *coredev) { - void *buffer = kmalloc(sizeof(struct SmsMsgHdr_ST) + SMS_DMA_ALIGNMENT, + void *buffer = kmalloc(sizeof(struct sms_msg_hdr) + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); - struct SmsMsgHdr_ST *msg = - (struct SmsMsgHdr_ST *) SMS_ALIGN_ADDRESS(buffer); + struct sms_msg_hdr *msg = + (struct sms_msg_hdr *) SMS_ALIGN_ADDRESS(buffer); int rc; if (!buffer) return -ENOMEM; SMS_INIT_MSG(msg, MSG_SMS_GET_VERSION_EX_REQ, - sizeof(struct SmsMsgHdr_ST)); + sizeof(struct sms_msg_hdr)); - rc = smscore_sendrequest_and_wait(coredev, msg, msg->msgLength, + rc = smscore_sendrequest_and_wait(coredev, msg, msg->msg_length, &coredev->version_ex_done); if (rc == -ETIME) { sms_err("MSG_SMS_GET_VERSION_EX_REQ failed first try"); @@ -1276,7 +1276,7 @@ static int smscore_detect_mode(struct smscore_device_t *coredev) if (wait_for_completion_timeout(&coredev->resume_done, msecs_to_jiffies(5000))) { rc = smscore_sendrequest_and_wait( - coredev, msg, msg->msgLength, + coredev, msg, msg->msg_length, &coredev->version_ex_done); if (rc < 0) sms_err("MSG_SMS_GET_VERSION_EX_REQ failed " @@ -1302,23 +1302,23 @@ static int smscore_detect_mode(struct smscore_device_t *coredev) int smscore_init_device(struct smscore_device_t *coredev, int mode) { void *buffer; - struct SmsMsgData_ST *msg; + struct sms_msg_data *msg; int rc = 0; - buffer = kmalloc(sizeof(struct SmsMsgData_ST) + + buffer = kmalloc(sizeof(struct sms_msg_data) + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); if (!buffer) { sms_err("Could not allocate buffer for init device message."); return -ENOMEM; } - msg = (struct SmsMsgData_ST *)SMS_ALIGN_ADDRESS(buffer); - SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, - sizeof(struct SmsMsgData_ST)); + msg = (struct sms_msg_data *)SMS_ALIGN_ADDRESS(buffer); + SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ, + sizeof(struct sms_msg_data)); msg->msgData[0] = mode; rc = smscore_sendrequest_and_wait(coredev, msg, - msg->xMsgHeader. msgLength, + msg->x_msg_header. msg_length, &coredev->init_device_done); kfree(buffer); @@ -1396,17 +1396,17 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) coredev->mode = mode; coredev->device_flags &= ~SMS_DEVICE_NOT_READY; - buffer = kmalloc(sizeof(struct SmsMsgData_ST) + + buffer = kmalloc(sizeof(struct sms_msg_data) + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); if (buffer) { - struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *) SMS_ALIGN_ADDRESS(buffer); + struct sms_msg_data *msg = (struct sms_msg_data *) SMS_ALIGN_ADDRESS(buffer); - SMS_INIT_MSG(&msg->xMsgHeader, MSG_SMS_INIT_DEVICE_REQ, - sizeof(struct SmsMsgData_ST)); + SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ, + sizeof(struct sms_msg_data)); msg->msgData[0] = mode; rc = smscore_sendrequest_and_wait( - coredev, msg, msg->xMsgHeader.msgLength, + coredev, msg, msg->x_msg_header.msg_length, &coredev->init_device_done); kfree(buffer); @@ -1483,7 +1483,7 @@ found: */ void smscore_onresponse(struct smscore_device_t *coredev, struct smscore_buffer_t *cb) { - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p + struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) ((u8 *) cb->p + cb->offset); struct smscore_client_t *client; int rc = -EBUSY; @@ -1505,14 +1505,14 @@ void smscore_onresponse(struct smscore_device_t *coredev, data_total += cb->size; /* Do we need to re-route? */ - if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) || - (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) { + if ((phdr->msg_type == MSG_SMS_HO_PER_SLICES_IND) || + (phdr->msg_type == MSG_SMS_TRANSMISSION_IND)) { if (coredev->mode == DEVICE_MODE_DVBT_BDA) - phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID; + phdr->msg_dst_id = DVBT_BDA_CONTROL_MSG_ID; } - client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId); + client = smscore_find_client(coredev, phdr->msg_type, phdr->msg_dst_id); /* If no client registered for type & id, * check for control client where type is not registered */ @@ -1520,7 +1520,7 @@ void smscore_onresponse(struct smscore_device_t *coredev, rc = client->onresponse_handler(client->context, cb); if (rc < 0) { - switch (phdr->msgType) { + switch (phdr->msg_type) { case MSG_SMS_ISDBT_TUNE_RES: break; case MSG_SMS_RF_TUNE_RES: @@ -1537,17 +1537,17 @@ void smscore_onresponse(struct smscore_device_t *coredev, break; case MSG_SMS_GET_VERSION_EX_RES: { - struct SmsVersionRes_ST *ver = - (struct SmsVersionRes_ST *) phdr; + struct sms_version_res *ver = + (struct sms_version_res *) phdr; sms_debug("Firmware id %d prots 0x%x ver %d.%d", - ver->FirmwareId, ver->SupportedProtocols, - ver->RomVersionMajor, ver->RomVersionMinor); + ver->firmware_id, ver->supported_protocols, + ver->rom_ver_major, ver->rom_ver_minor); - coredev->mode = ver->FirmwareId == 255 ? - DEVICE_MODE_NONE : ver->FirmwareId; - coredev->modes_supported = ver->SupportedProtocols; - coredev->fw_version = ver->RomVersionMajor << 8 | - ver->RomVersionMinor; + coredev->mode = ver->firmware_id == 255 ? + DEVICE_MODE_NONE : ver->firmware_id; + coredev->modes_supported = ver->supported_protocols; + coredev->fw_version = ver->rom_ver_major << 8 | + ver->rom_ver_minor; complete(&coredev->version_ex_done); break; @@ -1560,7 +1560,7 @@ void smscore_onresponse(struct smscore_device_t *coredev, break; case MSG_SMS_DATA_VALIDITY_RES: { - struct SmsMsgData_ST *validity = (struct SmsMsgData_ST *) phdr; + struct sms_msg_data *validity = (struct sms_msg_data *) phdr; sms_err("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x", validity->msgData[0]); @@ -1600,9 +1600,9 @@ void smscore_onresponse(struct smscore_device_t *coredev, sms_ir_event(coredev, (const char *) ((char *)phdr - + sizeof(struct SmsMsgHdr_ST)), - (int)phdr->msgLength - - sizeof(struct SmsMsgHdr_ST)); + + sizeof(struct sms_msg_hdr)), + (int)phdr->msg_length + - sizeof(struct sms_msg_hdr)); break; case MSG_SMS_DVBT_BDA_DATA: @@ -1616,8 +1616,8 @@ void smscore_onresponse(struct smscore_device_t *coredev, default: sms_debug("message %s(%d) not handled.", - smscore_translate_msg(phdr->msgType), - phdr->msgType); + smscore_translate_msg(phdr->msg_type), + phdr->msg_type); break; } smscore_putbuffer(coredev, cb); @@ -1799,7 +1799,7 @@ int smsclient_sendrequest(struct smscore_client_t *client, void *buffer, size_t size) { struct smscore_device_t *coredev; - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer; + struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer; int rc; if (client == NULL) { @@ -1816,7 +1816,7 @@ int smsclient_sendrequest(struct smscore_client_t *client, } rc = smscore_validate_client(client->coredev, client, 0, - phdr->msgSrcId); + phdr->msg_src_id); if (rc < 0) return rc; @@ -1830,16 +1830,16 @@ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, struct smscore_config_gpio *pinconfig) { struct { - struct SmsMsgHdr_ST hdr; + struct sms_msg_hdr hdr; u32 data[6]; } msg; if (coredev->device_flags & SMS_DEVICE_FAMILY2) { - msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - msg.hdr.msgDstId = HIF_TASK; - msg.hdr.msgFlags = 0; - msg.hdr.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; - msg.hdr.msgLength = sizeof(msg); + msg.hdr.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + msg.hdr.msg_dst_id = HIF_TASK; + msg.hdr.msg_flags = 0; + msg.hdr.msg_type = MSG_SMS_GPIO_CONFIG_EX_REQ; + msg.hdr.msg_length = sizeof(msg); msg.data[0] = pin; msg.data[1] = pinconfig->pullupdown; @@ -1875,18 +1875,18 @@ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level) { struct { - struct SmsMsgHdr_ST hdr; + struct sms_msg_hdr hdr; u32 data[3]; } msg; if (pin > MAX_GPIO_PIN_NUMBER) return -EINVAL; - msg.hdr.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - msg.hdr.msgDstId = HIF_TASK; - msg.hdr.msgFlags = 0; - msg.hdr.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; - msg.hdr.msgLength = sizeof(msg); + msg.hdr.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + msg.hdr.msg_dst_id = HIF_TASK; + msg.hdr.msg_flags = 0; + msg.hdr.msg_type = MSG_SMS_GPIO_SET_LEVEL_REQ; + msg.hdr.msg_length = sizeof(msg); msg.data[0] = pin; msg.data[1] = level ? 1 : 0; @@ -1897,47 +1897,47 @@ int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level) } /* new GPIO management implementation */ -static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum, +static int GetGpioPinParams(u32 pin_num, u32 *pTranslatedpin_num, u32 *pGroupNum, u32 *pGroupCfg) { *pGroupCfg = 1; - if (PinNum <= 1) { - *pTranslatedPinNum = 0; + if (pin_num <= 1) { + *pTranslatedpin_num = 0; *pGroupNum = 9; *pGroupCfg = 2; - } else if (PinNum >= 2 && PinNum <= 6) { - *pTranslatedPinNum = 2; + } else if (pin_num >= 2 && pin_num <= 6) { + *pTranslatedpin_num = 2; *pGroupNum = 0; *pGroupCfg = 2; - } else if (PinNum >= 7 && PinNum <= 11) { - *pTranslatedPinNum = 7; + } else if (pin_num >= 7 && pin_num <= 11) { + *pTranslatedpin_num = 7; *pGroupNum = 1; - } else if (PinNum >= 12 && PinNum <= 15) { - *pTranslatedPinNum = 12; + } else if (pin_num >= 12 && pin_num <= 15) { + *pTranslatedpin_num = 12; *pGroupNum = 2; *pGroupCfg = 3; - } else if (PinNum == 16) { - *pTranslatedPinNum = 16; + } else if (pin_num == 16) { + *pTranslatedpin_num = 16; *pGroupNum = 23; - } else if (PinNum >= 17 && PinNum <= 24) { - *pTranslatedPinNum = 17; + } else if (pin_num >= 17 && pin_num <= 24) { + *pTranslatedpin_num = 17; *pGroupNum = 3; - } else if (PinNum == 25) { - *pTranslatedPinNum = 25; + } else if (pin_num == 25) { + *pTranslatedpin_num = 25; *pGroupNum = 6; - } else if (PinNum >= 26 && PinNum <= 28) { - *pTranslatedPinNum = 26; + } else if (pin_num >= 26 && pin_num <= 28) { + *pTranslatedpin_num = 26; *pGroupNum = 4; - } else if (PinNum == 29) { - *pTranslatedPinNum = 29; + } else if (pin_num == 29) { + *pTranslatedpin_num = 29; *pGroupNum = 5; *pGroupCfg = 2; - } else if (PinNum == 30) { - *pTranslatedPinNum = 30; + } else if (pin_num == 30) { + *pTranslatedpin_num = 30; *pGroupNum = 8; - } else if (PinNum == 31) { - *pTranslatedPinNum = 31; + } else if (pin_num == 31) { + *pTranslatedpin_num = 31; *pGroupNum = 17; } else return -1; @@ -1947,11 +1947,11 @@ static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum, return 0; } -int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, - struct smscore_config_gpio *pGpioConfig) { +int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num, + struct smscore_config_gpio *p_gpio_config) { u32 totalLen; - u32 TranslatedPinNum = 0; + u32 Translatedpin_num = 0; u32 GroupNum = 0; u32 ElectricChar; u32 groupCfg; @@ -1959,18 +1959,18 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, int rc; struct SetGpioMsg { - struct SmsMsgHdr_ST xMsgHeader; + struct sms_msg_hdr x_msg_header; u32 msgData[6]; } *pMsg; - if (PinNum > MAX_GPIO_PIN_NUMBER) + if (pin_num > MAX_GPIO_PIN_NUMBER) return -EINVAL; - if (pGpioConfig == NULL) + if (p_gpio_config == NULL) return -EINVAL; - totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6); + totalLen = sizeof(struct sms_msg_hdr) + (sizeof(u32) * 6); buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); @@ -1979,35 +1979,35 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); - pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - pMsg->xMsgHeader.msgDstId = HIF_TASK; - pMsg->xMsgHeader.msgFlags = 0; - pMsg->xMsgHeader.msgLength = (u16) totalLen; - pMsg->msgData[0] = PinNum; + pMsg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + pMsg->x_msg_header.msg_dst_id = HIF_TASK; + pMsg->x_msg_header.msg_flags = 0; + pMsg->x_msg_header.msg_length = (u16) totalLen; + pMsg->msgData[0] = pin_num; if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) { - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ; - if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum, + pMsg->x_msg_header.msg_type = MSG_SMS_GPIO_CONFIG_REQ; + if (GetGpioPinParams(pin_num, &Translatedpin_num, &GroupNum, &groupCfg) != 0) { rc = -EINVAL; goto free; } - pMsg->msgData[1] = TranslatedPinNum; + pMsg->msgData[1] = Translatedpin_num; pMsg->msgData[2] = GroupNum; - ElectricChar = (pGpioConfig->pullupdown) - | (pGpioConfig->inputcharacteristics << 2) - | (pGpioConfig->outputslewrate << 3) - | (pGpioConfig->outputdriving << 4); + ElectricChar = (p_gpio_config->pullupdown) + | (p_gpio_config->inputcharacteristics << 2) + | (p_gpio_config->outputslewrate << 3) + | (p_gpio_config->outputdriving << 4); pMsg->msgData[3] = ElectricChar; - pMsg->msgData[4] = pGpioConfig->direction; + pMsg->msgData[4] = p_gpio_config->direction; pMsg->msgData[5] = groupCfg; } else { - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ; - pMsg->msgData[1] = pGpioConfig->pullupdown; - pMsg->msgData[2] = pGpioConfig->outputslewrate; - pMsg->msgData[3] = pGpioConfig->outputdriving; - pMsg->msgData[4] = pGpioConfig->direction; + pMsg->x_msg_header.msg_type = MSG_SMS_GPIO_CONFIG_EX_REQ; + pMsg->msgData[1] = p_gpio_config->pullupdown; + pMsg->msgData[2] = p_gpio_config->outputslewrate; + pMsg->msgData[3] = p_gpio_config->outputdriving; + pMsg->msgData[4] = p_gpio_config->direction; pMsg->msgData[5] = 0; } @@ -2026,22 +2026,22 @@ free: return rc; } -int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, - u8 NewLevel) { +int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 pin_num, + u8 new_level) { u32 totalLen; int rc; void *buffer; struct SetGpioMsg { - struct SmsMsgHdr_ST xMsgHeader; + struct sms_msg_hdr x_msg_header; u32 msgData[3]; /* keep it 3 ! */ } *pMsg; - if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER)) + if ((new_level > 1) || (pin_num > MAX_GPIO_PIN_NUMBER)) return -EINVAL; - totalLen = sizeof(struct SmsMsgHdr_ST) + + totalLen = sizeof(struct sms_msg_hdr) + (3 * sizeof(u32)); /* keep it 3 ! */ buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, @@ -2051,13 +2051,13 @@ int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); - pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - pMsg->xMsgHeader.msgDstId = HIF_TASK; - pMsg->xMsgHeader.msgFlags = 0; - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ; - pMsg->xMsgHeader.msgLength = (u16) totalLen; - pMsg->msgData[0] = PinNum; - pMsg->msgData[1] = NewLevel; + pMsg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + pMsg->x_msg_header.msg_dst_id = HIF_TASK; + pMsg->x_msg_header.msg_flags = 0; + pMsg->x_msg_header.msg_type = MSG_SMS_GPIO_SET_LEVEL_REQ; + pMsg->x_msg_header.msg_length = (u16) totalLen; + pMsg->msgData[0] = pin_num; + pMsg->msgData[1] = new_level; /* Send message to SMS */ rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, @@ -2074,7 +2074,7 @@ int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, return rc; } -int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, +int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num, u8 *level) { u32 totalLen; @@ -2082,15 +2082,15 @@ int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, void *buffer; struct SetGpioMsg { - struct SmsMsgHdr_ST xMsgHeader; + struct sms_msg_hdr x_msg_header; u32 msgData[2]; } *pMsg; - if (PinNum > MAX_GPIO_PIN_NUMBER) + if (pin_num > MAX_GPIO_PIN_NUMBER) return -EINVAL; - totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32)); + totalLen = sizeof(struct sms_msg_hdr) + (2 * sizeof(u32)); buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); @@ -2099,12 +2099,12 @@ int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); - pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - pMsg->xMsgHeader.msgDstId = HIF_TASK; - pMsg->xMsgHeader.msgFlags = 0; - pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ; - pMsg->xMsgHeader.msgLength = (u16) totalLen; - pMsg->msgData[0] = PinNum; + pMsg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + pMsg->x_msg_header.msg_dst_id = HIF_TASK; + pMsg->x_msg_header.msg_flags = 0; + pMsg->x_msg_header.msg_type = MSG_SMS_GPIO_GET_LEVEL_REQ; + pMsg->x_msg_header.msg_length = (u16) totalLen; + pMsg->msgData[0] = pin_num; pMsg->msgData[1] = 0; /* Send message to SMS */ diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index bb742469d40a..4b0cd7da22b7 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -577,8 +577,8 @@ enum msg_types { }; #define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \ - (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \ - (ptr)->msgLength = len; (ptr)->msgFlags = 0; \ + (ptr)->msg_type = type; (ptr)->msg_src_id = src; (ptr)->msg_dst_id = dst; \ + (ptr)->msg_length = len; (ptr)->msg_flags = 0; \ } while (0) #define SMS_INIT_MSG(ptr, type, len) \ @@ -611,78 +611,78 @@ enum SMS_DEVICE_MODE { DEVICE_MODE_MAX, }; -struct SmsMsgHdr_ST { - u16 msgType; - u8 msgSrcId; - u8 msgDstId; - u16 msgLength; /* Length of entire message, including header */ - u16 msgFlags; +struct sms_msg_hdr { + u16 msg_type; + u8 msg_src_id; + u8 msg_dst_id; + u16 msg_length; /* length of entire message, including header */ + u16 msg_flags; }; -struct SmsMsgData_ST { - struct SmsMsgHdr_ST xMsgHeader; +struct sms_msg_data { + struct sms_msg_hdr x_msg_header; u32 msgData[1]; }; -struct SmsMsgData_ST2 { - struct SmsMsgHdr_ST xMsgHeader; +struct sms_msg_data2 { + struct sms_msg_hdr x_msg_header; u32 msgData[2]; }; -struct SmsMsgData_ST4 { - struct SmsMsgHdr_ST xMsgHeader; +struct sms_msg_data4 { + struct sms_msg_hdr x_msg_header; u32 msgData[4]; }; -struct SmsDataDownload_ST { - struct SmsMsgHdr_ST xMsgHeader; - u32 MemAddr; - u8 Payload[SMS_MAX_PAYLOAD_SIZE]; +struct sms_data_download { + struct sms_msg_hdr x_msg_header; + u32 mem_addr; + u8 payload[SMS_MAX_PAYLOAD_SIZE]; }; -struct SmsVersionRes_ST { - struct SmsMsgHdr_ST xMsgHeader; +struct sms_version_res { + struct sms_msg_hdr x_msg_header; - u16 ChipModel; /* e.g. 0x1102 for SMS-1102 "Nova" */ - u8 Step; /* 0 - Step A */ - u8 MetalFix; /* 0 - Metal 0 */ + u16 chip_model; /* e.g. 0x1102 for SMS-1102 "Nova" */ + u8 step; /* 0 - step A */ + u8 metal_fix; /* 0 - Metal 0 */ - /* FirmwareId 0xFF if ROM, otherwise the + /* firmware_id 0xFF if ROM, otherwise the * value indicated by SMSHOSTLIB_DEVICE_MODES_E */ - u8 FirmwareId; - /* SupportedProtocols Bitwise OR combination of + u8 firmware_id; + /* supported_protocols Bitwise OR combination of * supported protocols */ - u8 SupportedProtocols; + u8 supported_protocols; - u8 VersionMajor; - u8 VersionMinor; - u8 VersionPatch; - u8 VersionFieldPatch; + u8 version_major; + u8 version_minor; + u8 version_patch; + u8 version_field_patch; - u8 RomVersionMajor; - u8 RomVersionMinor; - u8 RomVersionPatch; - u8 RomVersionFieldPatch; + u8 rom_ver_major; + u8 rom_ver_minor; + u8 rom_ver_patch; + u8 rom_ver_field_patch; u8 TextLabel[34]; }; -struct SmsFirmware_ST { - u32 CheckSum; - u32 Length; - u32 StartAddress; - u8 Payload[1]; +struct sms_firmware { + u32 check_sum; + u32 length; + u32 start_address; + u8 payload[1]; }; -/* Statistics information returned as response for - * SmsHostApiGetStatistics_Req */ +/* statistics information returned as response for + * SmsHostApiGetstatistics_Req */ struct SMSHOSTLIB_STATISTICS_ST { - u32 Reserved; /* Reserved */ + u32 reserved; /* reserved */ /* Common parameters */ - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + u32 is_rf_locked; /* 0 - not locked, 1 - locked */ + u32 is_demod_locked; /* 0 - not locked, 1 - locked */ + u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */ /* Reception quality */ s32 SNR; /* dB */ @@ -693,137 +693,137 @@ struct SMSHOSTLIB_STATISTICS_ST { u32 MFER; /* DVB-H frame error rate in percentage, 0xFFFFFFFF indicate N/A, valid only for DVB-H */ s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in bin/1024 */ + s32 in_band_pwr; /* In band power in dBM */ + s32 carrier_offset; /* Carrier Offset in bin/1024 */ /* Transmission parameters */ - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz, valid only for DVB-T/H */ - u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4, + u32 frequency; /* frequency in Hz */ + u32 bandwidth; /* bandwidth in MHz, valid only for DVB-T/H */ + u32 transmission_mode; /* Transmission Mode, for DAB modes 1-4, for DVB-T/H FFT mode carriers in Kilos */ - u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET, + u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET, valid only for DVB-T/H */ - u32 GuardInterval; /* Guard Interval from + u32 guard_interval; /* Guard Interval from SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */ - u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, + u32 code_rate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */ - u32 LPCodeRate; /* Low Priority Code Rate from + u32 lp_code_rate; /* Low Priority Code Rate from SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */ - u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET, + u32 hierarchy; /* hierarchy from SMSHOSTLIB_HIERARCHY_ET, valid only for DVB-T/H */ - u32 Constellation; /* Constellation from + u32 constellation; /* constellation from SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */ /* Burst parameters, valid only for DVB-H */ - u32 BurstSize; /* Current burst size in bytes, + u32 burst_size; /* Current burst size in bytes, valid only for DVB-H */ - u32 BurstDuration; /* Current burst duration in mSec, + u32 burst_duration; /* Current burst duration in mSec, valid only for DVB-H */ - u32 BurstCycleTime; /* Current burst cycle time in mSec, + u32 burst_cycle_time; /* Current burst cycle time in mSec, valid only for DVB-H */ - u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec, + u32 calc_burst_cycle_time;/* Current burst cycle time in mSec, as calculated by demodulator, valid only for DVB-H */ - u32 NumOfRows; /* Number of rows in MPE table, + u32 num_of_rows; /* Number of rows in MPE table, valid only for DVB-H */ - u32 NumOfPaddCols; /* Number of padding columns in MPE table, + u32 num_of_padd_cols; /* Number of padding columns in MPE table, valid only for DVB-H */ - u32 NumOfPunctCols; /* Number of puncturing columns in MPE table, + u32 num_of_punct_cols; /* Number of puncturing columns in MPE table, valid only for DVB-H */ - u32 ErrorTSPackets; /* Number of erroneous + u32 error_ts_packets; /* Number of erroneous transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ - u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include + u32 total_ts_packets; /* Total number of transport-stream packets */ + u32 num_of_valid_mpe_tlbs; /* Number of MPE tables which do not include errors after MPE RS decoding */ - u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors + u32 num_of_invalid_mpe_tlbs;/* Number of MPE tables which include errors after MPE RS decoding */ - u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were + u32 num_of_corrected_mpe_tlbs;/* Number of MPE tables which were corrected by MPE RS decoding */ /* Common params */ - u32 BERErrorCount; /* Number of errornous SYNC bits. */ - u32 BERBitCount; /* Total number of SYNC bits. */ + u32 ber_error_count; /* Number of errornous SYNC bits. */ + u32 ber_bit_count; /* Total number of SYNC bits. */ /* Interface information */ - u32 SmsToHostTxErrors; /* Total number of transmission errors. */ + u32 sms_to_host_tx_errors; /* Total number of transmission errors. */ /* DAB/T-DMB */ - u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ + u32 pre_ber; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ /* DVB-H TPS parameters */ - u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; + u32 cell_id; /* TPS Cell ID in bits 15..0, bits 31..16 zero; if set to 0xFFFFFFFF cell_id not yet recovered */ - u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - + u32 dvbh_srv_ind_hp; /* DVB-H service indication info, bit 1 - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - + u32 dvbh_srv_ind_lp; /* DVB-H service indication info, bit 1 - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - u32 NumMPEReceived; /* DVB-H, Num MPE section received */ + u32 num_mpe_received; /* DVB-H, Num MPE section received */ - u32 ReservedFields[10]; /* Reserved */ + u32 reservedFields[10]; /* reserved */ }; -struct SmsMsgStatisticsInfo_ST { - u32 RequestResult; +struct sms_msg_statistics_info { + u32 request_result; - struct SMSHOSTLIB_STATISTICS_ST Stat; + struct SMSHOSTLIB_STATISTICS_ST stat; /* Split the calc of the SNR in DAB */ - u32 Signal; /* dB */ - u32 Noise; /* dB */ + u32 signal; /* dB */ + u32 noise; /* dB */ }; struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST { /* Per-layer information */ - u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, + u32 code_rate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, * 255 means layer does not exist */ - u32 Constellation; /* Constellation from SMSHOSTLIB_CONSTELLATION_ET, + u32 constellation; /* constellation from SMSHOSTLIB_CONSTELLATION_ET, * 255 means layer does not exist */ u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ - u32 BERErrorCount; /* Post Viterbi Error Bits Count */ - u32 BERBitCount; /* Post Viterbi Total Bits Count */ - u32 PreBER; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ + u32 ber_error_count; /* Post Viterbi Error Bits Count */ + u32 ber_bit_count; /* Post Viterbi Total Bits Count */ + u32 pre_ber; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */ - u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ - u32 TILdepthI; /* Time interleaver depth I parameter, + u32 error_ts_packets; /* Number of erroneous transport-stream packets */ + u32 total_ts_packets; /* Total number of transport-stream packets */ + u32 ti_ldepth_i; /* Time interleaver depth I parameter, * 255 means layer does not exist */ - u32 NumberOfSegments; /* Number of segments in layer A, + u32 number_of_segments; /* Number of segments in layer A, * 255 means layer does not exist */ - u32 TMCCErrors; /* TMCC errors */ + u32 tmcc_errors; /* TMCC errors */ }; struct SMSHOSTLIB_STATISTICS_ISDBT_ST { - u32 StatisticsType; /* Enumerator identifying the type of the + u32 statistics_type; /* Enumerator identifying the type of the * structure. Values are the same as * SMSHOSTLIB_DEVICE_MODES_E * * This field MUST always be first in any * statistics structure */ - u32 FullSize; /* Total size of the structure returned by the modem. + u32 full_size; /* Total size of the structure returned by the modem. * If the size requested by the host is smaller than - * FullSize, the struct will be truncated */ + * full_size, the struct will be truncated */ /* Common parameters */ - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + u32 is_rf_locked; /* 0 - not locked, 1 - locked */ + u32 is_demod_locked; /* 0 - not locked, 1 - locked */ + u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */ /* Reception quality */ s32 SNR; /* dB */ s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in Hz */ + s32 in_band_pwr; /* In band power in dBM */ + s32 carrier_offset; /* Carrier Offset in Hz */ /* Transmission parameters */ - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz */ - u32 TransmissionMode; /* ISDB-T transmission mode */ - u32 ModemState; /* 0 - Acquisition, 1 - Locked */ - u32 GuardInterval; /* Guard Interval, 1 divided by value */ - u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */ - u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */ - u32 NumOfLayers; /* Number of ISDB-T layers in the network */ + u32 frequency; /* frequency in Hz */ + u32 bandwidth; /* bandwidth in MHz */ + u32 transmission_mode; /* ISDB-T transmission mode */ + u32 modem_state; /* 0 - Acquisition, 1 - Locked */ + u32 guard_interval; /* Guard Interval, 1 divided by value */ + u32 system_type; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */ + u32 partial_reception; /* TRUE - partial reception, FALSE otherwise */ + u32 num_of_layers; /* Number of ISDB-T layers in the network */ /* Per-layer information */ /* Layers A, B and C */ @@ -831,44 +831,44 @@ struct SMSHOSTLIB_STATISTICS_ISDBT_ST { /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */ /* Interface information */ - u32 SmsToHostTxErrors; /* Total number of transmission errors. */ + u32 sms_to_host_tx_errors; /* Total number of transmission errors. */ }; struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST { - u32 StatisticsType; /* Enumerator identifying the type of the + u32 statistics_type; /* Enumerator identifying the type of the * structure. Values are the same as * SMSHOSTLIB_DEVICE_MODES_E * * This field MUST always be first in any * statistics structure */ - u32 FullSize; /* Total size of the structure returned by the modem. + u32 full_size; /* Total size of the structure returned by the modem. * If the size requested by the host is smaller than - * FullSize, the struct will be truncated */ + * full_size, the struct will be truncated */ /* Common parameters */ - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + u32 is_rf_locked; /* 0 - not locked, 1 - locked */ + u32 is_demod_locked; /* 0 - not locked, 1 - locked */ + u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */ /* Reception quality */ s32 SNR; /* dB */ s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in Hz */ + s32 in_band_pwr; /* In band power in dBM */ + s32 carrier_offset; /* Carrier Offset in Hz */ /* Transmission parameters */ - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz */ - u32 TransmissionMode; /* ISDB-T transmission mode */ - u32 ModemState; /* 0 - Acquisition, 1 - Locked */ - u32 GuardInterval; /* Guard Interval, 1 divided by value */ - u32 SystemType; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */ - u32 PartialReception; /* TRUE - partial reception, FALSE otherwise */ - u32 NumOfLayers; /* Number of ISDB-T layers in the network */ - - u32 SegmentNumber; /* Segment number for ISDB-Tsb */ - u32 TuneBW; /* Tuned bandwidth - BW_ISDBT_1SEG / BW_ISDBT_3SEG */ + u32 frequency; /* frequency in Hz */ + u32 bandwidth; /* bandwidth in MHz */ + u32 transmission_mode; /* ISDB-T transmission mode */ + u32 modem_state; /* 0 - Acquisition, 1 - Locked */ + u32 guard_interval; /* Guard Interval, 1 divided by value */ + u32 system_type; /* ISDB-T system type (ISDB-T / ISDB-Tsb) */ + u32 partial_reception; /* TRUE - partial reception, FALSE otherwise */ + u32 num_of_layers; /* Number of ISDB-T layers in the network */ + + u32 segment_number; /* Segment number for ISDB-Tsb */ + u32 tune_bw; /* Tuned bandwidth - BW_ISDBT_1SEG / BW_ISDBT_3SEG */ /* Per-layer information */ /* Layers A, B and C */ @@ -876,21 +876,21 @@ struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST { /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */ /* Interface information */ - u32 Reserved1; /* Was SmsToHostTxErrors - obsolete . */ + u32 reserved1; /* Was sms_to_host_tx_errors - obsolete . */ /* Proprietary information */ - u32 ExtAntenna; /* Obsolete field. */ - u32 ReceptionQuality; - u32 EwsAlertActive; /* Signals if EWS alert is currently on */ - u32 LNAOnOff; /* Internal LNA state: 0: OFF, 1: ON */ - - u32 RfAgcLevel; /* RF AGC Level [linear units], full gain = 65535 (20dB) */ - u32 BbAgcLevel; /* Baseband AGC level [linear units], full gain = 65535 (71.5dB) */ - u32 FwErrorsCounter; /* Application errors - should be always zero */ + u32 ext_antenna; /* Obsolete field. */ + u32 reception_quality; + u32 ews_alert_active; /* signals if EWS alert is currently on */ + u32 lna_on_off; /* Internal LNA state: 0: OFF, 1: ON */ + + u32 rf_agc_level; /* RF AGC Level [linear units], full gain = 65535 (20dB) */ + u32 bb_agc_level; /* Baseband AGC level [linear units], full gain = 65535 (71.5dB) */ + u32 fw_errors_counter; /* Application errors - should be always zero */ u8 FwErrorsHistoryArr[8]; /* Last FW errors IDs - first is most recent, last is oldest */ s32 MRC_SNR; /* dB */ - u32 SNRFullRes; /* dB x 65536 */ - u32 Reserved4[4]; + u32 snr_full_res; /* dB x 65536 */ + u32 reserved4[4]; }; @@ -916,148 +916,148 @@ struct PID_DATA_S { }; #define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1) -#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth) +#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.bandwidth = 8 - _stat.bandwidth) #define CORRECT_STAT_TRANSMISSON_MODE(_stat) \ - if (_stat.TransmissionMode == 0) \ - _stat.TransmissionMode = 2; \ - else if (_stat.TransmissionMode == 1) \ - _stat.TransmissionMode = 8; \ + if (_stat.transmission_mode == 0) \ + _stat.transmission_mode = 2; \ + else if (_stat.transmission_mode == 1) \ + _stat.transmission_mode = 8; \ else \ - _stat.TransmissionMode = 4; + _stat.transmission_mode = 4; struct TRANSMISSION_STATISTICS_S { - u32 Frequency; /* Frequency in Hz */ - u32 Bandwidth; /* Bandwidth in MHz */ - u32 TransmissionMode; /* FFT mode carriers in Kilos */ - u32 GuardInterval; /* Guard Interval from + u32 frequency; /* frequency in Hz */ + u32 bandwidth; /* bandwidth in MHz */ + u32 transmission_mode; /* FFT mode carriers in Kilos */ + u32 guard_interval; /* Guard Interval from SMSHOSTLIB_GUARD_INTERVALS_ET */ - u32 CodeRate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */ - u32 LPCodeRate; /* Low Priority Code Rate from + u32 code_rate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */ + u32 lp_code_rate; /* Low Priority Code Rate from SMSHOSTLIB_CODE_RATE_ET */ - u32 Hierarchy; /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */ - u32 Constellation; /* Constellation from + u32 hierarchy; /* hierarchy from SMSHOSTLIB_HIERARCHY_ET */ + u32 constellation; /* constellation from SMSHOSTLIB_CONSTELLATION_ET */ /* DVB-H TPS parameters */ - u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero; + u32 cell_id; /* TPS Cell ID in bits 15..0, bits 31..16 zero; if set to 0xFFFFFFFF cell_id not yet recovered */ - u32 DvbhSrvIndHP; /* DVB-H service indication info, bit 1 - + u32 dvbh_srv_ind_hp; /* DVB-H service indication info, bit 1 - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - u32 DvbhSrvIndLP; /* DVB-H service indication info, bit 1 - + u32 dvbh_srv_ind_lp; /* DVB-H service indication info, bit 1 - Time Slicing indicator, bit 0 - MPE-FEC indicator */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 is_demod_locked; /* 0 - not locked, 1 - locked */ }; struct RECEPTION_STATISTICS_S { - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + u32 is_rf_locked; /* 0 - not locked, 1 - locked */ + u32 is_demod_locked; /* 0 - not locked, 1 - locked */ + u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */ - u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ + u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ s32 SNR; /* dB */ u32 BER; /* Post Viterbi BER [1E-5] */ - u32 BERErrorCount; /* Number of erronous SYNC bits. */ - u32 BERBitCount; /* Total number of SYNC bits. */ + u32 ber_error_count; /* Number of erronous SYNC bits. */ + u32 ber_bit_count; /* Total number of SYNC bits. */ u32 TS_PER; /* Transport stream PER, 0xFFFFFFFF indicate N/A */ u32 MFER; /* DVB-H frame error rate in percentage, 0xFFFFFFFF indicate N/A, valid only for DVB-H */ s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in bin/1024 */ - u32 ErrorTSPackets; /* Number of erroneous + s32 in_band_pwr; /* In band power in dBM */ + s32 carrier_offset; /* Carrier Offset in bin/1024 */ + u32 error_ts_packets; /* Number of erroneous transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ + u32 total_ts_packets; /* Total number of transport-stream packets */ s32 MRC_SNR; /* dB */ s32 MRC_RSSI; /* dBm */ - s32 MRC_InBandPwr; /* In band power in dBM */ + s32 mrc_in_band_pwr; /* In band power in dBM */ }; struct RECEPTION_STATISTICS_EX_S { - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ - u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */ + u32 is_rf_locked; /* 0 - not locked, 1 - locked */ + u32 is_demod_locked; /* 0 - not locked, 1 - locked */ + u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */ - u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ + u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ s32 SNR; /* dB */ u32 BER; /* Post Viterbi BER [1E-5] */ - u32 BERErrorCount; /* Number of erronous SYNC bits. */ - u32 BERBitCount; /* Total number of SYNC bits. */ + u32 ber_error_count; /* Number of erronous SYNC bits. */ + u32 ber_bit_count; /* Total number of SYNC bits. */ u32 TS_PER; /* Transport stream PER, 0xFFFFFFFF indicate N/A */ u32 MFER; /* DVB-H frame error rate in percentage, 0xFFFFFFFF indicate N/A, valid only for DVB-H */ s32 RSSI; /* dBm */ - s32 InBandPwr; /* In band power in dBM */ - s32 CarrierOffset; /* Carrier Offset in bin/1024 */ - u32 ErrorTSPackets; /* Number of erroneous + s32 in_band_pwr; /* In band power in dBM */ + s32 carrier_offset; /* Carrier Offset in bin/1024 */ + u32 error_ts_packets; /* Number of erroneous transport-stream packets */ - u32 TotalTSPackets; /* Total number of transport-stream packets */ + u32 total_ts_packets; /* Total number of transport-stream packets */ - s32 RefDevPPM; - s32 FreqDevHz; + s32 ref_dev_ppm; + s32 freq_dev_hz; s32 MRC_SNR; /* dB */ s32 MRC_RSSI; /* dBm */ - s32 MRC_InBandPwr; /* In band power in dBM */ + s32 mrc_in_band_pwr; /* In band power in dBM */ }; -/* Statistics information returned as response for - * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */ +/* statistics information returned as response for + * SmsHostApiGetstatisticsEx_Req for DVB applications, SMS1100 and up */ struct SMSHOSTLIB_STATISTICS_DVB_S { /* Reception */ - struct RECEPTION_STATISTICS_S ReceptionData; + struct RECEPTION_STATISTICS_S reception_data; /* Transmission parameters */ - struct TRANSMISSION_STATISTICS_S TransmissionData; + struct TRANSMISSION_STATISTICS_S transmission_data; /* Burst parameters, valid only for DVB-H */ #define SRVM_MAX_PID_FILTERS 8 - struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS]; + struct PID_DATA_S pid_data[SRVM_MAX_PID_FILTERS]; }; -/* Statistics information returned as response for - * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */ +/* statistics information returned as response for + * SmsHostApiGetstatisticsEx_Req for DVB applications, SMS1100 and up */ struct SMSHOSTLIB_STATISTICS_DVB_EX_S { /* Reception */ - struct RECEPTION_STATISTICS_EX_S ReceptionData; + struct RECEPTION_STATISTICS_EX_S reception_data; /* Transmission parameters */ - struct TRANSMISSION_STATISTICS_S TransmissionData; + struct TRANSMISSION_STATISTICS_S transmission_data; /* Burst parameters, valid only for DVB-H */ #define SRVM_MAX_PID_FILTERS 8 - struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS]; + struct PID_DATA_S pid_data[SRVM_MAX_PID_FILTERS]; }; struct SRVM_SIGNAL_STATUS_S { u32 result; u32 snr; - u32 tsPackets; - u32 etsPackets; + u32 ts_packets; + u32 ets_packets; u32 constellation; - u32 hpCode; - u32 tpsSrvIndLP; - u32 tpsSrvIndHP; - u32 cellId; + u32 hp_code; + u32 tps_srv_ind_lp; + u32 tps_srv_ind_hp; + u32 cell_id; u32 reason; - s32 inBandPower; - u32 requestId; + s32 in_band_power; + u32 request_id; }; struct SMSHOSTLIB_I2C_REQ_ST { - u32 DeviceAddress; /* I2c device address */ - u32 WriteCount; /* number of bytes to write */ - u32 ReadCount; /* number of bytes to read */ + u32 device_address; /* I2c device address */ + u32 write_count; /* number of bytes to write */ + u32 read_count; /* number of bytes to read */ u8 Data[1]; }; struct SMSHOSTLIB_I2C_RES_ST { - u32 Status; /* non-zero value in case of failure */ - u32 ReadCount; /* number of bytes read */ + u32 status; /* non-zero value in case of failure */ + u32 read_count; /* number of bytes read */ u8 Data[1]; }; @@ -1154,11 +1154,11 @@ int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin, int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level); /* new GPIO management */ -extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum, - struct smscore_config_gpio *pGpioConfig); -extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum, - u8 NewLevel); -extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum, +extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num, + struct smscore_config_gpio *p_gpio_config); +extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 pin_num, + u8 new_level); +extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num, u8 *level); void smscore_set_board_id(struct smscore_device_t *core, int id); diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index 0219be36c289..5a28506d7bba 100644 --- a/drivers/media/common/siano/smsdvb-debugfs.c +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -63,11 +63,11 @@ void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data, buf = debug_data->stats_data; n += snprintf(&buf[n], PAGE_SIZE - n, - "IsRfLocked = %d\n", p->IsRfLocked); + "is_rf_locked = %d\n", p->is_rf_locked); n += snprintf(&buf[n], PAGE_SIZE - n, - "IsDemodLocked = %d\n", p->IsDemodLocked); + "is_demod_locked = %d\n", p->is_demod_locked); n += snprintf(&buf[n], PAGE_SIZE - n, - "IsExternalLNAOn = %d\n", p->IsExternalLNAOn); + "is_external_lna_on = %d\n", p->is_external_lna_on); n += snprintf(&buf[n], PAGE_SIZE - n, "SNR = %d\n", p->SNR); n += snprintf(&buf[n], PAGE_SIZE - n, @@ -81,70 +81,70 @@ void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data, n += snprintf(&buf[n], PAGE_SIZE - n, "RSSI = %d\n", p->RSSI); n += snprintf(&buf[n], PAGE_SIZE - n, - "InBandPwr = %d\n", p->InBandPwr); + "in_band_pwr = %d\n", p->in_band_pwr); n += snprintf(&buf[n], PAGE_SIZE - n, - "CarrierOffset = %d\n", p->CarrierOffset); + "carrier_offset = %d\n", p->carrier_offset); n += snprintf(&buf[n], PAGE_SIZE - n, - "ModemState = %d\n", p->ModemState); + "modem_state = %d\n", p->modem_state); n += snprintf(&buf[n], PAGE_SIZE - n, - "Frequency = %d\n", p->Frequency); + "frequency = %d\n", p->frequency); n += snprintf(&buf[n], PAGE_SIZE - n, - "Bandwidth = %d\n", p->Bandwidth); + "bandwidth = %d\n", p->bandwidth); n += snprintf(&buf[n], PAGE_SIZE - n, - "TransmissionMode = %d\n", p->TransmissionMode); + "transmission_mode = %d\n", p->transmission_mode); n += snprintf(&buf[n], PAGE_SIZE - n, - "ModemState = %d\n", p->ModemState); + "modem_state = %d\n", p->modem_state); n += snprintf(&buf[n], PAGE_SIZE - n, - "GuardInterval = %d\n", p->GuardInterval); + "guard_interval = %d\n", p->guard_interval); n += snprintf(&buf[n], PAGE_SIZE - n, - "CodeRate = %d\n", p->CodeRate); + "code_rate = %d\n", p->code_rate); n += snprintf(&buf[n], PAGE_SIZE - n, - "LPCodeRate = %d\n", p->LPCodeRate); + "lp_code_rate = %d\n", p->lp_code_rate); n += snprintf(&buf[n], PAGE_SIZE - n, - "Hierarchy = %d\n", p->Hierarchy); + "hierarchy = %d\n", p->hierarchy); n += snprintf(&buf[n], PAGE_SIZE - n, - "Constellation = %d\n", p->Constellation); + "constellation = %d\n", p->constellation); n += snprintf(&buf[n], PAGE_SIZE - n, - "BurstSize = %d\n", p->BurstSize); + "burst_size = %d\n", p->burst_size); n += snprintf(&buf[n], PAGE_SIZE - n, - "BurstDuration = %d\n", p->BurstDuration); + "burst_duration = %d\n", p->burst_duration); n += snprintf(&buf[n], PAGE_SIZE - n, - "BurstCycleTime = %d\n", p->BurstCycleTime); + "burst_cycle_time = %d\n", p->burst_cycle_time); n += snprintf(&buf[n], PAGE_SIZE - n, - "CalculatedBurstCycleTime = %d\n", - p->CalculatedBurstCycleTime); + "calc_burst_cycle_time = %d\n", + p->calc_burst_cycle_time); n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfRows = %d\n", p->NumOfRows); + "num_of_rows = %d\n", p->num_of_rows); n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfPaddCols = %d\n", p->NumOfPaddCols); + "num_of_padd_cols = %d\n", p->num_of_padd_cols); n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfPunctCols = %d\n", p->NumOfPunctCols); + "num_of_punct_cols = %d\n", p->num_of_punct_cols); n += snprintf(&buf[n], PAGE_SIZE - n, - "ErrorTSPackets = %d\n", p->ErrorTSPackets); + "error_ts_packets = %d\n", p->error_ts_packets); n += snprintf(&buf[n], PAGE_SIZE - n, - "TotalTSPackets = %d\n", p->TotalTSPackets); + "total_ts_packets = %d\n", p->total_ts_packets); n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfValidMpeTlbs = %d\n", p->NumOfValidMpeTlbs); + "num_of_valid_mpe_tlbs = %d\n", p->num_of_valid_mpe_tlbs); n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfInvalidMpeTlbs = %d\n", p->NumOfInvalidMpeTlbs); + "num_of_invalid_mpe_tlbs = %d\n", p->num_of_invalid_mpe_tlbs); n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfCorrectedMpeTlbs = %d\n", p->NumOfCorrectedMpeTlbs); + "num_of_corrected_mpe_tlbs = %d\n", p->num_of_corrected_mpe_tlbs); n += snprintf(&buf[n], PAGE_SIZE - n, - "BERErrorCount = %d\n", p->BERErrorCount); + "ber_error_count = %d\n", p->ber_error_count); n += snprintf(&buf[n], PAGE_SIZE - n, - "BERBitCount = %d\n", p->BERBitCount); + "ber_bit_count = %d\n", p->ber_bit_count); n += snprintf(&buf[n], PAGE_SIZE - n, - "SmsToHostTxErrors = %d\n", p->SmsToHostTxErrors); + "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors); n += snprintf(&buf[n], PAGE_SIZE - n, - "PreBER = %d\n", p->PreBER); + "pre_ber = %d\n", p->pre_ber); n += snprintf(&buf[n], PAGE_SIZE - n, - "CellId = %d\n", p->CellId); + "cell_id = %d\n", p->cell_id); n += snprintf(&buf[n], PAGE_SIZE - n, - "DvbhSrvIndHP = %d\n", p->DvbhSrvIndHP); + "dvbh_srv_ind_hp = %d\n", p->dvbh_srv_ind_hp); n += snprintf(&buf[n], PAGE_SIZE - n, - "DvbhSrvIndLP = %d\n", p->DvbhSrvIndLP); + "dvbh_srv_ind_lp = %d\n", p->dvbh_srv_ind_lp); n += snprintf(&buf[n], PAGE_SIZE - n, - "NumMPEReceived = %d\n", p->NumMPEReceived); + "num_mpe_received = %d\n", p->num_mpe_received); debug_data->stats_count = n; spin_unlock(&debug_data->lock); @@ -166,74 +166,74 @@ void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data, buf = debug_data->stats_data; n += snprintf(&buf[n], PAGE_SIZE - n, - "StatisticsType = %d\t", p->StatisticsType); + "statistics_type = %d\t", p->statistics_type); n += snprintf(&buf[n], PAGE_SIZE - n, - "FullSize = %d\n", p->FullSize); + "full_size = %d\n", p->full_size); n += snprintf(&buf[n], PAGE_SIZE - n, - "IsRfLocked = %d\t\t", p->IsRfLocked); + "is_rf_locked = %d\t\t", p->is_rf_locked); n += snprintf(&buf[n], PAGE_SIZE - n, - "IsDemodLocked = %d\t", p->IsDemodLocked); + "is_demod_locked = %d\t", p->is_demod_locked); n += snprintf(&buf[n], PAGE_SIZE - n, - "IsExternalLNAOn = %d\n", p->IsExternalLNAOn); + "is_external_lna_on = %d\n", p->is_external_lna_on); n += snprintf(&buf[n], PAGE_SIZE - n, "SNR = %d dB\t\t", p->SNR); n += snprintf(&buf[n], PAGE_SIZE - n, "RSSI = %d dBm\t\t", p->RSSI); n += snprintf(&buf[n], PAGE_SIZE - n, - "InBandPwr = %d dBm\n", p->InBandPwr); + "in_band_pwr = %d dBm\n", p->in_band_pwr); n += snprintf(&buf[n], PAGE_SIZE - n, - "CarrierOffset = %d\t", p->CarrierOffset); + "carrier_offset = %d\t", p->carrier_offset); n += snprintf(&buf[n], PAGE_SIZE - n, - "Bandwidth = %d\t\t", p->Bandwidth); + "bandwidth = %d\t\t", p->bandwidth); n += snprintf(&buf[n], PAGE_SIZE - n, - "Frequency = %d Hz\n", p->Frequency); + "frequency = %d Hz\n", p->frequency); n += snprintf(&buf[n], PAGE_SIZE - n, - "TransmissionMode = %d\t", p->TransmissionMode); + "transmission_mode = %d\t", p->transmission_mode); n += snprintf(&buf[n], PAGE_SIZE - n, - "ModemState = %d\t\t", p->ModemState); + "modem_state = %d\t\t", p->modem_state); n += snprintf(&buf[n], PAGE_SIZE - n, - "GuardInterval = %d\n", p->GuardInterval); + "guard_interval = %d\n", p->guard_interval); n += snprintf(&buf[n], PAGE_SIZE - n, - "SystemType = %d\t\t", p->SystemType); + "system_type = %d\t\t", p->system_type); n += snprintf(&buf[n], PAGE_SIZE - n, - "PartialReception = %d\t", p->PartialReception); + "partial_reception = %d\t", p->partial_reception); n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfLayers = %d\n", p->NumOfLayers); + "num_of_layers = %d\n", p->num_of_layers); n += snprintf(&buf[n], PAGE_SIZE - n, - "SmsToHostTxErrors = %d\n", p->SmsToHostTxErrors); + "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors); for (i = 0; i < 3; i++) { - if (p->LayerInfo[i].NumberOfSegments < 1 || - p->LayerInfo[i].NumberOfSegments > 13) + if (p->LayerInfo[i].number_of_segments < 1 || + p->LayerInfo[i].number_of_segments > 13) continue; n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tCodeRate = %d\t", - p->LayerInfo[i].CodeRate); - n += snprintf(&buf[n], PAGE_SIZE - n, "Constellation = %d\n", - p->LayerInfo[i].Constellation); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t", + p->LayerInfo[i].code_rate); + n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n", + p->LayerInfo[i].constellation); n += snprintf(&buf[n], PAGE_SIZE - n, "\tBER = %-5d\t", p->LayerInfo[i].BER); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tBERErrorCount = %-5d\t", - p->LayerInfo[i].BERErrorCount); - n += snprintf(&buf[n], PAGE_SIZE - n, "BERBitCount = %-5d\n", - p->LayerInfo[i].BERBitCount); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tPreBER = %-5d\t", - p->LayerInfo[i].PreBER); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t", + p->LayerInfo[i].ber_error_count); + n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n", + p->LayerInfo[i].ber_bit_count); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t", + p->LayerInfo[i].pre_ber); n += snprintf(&buf[n], PAGE_SIZE - n, "\tTS_PER = %-5d\n", p->LayerInfo[i].TS_PER); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tErrorTSPackets = %-5d\t", - p->LayerInfo[i].ErrorTSPackets); - n += snprintf(&buf[n], PAGE_SIZE - n, "TotalTSPackets = %-5d\t", - p->LayerInfo[i].TotalTSPackets); - n += snprintf(&buf[n], PAGE_SIZE - n, "TILdepthI = %d\n", - p->LayerInfo[i].TILdepthI); + n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t", + p->LayerInfo[i].error_ts_packets); + n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t", + p->LayerInfo[i].total_ts_packets); + n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n", + p->LayerInfo[i].ti_ldepth_i); n += snprintf(&buf[n], PAGE_SIZE - n, - "\tNumberOfSegments = %d\t", - p->LayerInfo[i].NumberOfSegments); - n += snprintf(&buf[n], PAGE_SIZE - n, "TMCCErrors = %d\n", - p->LayerInfo[i].TMCCErrors); + "\tnumber_of_segments = %d\t", + p->LayerInfo[i].number_of_segments); + n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n", + p->LayerInfo[i].tmcc_errors); } debug_data->stats_count = n; @@ -256,76 +256,76 @@ void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data, buf = debug_data->stats_data; n += snprintf(&buf[n], PAGE_SIZE - n, - "StatisticsType = %d\t", p->StatisticsType); + "statistics_type = %d\t", p->statistics_type); n += snprintf(&buf[n], PAGE_SIZE - n, - "FullSize = %d\n", p->FullSize); + "full_size = %d\n", p->full_size); n += snprintf(&buf[n], PAGE_SIZE - n, - "IsRfLocked = %d\t\t", p->IsRfLocked); + "is_rf_locked = %d\t\t", p->is_rf_locked); n += snprintf(&buf[n], PAGE_SIZE - n, - "IsDemodLocked = %d\t", p->IsDemodLocked); + "is_demod_locked = %d\t", p->is_demod_locked); n += snprintf(&buf[n], PAGE_SIZE - n, - "IsExternalLNAOn = %d\n", p->IsExternalLNAOn); + "is_external_lna_on = %d\n", p->is_external_lna_on); n += snprintf(&buf[n], PAGE_SIZE - n, "SNR = %d dB\t\t", p->SNR); n += snprintf(&buf[n], PAGE_SIZE - n, "RSSI = %d dBm\t\t", p->RSSI); n += snprintf(&buf[n], PAGE_SIZE - n, - "InBandPwr = %d dBm\n", p->InBandPwr); + "in_band_pwr = %d dBm\n", p->in_band_pwr); n += snprintf(&buf[n], PAGE_SIZE - n, - "CarrierOffset = %d\t", p->CarrierOffset); + "carrier_offset = %d\t", p->carrier_offset); n += snprintf(&buf[n], PAGE_SIZE - n, - "Bandwidth = %d\t\t", p->Bandwidth); + "bandwidth = %d\t\t", p->bandwidth); n += snprintf(&buf[n], PAGE_SIZE - n, - "Frequency = %d Hz\n", p->Frequency); + "frequency = %d Hz\n", p->frequency); n += snprintf(&buf[n], PAGE_SIZE - n, - "TransmissionMode = %d\t", p->TransmissionMode); + "transmission_mode = %d\t", p->transmission_mode); n += snprintf(&buf[n], PAGE_SIZE - n, - "ModemState = %d\t\t", p->ModemState); + "modem_state = %d\t\t", p->modem_state); n += snprintf(&buf[n], PAGE_SIZE - n, - "GuardInterval = %d\n", p->GuardInterval); + "guard_interval = %d\n", p->guard_interval); n += snprintf(&buf[n], PAGE_SIZE - n, - "SystemType = %d\t\t", p->SystemType); + "system_type = %d\t\t", p->system_type); n += snprintf(&buf[n], PAGE_SIZE - n, - "PartialReception = %d\t", p->PartialReception); + "partial_reception = %d\t", p->partial_reception); n += snprintf(&buf[n], PAGE_SIZE - n, - "NumOfLayers = %d\n", p->NumOfLayers); - n += snprintf(&buf[n], PAGE_SIZE - n, "SegmentNumber = %d\t", - p->SegmentNumber); - n += snprintf(&buf[n], PAGE_SIZE - n, "TuneBW = %d\n", - p->TuneBW); + "num_of_layers = %d\n", p->num_of_layers); + n += snprintf(&buf[n], PAGE_SIZE - n, "segment_number = %d\t", + p->segment_number); + n += snprintf(&buf[n], PAGE_SIZE - n, "tune_bw = %d\n", + p->tune_bw); for (i = 0; i < 3; i++) { - if (p->LayerInfo[i].NumberOfSegments < 1 || - p->LayerInfo[i].NumberOfSegments > 13) + if (p->LayerInfo[i].number_of_segments < 1 || + p->LayerInfo[i].number_of_segments > 13) continue; n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tCodeRate = %d\t", - p->LayerInfo[i].CodeRate); - n += snprintf(&buf[n], PAGE_SIZE - n, "Constellation = %d\n", - p->LayerInfo[i].Constellation); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t", + p->LayerInfo[i].code_rate); + n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n", + p->LayerInfo[i].constellation); n += snprintf(&buf[n], PAGE_SIZE - n, "\tBER = %-5d\t", p->LayerInfo[i].BER); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tBERErrorCount = %-5d\t", - p->LayerInfo[i].BERErrorCount); - n += snprintf(&buf[n], PAGE_SIZE - n, "BERBitCount = %-5d\n", - p->LayerInfo[i].BERBitCount); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tPreBER = %-5d\t", - p->LayerInfo[i].PreBER); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t", + p->LayerInfo[i].ber_error_count); + n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n", + p->LayerInfo[i].ber_bit_count); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t", + p->LayerInfo[i].pre_ber); n += snprintf(&buf[n], PAGE_SIZE - n, "\tTS_PER = %-5d\n", p->LayerInfo[i].TS_PER); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tErrorTSPackets = %-5d\t", - p->LayerInfo[i].ErrorTSPackets); - n += snprintf(&buf[n], PAGE_SIZE - n, "TotalTSPackets = %-5d\t", - p->LayerInfo[i].TotalTSPackets); - n += snprintf(&buf[n], PAGE_SIZE - n, "TILdepthI = %d\n", - p->LayerInfo[i].TILdepthI); + n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t", + p->LayerInfo[i].error_ts_packets); + n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t", + p->LayerInfo[i].total_ts_packets); + n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n", + p->LayerInfo[i].ti_ldepth_i); n += snprintf(&buf[n], PAGE_SIZE - n, - "\tNumberOfSegments = %d\t", - p->LayerInfo[i].NumberOfSegments); - n += snprintf(&buf[n], PAGE_SIZE - n, "TMCCErrors = %d\n", - p->LayerInfo[i].TMCCErrors); + "\tnumber_of_segments = %d\t", + p->LayerInfo[i].number_of_segments); + n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n", + p->LayerInfo[i].tmcc_errors); } diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index a2882f5cfdd0..cec85fef2a1b 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -228,15 +228,15 @@ static void smsdvb_update_tx_params(struct smsdvb_client_t *client, struct dvb_frontend *fe = &client->frontend; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - c->frequency = p->Frequency; - client->fe_status = sms_to_status(p->IsDemodLocked, 0); - c->bandwidth_hz = sms_to_bw(p->Bandwidth); - c->transmission_mode = sms_to_mode(p->TransmissionMode); - c->guard_interval = sms_to_guard_interval(p->GuardInterval); - c->code_rate_HP = sms_to_code_rate(p->CodeRate); - c->code_rate_LP = sms_to_code_rate(p->LPCodeRate); - c->hierarchy = sms_to_hierarchy(p->Hierarchy); - c->modulation = sms_to_modulation(p->Constellation); + c->frequency = p->frequency; + client->fe_status = sms_to_status(p->is_demod_locked, 0); + c->bandwidth_hz = sms_to_bw(p->bandwidth); + c->transmission_mode = sms_to_mode(p->transmission_mode); + c->guard_interval = sms_to_guard_interval(p->guard_interval); + c->code_rate_HP = sms_to_code_rate(p->code_rate); + c->code_rate_LP = sms_to_code_rate(p->lp_code_rate); + c->hierarchy = sms_to_hierarchy(p->hierarchy); + c->modulation = sms_to_modulation(p->constellation); } static void smsdvb_update_per_slices(struct smsdvb_client_t *client, @@ -245,35 +245,35 @@ static void smsdvb_update_per_slices(struct smsdvb_client_t *client, struct dvb_frontend *fe = &client->frontend; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked); + client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked); c->modulation = sms_to_modulation(p->constellation); - /* Signal Strength, in DBm */ - c->strength.stat[0].uvalue = p->inBandPower * 1000; + /* signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->in_band_power * 1000; - /* Carrier to Noise ratio, in DB */ + /* Carrier to noise ratio, in DB */ c->cnr.stat[0].svalue = p->snr * 1000; /* PER/BER requires demod lock */ - if (!p->IsDemodLocked) + if (!p->is_demod_locked) return; /* TS PER */ client->last_per = c->block_error.stat[0].uvalue; c->block_error.stat[0].scale = FE_SCALE_COUNTER; c->block_count.stat[0].scale = FE_SCALE_COUNTER; - c->block_error.stat[0].uvalue += p->etsPackets; - c->block_count.stat[0].uvalue += p->etsPackets + p->tsPackets; + c->block_error.stat[0].uvalue += p->ets_packets; + c->block_count.stat[0].uvalue += p->ets_packets + p->ts_packets; /* BER */ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[0].uvalue += p->BERErrorCount; - c->post_bit_count.stat[0].uvalue += p->BERBitCount; + c->post_bit_error.stat[0].uvalue += p->ber_error_count; + c->post_bit_count.stat[0].uvalue += p->ber_bit_count; /* Legacy PER/BER */ - client->legacy_per = (p->etsPackets * 65535) / - (p->tsPackets + p->etsPackets); + client->legacy_per = (p->ets_packets * 65535) / + (p->ts_packets + p->ets_packets); } static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client, @@ -285,44 +285,44 @@ static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client, if (client->prt_dvb_stats) client->prt_dvb_stats(client->debug_data, p); - client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked); + client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked); /* Update DVB modulation parameters */ - c->frequency = p->Frequency; - client->fe_status = sms_to_status(p->IsDemodLocked, 0); - c->bandwidth_hz = sms_to_bw(p->Bandwidth); - c->transmission_mode = sms_to_mode(p->TransmissionMode); - c->guard_interval = sms_to_guard_interval(p->GuardInterval); - c->code_rate_HP = sms_to_code_rate(p->CodeRate); - c->code_rate_LP = sms_to_code_rate(p->LPCodeRate); - c->hierarchy = sms_to_hierarchy(p->Hierarchy); - c->modulation = sms_to_modulation(p->Constellation); + c->frequency = p->frequency; + client->fe_status = sms_to_status(p->is_demod_locked, 0); + c->bandwidth_hz = sms_to_bw(p->bandwidth); + c->transmission_mode = sms_to_mode(p->transmission_mode); + c->guard_interval = sms_to_guard_interval(p->guard_interval); + c->code_rate_HP = sms_to_code_rate(p->code_rate); + c->code_rate_LP = sms_to_code_rate(p->lp_code_rate); + c->hierarchy = sms_to_hierarchy(p->hierarchy); + c->modulation = sms_to_modulation(p->constellation); /* update reception data */ - c->lna = p->IsExternalLNAOn ? 1 : 0; + c->lna = p->is_external_lna_on ? 1 : 0; - /* Carrier to Noise ratio, in DB */ + /* Carrier to noise ratio, in DB */ c->cnr.stat[0].svalue = p->SNR * 1000; - /* Signal Strength, in DBm */ - c->strength.stat[0].uvalue = p->InBandPwr * 1000; + /* signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->in_band_pwr * 1000; /* PER/BER requires demod lock */ - if (!p->IsDemodLocked) + if (!p->is_demod_locked) return; /* TS PER */ client->last_per = c->block_error.stat[0].uvalue; c->block_error.stat[0].scale = FE_SCALE_COUNTER; c->block_count.stat[0].scale = FE_SCALE_COUNTER; - c->block_error.stat[0].uvalue += p->ErrorTSPackets; - c->block_count.stat[0].uvalue += p->TotalTSPackets; + c->block_error.stat[0].uvalue += p->error_ts_packets; + c->block_count.stat[0].uvalue += p->total_ts_packets; /* BER */ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[0].uvalue += p->BERErrorCount; - c->post_bit_count.stat[0].uvalue += p->BERBitCount; + c->post_bit_error.stat[0].uvalue += p->ber_error_count; + c->post_bit_count.stat[0].uvalue += p->ber_bit_count; /* Legacy PER/BER */ client->legacy_ber = p->BER; @@ -339,26 +339,26 @@ static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, if (client->prt_isdb_stats) client->prt_isdb_stats(client->debug_data, p); - client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked); + client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked); /* * Firmware 2.1 seems to report only lock status and - * Signal strength. The signal strength indicator is at the + * signal strength. The signal strength indicator is at the * wrong field. */ - if (p->StatisticsType == 0) { - c->strength.stat[0].uvalue = ((s32)p->TransmissionMode) * 1000; + if (p->statistics_type == 0) { + c->strength.stat[0].uvalue = ((s32)p->transmission_mode) * 1000; c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; return; } /* Update ISDB-T transmission parameters */ - c->frequency = p->Frequency; - c->bandwidth_hz = sms_to_bw(p->Bandwidth); - c->transmission_mode = sms_to_mode(p->TransmissionMode); - c->guard_interval = sms_to_guard_interval(p->GuardInterval); - c->isdbt_partial_reception = p->PartialReception ? 1 : 0; - n_layers = p->NumOfLayers; + c->frequency = p->frequency; + c->bandwidth_hz = sms_to_bw(p->bandwidth); + c->transmission_mode = sms_to_mode(p->transmission_mode); + c->guard_interval = sms_to_guard_interval(p->guard_interval); + c->isdbt_partial_reception = p->partial_reception ? 1 : 0; + n_layers = p->num_of_layers; if (n_layers < 1) n_layers = 1; if (n_layers > 3) @@ -366,16 +366,16 @@ static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, c->isdbt_layer_enabled = 0; /* update reception data */ - c->lna = p->IsExternalLNAOn ? 1 : 0; + c->lna = p->is_external_lna_on ? 1 : 0; - /* Carrier to Noise ratio, in DB */ + /* Carrier to noise ratio, in DB */ c->cnr.stat[0].svalue = p->SNR * 1000; - /* Signal Strength, in DBm */ - c->strength.stat[0].uvalue = p->InBandPwr * 1000; + /* signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->in_band_pwr * 1000; /* PER/BER and per-layer stats require demod lock */ - if (!p->IsDemodLocked) + if (!p->is_demod_locked) return; client->last_per = c->block_error.stat[0].uvalue; @@ -394,33 +394,33 @@ static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, lr = &p->LayerInfo[i]; /* Update per-layer transmission parameters */ - if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) { + if (lr->number_of_segments > 0 && lr->number_of_segments < 13) { c->isdbt_layer_enabled |= 1 << i; - c->layer[i].segment_count = lr->NumberOfSegments; + c->layer[i].segment_count = lr->number_of_segments; } else { continue; } - c->layer[i].modulation = sms_to_modulation(lr->Constellation); + c->layer[i].modulation = sms_to_modulation(lr->constellation); /* TS PER */ c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER; c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER; - c->block_error.stat[i + 1].uvalue += lr->ErrorTSPackets; - c->block_count.stat[i + 1].uvalue += lr->TotalTSPackets; + c->block_error.stat[i + 1].uvalue += lr->error_ts_packets; + c->block_count.stat[i + 1].uvalue += lr->total_ts_packets; /* Update global PER counter */ - c->block_error.stat[0].uvalue += lr->ErrorTSPackets; - c->block_count.stat[0].uvalue += lr->TotalTSPackets; + c->block_error.stat[0].uvalue += lr->error_ts_packets; + c->block_count.stat[0].uvalue += lr->total_ts_packets; /* BER */ c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER; c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[i + 1].uvalue += lr->BERErrorCount; - c->post_bit_count.stat[i + 1].uvalue += lr->BERBitCount; + c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count; + c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count; /* Update global BER counter */ - c->post_bit_error.stat[0].uvalue += lr->BERErrorCount; - c->post_bit_count.stat[0].uvalue += lr->BERBitCount; + c->post_bit_error.stat[0].uvalue += lr->ber_error_count; + c->post_bit_count.stat[0].uvalue += lr->ber_bit_count; } } @@ -436,13 +436,13 @@ static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, client->prt_isdb_stats_ex(client->debug_data, p); /* Update ISDB-T transmission parameters */ - c->frequency = p->Frequency; - client->fe_status = sms_to_status(p->IsDemodLocked, 0); - c->bandwidth_hz = sms_to_bw(p->Bandwidth); - c->transmission_mode = sms_to_mode(p->TransmissionMode); - c->guard_interval = sms_to_guard_interval(p->GuardInterval); - c->isdbt_partial_reception = p->PartialReception ? 1 : 0; - n_layers = p->NumOfLayers; + c->frequency = p->frequency; + client->fe_status = sms_to_status(p->is_demod_locked, 0); + c->bandwidth_hz = sms_to_bw(p->bandwidth); + c->transmission_mode = sms_to_mode(p->transmission_mode); + c->guard_interval = sms_to_guard_interval(p->guard_interval); + c->isdbt_partial_reception = p->partial_reception ? 1 : 0; + n_layers = p->num_of_layers; if (n_layers < 1) n_layers = 1; if (n_layers > 3) @@ -450,16 +450,16 @@ static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, c->isdbt_layer_enabled = 0; /* update reception data */ - c->lna = p->IsExternalLNAOn ? 1 : 0; + c->lna = p->is_external_lna_on ? 1 : 0; - /* Carrier to Noise ratio, in DB */ + /* Carrier to noise ratio, in DB */ c->cnr.stat[0].svalue = p->SNR * 1000; - /* Signal Strength, in DBm */ - c->strength.stat[0].uvalue = p->InBandPwr * 1000; + /* signal Strength, in DBm */ + c->strength.stat[0].uvalue = p->in_band_pwr * 1000; /* PER/BER and per-layer stats require demod lock */ - if (!p->IsDemodLocked) + if (!p->is_demod_locked) return; client->last_per = c->block_error.stat[0].uvalue; @@ -482,47 +482,47 @@ static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, lr = &p->LayerInfo[i]; /* Update per-layer transmission parameters */ - if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) { + if (lr->number_of_segments > 0 && lr->number_of_segments < 13) { c->isdbt_layer_enabled |= 1 << i; - c->layer[i].segment_count = lr->NumberOfSegments; + c->layer[i].segment_count = lr->number_of_segments; } else { continue; } - c->layer[i].modulation = sms_to_modulation(lr->Constellation); + c->layer[i].modulation = sms_to_modulation(lr->constellation); /* TS PER */ c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER; c->block_count.stat[i + 1].scale = FE_SCALE_COUNTER; - c->block_error.stat[i + 1].uvalue += lr->ErrorTSPackets; - c->block_count.stat[i + 1].uvalue += lr->TotalTSPackets; + c->block_error.stat[i + 1].uvalue += lr->error_ts_packets; + c->block_count.stat[i + 1].uvalue += lr->total_ts_packets; /* Update global PER counter */ - c->block_error.stat[0].uvalue += lr->ErrorTSPackets; - c->block_count.stat[0].uvalue += lr->TotalTSPackets; + c->block_error.stat[0].uvalue += lr->error_ts_packets; + c->block_count.stat[0].uvalue += lr->total_ts_packets; /* BER */ c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER; c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[i + 1].uvalue += lr->BERErrorCount; - c->post_bit_count.stat[i + 1].uvalue += lr->BERBitCount; + c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count; + c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count; /* Update global BER counter */ - c->post_bit_error.stat[0].uvalue += lr->BERErrorCount; - c->post_bit_count.stat[0].uvalue += lr->BERBitCount; + c->post_bit_error.stat[0].uvalue += lr->ber_error_count; + c->post_bit_count.stat[0].uvalue += lr->ber_bit_count; } } static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) { struct smsdvb_client_t *client = (struct smsdvb_client_t *) context; - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p) + struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) (((u8 *) cb->p) + cb->offset); void *p = phdr + 1; struct dvb_frontend *fe = &client->frontend; struct dtv_frontend_properties *c = &fe->dtv_property_cache; bool is_status_update = false; - switch (phdr->msgType) { + switch (phdr->msg_type) { case MSG_SMS_DVBT_BDA_DATA: /* * Only feed data to dvb demux if are there any feed listening @@ -530,7 +530,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) */ if (client->feed_users && client->has_tuned) dvb_dmx_swfilter(&client->demux, p, - cb->size - sizeof(struct SmsMsgHdr_ST)); + cb->size - sizeof(struct sms_msg_hdr)); break; case MSG_SMS_RF_TUNE_RES: @@ -571,7 +571,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) smsdvb_update_isdbt_stats(client, p); break; default: - /* Skip SmsMsgStatisticsInfo_ST:RequestResult field */ + /* Skip sms_msg_statistics_info:request_result field */ smsdvb_update_dvb_stats(client, p + sizeof(u32)); } @@ -580,7 +580,7 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb) /* Only for ISDB-T */ case MSG_SMS_GET_STATISTICS_EX_RES: - /* Skip SmsMsgStatisticsInfo_ST:RequestResult field? */ + /* Skip sms_msg_statistics_info:request_result field? */ smsdvb_update_isdbt_stats_ex(client, p + sizeof(u32)); is_status_update = true; break; @@ -636,18 +636,18 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed) { struct smsdvb_client_t *client = container_of(feed->demux, struct smsdvb_client_t, demux); - struct SmsMsgData_ST PidMsg; + struct sms_msg_data PidMsg; sms_debug("add pid %d(%x)", feed->pid, feed->pid); client->feed_users++; - PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - PidMsg.xMsgHeader.msgDstId = HIF_TASK; - PidMsg.xMsgHeader.msgFlags = 0; - PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ; - PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); + PidMsg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + PidMsg.x_msg_header.msg_dst_id = HIF_TASK; + PidMsg.x_msg_header.msg_flags = 0; + PidMsg.x_msg_header.msg_type = MSG_SMS_ADD_PID_FILTER_REQ; + PidMsg.x_msg_header.msg_length = sizeof(PidMsg); PidMsg.msgData[0] = feed->pid; return smsclient_sendrequest(client->smsclient, @@ -658,18 +658,18 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed) { struct smsdvb_client_t *client = container_of(feed->demux, struct smsdvb_client_t, demux); - struct SmsMsgData_ST PidMsg; + struct sms_msg_data PidMsg; sms_debug("remove pid %d(%x)", feed->pid, feed->pid); client->feed_users--; - PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - PidMsg.xMsgHeader.msgDstId = HIF_TASK; - PidMsg.xMsgHeader.msgFlags = 0; - PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ; - PidMsg.xMsgHeader.msgLength = sizeof(PidMsg); + PidMsg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + PidMsg.x_msg_header.msg_dst_id = HIF_TASK; + PidMsg.x_msg_header.msg_flags = 0; + PidMsg.x_msg_header.msg_type = MSG_SMS_REMOVE_PID_FILTER_REQ; + PidMsg.x_msg_header.msg_length = sizeof(PidMsg); PidMsg.msgData[0] = feed->pid; return smsclient_sendrequest(client->smsclient, @@ -694,7 +694,7 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) { int rc; - struct SmsMsgHdr_ST Msg; + struct sms_msg_hdr Msg; /* Don't request stats too fast */ if (client->get_stats_jiffies && @@ -702,10 +702,10 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) return 0; client->get_stats_jiffies = jiffies + msecs_to_jiffies(100); - Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - Msg.msgDstId = HIF_TASK; - Msg.msgFlags = 0; - Msg.msgLength = sizeof(Msg); + Msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + Msg.msg_dst_id = HIF_TASK; + Msg.msg_flags = 0; + Msg.msg_length = sizeof(Msg); switch (smscore_get_device_mode(client->coredev)) { case DEVICE_MODE_ISDBT: @@ -714,12 +714,12 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) * Check for firmware version, to avoid breaking for old cards */ if (client->coredev->fw_version >= 0x800) - Msg.msgType = MSG_SMS_GET_STATISTICS_EX_REQ; + Msg.msg_type = MSG_SMS_GET_STATISTICS_EX_REQ; else - Msg.msgType = MSG_SMS_GET_STATISTICS_REQ; + Msg.msg_type = MSG_SMS_GET_STATISTICS_REQ; break; default: - Msg.msgType = MSG_SMS_GET_STATISTICS_REQ; + Msg.msg_type = MSG_SMS_GET_STATISTICS_REQ; } rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), @@ -845,7 +845,7 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) container_of(fe, struct smsdvb_client_t, frontend); struct { - struct SmsMsgHdr_ST Msg; + struct sms_msg_hdr Msg; u32 Data[3]; } Msg; @@ -856,11 +856,11 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) client->event_unc_state = -1; fe->dtv_property_cache.delivery_system = SYS_DVBT; - Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - Msg.Msg.msgDstId = HIF_TASK; - Msg.Msg.msgFlags = 0; - Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ; - Msg.Msg.msgLength = sizeof(Msg); + Msg.Msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + Msg.Msg.msg_dst_id = HIF_TASK; + Msg.Msg.msg_flags = 0; + Msg.Msg.msg_type = MSG_SMS_RF_TUNE_REQ; + Msg.Msg.msg_length = sizeof(Msg); Msg.Data[0] = c->frequency; Msg.Data[2] = 12000000; @@ -915,17 +915,17 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) int ret; struct { - struct SmsMsgHdr_ST Msg; + struct sms_msg_hdr Msg; u32 Data[4]; } Msg; fe->dtv_property_cache.delivery_system = SYS_ISDBT; - Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID; - Msg.Msg.msgDstId = HIF_TASK; - Msg.Msg.msgFlags = 0; - Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ; - Msg.Msg.msgLength = sizeof(Msg); + Msg.Msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + Msg.Msg.msg_dst_id = HIF_TASK; + Msg.Msg.msg_flags = 0; + Msg.Msg.msg_type = MSG_SMS_ISDBT_TUNE_REQ; + Msg.Msg.msg_length = sizeof(Msg); if (c->isdbt_sb_segment_idx == -1) c->isdbt_sb_segment_idx = 0; diff --git a/drivers/media/common/siano/smsdvb.h b/drivers/media/common/siano/smsdvb.h index 63cdd755521e..e1ff07c2e6c8 100644 --- a/drivers/media/common/siano/smsdvb.h +++ b/drivers/media/common/siano/smsdvb.h @@ -57,7 +57,7 @@ struct smsdvb_client_t { int feed_users; bool has_tuned; - /* Stats debugfs data */ + /* stats debugfs data */ struct dentry *debugfs; struct smsdvb_debugfs *debug_data; @@ -74,30 +74,30 @@ struct smsdvb_client_t { struct RECEPTION_STATISTICS_PER_SLICES_S { u32 result; u32 snr; - s32 inBandPower; - u32 tsPackets; - u32 etsPackets; + s32 in_band_power; + u32 ts_packets; + u32 ets_packets; u32 constellation; - u32 hpCode; - u32 tpsSrvIndLP; - u32 tpsSrvIndHP; - u32 cellId; + u32 hp_code; + u32 tps_srv_ind_lp; + u32 tps_srv_ind_hp; + u32 cell_id; u32 reason; - u32 requestId; - u32 ModemState; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ + u32 request_id; + u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ u32 BER; /* Post Viterbi BER [1E-5] */ s32 RSSI; /* dBm */ - s32 CarrierOffset; /* Carrier Offset in bin/1024 */ + s32 carrier_offset; /* Carrier Offset in bin/1024 */ - u32 IsRfLocked; /* 0 - not locked, 1 - locked */ - u32 IsDemodLocked; /* 0 - not locked, 1 - locked */ + u32 is_rf_locked; /* 0 - not locked, 1 - locked */ + u32 is_demod_locked; /* 0 - not locked, 1 - locked */ - u32 BERBitCount; /* Total number of SYNC bits. */ - u32 BERErrorCount; /* Number of erronous SYNC bits. */ + u32 ber_bit_count; /* Total number of SYNC bits. */ + u32 ber_error_count; /* Number of erronous SYNC bits. */ s32 MRC_SNR; /* dB */ - s32 MRC_InBandPwr; /* In band power in dBM */ + s32 mrc_in_band_pwr; /* In band power in dBM */ s32 MRC_RSSI; /* dBm */ }; diff --git a/drivers/media/common/siano/smsendian.c b/drivers/media/common/siano/smsendian.c index e2657c2f0109..32a7b28bd324 100644 --- a/drivers/media/common/siano/smsendian.c +++ b/drivers/media/common/siano/smsendian.c @@ -28,11 +28,11 @@ void smsendian_handle_tx_message(void *buffer) { #ifdef __BIG_ENDIAN - struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; + struct sms_msg_data *msg = (struct sms_msg_data *)buffer; int i; int msgWords; - switch (msg->xMsgHeader.msgType) { + switch (msg->x_msg_header.msg_type) { case MSG_SMS_DATA_DOWNLOAD_REQ: { msg->msgData[0] = le32_to_cpu(msg->msgData[0]); @@ -40,8 +40,8 @@ void smsendian_handle_tx_message(void *buffer) } default: - msgWords = (msg->xMsgHeader.msgLength - - sizeof(struct SmsMsgHdr_ST))/4; + msgWords = (msg->x_msg_header.msg_length - + sizeof(struct sms_msg_hdr))/4; for (i = 0; i < msgWords; i++) msg->msgData[i] = le32_to_cpu(msg->msgData[i]); @@ -55,16 +55,16 @@ EXPORT_SYMBOL_GPL(smsendian_handle_tx_message); void smsendian_handle_rx_message(void *buffer) { #ifdef __BIG_ENDIAN - struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer; + struct sms_msg_data *msg = (struct sms_msg_data *)buffer; int i; int msgWords; - switch (msg->xMsgHeader.msgType) { + switch (msg->x_msg_header.msg_type) { case MSG_SMS_GET_VERSION_EX_RES: { - struct SmsVersionRes_ST *ver = - (struct SmsVersionRes_ST *) msg; - ver->ChipModel = le16_to_cpu(ver->ChipModel); + struct sms_version_res *ver = + (struct sms_version_res *) msg; + ver->chip_model = le16_to_cpu(ver->chip_model); break; } @@ -77,8 +77,8 @@ void smsendian_handle_rx_message(void *buffer) default: { - msgWords = (msg->xMsgHeader.msgLength - - sizeof(struct SmsMsgHdr_ST))/4; + msgWords = (msg->x_msg_header.msg_length - + sizeof(struct sms_msg_hdr))/4; for (i = 0; i < msgWords; i++) msg->msgData[i] = le32_to_cpu(msg->msgData[i]); @@ -93,11 +93,11 @@ EXPORT_SYMBOL_GPL(smsendian_handle_rx_message); void smsendian_handle_message_header(void *msg) { #ifdef __BIG_ENDIAN - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg; + struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)msg; - phdr->msgType = le16_to_cpu(phdr->msgType); - phdr->msgLength = le16_to_cpu(phdr->msgLength); - phdr->msgFlags = le16_to_cpu(phdr->msgFlags); + phdr->msg_type = le16_to_cpu(phdr->msg_type); + phdr->msg_length = le16_to_cpu(phdr->msg_length); + phdr->msg_flags = le16_to_cpu(phdr->msg_flags); #endif /* __BIG_ENDIAN */ } EXPORT_SYMBOL_GPL(smsendian_handle_message_header); diff --git a/drivers/media/mmc/siano/smssdio.c b/drivers/media/mmc/siano/smssdio.c index 8834c435acae..912c2814c6cf 100644 --- a/drivers/media/mmc/siano/smssdio.c +++ b/drivers/media/mmc/siano/smssdio.c @@ -98,7 +98,7 @@ static int smssdio_sendrequest(void *context, void *buffer, size_t size) sdio_claim_host(smsdev->func); - smsendian_handle_tx_message((struct SmsMsgData_ST *) buffer); + smsendian_handle_tx_message((struct sms_msg_data *) buffer); while (size >= smsdev->func->cur_blksize) { ret = sdio_memcpy_toio(smsdev->func, SMSSDIO_DATA, buffer, smsdev->func->cur_blksize); @@ -130,7 +130,7 @@ static void smssdio_interrupt(struct sdio_func *func) struct smssdio_device *smsdev; struct smscore_buffer_t *cb; - struct SmsMsgHdr_ST *hdr; + struct sms_msg_hdr *hdr; size_t size; smsdev = sdio_get_drvdata(func); @@ -163,20 +163,20 @@ static void smssdio_interrupt(struct sdio_func *func) hdr = cb->p; - if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) { + if (hdr->msg_flags & MSG_HDR_FLAG_SPLIT_MSG) { smsdev->split_cb = cb; return; } - if (hdr->msgLength > smsdev->func->cur_blksize) - size = hdr->msgLength - smsdev->func->cur_blksize; + if (hdr->msg_length > smsdev->func->cur_blksize) + size = hdr->msg_length - smsdev->func->cur_blksize; else size = 0; } else { cb = smsdev->split_cb; hdr = cb->p; - size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST); + size = hdr->msg_length - sizeof(struct sms_msg_hdr); smsdev->split_cb = NULL; } @@ -184,7 +184,7 @@ static void smssdio_interrupt(struct sdio_func *func) if (size) { void *buffer; - buffer = cb->p + (hdr->msgLength - size); + buffer = cb->p + (hdr->msg_length - size); size = ALIGN(size, SMSSDIO_BLOCK_SIZE); BUG_ON(smsdev->func->cur_blksize != SMSSDIO_BLOCK_SIZE); @@ -230,10 +230,10 @@ static void smssdio_interrupt(struct sdio_func *func) } } - cb->size = hdr->msgLength; + cb->size = hdr->msg_length; cb->offset = 0; - smsendian_handle_rx_message((struct SmsMsgData_ST *) cb->p); + smsendian_handle_rx_message((struct sms_msg_data *) cb->p); smscore_onresponse(smsdev->coredev, cb); } diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 01a0f39a7cec..3a290f175c82 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -93,26 +93,26 @@ static void smsusb_onresponse(struct urb *urb) } if ((urb->actual_length > 0) && (urb->status == 0)) { - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p; + struct sms_msg_hdr *phdr = (struct sms_msg_hdr *)surb->cb->p; smsendian_handle_message_header(phdr); - if (urb->actual_length >= phdr->msgLength) { - surb->cb->size = phdr->msgLength; + if (urb->actual_length >= phdr->msg_length) { + surb->cb->size = phdr->msg_length; if (dev->response_alignment && - (phdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG)) { + (phdr->msg_flags & MSG_HDR_FLAG_SPLIT_MSG)) { surb->cb->offset = dev->response_alignment + - ((phdr->msgFlags >> 8) & 3); + ((phdr->msg_flags >> 8) & 3); /* sanity check */ - if (((int) phdr->msgLength + + if (((int) phdr->msg_length + surb->cb->offset) > urb->actual_length) { sms_err("invalid response " "msglen %d offset %d " "size %d", - phdr->msgLength, + phdr->msg_length, surb->cb->offset, urb->actual_length); goto exit_and_resubmit; @@ -121,22 +121,22 @@ static void smsusb_onresponse(struct urb *urb) /* move buffer pointer and * copy header to its new location */ memcpy((char *) phdr + surb->cb->offset, - phdr, sizeof(struct SmsMsgHdr_ST)); + phdr, sizeof(struct sms_msg_hdr)); } else surb->cb->offset = 0; sms_debug("received %s(%d) size: %d", - smscore_translate_msg(phdr->msgType), - phdr->msgType, phdr->msgLength); + smscore_translate_msg(phdr->msg_type), + phdr->msg_type, phdr->msg_length); - smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr); + smsendian_handle_rx_message((struct sms_msg_data *) phdr); smscore_onresponse(dev->coredev, surb->cb); surb->cb = NULL; } else { sms_err("invalid response " "msglen %d actual %d", - phdr->msgLength, urb->actual_length); + phdr->msg_length, urb->actual_length); } } else sms_err("error, urb status %d, %d bytes", @@ -206,18 +206,18 @@ static int smsusb_start_streaming(struct smsusb_device_t *dev) static int smsusb_sendrequest(void *context, void *buffer, size_t size) { struct smsusb_device_t *dev = (struct smsusb_device_t *) context; - struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) buffer; + struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer; int dummy; if (dev->state != SMSUSB_ACTIVE) return -ENOENT; sms_debug("sending %s(%d) size: %d", - smscore_translate_msg(phdr->msgType), phdr->msgType, - phdr->msgLength); + smscore_translate_msg(phdr->msg_type), phdr->msg_type, + phdr->msg_length); - smsendian_handle_tx_message((struct SmsMsgData_ST *) phdr); - smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer); + smsendian_handle_tx_message((struct sms_msg_data *) phdr); + smsendian_handle_message_header((struct sms_msg_hdr *)buffer); return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), buffer, size, &dummy, 1000); } @@ -310,8 +310,8 @@ static void smsusb1_detectmode(void *context, int *mode) static int smsusb1_setmode(void *context, int mode) { - struct SmsMsgHdr_ST Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK, - sizeof(struct SmsMsgHdr_ST), 0 }; + struct sms_msg_hdr Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK, + sizeof(struct sms_msg_hdr), 0 }; if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { sms_err("invalid firmware id specified %d", mode); @@ -375,7 +375,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id) dev->buffer_size = USB2_BUFFER_SIZE; dev->response_alignment = le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) - - sizeof(struct SmsMsgHdr_ST); + sizeof(struct sms_msg_hdr); params.flags |= SMS_DEVICE_FAMILY2; break; -- cgit v1.2.3 From cf0e9cfcc70d8aaeabf19356f42041f8a5495301 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Mar 2013 09:06:03 -0300 Subject: [media] siano: convert structure names to lowercase There are several structures defined in uppercase. Convert them to lowercase, and simplify their names, when possible. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.h | 52 ++++++++++++++--------------- drivers/media/common/siano/smsdvb-debugfs.c | 6 ++-- drivers/media/common/siano/smsdvb-main.c | 12 +++---- drivers/media/common/siano/smsdvb.h | 9 ++--- 4 files changed, 40 insertions(+), 39 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index 4b0cd7da22b7..b65232aabf5e 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -676,7 +676,7 @@ struct sms_firmware { /* statistics information returned as response for * SmsHostApiGetstatistics_Req */ -struct SMSHOSTLIB_STATISTICS_ST { +struct sms_stats { u32 reserved; /* reserved */ /* Common parameters */ @@ -764,7 +764,7 @@ struct SMSHOSTLIB_STATISTICS_ST { struct sms_msg_statistics_info { u32 request_result; - struct SMSHOSTLIB_STATISTICS_ST stat; + struct sms_stats stat; /* Split the calc of the SNR in DAB */ u32 signal; /* dB */ @@ -772,7 +772,7 @@ struct sms_msg_statistics_info { }; -struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST { +struct sms_isdbt_layer_stats { /* Per-layer information */ u32 code_rate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, * 255 means layer does not exist */ @@ -792,7 +792,7 @@ struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST { u32 tmcc_errors; /* TMCC errors */ }; -struct SMSHOSTLIB_STATISTICS_ISDBT_ST { +struct sms_isdbt_stats { u32 statistics_type; /* Enumerator identifying the type of the * structure. Values are the same as * SMSHOSTLIB_DEVICE_MODES_E @@ -827,14 +827,14 @@ struct SMSHOSTLIB_STATISTICS_ISDBT_ST { /* Per-layer information */ /* Layers A, B and C */ - struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3]; - /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */ + struct sms_isdbt_layer_stats LayerInfo[3]; + /* Per-layer statistics, see sms_isdbt_layer_stats */ /* Interface information */ u32 sms_to_host_tx_errors; /* Total number of transmission errors. */ }; -struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST { +struct sms_isdbt_stats_ex { u32 statistics_type; /* Enumerator identifying the type of the * structure. Values are the same as * SMSHOSTLIB_DEVICE_MODES_E @@ -872,8 +872,8 @@ struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST { /* Per-layer information */ /* Layers A, B and C */ - struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST LayerInfo[3]; - /* Per-layer statistics, see SMSHOSTLIB_ISDBT_LAYER_STAT_ST */ + struct sms_isdbt_layer_stats LayerInfo[3]; + /* Per-layer statistics, see sms_isdbt_layer_stats */ /* Interface information */ u32 reserved1; /* Was sms_to_host_tx_errors - obsolete . */ @@ -894,7 +894,7 @@ struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST { }; -struct PID_STATISTICS_DATA_S { +struct sms_pid_stats_data { struct PID_BURST_S { u32 size; u32 padding_cols; @@ -909,10 +909,10 @@ struct PID_STATISTICS_DATA_S { u32 tot_cor_tbl; }; -struct PID_DATA_S { +struct sms_pid_data { u32 pid; u32 num_rows; - struct PID_STATISTICS_DATA_S pid_statistics; + struct sms_pid_stats_data pid_statistics; }; #define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1) @@ -925,7 +925,7 @@ struct PID_DATA_S { else \ _stat.transmission_mode = 4; -struct TRANSMISSION_STATISTICS_S { +struct sms_tx_stats { u32 frequency; /* frequency in Hz */ u32 bandwidth; /* bandwidth in MHz */ u32 transmission_mode; /* FFT mode carriers in Kilos */ @@ -948,7 +948,7 @@ struct TRANSMISSION_STATISTICS_S { u32 is_demod_locked; /* 0 - not locked, 1 - locked */ }; -struct RECEPTION_STATISTICS_S { +struct sms_rx_stats { u32 is_rf_locked; /* 0 - not locked, 1 - locked */ u32 is_demod_locked; /* 0 - not locked, 1 - locked */ u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */ @@ -974,7 +974,7 @@ struct RECEPTION_STATISTICS_S { s32 mrc_in_band_pwr; /* In band power in dBM */ }; -struct RECEPTION_STATISTICS_EX_S { +struct sms_rx_stats_ex { u32 is_rf_locked; /* 0 - not locked, 1 - locked */ u32 is_demod_locked; /* 0 - not locked, 1 - locked */ u32 is_external_lna_on; /* 0 - external LNA off, 1 - external LNA on */ @@ -1006,33 +1006,33 @@ struct RECEPTION_STATISTICS_EX_S { /* statistics information returned as response for * SmsHostApiGetstatisticsEx_Req for DVB applications, SMS1100 and up */ -struct SMSHOSTLIB_STATISTICS_DVB_S { +struct sms_stats_dvb { /* Reception */ - struct RECEPTION_STATISTICS_S reception_data; + struct sms_rx_stats reception_data; /* Transmission parameters */ - struct TRANSMISSION_STATISTICS_S transmission_data; + struct sms_tx_stats transmission_data; /* Burst parameters, valid only for DVB-H */ #define SRVM_MAX_PID_FILTERS 8 - struct PID_DATA_S pid_data[SRVM_MAX_PID_FILTERS]; + struct sms_pid_data pid_data[SRVM_MAX_PID_FILTERS]; }; /* statistics information returned as response for * SmsHostApiGetstatisticsEx_Req for DVB applications, SMS1100 and up */ -struct SMSHOSTLIB_STATISTICS_DVB_EX_S { +struct sms_stats_dvb_ex { /* Reception */ - struct RECEPTION_STATISTICS_EX_S reception_data; + struct sms_rx_stats_ex reception_data; /* Transmission parameters */ - struct TRANSMISSION_STATISTICS_S transmission_data; + struct sms_tx_stats transmission_data; /* Burst parameters, valid only for DVB-H */ #define SRVM_MAX_PID_FILTERS 8 - struct PID_DATA_S pid_data[SRVM_MAX_PID_FILTERS]; + struct sms_pid_data pid_data[SRVM_MAX_PID_FILTERS]; }; -struct SRVM_SIGNAL_STATUS_S { +struct sms_srvm_signal_status { u32 result; u32 snr; u32 ts_packets; @@ -1048,14 +1048,14 @@ struct SRVM_SIGNAL_STATUS_S { u32 request_id; }; -struct SMSHOSTLIB_I2C_REQ_ST { +struct sms_i2c_req { u32 device_address; /* I2c device address */ u32 write_count; /* number of bytes to write */ u32 read_count; /* number of bytes to read */ u8 Data[1]; }; -struct SMSHOSTLIB_I2C_RES_ST { +struct sms_i2c_res { u32 status; /* non-zero value in case of failure */ u32 read_count; /* number of bytes read */ u8 Data[1]; diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index 5a28506d7bba..f63121ccbd10 100644 --- a/drivers/media/common/siano/smsdvb-debugfs.c +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -49,7 +49,7 @@ struct smsdvb_debugfs { }; void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data, - struct SMSHOSTLIB_STATISTICS_ST *p) + struct sms_stats *p) { int n = 0; char *buf; @@ -152,7 +152,7 @@ void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data, } void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data, - struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) + struct sms_isdbt_stats *p) { int i, n = 0; char *buf; @@ -242,7 +242,7 @@ void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data, } void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data, - struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p) + struct sms_isdbt_stats_ex *p) { int i, n = 0; char *buf; diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index cec85fef2a1b..29d1c41bbd66 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -223,7 +223,7 @@ static inline u32 sms_to_bw(u32 value) FEC_NONE); static void smsdvb_update_tx_params(struct smsdvb_client_t *client, - struct TRANSMISSION_STATISTICS_S *p) + struct sms_tx_stats *p) { struct dvb_frontend *fe = &client->frontend; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -277,7 +277,7 @@ static void smsdvb_update_per_slices(struct smsdvb_client_t *client, } static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client, - struct SMSHOSTLIB_STATISTICS_ST *p) + struct sms_stats *p) { struct dvb_frontend *fe = &client->frontend; struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -329,11 +329,11 @@ static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client, }; static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, - struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p) + struct sms_isdbt_stats *p) { struct dvb_frontend *fe = &client->frontend; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr; + struct sms_isdbt_layer_stats *lr; int i, n_layers; if (client->prt_isdb_stats) @@ -425,11 +425,11 @@ static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, } static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, - struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p) + struct sms_isdbt_stats_ex *p) { struct dvb_frontend *fe = &client->frontend; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr; + struct sms_isdbt_layer_stats *lr; int i, n_layers; if (client->prt_isdb_stats_ex) diff --git a/drivers/media/common/siano/smsdvb.h b/drivers/media/common/siano/smsdvb.h index e1ff07c2e6c8..513f85366209 100644 --- a/drivers/media/common/siano/smsdvb.h +++ b/drivers/media/common/siano/smsdvb.h @@ -19,14 +19,14 @@ struct smsdvb_debugfs; struct smsdvb_client_t; typedef void (*sms_prt_dvb_stats_t)(struct smsdvb_debugfs *debug_data, - struct SMSHOSTLIB_STATISTICS_ST *p); + struct sms_stats *p); typedef void (*sms_prt_isdb_stats_t)(struct smsdvb_debugfs *debug_data, - struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p); + struct sms_isdbt_stats *p); typedef void (*sms_prt_isdb_stats_ex_t) (struct smsdvb_debugfs *debug_data, - struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p); + struct sms_isdbt_stats_ex *p); struct smsdvb_client_t { @@ -68,7 +68,8 @@ struct smsdvb_client_t { }; /* - * This struct is a mix of RECEPTION_STATISTICS_EX_S and SRVM_SIGNAL_STATUS_S. + * This struct is a mix of struct sms_rx_stats_ex and + * struct sms_srvm_signal_status. * It was obtained by comparing the way it was filled by the original code */ struct RECEPTION_STATISTICS_PER_SLICES_S { -- cgit v1.2.3 From 90414248bf23ba3c96811f48053b47bfc330fce3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Mar 2013 09:10:22 -0300 Subject: [media] siano: fix checkpatch.pl compliants on smscoreapi.h Fix the remaining checkpatch.pl compliants at smscoreapi.h, except by the "line over 80 characters" on comments. Fixing those would require more time, as the better is to convert them into the struct descriptions used inside the kernel, as described at: Documentation/kernel-doc-nano-HOWTO.txt Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index b65232aabf5e..b0253d2d2091 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -577,8 +577,11 @@ enum msg_types { }; #define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \ - (ptr)->msg_type = type; (ptr)->msg_src_id = src; (ptr)->msg_dst_id = dst; \ - (ptr)->msg_length = len; (ptr)->msg_flags = 0; \ + (ptr)->msg_type = type; \ + (ptr)->msg_src_id = src; \ + (ptr)->msg_dst_id = dst; \ + (ptr)->msg_length = len; \ + (ptr)->msg_flags = 0; \ } while (0) #define SMS_INIT_MSG(ptr, type, len) \ @@ -704,7 +707,7 @@ struct sms_stats { u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET, valid only for DVB-T/H */ u32 guard_interval; /* Guard Interval from - SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */ + SMSHOSTLIB_GUARD_INTERVALS_ET, valid only for DVB-T/H */ u32 code_rate; /* Code Rate from SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */ u32 lp_code_rate; /* Low Priority Code Rate from @@ -746,7 +749,7 @@ struct sms_stats { u32 sms_to_host_tx_errors; /* Total number of transmission errors. */ /* DAB/T-DMB */ - u32 pre_ber; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ + u32 pre_ber; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ /* DVB-H TPS parameters */ u32 cell_id; /* TPS Cell ID in bits 15..0, bits 31..16 zero; @@ -1177,7 +1180,8 @@ int smscore_led_state(struct smscore_device_t *core, int led); #define dprintk(kern, lvl, fmt, arg...) do {\ if (sms_dbg & lvl) \ - sms_printk(kern, fmt, ##arg); } while (0) + sms_printk(kern, fmt, ##arg); \ +} while (0) #define sms_log(fmt, arg...) sms_printk(KERN_INFO, fmt, ##arg) #define sms_err(fmt, arg...) \ -- cgit v1.2.3 From 28a59df4d7cb8f749ba92ad304df4063ccf108fd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Mar 2013 09:27:37 -0300 Subject: [media] siano: remove the remaining CamelCase compliants Remove the remaining CamelCase checkpatch.pl compliants. There are still a few left, but those are due to USB and DVB APIs. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/sms-cards.c | 4 +- drivers/media/common/siano/smscoreapi.c | 256 ++++++++++++++-------------- drivers/media/common/siano/smscoreapi.h | 30 ++-- drivers/media/common/siano/smsdvb-debugfs.c | 68 ++++---- drivers/media/common/siano/smsdvb-main.c | 124 +++++++------- drivers/media/common/siano/smsdvb.h | 2 +- drivers/media/common/siano/smsendian.c | 18 +- drivers/media/usb/siano/smsusb.c | 4 +- 8 files changed, 253 insertions(+), 253 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 9bd7aa1f43ec..82769993eeb7 100644 --- a/drivers/media/common/siano/sms-cards.c +++ b/drivers/media/common/siano/sms-cards.c @@ -179,9 +179,9 @@ static inline void sms_gpio_assign_11xx_default_led_config( int sms_board_event(struct smscore_device_t *coredev, enum SMS_BOARD_EVENTS gevent) { - struct smscore_config_gpio MyGpioConfig; + struct smscore_config_gpio my_gpio_config; - sms_gpio_assign_11xx_default_led_config(&MyGpioConfig); + sms_gpio_assign_11xx_default_led_config(&my_gpio_config); switch (gevent) { case BOARD_EVENT_POWER_INIT: /* including hotplug */ diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index e5fa4056adb3..19e7a5fb4183 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -803,8 +803,8 @@ static int smscore_init_ir(struct smscore_device_t *coredev) SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_START_IR_REQ, sizeof(struct sms_msg_data2)); - msg->msgData[0] = coredev->ir.controller; - msg->msgData[1] = coredev->ir.timeout; + msg->msg_data[0] = coredev->ir.controller; + msg->msg_data[1] = coredev->ir.timeout; rc = smscore_sendrequest_and_wait(coredev, msg, msg->x_msg_header. msg_length, @@ -840,31 +840,31 @@ int smscore_configure_board(struct smscore_device_t *coredev) } if (board->mtu) { - struct sms_msg_data MtuMsg; + struct sms_msg_data mtu_msg; sms_debug("set max transmit unit %d", board->mtu); - MtuMsg.x_msg_header.msg_src_id = 0; - MtuMsg.x_msg_header.msg_dst_id = HIF_TASK; - MtuMsg.x_msg_header.msg_flags = 0; - MtuMsg.x_msg_header.msg_type = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ; - MtuMsg.x_msg_header.msg_length = sizeof(MtuMsg); - MtuMsg.msgData[0] = board->mtu; + mtu_msg.x_msg_header.msg_src_id = 0; + mtu_msg.x_msg_header.msg_dst_id = HIF_TASK; + mtu_msg.x_msg_header.msg_flags = 0; + mtu_msg.x_msg_header.msg_type = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ; + mtu_msg.x_msg_header.msg_length = sizeof(mtu_msg); + mtu_msg.msg_data[0] = board->mtu; - coredev->sendrequest_handler(coredev->context, &MtuMsg, - sizeof(MtuMsg)); + coredev->sendrequest_handler(coredev->context, &mtu_msg, + sizeof(mtu_msg)); } if (board->crystal) { - struct sms_msg_data CrysMsg; + struct sms_msg_data crys_msg; sms_debug("set crystal value %d", board->crystal); - SMS_INIT_MSG(&CrysMsg.x_msg_header, + SMS_INIT_MSG(&crys_msg.x_msg_header, MSG_SMS_NEW_CRYSTAL_REQ, - sizeof(CrysMsg)); - CrysMsg.msgData[0] = board->crystal; + sizeof(crys_msg)); + crys_msg.msg_data[0] = board->crystal; - coredev->sendrequest_handler(coredev->context, &CrysMsg, - sizeof(CrysMsg)); + coredev->sendrequest_handler(coredev->context, &crys_msg, + sizeof(crys_msg)); } return 0; @@ -959,7 +959,7 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, calc_checksum += *ptr; while (size && rc >= 0) { - struct sms_data_download *DataMsg = + struct sms_data_download *data_msg = (struct sms_data_download *) msg; int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE); @@ -967,11 +967,11 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, (u16)(sizeof(struct sms_msg_hdr) + sizeof(u32) + payload_size)); - DataMsg->mem_addr = mem_address; - memcpy(DataMsg->payload, payload, payload_size); + data_msg->mem_addr = mem_address; + memcpy(data_msg->payload, payload, payload_size); - rc = smscore_sendrequest_and_wait(coredev, DataMsg, - DataMsg->x_msg_header.msg_length, + rc = smscore_sendrequest_and_wait(coredev, data_msg, + data_msg->x_msg_header.msg_length, &coredev->data_download_done); payload += payload_size; @@ -987,10 +987,10 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_DATA_VALIDITY_REQ, sizeof(msg->x_msg_header) + sizeof(u32) * 3); - msg->msgData[0] = firmware->start_address; + msg->msg_data[0] = firmware->start_address; /* Entry point */ - msg->msgData[1] = firmware->length; - msg->msgData[2] = 0; /* Regular checksum*/ + msg->msg_data[1] = firmware->length; + msg->msg_data[2] = 0; /* Regular checksum*/ rc = smscore_sendrequest_and_wait(coredev, msg, msg->x_msg_header.msg_length, &coredev->data_validity_done); @@ -998,7 +998,7 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, goto exit_fw_download; if (coredev->mode == DEVICE_MODE_NONE) { - struct sms_msg_data *TriggerMsg = + struct sms_msg_data *trigger_msg = (struct sms_msg_data *) msg; sms_debug("sending MSG_SMS_SWDOWNLOAD_TRIGGER_REQ"); @@ -1007,15 +1007,15 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, sizeof(struct sms_msg_hdr) + sizeof(u32) * 5); - TriggerMsg->msgData[0] = firmware->start_address; + trigger_msg->msg_data[0] = firmware->start_address; /* Entry point */ - TriggerMsg->msgData[1] = 6; /* Priority */ - TriggerMsg->msgData[2] = 0x200; /* Stack size */ - TriggerMsg->msgData[3] = 0; /* Parameter */ - TriggerMsg->msgData[4] = 4; /* Task ID */ + trigger_msg->msg_data[1] = 6; /* Priority */ + trigger_msg->msg_data[2] = 0x200; /* Stack size */ + trigger_msg->msg_data[3] = 0; /* Parameter */ + trigger_msg->msg_data[4] = 4; /* Task ID */ - rc = smscore_sendrequest_and_wait(coredev, TriggerMsg, - TriggerMsg->x_msg_header.msg_length, + rc = smscore_sendrequest_and_wait(coredev, trigger_msg, + trigger_msg->x_msg_header.msg_length, &coredev->trigger_done); } else { SMS_INIT_MSG(&msg->x_msg_header, MSG_SW_RELOAD_EXEC_REQ, @@ -1315,7 +1315,7 @@ int smscore_init_device(struct smscore_device_t *coredev, int mode) msg = (struct sms_msg_data *)SMS_ALIGN_ADDRESS(buffer); SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ, sizeof(struct sms_msg_data)); - msg->msgData[0] = mode; + msg->msg_data[0] = mode; rc = smscore_sendrequest_and_wait(coredev, msg, msg->x_msg_header. msg_length, @@ -1403,7 +1403,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ, sizeof(struct sms_msg_data)); - msg->msgData[0] = mode; + msg->msg_data[0] = mode; rc = smscore_sendrequest_and_wait( coredev, msg, msg->x_msg_header.msg_length, @@ -1563,7 +1563,7 @@ void smscore_onresponse(struct smscore_device_t *coredev, struct sms_msg_data *validity = (struct sms_msg_data *) phdr; sms_err("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x", - validity->msgData[0]); + validity->msg_data[0]); complete(&coredev->data_validity_done); break; } @@ -1897,52 +1897,52 @@ int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level) } /* new GPIO management implementation */ -static int GetGpioPinParams(u32 pin_num, u32 *pTranslatedpin_num, - u32 *pGroupNum, u32 *pGroupCfg) { +static int get_gpio_pin_params(u32 pin_num, u32 *p_translatedpin_num, + u32 *p_group_num, u32 *p_group_cfg) { - *pGroupCfg = 1; + *p_group_cfg = 1; if (pin_num <= 1) { - *pTranslatedpin_num = 0; - *pGroupNum = 9; - *pGroupCfg = 2; + *p_translatedpin_num = 0; + *p_group_num = 9; + *p_group_cfg = 2; } else if (pin_num >= 2 && pin_num <= 6) { - *pTranslatedpin_num = 2; - *pGroupNum = 0; - *pGroupCfg = 2; + *p_translatedpin_num = 2; + *p_group_num = 0; + *p_group_cfg = 2; } else if (pin_num >= 7 && pin_num <= 11) { - *pTranslatedpin_num = 7; - *pGroupNum = 1; + *p_translatedpin_num = 7; + *p_group_num = 1; } else if (pin_num >= 12 && pin_num <= 15) { - *pTranslatedpin_num = 12; - *pGroupNum = 2; - *pGroupCfg = 3; + *p_translatedpin_num = 12; + *p_group_num = 2; + *p_group_cfg = 3; } else if (pin_num == 16) { - *pTranslatedpin_num = 16; - *pGroupNum = 23; + *p_translatedpin_num = 16; + *p_group_num = 23; } else if (pin_num >= 17 && pin_num <= 24) { - *pTranslatedpin_num = 17; - *pGroupNum = 3; + *p_translatedpin_num = 17; + *p_group_num = 3; } else if (pin_num == 25) { - *pTranslatedpin_num = 25; - *pGroupNum = 6; + *p_translatedpin_num = 25; + *p_group_num = 6; } else if (pin_num >= 26 && pin_num <= 28) { - *pTranslatedpin_num = 26; - *pGroupNum = 4; + *p_translatedpin_num = 26; + *p_group_num = 4; } else if (pin_num == 29) { - *pTranslatedpin_num = 29; - *pGroupNum = 5; - *pGroupCfg = 2; + *p_translatedpin_num = 29; + *p_group_num = 5; + *p_group_cfg = 2; } else if (pin_num == 30) { - *pTranslatedpin_num = 30; - *pGroupNum = 8; + *p_translatedpin_num = 30; + *p_group_num = 8; } else if (pin_num == 31) { - *pTranslatedpin_num = 31; - *pGroupNum = 17; + *p_translatedpin_num = 31; + *p_group_num = 17; } else return -1; - *pGroupCfg <<= 24; + *p_group_cfg <<= 24; return 0; } @@ -1950,18 +1950,18 @@ static int GetGpioPinParams(u32 pin_num, u32 *pTranslatedpin_num, int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num, struct smscore_config_gpio *p_gpio_config) { - u32 totalLen; - u32 Translatedpin_num = 0; - u32 GroupNum = 0; - u32 ElectricChar; - u32 groupCfg; + u32 total_len; + u32 translatedpin_num = 0; + u32 group_num = 0; + u32 electric_char; + u32 group_cfg; void *buffer; int rc; - struct SetGpioMsg { + struct set_gpio_msg { struct sms_msg_hdr x_msg_header; - u32 msgData[6]; - } *pMsg; + u32 msg_data[6]; + } *p_msg; if (pin_num > MAX_GPIO_PIN_NUMBER) @@ -1970,48 +1970,48 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num, if (p_gpio_config == NULL) return -EINVAL; - totalLen = sizeof(struct sms_msg_hdr) + (sizeof(u32) * 6); + total_len = sizeof(struct sms_msg_hdr) + (sizeof(u32) * 6); - buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); if (!buffer) return -ENOMEM; - pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + p_msg = (struct set_gpio_msg *) SMS_ALIGN_ADDRESS(buffer); - pMsg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; - pMsg->x_msg_header.msg_dst_id = HIF_TASK; - pMsg->x_msg_header.msg_flags = 0; - pMsg->x_msg_header.msg_length = (u16) totalLen; - pMsg->msgData[0] = pin_num; + p_msg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + p_msg->x_msg_header.msg_dst_id = HIF_TASK; + p_msg->x_msg_header.msg_flags = 0; + p_msg->x_msg_header.msg_length = (u16) total_len; + p_msg->msg_data[0] = pin_num; if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) { - pMsg->x_msg_header.msg_type = MSG_SMS_GPIO_CONFIG_REQ; - if (GetGpioPinParams(pin_num, &Translatedpin_num, &GroupNum, - &groupCfg) != 0) { + p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_CONFIG_REQ; + if (get_gpio_pin_params(pin_num, &translatedpin_num, &group_num, + &group_cfg) != 0) { rc = -EINVAL; goto free; } - pMsg->msgData[1] = Translatedpin_num; - pMsg->msgData[2] = GroupNum; - ElectricChar = (p_gpio_config->pullupdown) + p_msg->msg_data[1] = translatedpin_num; + p_msg->msg_data[2] = group_num; + electric_char = (p_gpio_config->pullupdown) | (p_gpio_config->inputcharacteristics << 2) | (p_gpio_config->outputslewrate << 3) | (p_gpio_config->outputdriving << 4); - pMsg->msgData[3] = ElectricChar; - pMsg->msgData[4] = p_gpio_config->direction; - pMsg->msgData[5] = groupCfg; + p_msg->msg_data[3] = electric_char; + p_msg->msg_data[4] = p_gpio_config->direction; + p_msg->msg_data[5] = group_cfg; } else { - pMsg->x_msg_header.msg_type = MSG_SMS_GPIO_CONFIG_EX_REQ; - pMsg->msgData[1] = p_gpio_config->pullupdown; - pMsg->msgData[2] = p_gpio_config->outputslewrate; - pMsg->msgData[3] = p_gpio_config->outputdriving; - pMsg->msgData[4] = p_gpio_config->direction; - pMsg->msgData[5] = 0; + p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_CONFIG_EX_REQ; + p_msg->msg_data[1] = p_gpio_config->pullupdown; + p_msg->msg_data[2] = p_gpio_config->outputslewrate; + p_msg->msg_data[3] = p_gpio_config->outputdriving; + p_msg->msg_data[4] = p_gpio_config->direction; + p_msg->msg_data[5] = 0; } - rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + rc = smscore_sendrequest_and_wait(coredev, p_msg, total_len, &coredev->gpio_configuration_done); if (rc != 0) { @@ -2029,38 +2029,38 @@ free: int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 pin_num, u8 new_level) { - u32 totalLen; + u32 total_len; int rc; void *buffer; - struct SetGpioMsg { + struct set_gpio_msg { struct sms_msg_hdr x_msg_header; - u32 msgData[3]; /* keep it 3 ! */ - } *pMsg; + u32 msg_data[3]; /* keep it 3 ! */ + } *p_msg; if ((new_level > 1) || (pin_num > MAX_GPIO_PIN_NUMBER)) return -EINVAL; - totalLen = sizeof(struct sms_msg_hdr) + + total_len = sizeof(struct sms_msg_hdr) + (3 * sizeof(u32)); /* keep it 3 ! */ - buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); if (!buffer) return -ENOMEM; - pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + p_msg = (struct set_gpio_msg *) SMS_ALIGN_ADDRESS(buffer); - pMsg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; - pMsg->x_msg_header.msg_dst_id = HIF_TASK; - pMsg->x_msg_header.msg_flags = 0; - pMsg->x_msg_header.msg_type = MSG_SMS_GPIO_SET_LEVEL_REQ; - pMsg->x_msg_header.msg_length = (u16) totalLen; - pMsg->msgData[0] = pin_num; - pMsg->msgData[1] = new_level; + p_msg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + p_msg->x_msg_header.msg_dst_id = HIF_TASK; + p_msg->x_msg_header.msg_flags = 0; + p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_SET_LEVEL_REQ; + p_msg->x_msg_header.msg_length = (u16) total_len; + p_msg->msg_data[0] = pin_num; + p_msg->msg_data[1] = new_level; /* Send message to SMS */ - rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + rc = smscore_sendrequest_and_wait(coredev, p_msg, total_len, &coredev->gpio_set_level_done); if (rc != 0) { @@ -2077,38 +2077,38 @@ int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 pin_num, int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num, u8 *level) { - u32 totalLen; + u32 total_len; int rc; void *buffer; - struct SetGpioMsg { + struct set_gpio_msg { struct sms_msg_hdr x_msg_header; - u32 msgData[2]; - } *pMsg; + u32 msg_data[2]; + } *p_msg; if (pin_num > MAX_GPIO_PIN_NUMBER) return -EINVAL; - totalLen = sizeof(struct sms_msg_hdr) + (2 * sizeof(u32)); + total_len = sizeof(struct sms_msg_hdr) + (2 * sizeof(u32)); - buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT, + buffer = kmalloc(total_len + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); if (!buffer) return -ENOMEM; - pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer); + p_msg = (struct set_gpio_msg *) SMS_ALIGN_ADDRESS(buffer); - pMsg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; - pMsg->x_msg_header.msg_dst_id = HIF_TASK; - pMsg->x_msg_header.msg_flags = 0; - pMsg->x_msg_header.msg_type = MSG_SMS_GPIO_GET_LEVEL_REQ; - pMsg->x_msg_header.msg_length = (u16) totalLen; - pMsg->msgData[0] = pin_num; - pMsg->msgData[1] = 0; + p_msg->x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + p_msg->x_msg_header.msg_dst_id = HIF_TASK; + p_msg->x_msg_header.msg_flags = 0; + p_msg->x_msg_header.msg_type = MSG_SMS_GPIO_GET_LEVEL_REQ; + p_msg->x_msg_header.msg_length = (u16) total_len; + p_msg->msg_data[0] = pin_num; + p_msg->msg_data[1] = 0; /* Send message to SMS */ - rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen, + rc = smscore_sendrequest_and_wait(coredev, p_msg, total_len, &coredev->gpio_get_level_done); if (rc != 0) { diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index b0253d2d2091..d3e781fedbc9 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -624,17 +624,17 @@ struct sms_msg_hdr { struct sms_msg_data { struct sms_msg_hdr x_msg_header; - u32 msgData[1]; + u32 msg_data[1]; }; struct sms_msg_data2 { struct sms_msg_hdr x_msg_header; - u32 msgData[2]; + u32 msg_data[2]; }; struct sms_msg_data4 { struct sms_msg_hdr x_msg_header; - u32 msgData[4]; + u32 msg_data[4]; }; struct sms_data_download { @@ -689,9 +689,9 @@ struct sms_stats { /* Reception quality */ s32 SNR; /* dB */ - u32 BER; /* Post Viterbi BER [1E-5] */ + u32 ber; /* Post Viterbi ber [1E-5] */ u32 FIB_CRC; /* CRC errors percentage, valid only for DAB */ - u32 TS_PER; /* Transport stream PER, + u32 ts_per; /* Transport stream PER, 0xFFFFFFFF indicate N/A, valid only for DVB-T/H */ u32 MFER; /* DVB-H frame error rate in percentage, 0xFFFFFFFF indicate N/A, valid only for DVB-H */ @@ -749,7 +749,7 @@ struct sms_stats { u32 sms_to_host_tx_errors; /* Total number of transmission errors. */ /* DAB/T-DMB */ - u32 pre_ber; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */ + u32 pre_ber; /* DAB/T-DMB only: Pre Viterbi ber [1E-5] */ /* DVB-H TPS parameters */ u32 cell_id; /* TPS Cell ID in bits 15..0, bits 31..16 zero; @@ -781,11 +781,11 @@ struct sms_isdbt_layer_stats { * 255 means layer does not exist */ u32 constellation; /* constellation from SMSHOSTLIB_CONSTELLATION_ET, * 255 means layer does not exist */ - u32 BER; /* Post Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ + u32 ber; /* Post Viterbi ber [1E-5], 0xFFFFFFFF indicate N/A */ u32 ber_error_count; /* Post Viterbi Error Bits Count */ u32 ber_bit_count; /* Post Viterbi Total Bits Count */ - u32 pre_ber; /* Pre Viterbi BER [1E-5], 0xFFFFFFFF indicate N/A */ - u32 TS_PER; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */ + u32 pre_ber; /* Pre Viterbi ber [1E-5], 0xFFFFFFFF indicate N/A */ + u32 ts_per; /* Transport stream PER [%], 0xFFFFFFFF indicate N/A */ u32 error_ts_packets; /* Number of erroneous transport-stream packets */ u32 total_ts_packets; /* Total number of transport-stream packets */ u32 ti_ldepth_i; /* Time interleaver depth I parameter, @@ -830,7 +830,7 @@ struct sms_isdbt_stats { /* Per-layer information */ /* Layers A, B and C */ - struct sms_isdbt_layer_stats LayerInfo[3]; + struct sms_isdbt_layer_stats layer_info[3]; /* Per-layer statistics, see sms_isdbt_layer_stats */ /* Interface information */ @@ -875,7 +875,7 @@ struct sms_isdbt_stats_ex { /* Per-layer information */ /* Layers A, B and C */ - struct sms_isdbt_layer_stats LayerInfo[3]; + struct sms_isdbt_layer_stats layer_info[3]; /* Per-layer statistics, see sms_isdbt_layer_stats */ /* Interface information */ @@ -958,10 +958,10 @@ struct sms_rx_stats { u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ s32 SNR; /* dB */ - u32 BER; /* Post Viterbi BER [1E-5] */ + u32 ber; /* Post Viterbi ber [1E-5] */ u32 ber_error_count; /* Number of erronous SYNC bits. */ u32 ber_bit_count; /* Total number of SYNC bits. */ - u32 TS_PER; /* Transport stream PER, + u32 ts_per; /* Transport stream PER, 0xFFFFFFFF indicate N/A */ u32 MFER; /* DVB-H frame error rate in percentage, 0xFFFFFFFF indicate N/A, valid only for DVB-H */ @@ -984,10 +984,10 @@ struct sms_rx_stats_ex { u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ s32 SNR; /* dB */ - u32 BER; /* Post Viterbi BER [1E-5] */ + u32 ber; /* Post Viterbi ber [1E-5] */ u32 ber_error_count; /* Number of erronous SYNC bits. */ u32 ber_bit_count; /* Total number of SYNC bits. */ - u32 TS_PER; /* Transport stream PER, + u32 ts_per; /* Transport stream PER, 0xFFFFFFFF indicate N/A */ u32 MFER; /* DVB-H frame error rate in percentage, 0xFFFFFFFF indicate N/A, valid only for DVB-H */ diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index f63121ccbd10..a881da548251 100644 --- a/drivers/media/common/siano/smsdvb-debugfs.c +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -71,11 +71,11 @@ void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data, n += snprintf(&buf[n], PAGE_SIZE - n, "SNR = %d\n", p->SNR); n += snprintf(&buf[n], PAGE_SIZE - n, - "BER = %d\n", p->BER); + "ber = %d\n", p->ber); n += snprintf(&buf[n], PAGE_SIZE - n, "FIB_CRC = %d\n", p->FIB_CRC); n += snprintf(&buf[n], PAGE_SIZE - n, - "TS_PER = %d\n", p->TS_PER); + "ts_per = %d\n", p->ts_per); n += snprintf(&buf[n], PAGE_SIZE - n, "MFER = %d\n", p->MFER); n += snprintf(&buf[n], PAGE_SIZE - n, @@ -204,36 +204,36 @@ void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data, "sms_to_host_tx_errors = %d\n", p->sms_to_host_tx_errors); for (i = 0; i < 3; i++) { - if (p->LayerInfo[i].number_of_segments < 1 || - p->LayerInfo[i].number_of_segments > 13) + if (p->layer_info[i].number_of_segments < 1 || + p->layer_info[i].number_of_segments > 13) continue; n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t", - p->LayerInfo[i].code_rate); + p->layer_info[i].code_rate); n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n", - p->LayerInfo[i].constellation); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tBER = %-5d\t", - p->LayerInfo[i].BER); + p->layer_info[i].constellation); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t", + p->layer_info[i].ber); n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t", - p->LayerInfo[i].ber_error_count); + p->layer_info[i].ber_error_count); n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n", - p->LayerInfo[i].ber_bit_count); + p->layer_info[i].ber_bit_count); n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t", - p->LayerInfo[i].pre_ber); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tTS_PER = %-5d\n", - p->LayerInfo[i].TS_PER); + p->layer_info[i].pre_ber); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n", + p->layer_info[i].ts_per); n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t", - p->LayerInfo[i].error_ts_packets); + p->layer_info[i].error_ts_packets); n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t", - p->LayerInfo[i].total_ts_packets); + p->layer_info[i].total_ts_packets); n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n", - p->LayerInfo[i].ti_ldepth_i); + p->layer_info[i].ti_ldepth_i); n += snprintf(&buf[n], PAGE_SIZE - n, "\tnumber_of_segments = %d\t", - p->LayerInfo[i].number_of_segments); + p->layer_info[i].number_of_segments); n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n", - p->LayerInfo[i].tmcc_errors); + p->layer_info[i].tmcc_errors); } debug_data->stats_count = n; @@ -296,36 +296,36 @@ void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data, p->tune_bw); for (i = 0; i < 3; i++) { - if (p->LayerInfo[i].number_of_segments < 1 || - p->LayerInfo[i].number_of_segments > 13) + if (p->layer_info[i].number_of_segments < 1 || + p->layer_info[i].number_of_segments > 13) continue; n += snprintf(&buf[n], PAGE_SIZE - n, "\nLayer %d\n", i); n += snprintf(&buf[n], PAGE_SIZE - n, "\tcode_rate = %d\t", - p->LayerInfo[i].code_rate); + p->layer_info[i].code_rate); n += snprintf(&buf[n], PAGE_SIZE - n, "constellation = %d\n", - p->LayerInfo[i].constellation); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tBER = %-5d\t", - p->LayerInfo[i].BER); + p->layer_info[i].constellation); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tber = %-5d\t", + p->layer_info[i].ber); n += snprintf(&buf[n], PAGE_SIZE - n, "\tber_error_count = %-5d\t", - p->LayerInfo[i].ber_error_count); + p->layer_info[i].ber_error_count); n += snprintf(&buf[n], PAGE_SIZE - n, "ber_bit_count = %-5d\n", - p->LayerInfo[i].ber_bit_count); + p->layer_info[i].ber_bit_count); n += snprintf(&buf[n], PAGE_SIZE - n, "\tpre_ber = %-5d\t", - p->LayerInfo[i].pre_ber); - n += snprintf(&buf[n], PAGE_SIZE - n, "\tTS_PER = %-5d\n", - p->LayerInfo[i].TS_PER); + p->layer_info[i].pre_ber); + n += snprintf(&buf[n], PAGE_SIZE - n, "\tts_per = %-5d\n", + p->layer_info[i].ts_per); n += snprintf(&buf[n], PAGE_SIZE - n, "\terror_ts_packets = %-5d\t", - p->LayerInfo[i].error_ts_packets); + p->layer_info[i].error_ts_packets); n += snprintf(&buf[n], PAGE_SIZE - n, "total_ts_packets = %-5d\t", - p->LayerInfo[i].total_ts_packets); + p->layer_info[i].total_ts_packets); n += snprintf(&buf[n], PAGE_SIZE - n, "ti_ldepth_i = %d\n", - p->LayerInfo[i].ti_ldepth_i); + p->layer_info[i].ti_ldepth_i); n += snprintf(&buf[n], PAGE_SIZE - n, "\tnumber_of_segments = %d\t", - p->LayerInfo[i].number_of_segments); + p->layer_info[i].number_of_segments); n += snprintf(&buf[n], PAGE_SIZE - n, "tmcc_errors = %d\n", - p->LayerInfo[i].tmcc_errors); + p->layer_info[i].tmcc_errors); } diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index 29d1c41bbd66..d965a7ae5982 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -265,7 +265,7 @@ static void smsdvb_update_per_slices(struct smsdvb_client_t *client, c->block_error.stat[0].uvalue += p->ets_packets; c->block_count.stat[0].uvalue += p->ets_packets + p->ts_packets; - /* BER */ + /* ber */ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; c->post_bit_error.stat[0].uvalue += p->ber_error_count; @@ -318,14 +318,14 @@ static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client, c->block_error.stat[0].uvalue += p->error_ts_packets; c->block_count.stat[0].uvalue += p->total_ts_packets; - /* BER */ + /* ber */ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; c->post_bit_error.stat[0].uvalue += p->ber_error_count; c->post_bit_count.stat[0].uvalue += p->ber_bit_count; /* Legacy PER/BER */ - client->legacy_ber = p->BER; + client->legacy_ber = p->ber; }; static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, @@ -391,7 +391,7 @@ static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; for (i = 0; i < n_layers; i++) { - lr = &p->LayerInfo[i]; + lr = &p->layer_info[i]; /* Update per-layer transmission parameters */ if (lr->number_of_segments > 0 && lr->number_of_segments < 13) { @@ -479,7 +479,7 @@ static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, c->block_error.len = n_layers + 1; c->block_count.len = n_layers + 1; for (i = 0; i < n_layers; i++) { - lr = &p->LayerInfo[i]; + lr = &p->layer_info[i]; /* Update per-layer transmission parameters */ if (lr->number_of_segments > 0 && lr->number_of_segments < 13) { @@ -500,13 +500,13 @@ static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, c->block_error.stat[0].uvalue += lr->error_ts_packets; c->block_count.stat[0].uvalue += lr->total_ts_packets; - /* BER */ + /* ber */ c->post_bit_error.stat[i + 1].scale = FE_SCALE_COUNTER; c->post_bit_count.stat[i + 1].scale = FE_SCALE_COUNTER; c->post_bit_error.stat[i + 1].uvalue += lr->ber_error_count; c->post_bit_count.stat[i + 1].uvalue += lr->ber_bit_count; - /* Update global BER counter */ + /* Update global ber counter */ c->post_bit_error.stat[0].uvalue += lr->ber_error_count; c->post_bit_count.stat[0].uvalue += lr->ber_bit_count; } @@ -636,44 +636,44 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed) { struct smsdvb_client_t *client = container_of(feed->demux, struct smsdvb_client_t, demux); - struct sms_msg_data PidMsg; + struct sms_msg_data pid_msg; sms_debug("add pid %d(%x)", feed->pid, feed->pid); client->feed_users++; - PidMsg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; - PidMsg.x_msg_header.msg_dst_id = HIF_TASK; - PidMsg.x_msg_header.msg_flags = 0; - PidMsg.x_msg_header.msg_type = MSG_SMS_ADD_PID_FILTER_REQ; - PidMsg.x_msg_header.msg_length = sizeof(PidMsg); - PidMsg.msgData[0] = feed->pid; + pid_msg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + pid_msg.x_msg_header.msg_dst_id = HIF_TASK; + pid_msg.x_msg_header.msg_flags = 0; + pid_msg.x_msg_header.msg_type = MSG_SMS_ADD_PID_FILTER_REQ; + pid_msg.x_msg_header.msg_length = sizeof(pid_msg); + pid_msg.msg_data[0] = feed->pid; return smsclient_sendrequest(client->smsclient, - &PidMsg, sizeof(PidMsg)); + &pid_msg, sizeof(pid_msg)); } static int smsdvb_stop_feed(struct dvb_demux_feed *feed) { struct smsdvb_client_t *client = container_of(feed->demux, struct smsdvb_client_t, demux); - struct sms_msg_data PidMsg; + struct sms_msg_data pid_msg; sms_debug("remove pid %d(%x)", feed->pid, feed->pid); client->feed_users--; - PidMsg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; - PidMsg.x_msg_header.msg_dst_id = HIF_TASK; - PidMsg.x_msg_header.msg_flags = 0; - PidMsg.x_msg_header.msg_type = MSG_SMS_REMOVE_PID_FILTER_REQ; - PidMsg.x_msg_header.msg_length = sizeof(PidMsg); - PidMsg.msgData[0] = feed->pid; + pid_msg.x_msg_header.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + pid_msg.x_msg_header.msg_dst_id = HIF_TASK; + pid_msg.x_msg_header.msg_flags = 0; + pid_msg.x_msg_header.msg_type = MSG_SMS_REMOVE_PID_FILTER_REQ; + pid_msg.x_msg_header.msg_length = sizeof(pid_msg); + pid_msg.msg_data[0] = feed->pid; return smsclient_sendrequest(client->smsclient, - &PidMsg, sizeof(PidMsg)); + &pid_msg, sizeof(pid_msg)); } static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, @@ -694,7 +694,7 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client, static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) { int rc; - struct sms_msg_hdr Msg; + struct sms_msg_hdr msg; /* Don't request stats too fast */ if (client->get_stats_jiffies && @@ -702,10 +702,10 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) return 0; client->get_stats_jiffies = jiffies + msecs_to_jiffies(100); - Msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; - Msg.msg_dst_id = HIF_TASK; - Msg.msg_flags = 0; - Msg.msg_length = sizeof(Msg); + msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + msg.msg_dst_id = HIF_TASK; + msg.msg_flags = 0; + msg.msg_length = sizeof(msg); switch (smscore_get_device_mode(client->coredev)) { case DEVICE_MODE_ISDBT: @@ -714,15 +714,15 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client) * Check for firmware version, to avoid breaking for old cards */ if (client->coredev->fw_version >= 0x800) - Msg.msg_type = MSG_SMS_GET_STATISTICS_EX_REQ; + msg.msg_type = MSG_SMS_GET_STATISTICS_EX_REQ; else - Msg.msg_type = MSG_SMS_GET_STATISTICS_REQ; + msg.msg_type = MSG_SMS_GET_STATISTICS_REQ; break; default: - Msg.msg_type = MSG_SMS_GET_STATISTICS_REQ; + msg.msg_type = MSG_SMS_GET_STATISTICS_REQ; } - rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + rc = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg), &client->stats_done); return rc; @@ -845,9 +845,9 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) container_of(fe, struct smsdvb_client_t, frontend); struct { - struct sms_msg_hdr Msg; + struct sms_msg_hdr msg; u32 Data[3]; - } Msg; + } msg; int ret; @@ -856,26 +856,26 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) client->event_unc_state = -1; fe->dtv_property_cache.delivery_system = SYS_DVBT; - Msg.Msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; - Msg.Msg.msg_dst_id = HIF_TASK; - Msg.Msg.msg_flags = 0; - Msg.Msg.msg_type = MSG_SMS_RF_TUNE_REQ; - Msg.Msg.msg_length = sizeof(Msg); - Msg.Data[0] = c->frequency; - Msg.Data[2] = 12000000; + msg.msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + msg.msg.msg_dst_id = HIF_TASK; + msg.msg.msg_flags = 0; + msg.msg.msg_type = MSG_SMS_RF_TUNE_REQ; + msg.msg.msg_length = sizeof(msg); + msg.Data[0] = c->frequency; + msg.Data[2] = 12000000; sms_info("%s: freq %d band %d", __func__, c->frequency, c->bandwidth_hz); switch (c->bandwidth_hz / 1000000) { case 8: - Msg.Data[1] = BW_8_MHZ; + msg.Data[1] = BW_8_MHZ; break; case 7: - Msg.Data[1] = BW_7_MHZ; + msg.Data[1] = BW_7_MHZ; break; case 6: - Msg.Data[1] = BW_6_MHZ; + msg.Data[1] = BW_6_MHZ; break; case 0: return -EOPNOTSUPP; @@ -888,7 +888,7 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) fe_status_t status; /* tune with LNA off at first */ - ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + ret = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg), &client->tune_done); smsdvb_read_status(fe, &status); @@ -900,7 +900,7 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe) sms_board_lna_control(client->coredev, 1); } - return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + return smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg), &client->tune_done); } @@ -915,17 +915,17 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) int ret; struct { - struct sms_msg_hdr Msg; + struct sms_msg_hdr msg; u32 Data[4]; - } Msg; + } msg; fe->dtv_property_cache.delivery_system = SYS_ISDBT; - Msg.Msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; - Msg.Msg.msg_dst_id = HIF_TASK; - Msg.Msg.msg_flags = 0; - Msg.Msg.msg_type = MSG_SMS_ISDBT_TUNE_REQ; - Msg.Msg.msg_length = sizeof(Msg); + msg.msg.msg_src_id = DVBT_BDA_CONTROL_MSG_ID; + msg.msg.msg_dst_id = HIF_TASK; + msg.msg.msg_flags = 0; + msg.msg.msg_type = MSG_SMS_ISDBT_TUNE_REQ; + msg.msg.msg_length = sizeof(msg); if (c->isdbt_sb_segment_idx == -1) c->isdbt_sb_segment_idx = 0; @@ -933,19 +933,19 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) if (!c->isdbt_layer_enabled) c->isdbt_layer_enabled = 7; - Msg.Data[0] = c->frequency; - Msg.Data[1] = BW_ISDBT_1SEG; - Msg.Data[2] = 12000000; - Msg.Data[3] = c->isdbt_sb_segment_idx; + msg.Data[0] = c->frequency; + msg.Data[1] = BW_ISDBT_1SEG; + msg.Data[2] = 12000000; + msg.Data[3] = c->isdbt_sb_segment_idx; if (c->isdbt_partial_reception) { if ((type == SMS_PELE || type == SMS_RIO) && c->isdbt_sb_segment_count > 3) - Msg.Data[1] = BW_ISDBT_13SEG; + msg.Data[1] = BW_ISDBT_13SEG; else if (c->isdbt_sb_segment_count > 1) - Msg.Data[1] = BW_ISDBT_3SEG; + msg.Data[1] = BW_ISDBT_3SEG; } else if (type == SMS_PELE || type == SMS_RIO) - Msg.Data[1] = BW_ISDBT_13SEG; + msg.Data[1] = BW_ISDBT_13SEG; c->bandwidth_hz = 6000000; @@ -959,7 +959,7 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) fe_status_t status; /* tune with LNA off at first */ - ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + ret = smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg), &client->tune_done); smsdvb_read_status(fe, &status); @@ -970,7 +970,7 @@ static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe) /* previous tune didn't lock - enable LNA and tune again */ sms_board_lna_control(client->coredev, 1); } - return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), + return smsdvb_sendrequest_and_wait(client, &msg, sizeof(msg), &client->tune_done); } diff --git a/drivers/media/common/siano/smsdvb.h b/drivers/media/common/siano/smsdvb.h index 513f85366209..92c413ba0c79 100644 --- a/drivers/media/common/siano/smsdvb.h +++ b/drivers/media/common/siano/smsdvb.h @@ -87,7 +87,7 @@ struct RECEPTION_STATISTICS_PER_SLICES_S { u32 request_id; u32 modem_state; /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */ - u32 BER; /* Post Viterbi BER [1E-5] */ + u32 ber; /* Post Viterbi BER [1E-5] */ s32 RSSI; /* dBm */ s32 carrier_offset; /* Carrier Offset in bin/1024 */ diff --git a/drivers/media/common/siano/smsendian.c b/drivers/media/common/siano/smsendian.c index 32a7b28bd324..bfe831c10b1c 100644 --- a/drivers/media/common/siano/smsendian.c +++ b/drivers/media/common/siano/smsendian.c @@ -30,21 +30,21 @@ void smsendian_handle_tx_message(void *buffer) #ifdef __BIG_ENDIAN struct sms_msg_data *msg = (struct sms_msg_data *)buffer; int i; - int msgWords; + int msg_words; switch (msg->x_msg_header.msg_type) { case MSG_SMS_DATA_DOWNLOAD_REQ: { - msg->msgData[0] = le32_to_cpu(msg->msgData[0]); + msg->msg_data[0] = le32_to_cpu(msg->msg_data[0]); break; } default: - msgWords = (msg->x_msg_header.msg_length - + msg_words = (msg->x_msg_header.msg_length - sizeof(struct sms_msg_hdr))/4; - for (i = 0; i < msgWords; i++) - msg->msgData[i] = le32_to_cpu(msg->msgData[i]); + for (i = 0; i < msg_words; i++) + msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]); break; } @@ -57,7 +57,7 @@ void smsendian_handle_rx_message(void *buffer) #ifdef __BIG_ENDIAN struct sms_msg_data *msg = (struct sms_msg_data *)buffer; int i; - int msgWords; + int msg_words; switch (msg->x_msg_header.msg_type) { case MSG_SMS_GET_VERSION_EX_RES: @@ -77,11 +77,11 @@ void smsendian_handle_rx_message(void *buffer) default: { - msgWords = (msg->x_msg_header.msg_length - + msg_words = (msg->x_msg_header.msg_length - sizeof(struct sms_msg_hdr))/4; - for (i = 0; i < msgWords; i++) - msg->msgData[i] = le32_to_cpu(msg->msgData[i]); + for (i = 0; i < msg_words; i++) + msg->msg_data[i] = le32_to_cpu(msg->msg_data[i]); break; } diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 3a290f175c82..03761c6f472f 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -310,7 +310,7 @@ static void smsusb1_detectmode(void *context, int *mode) static int smsusb1_setmode(void *context, int mode) { - struct sms_msg_hdr Msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK, + struct sms_msg_hdr msg = { MSG_SW_RELOAD_REQ, 0, HIF_TASK, sizeof(struct sms_msg_hdr), 0 }; if (mode < DEVICE_MODE_DVBT || mode > DEVICE_MODE_DVBT_BDA) { @@ -318,7 +318,7 @@ static int smsusb1_setmode(void *context, int mode) return -EINVAL; } - return smsusb_sendrequest(context, &Msg, sizeof(Msg)); + return smsusb_sendrequest(context, &msg, sizeof(msg)); } static void smsusb_term_device(struct usb_interface *intf) -- cgit v1.2.3 From 05ad412a63d66175f8f5a3d08894cf3f1d118cbc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Mar 2013 09:40:22 -0300 Subject: [media] siano: Fix the remaining checkpatch.pl compliants Fix all other remaining checkpatch.pl compliants on the Siano driver, except for the 80-cols (soft) limit. Those are harder to fix, and probably not worth to do right now. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 15 +++++++-------- drivers/media/common/siano/smscoreapi.h | 4 ---- drivers/media/common/siano/smsdvb-debugfs.c | 7 ++----- 3 files changed, 9 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 19e7a5fb4183..e7fc4deded56 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -57,8 +57,8 @@ struct smscore_client_t { struct list_head entry; struct smscore_device_t *coredev; void *context; - struct list_head idlist; - onresponse_t onresponse_handler; + struct list_head idlist; + onresponse_t onresponse_handler; onremove_t onremove_handler; }; @@ -874,7 +874,7 @@ int smscore_configure_board(struct smscore_device_t *coredev) * sets initial device mode and notifies client hotplugs that device is ready * * @param coredev pointer to a coredev object returned by - * smscore_register_device + * smscore_register_device * * @return 0 on success, <0 on error. */ @@ -961,7 +961,7 @@ static int smscore_load_firmware_family2(struct smscore_device_t *coredev, while (size && rc >= 0) { struct sms_data_download *data_msg = (struct sms_data_download *) msg; - int payload_size = min((int) size, SMS_MAX_PAYLOAD_SIZE); + int payload_size = min_t(int, size, SMS_MAX_PAYLOAD_SIZE); SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_DATA_DOWNLOAD_REQ, (u16)(sizeof(struct sms_msg_hdr) + @@ -1225,8 +1225,7 @@ void smscore_unregister_device(struct smscore_device_t *coredev) if (num_buffers == coredev->num_buffers) break; if (++retry > 10) { - sms_info("exiting although " - "not all buffers released."); + sms_info("exiting although not all buffers released."); break; } @@ -1279,8 +1278,8 @@ static int smscore_detect_mode(struct smscore_device_t *coredev) coredev, msg, msg->msg_length, &coredev->version_ex_done); if (rc < 0) - sms_err("MSG_SMS_GET_VERSION_EX_REQ failed " - "second try, rc %d", rc); + sms_err("MSG_SMS_GET_VERSION_EX_REQ failed second try, rc %d", + rc); } else rc = -ETIME; } diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index d3e781fedbc9..d0799e323364 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -40,10 +40,6 @@ along with this program. If not, see . #define kmutex_trylock(_p_) mutex_trylock(_p_) #define kmutex_unlock(_p_) mutex_unlock(_p_) -#ifndef min -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#endif - /* * Define the firmware names used by the driver. * Those should match what's used at smscoreapi.c and sms-cards.c diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index a881da548251..4c5691ee9eaf 100644 --- a/drivers/media/common/siano/smsdvb-debugfs.c +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -112,7 +112,7 @@ void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data, "burst_cycle_time = %d\n", p->burst_cycle_time); n += snprintf(&buf[n], PAGE_SIZE - n, "calc_burst_cycle_time = %d\n", - p->calc_burst_cycle_time); + p->calc_burst_cycle_time); n += snprintf(&buf[n], PAGE_SIZE - n, "num_of_rows = %d\n", p->num_of_rows); n += snprintf(&buf[n], PAGE_SIZE - n, @@ -509,8 +509,6 @@ void smsdvb_debugfs_release(struct smsdvb_client_t *client) if (!client->debugfs) return; -printk("%s\n", __func__); - client->prt_dvb_stats = NULL; client->prt_isdb_stats = NULL; client->prt_isdb_stats_ex = NULL; @@ -548,7 +546,6 @@ int smsdvb_debugfs_register(void) void smsdvb_debugfs_unregister(void) { - if (smsdvb_debugfs_usb_root) - debugfs_remove_recursive(smsdvb_debugfs_usb_root); + debugfs_remove_recursive(smsdvb_debugfs_usb_root); smsdvb_debugfs_usb_root = NULL; } -- cgit v1.2.3 From 2bf0f93e0d3044478bdd9e3dada19799d34dbfc2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Mar 2013 10:01:47 -0300 Subject: [media] siano: make some functions static drivers/media/common/siano/smsdvb-debugfs.c:51:6: warning: no previous prototype for 'smsdvb_print_dvb_stats' [-Wmissing-prototypes] drivers/media/common/siano/smsdvb-debugfs.c:154:6: warning: no previous prototype for 'smsdvb_print_isdb_stats' [-Wmissing-prototypes] drivers/media/common/siano/smsdvb-debugfs.c:244:6: warning: no previous prototype for 'smsdvb_print_isdb_stats_ex' [-Wmissing-prototypes] drivers/media/common/siano/smscoreapi.c:832:5: warning: no previous prototype for 'smscore_configure_board' [-Wmissing-prototypes] drivers/media/common/siano/smscoreapi.c:1301:5: warning: no previous prototype for 'smscore_init_device' [-Wmissing-prototypes] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 4 ++-- drivers/media/common/siano/smsdvb-debugfs.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index e7fc4deded56..ebb9eceb1dca 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -829,7 +829,7 @@ static int smscore_init_ir(struct smscore_device_t *coredev) * * @return 0 on success, <0 on error. */ -int smscore_configure_board(struct smscore_device_t *coredev) +static int smscore_configure_board(struct smscore_device_t *coredev) { struct sms_board *board; @@ -1298,7 +1298,7 @@ static int smscore_detect_mode(struct smscore_device_t *coredev) * * @return 0 on success, <0 on error. */ -int smscore_init_device(struct smscore_device_t *coredev, int mode) +static int smscore_init_device(struct smscore_device_t *coredev, int mode) { void *buffer; struct sms_msg_data *msg; diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index 4c5691ee9eaf..0bb4430535f9 100644 --- a/drivers/media/common/siano/smsdvb-debugfs.c +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -48,7 +48,7 @@ struct smsdvb_debugfs { wait_queue_head_t stats_queue; }; -void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data, +static void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data, struct sms_stats *p) { int n = 0; @@ -151,7 +151,7 @@ void smsdvb_print_dvb_stats(struct smsdvb_debugfs *debug_data, wake_up(&debug_data->stats_queue); } -void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data, +static void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data, struct sms_isdbt_stats *p) { int i, n = 0; @@ -241,7 +241,7 @@ void smsdvb_print_isdb_stats(struct smsdvb_debugfs *debug_data, wake_up(&debug_data->stats_queue); } -void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data, +static void smsdvb_print_isdb_stats_ex(struct smsdvb_debugfs *debug_data, struct sms_isdbt_stats_ex *p) { int i, n = 0; -- cgit v1.2.3 From 2b0e1f3afda10dfc33a6bdae07caa24b906d1114 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Mar 2013 06:36:41 -0300 Subject: [media] drxk: remove dummy BER read code The BER code does nothing but filling it with zero. Remove it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drxk_hard.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index c2fc7da0d6bf..0e40832a9a59 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -6408,21 +6408,6 @@ static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status) return 0; } -static int drxk_read_ber(struct dvb_frontend *fe, u32 *ber) -{ - struct drxk_state *state = fe->demodulator_priv; - - dprintk(1, "\n"); - - if (state->m_DrxkState == DRXK_NO_DEV) - return -ENODEV; - if (state->m_DrxkState == DRXK_UNINITIALIZED) - return -EAGAIN; - - *ber = 0; - return 0; -} - static int drxk_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { @@ -6529,7 +6514,6 @@ static struct dvb_frontend_ops drxk_ops = { .get_tune_settings = drxk_get_tune_settings, .read_status = drxk_read_status, - .read_ber = drxk_read_ber, .read_signal_strength = drxk_read_signal_strength, .read_snr = drxk_read_snr, .read_ucblocks = drxk_read_ucblocks, -- cgit v1.2.3 From 8f3741e02831d1181be9ca0ea711dd0c8d7f8a7b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Mar 2013 06:15:45 -0300 Subject: [media] drxk: Add pre/post BER and PER/UCB stats The original az6007 driver has the code to calculate such stats. Add it to the driver, reporting them via DVBv5 stats API. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drxk_hard.c | 179 +++++++++++++++++++++++++++++--- drivers/media/dvb-frontends/drxk_hard.h | 2 + drivers/media/dvb-frontends/drxk_map.h | 3 + 3 files changed, 172 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 0e40832a9a59..8c4de7cc4500 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -2655,11 +2655,6 @@ static int GetDVBTSignalToNoise(struct drxk_state *state, c = Log10Times100(SqrErrIQ); iMER = a + b; - /* No negative MER, clip to zero */ - if (iMER > c) - iMER -= c; - else - iMER = 0; } *pSignalToNoise = iMER; @@ -6380,31 +6375,165 @@ static int drxk_set_parameters(struct dvb_frontend *fe) fe->ops.tuner_ops.get_if_frequency(fe, &IF); Start(state, 0, IF); + /* After set_frontend, stats aren't avaliable */ + p->strength.stat[0].scale = FE_SCALE_RELATIVE; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + /* printk(KERN_DEBUG "drxk: %s IF=%d done\n", __func__, IF); */ return 0; } -static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status) +static int drxk_get_stats(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct drxk_state *state = fe->demodulator_priv; + int status; u32 stat; - - dprintk(1, "\n"); + u16 reg16; + u32 post_bit_count; + u32 post_bit_err_count; + u32 post_bit_error_scale; + u32 pre_bit_err_count; + u32 pre_bit_count; + u32 pkt_count; + u32 pkt_error_count; + s32 cnr, gain; if (state->m_DrxkState == DRXK_NO_DEV) return -ENODEV; if (state->m_DrxkState == DRXK_UNINITIALIZED) return -EAGAIN; - *status = 0; + /* get status */ + state->fe_status = 0; GetLockStatus(state, &stat, 0); if (stat == MPEG_LOCK) - *status |= 0x1f; + state->fe_status |= 0x1f; if (stat == FEC_LOCK) - *status |= 0x0f; + state->fe_status |= 0x0f; if (stat == DEMOD_LOCK) - *status |= 0x07; + state->fe_status |= 0x07; + + if (stat >= DEMOD_LOCK) { + GetSignalToNoise(state, &cnr); + c->cnr.stat[0].svalue = cnr * 100; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + } else { + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + if (stat < FEC_LOCK) { + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return 0; + } + + /* Get post BER */ + + /* BER measurement is valid if at least FEC lock is achieved */ + + /* OFDM_EC_VD_REQ_SMB_CNT__A and/or OFDM_EC_VD_REQ_BIT_CNT can be written + to set nr of symbols or bits over which + to measure EC_VD_REG_ERR_BIT_CNT__A . See CtrlSetCfg(). */ + + /* Read registers for post/preViterbi BER calculation */ + status = read16(state, OFDM_EC_VD_ERR_BIT_CNT__A, ®16); + if (status < 0) + goto error; + pre_bit_err_count = reg16; + + status = read16(state, OFDM_EC_VD_IN_BIT_CNT__A , ®16); + if (status < 0) + goto error; + pre_bit_count = reg16; + + /* Number of bit-errors */ + status = read16(state, FEC_RS_NR_BIT_ERRORS__A, ®16); + if (status < 0) + goto error; + post_bit_err_count = reg16; + + status = read16(state, FEC_RS_MEASUREMENT_PRESCALE__A, ®16); + if (status < 0) + goto error; + post_bit_error_scale = reg16; + + status = read16(state, FEC_RS_MEASUREMENT_PERIOD__A, ®16); + if (status < 0) + goto error; + pkt_count = reg16; + + status = read16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, ®16); + if (status < 0) + goto error; + pkt_error_count = reg16; + write16(state, SCU_RAM_FEC_ACCUM_PKT_FAILURES__A, 0); + + post_bit_err_count *= post_bit_error_scale; + + post_bit_count = pkt_count * 204 * 8; + + /* Store the results */ + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += pkt_error_count; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].uvalue += pkt_count; + + c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->pre_bit_error.stat[0].uvalue += pre_bit_err_count; + c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->pre_bit_count.stat[0].uvalue += pre_bit_count; + + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += post_bit_err_count; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue += post_bit_count; + + /* + * Read AGC gain + * + * IFgain = (IQM_AF_AGC_IF__A * 26.75) (nA) + */ + status = read16(state, IQM_AF_AGC_IF__A, ®16); + if (status < 0) { + printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); + return status; + } + gain = 2675 * (reg16 - DRXK_AGC_DAC_OFFSET) / 100; + + /* FIXME: it makes sense to fix the scale here to dBm */ + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + c->strength.stat[0].uvalue = gain; + +error: + return status; +} + + +static int drxk_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct drxk_state *state = fe->demodulator_priv; + int rc; + + dprintk(1, "\n"); + + rc = drxk_get_stats(fe); + if (rc < 0) + return rc; + + *status = state->fe_status; + return 0; } @@ -6439,6 +6568,10 @@ static int drxk_read_snr(struct dvb_frontend *fe, u16 *snr) return -EAGAIN; GetSignalToNoise(state, &snr2); + + /* No negative SNR, clip to zero */ + if (snr2 < 0) + snr2 = 0; *snr = snr2 & 0xffff; return 0; } @@ -6522,6 +6655,7 @@ static struct dvb_frontend_ops drxk_ops = { struct dvb_frontend *drxk_attach(const struct drxk_config *config, struct i2c_adapter *i2c) { + struct dtv_frontend_properties *p; struct drxk_state *state = NULL; u8 adr = config->adr; int status; @@ -6602,6 +6736,27 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config, } else if (init_drxk(state) < 0) goto error; + + /* Initialize stats */ + p = &state->frontend.dtv_property_cache; + p->strength.len = 1; + p->cnr.len = 1; + p->block_error.len = 1; + p->block_count.len = 1; + p->pre_bit_error.len = 1; + p->pre_bit_count.len = 1; + p->post_bit_error.len = 1; + p->post_bit_count.len = 1; + + p->strength.stat[0].scale = FE_SCALE_RELATIVE; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + printk(KERN_INFO "drxk: frontend initialized.\n"); return &state->frontend; diff --git a/drivers/media/dvb-frontends/drxk_hard.h b/drivers/media/dvb-frontends/drxk_hard.h index d18a896a9835..b8424f15f9a6 100644 --- a/drivers/media/dvb-frontends/drxk_hard.h +++ b/drivers/media/dvb-frontends/drxk_hard.h @@ -345,6 +345,8 @@ struct drxk_state { bool antenna_dvbt; u16 antenna_gpio; + fe_status_t fe_status; + /* Firmware */ const char *microcode_name; struct completion fw_wait_load; diff --git a/drivers/media/dvb-frontends/drxk_map.h b/drivers/media/dvb-frontends/drxk_map.h index 23e16c12f234..761613f9fd5a 100644 --- a/drivers/media/dvb-frontends/drxk_map.h +++ b/drivers/media/dvb-frontends/drxk_map.h @@ -10,6 +10,7 @@ #define FEC_RS_COMM_EXEC_STOP 0x0 #define FEC_RS_MEASUREMENT_PERIOD__A 0x1C30012 #define FEC_RS_MEASUREMENT_PRESCALE__A 0x1C30013 +#define FEC_RS_NR_BIT_ERRORS__A 0x1C30014 #define FEC_OC_MODE__A 0x1C40011 #define FEC_OC_MODE_PARITY__M 0x1 #define FEC_OC_DTO_MODE__A 0x1C40014 @@ -129,6 +130,8 @@ #define OFDM_EC_SB_PRIOR__A 0x3410013 #define OFDM_EC_SB_PRIOR_HI 0x0 #define OFDM_EC_SB_PRIOR_LO 0x1 +#define OFDM_EC_VD_ERR_BIT_CNT__A 0x3420017 +#define OFDM_EC_VD_IN_BIT_CNT__A 0x3420018 #define OFDM_EQ_TOP_TD_TPS_CONST__A 0x3010054 #define OFDM_EQ_TOP_TD_TPS_CONST__M 0x3 #define OFDM_EQ_TOP_TD_TPS_CONST_64QAM 0x2 -- cgit v1.2.3 From 59a7a23c4755f12757fe17234c693188a9e6bcf5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Mar 2013 08:21:52 -0300 Subject: [media] drxk: use a better calculus for RF strength The AZ6007 driver released by Terratec has a better way to estimate the signal strength, at CtrlSigStrength(). Port it to the driver. It should be noticed that there are two parameters there that are tuner-specific. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drxk_hard.c | 126 +++++++++++++++++++++++++++----- 1 file changed, 109 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 8c4de7cc4500..6e250533b628 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -6390,6 +6390,107 @@ static int drxk_set_parameters(struct dvb_frontend *fe) return 0; } +static int get_strength(struct drxk_state *state, u64 *strength) +{ + int status; + struct SCfgAgc rfAgc, ifAgc; + u32 totalGain = 0; + u32 atten = 0; + u32 agcRange = 0; + u16 scu_lvl = 0; + u16 scu_coc = 0; + /* FIXME: those are part of the tuner presets */ + u16 tunerRfGain = 50; /* Default value on az6007 driver */ + u16 tunerIfGain = 40; /* Default value on az6007 driver */ + + *strength = 0; + + if (IsDVBT(state)) { + rfAgc = state->m_dvbtRfAgcCfg; + ifAgc = state->m_dvbtIfAgcCfg; + } else if (IsQAM(state)) { + rfAgc = state->m_qamRfAgcCfg; + ifAgc = state->m_qamIfAgcCfg; + } else { + rfAgc = state->m_atvRfAgcCfg; + ifAgc = state->m_atvIfAgcCfg; + } + + if (rfAgc.ctrlMode == DRXK_AGC_CTRL_AUTO) { + /* SCU outputLevel */ + status = read16(state, SCU_RAM_AGC_RF_IACCU_HI__A, &scu_lvl); + if (status < 0) + return status; + + /* SCU c.o.c. */ + read16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, &scu_coc); + if (status < 0) + return status; + + if (((u32) scu_lvl + (u32) scu_coc) < 0xffff) + rfAgc.outputLevel = scu_lvl + scu_coc; + else + rfAgc.outputLevel = 0xffff; + + /* Take RF gain into account */ + totalGain += tunerRfGain; + + /* clip output value */ + if (rfAgc.outputLevel < rfAgc.minOutputLevel) + rfAgc.outputLevel = rfAgc.minOutputLevel; + if (rfAgc.outputLevel > rfAgc.maxOutputLevel) + rfAgc.outputLevel = rfAgc.maxOutputLevel; + + agcRange = (u32) (rfAgc.maxOutputLevel - rfAgc.minOutputLevel); + if (agcRange > 0) { + atten += 100UL * + ((u32)(tunerRfGain)) * + ((u32)(rfAgc.outputLevel - rfAgc.minOutputLevel)) + / agcRange; + } + } + + if (ifAgc.ctrlMode == DRXK_AGC_CTRL_AUTO) { + status = read16(state, SCU_RAM_AGC_IF_IACCU_HI__A, + &ifAgc.outputLevel); + if (status < 0) + return status; + + status = read16(state, SCU_RAM_AGC_INGAIN_TGT_MIN__A, + &ifAgc.top); + if (status < 0) + return status; + + /* Take IF gain into account */ + totalGain += (u32) tunerIfGain; + + /* clip output value */ + if (ifAgc.outputLevel < ifAgc.minOutputLevel) + ifAgc.outputLevel = ifAgc.minOutputLevel; + if (ifAgc.outputLevel > ifAgc.maxOutputLevel) + ifAgc.outputLevel = ifAgc.maxOutputLevel; + + agcRange = (u32) (ifAgc.maxOutputLevel - ifAgc.minOutputLevel); + if (agcRange > 0) { + atten += 100UL * + ((u32)(tunerIfGain)) * + ((u32)(ifAgc.outputLevel - ifAgc.minOutputLevel)) + / agcRange; + } + } + + /* + * Convert to 0..65535 scale. + * If it can't be measured (AGC is disabled), just show 100%. + */ + if (totalGain > 0) + *strength = (65535UL * atten / totalGain); + else + *strength = 65535; + + return 0; +} + static int drxk_get_stats(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -6404,7 +6505,7 @@ static int drxk_get_stats(struct dvb_frontend *fe) u32 pre_bit_count; u32 pkt_count; u32 pkt_error_count; - s32 cnr, gain; + s32 cnr; if (state->m_DrxkState == DRXK_NO_DEV) return -ENODEV; @@ -6421,6 +6522,13 @@ static int drxk_get_stats(struct dvb_frontend *fe) if (stat == DEMOD_LOCK) state->fe_status |= 0x07; + /* + * Estimate signal strength from AGC + */ + get_strength(state, &c->strength.stat[0].uvalue); + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + + if (stat >= DEMOD_LOCK) { GetSignalToNoise(state, &cnr); c->cnr.stat[0].svalue = cnr * 100; @@ -6500,22 +6608,6 @@ static int drxk_get_stats(struct dvb_frontend *fe) c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; c->post_bit_count.stat[0].uvalue += post_bit_count; - /* - * Read AGC gain - * - * IFgain = (IQM_AF_AGC_IF__A * 26.75) (nA) - */ - status = read16(state, IQM_AF_AGC_IF__A, ®16); - if (status < 0) { - printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); - return status; - } - gain = 2675 * (reg16 - DRXK_AGC_DAC_OFFSET) / 100; - - /* FIXME: it makes sense to fix the scale here to dBm */ - c->strength.stat[0].scale = FE_SCALE_RELATIVE; - c->strength.stat[0].uvalue = gain; - error: return status; } -- cgit v1.2.3 From 340e76965c868caa645268d2d36edb89af801fa4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Mar 2013 08:57:42 -0300 Subject: [media] drxk: Fix bogus signal strength indicator The DVBv3 signal strength indicator is bogus: it doesn't range from 0 to 65535 as it would be expected. Also, 0 means the max signal strength. Now that a better way to estimate it was added, use the new way. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drxk_hard.c | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 6e250533b628..fc93bd396cf4 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -2490,32 +2490,6 @@ error: return status; } -static int ReadIFAgc(struct drxk_state *state, u32 *pValue) -{ - u16 agcDacLvl; - int status; - u16 Level = 0; - - dprintk(1, "\n"); - - status = read16(state, IQM_AF_AGC_IF__A, &agcDacLvl); - if (status < 0) { - printk(KERN_ERR "drxk: Error %d on %s\n", status, __func__); - return status; - } - - *pValue = 0; - - if (agcDacLvl > DRXK_AGC_DAC_OFFSET) - Level = agcDacLvl - DRXK_AGC_DAC_OFFSET; - if (Level < 14000) - *pValue = (14000 - Level) / 4; - else - *pValue = 0; - - return status; -} - static int GetQAMSignalToNoise(struct drxk_state *state, s32 *pSignalToNoise) { @@ -6484,7 +6458,7 @@ static int get_strength(struct drxk_state *state, u64 *strength) * If it can't be measured (AGC is disabled), just show 100%. */ if (totalGain > 0) - *strength = (65535UL * atten / totalGain); + *strength = (65535UL * atten / totalGain / 100); else *strength = 65535; @@ -6633,7 +6607,7 @@ static int drxk_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { struct drxk_state *state = fe->demodulator_priv; - u32 val = 0; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; dprintk(1, "\n"); @@ -6642,8 +6616,7 @@ static int drxk_read_signal_strength(struct dvb_frontend *fe, if (state->m_DrxkState == DRXK_UNINITIALIZED) return -EAGAIN; - ReadIFAgc(state, &val); - *strength = val & 0xffff; + *strength = c->strength.stat[0].uvalue; return 0; } -- cgit v1.2.3 From 808d24d6c0b5c30c8f804b251caf476ea63954ef Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Mar 2013 10:39:31 -0300 Subject: [media] dvb-core: don't clear stats at DTV_CLEAR The stats are cleared by the frontend. Don't do it at DTV_CLEAR. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index eaa0a74e6a87..57601c0704c1 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -920,7 +920,7 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) u32 delsys; delsys = c->delivery_system; - memset(c, 0, sizeof(struct dtv_frontend_properties)); + memset(c, 0, offsetof(struct dtv_frontend_properties, strength)); c->delivery_system = delsys; c->state = DTV_CLEAR; -- cgit v1.2.3 From b6ba2057f7823352bbc44ee846faa03b36e8b6ac Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 1 Mar 2013 15:44:20 -0300 Subject: [media] videobuf2: add gfp_flags Some drivers have special memory requirements for their buffers, usually related to DMA (e.g. GFP_DMA or __GFP_DMA32). Make it possible to specify additional GFP flags for those buffers by adding a gfp_flags field to vb2_queue. Note that this field will be replaced in the future with a different mechanism, but that is still work in progress and we need this feature now so we won't be able to convert drivers with such requirements to vb2. Signed-off-by: Hans Verkuil Acked-by: Marek Szyprowski Acked-by: Federico Vaga Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 2 +- drivers/media/v4l2-core/videobuf2-dma-contig.c | 5 +++-- drivers/media/v4l2-core/videobuf2-dma-sg.c | 5 +++-- drivers/media/v4l2-core/videobuf2-vmalloc.c | 4 ++-- include/media/videobuf2-core.h | 10 ++++++++-- 5 files changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index be0448161c60..70827feb87b4 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -57,7 +57,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) /* Allocate memory for all planes in this buffer */ for (plane = 0; plane < vb->num_planes; ++plane) { mem_priv = call_memop(q, alloc, q->alloc_ctx[plane], - q->plane_sizes[plane]); + q->plane_sizes[plane], q->gfp_flags); if (IS_ERR_OR_NULL(mem_priv)) goto free; diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 10beaee7f0ae..ae35d255a430 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -152,7 +152,7 @@ static void vb2_dc_put(void *buf_priv) kfree(buf); } -static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size) +static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags) { struct vb2_dc_conf *conf = alloc_ctx; struct device *dev = conf->dev; @@ -165,7 +165,8 @@ static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size) /* align image size to PAGE_SIZE */ size = PAGE_ALIGN(size); - buf->vaddr = dma_alloc_coherent(dev, size, &buf->dma_addr, GFP_KERNEL); + buf->vaddr = dma_alloc_coherent(dev, size, &buf->dma_addr, + GFP_KERNEL | gfp_flags); if (!buf->vaddr) { dev_err(dev, "dma_alloc_coherent of size %ld failed\n", size); kfree(buf); diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index 25c3b360e1ad..952776fafe2c 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c @@ -33,7 +33,7 @@ struct vb2_dma_sg_buf { static void vb2_dma_sg_put(void *buf_priv); -static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size) +static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags) { struct vb2_dma_sg_buf *buf; int i; @@ -60,7 +60,8 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size) goto fail_pages_array_alloc; for (i = 0; i < buf->sg_desc.num_pages; ++i) { - buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN); + buf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO | + __GFP_NOWARN | gfp_flags); if (NULL == buf->pages[i]) goto fail_pages_alloc; sg_set_page(&buf->sg_desc.sglist[i], diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index a47fd4f589a1..313d9771b2bc 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -35,11 +35,11 @@ struct vb2_vmalloc_buf { static void vb2_vmalloc_put(void *buf_priv); -static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size) +static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags) { struct vb2_vmalloc_buf *buf; - buf = kzalloc(sizeof(*buf), GFP_KERNEL); + buf = kzalloc(sizeof(*buf), GFP_KERNEL | gfp_flags); if (!buf) return NULL; diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index a2d427450780..d88a098d1aff 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -27,7 +27,9 @@ struct vb2_fileio_data; * return NULL on failure or a pointer to allocator private, * per-buffer data on success; the returned private structure * will then be passed as buf_priv argument to other ops in this - * structure + * structure. Additional gfp_flags to use when allocating the + * are also passed to this operation. These flags are from the + * gfp_flags field of vb2_queue. * @put: inform the allocator that the buffer will no longer be used; * usually will result in the allocator freeing the buffer (if * no other users of this buffer are present); the buf_priv @@ -79,7 +81,7 @@ struct vb2_fileio_data; * unmap_dmabuf. */ struct vb2_mem_ops { - void *(*alloc)(void *alloc_ctx, unsigned long size); + void *(*alloc)(void *alloc_ctx, unsigned long size, gfp_t gfp_flags); void (*put)(void *buf_priv); struct dma_buf *(*get_dmabuf)(void *buf_priv); @@ -302,6 +304,9 @@ struct v4l2_fh; * @buf_struct_size: size of the driver-specific buffer structure; * "0" indicates the driver doesn't want to use a custom buffer * structure type, so sizeof(struct vb2_buffer) will is used + * @gfp_flags: additional gfp flags used when allocating the buffers. + * Typically this is 0, but it may be e.g. GFP_DMA or __GFP_DMA32 + * to force the buffer allocation to a specific memory zone. * * @memory: current memory type used * @bufs: videobuf buffer structures @@ -327,6 +332,7 @@ struct vb2_queue { void *drv_priv; unsigned int buf_struct_size; u32 timestamp_type; + gfp_t gfp_flags; /* private: internal use only */ enum v4l2_memory memory; -- cgit v1.2.3 From ffdc78efe1a8a013036aa7a63402f2708ed4f483 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 2 Mar 2013 05:12:08 -0300 Subject: [media] vb2-dma-sg: add debug module option This prevents the kernel log from being spammed with these messages. By turning on the debug option you will see them again. Signed-off-by: Hans Verkuil Acked-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-dma-sg.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index 952776fafe2c..59522b2ebae1 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c @@ -21,6 +21,15 @@ #include #include +static int debug; +module_param(debug, int, 0644); + +#define dprintk(level, fmt, arg...) \ + do { \ + if (debug >= level) \ + printk(KERN_DEBUG "vb2-dma-sg: " fmt, ## arg); \ + } while (0) + struct vb2_dma_sg_buf { void *vaddr; struct page **pages; @@ -74,7 +83,7 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_fla atomic_inc(&buf->refcount); - printk(KERN_DEBUG "%s: Allocated buffer of %d pages\n", + dprintk(1, "%s: Allocated buffer of %d pages\n", __func__, buf->sg_desc.num_pages); return buf; @@ -97,7 +106,7 @@ static void vb2_dma_sg_put(void *buf_priv) int i = buf->sg_desc.num_pages; if (atomic_dec_and_test(&buf->refcount)) { - printk(KERN_DEBUG "%s: Freeing buffer of %d pages\n", __func__, + dprintk(1, "%s: Freeing buffer of %d pages\n", __func__, buf->sg_desc.num_pages); if (buf->vaddr) vm_unmap_ram(buf->vaddr, buf->sg_desc.num_pages); @@ -163,7 +172,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr, return buf; userptr_fail_get_user_pages: - printk(KERN_DEBUG "get_user_pages requested/got: %d/%d]\n", + dprintk(1, "get_user_pages requested/got: %d/%d]\n", num_pages_from_user, buf->sg_desc.num_pages); while (--num_pages_from_user >= 0) put_page(buf->pages[num_pages_from_user]); @@ -186,7 +195,7 @@ static void vb2_dma_sg_put_userptr(void *buf_priv) struct vb2_dma_sg_buf *buf = buf_priv; int i = buf->sg_desc.num_pages; - printk(KERN_DEBUG "%s: Releasing userspace buffer of %d pages\n", + dprintk(1, "%s: Releasing userspace buffer of %d pages\n", __func__, buf->sg_desc.num_pages); if (buf->vaddr) vm_unmap_ram(buf->vaddr, buf->sg_desc.num_pages); -- cgit v1.2.3 From 88da0183eb2b72048099b4e0ecae1705f5309c94 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Mon, 18 Feb 2013 07:56:41 -0300 Subject: [media] media: ths7353: add support for ths7353 video amplifier The patch adds support for THS7353 video amplifier. The the THS7353 amplifier is very much similar to the existing THS7303 video amplifier driver. This patch appropriately makes changes to the existing ths7303 driver and adds support for the THS7353. This patch also adds V4L2_IDENT_THS7353 for the THS7353 chip and appropriate changes to Kconfig file for building. Signed-off-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Martin Bugge Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 6 +- drivers/media/i2c/ths7303.c | 351 +++++++++++++++++++++++++++++++++------- include/media/ths7303.h | 42 +++++ include/media/v4l2-chip-ident.h | 3 + 4 files changed, 340 insertions(+), 62 deletions(-) create mode 100644 include/media/ths7303.h (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 7b771baa2212..ec07ceb41c9c 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -550,10 +550,10 @@ config VIDEO_UPD64083 comment "Miscelaneous helper chips" config VIDEO_THS7303 - tristate "THS7303 Video Amplifier" - depends on I2C + tristate "THS7303/53 Video Amplifier" + depends on VIDEO_V4L2 && I2C help - Support for TI THS7303 video amplifier + Support for TI THS7303/53 video amplifier To compile this driver as a module, choose M here: the module will be called ths7303. diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index e747524ba6ed..3ca60c7cd95f 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c @@ -1,7 +1,15 @@ /* - * ths7303- THS7303 Video Amplifier driver + * ths7303/53- THS7303/53 Video Amplifier driver * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. + * + * Author: Chaithrika U S + * + * Contributors: + * Hans Verkuil + * Lad, Prabhakar + * Martin Bugge * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -13,25 +21,27 @@ * GNU General Public License for more details. */ -#include -#include -#include -#include #include -#include -#include #include -#include -#include +#include -#include -#include +#include #include +#include #define THS7303_CHANNEL_1 1 #define THS7303_CHANNEL_2 2 #define THS7303_CHANNEL_3 3 +struct ths7303_state { + struct v4l2_subdev sd; + struct ths7303_platform_data pdata; + struct v4l2_bt_timings bt; + int std_id; + int stream_on; + int driver_data; +}; + enum ths7303_filter_mode { THS7303_FILTER_MODE_480I_576I, THS7303_FILTER_MODE_480P_576P, @@ -48,64 +58,84 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level 0-1"); +static inline struct ths7303_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ths7303_state, sd); +} + +static int ths7303_read(struct v4l2_subdev *sd, u8 reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_read_byte_data(client, reg); +} + +static int ths7303_write(struct v4l2_subdev *sd, u8 reg, u8 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + int i; + + for (i = 0; i < 3; i++) { + ret = i2c_smbus_write_byte_data(client, reg, val); + if (ret == 0) + return 0; + } + return ret; +} + /* following function is used to set ths7303 */ int ths7303_setval(struct v4l2_subdev *sd, enum ths7303_filter_mode mode) { - u8 input_bias_chroma = 3; - u8 input_bias_luma = 3; - int disable = 0; - int err = 0; - u8 val = 0; - u8 temp; - struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ths7303_state *state = to_state(sd); + struct ths7303_platform_data *pdata = &state->pdata; + u8 val, sel = 0; + int err, disable = 0; if (!client) return -EINVAL; switch (mode) { case THS7303_FILTER_MODE_1080P: - val = (3 << 6); - val |= (3 << 3); + sel = 0x3; /*1080p and SXGA/UXGA */ break; case THS7303_FILTER_MODE_720P_1080I: - val = (2 << 6); - val |= (2 << 3); + sel = 0x2; /*720p, 1080i and SVGA/XGA */ break; case THS7303_FILTER_MODE_480P_576P: - val = (1 << 6); - val |= (1 << 3); + sel = 0x1; /* EDTV 480p/576p and VGA */ break; case THS7303_FILTER_MODE_480I_576I: + sel = 0x0; /* SDTV, S-Video, 480i/576i */ break; - case THS7303_FILTER_MODE_DISABLE: - pr_info("mode disabled\n"); - /* disable all channels */ - disable = 1; default: /* disable all channels */ disable = 1; } - /* Setup channel 2 - Luma - Green */ - temp = val; + + val = (sel << 6) | (sel << 3); if (!disable) - val |= input_bias_luma; - err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_2, val); + val |= (pdata->ch_1 & 0x27); + err = ths7303_write(sd, THS7303_CHANNEL_1, val); if (err) goto out; - /* setup two chroma channels */ + val = (sel << 6) | (sel << 3); if (!disable) - temp |= input_bias_chroma; - - err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_1, temp); + val |= (pdata->ch_2 & 0x27); + err = ths7303_write(sd, THS7303_CHANNEL_2, val); if (err) goto out; - err = i2c_smbus_write_byte_data(client, THS7303_CHANNEL_3, temp); + val = (sel << 6) | (sel << 3); + if (!disable) + val |= (pdata->ch_3 & 0x27); + err = ths7303_write(sd, THS7303_CHANNEL_3, val); if (err) goto out; - return err; + + return 0; out: pr_info("write byte data failed\n"); return err; @@ -113,49 +143,209 @@ out: static int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm) { - if (norm & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) + struct ths7303_state *state = to_state(sd); + + if (norm & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) { + state->std_id = 1; + state->bt.pixelclock = 0; return ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I); - else - return ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE); + } + + return ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE); } -/* for setting filter for HD output */ -static int ths7303_s_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *dv_timings) +static int ths7303_config(struct v4l2_subdev *sd) { - u32 height = dv_timings->bt.height; - int interlaced = dv_timings->bt.interlaced; - int res = 0; + struct ths7303_state *state = to_state(sd); + int res; + + if (!state->stream_on) { + ths7303_write(sd, THS7303_CHANNEL_1, + (ths7303_read(sd, THS7303_CHANNEL_1) & 0xf8) | + 0x00); + ths7303_write(sd, THS7303_CHANNEL_2, + (ths7303_read(sd, THS7303_CHANNEL_2) & 0xf8) | + 0x00); + ths7303_write(sd, THS7303_CHANNEL_3, + (ths7303_read(sd, THS7303_CHANNEL_3) & 0xf8) | + 0x00); + return 0; + } - if (height == 1080 && !interlaced) + if (state->bt.pixelclock > 120000000) res = ths7303_setval(sd, THS7303_FILTER_MODE_1080P); - else if ((height == 720 && !interlaced) || - (height == 1080 && interlaced)) + else if (state->bt.pixelclock > 70000000) res = ths7303_setval(sd, THS7303_FILTER_MODE_720P_1080I); - else if ((height == 480 || height == 576) && !interlaced) + else if (state->bt.pixelclock > 20000000) res = ths7303_setval(sd, THS7303_FILTER_MODE_480P_576P); + else if (state->std_id) + res = ths7303_setval(sd, THS7303_FILTER_MODE_480I_576I); else /* disable all channels */ res = ths7303_setval(sd, THS7303_FILTER_MODE_DISABLE); return res; + +} + +static int ths7303_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ths7303_state *state = to_state(sd); + + state->stream_on = enable; + + return ths7303_config(sd); +} + +/* for setting filter for HD output */ +static int ths7303_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *dv_timings) +{ + struct ths7303_state *state = to_state(sd); + + if (!dv_timings || dv_timings->type != V4L2_DV_BT_656_1120) + return -EINVAL; + + state->bt = dv_timings->bt; + state->std_id = 0; + + return ths7303_config(sd); } static int ths7303_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ths7303_state *state = to_state(sd); - return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_THS7303, 0); + return v4l2_chip_ident_i2c_client(client, chip, state->driver_data, 0); } static const struct v4l2_subdev_video_ops ths7303_video_ops = { + .s_stream = ths7303_s_stream, .s_std_output = ths7303_s_std_output, - .s_dv_timings = ths7303_s_dv_timings, + .s_dv_timings = ths7303_s_dv_timings, }; +#ifdef CONFIG_VIDEO_ADV_DEBUG + +static int ths7303_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + reg->size = 1; + reg->val = ths7303_read(sd, reg->reg); + return 0; +} + +static int ths7303_s_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!v4l2_chip_match_i2c_client(client, ®->match)) + return -EINVAL; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + ths7303_write(sd, reg->reg, reg->val); + return 0; +} +#endif + +static const char * const stc_lpf_sel_txt[4] = { + "500-kHz Filter", + "2.5-MHz Filter", + "5-MHz Filter", + "5-MHz Filter", +}; + +static const char * const in_mux_sel_txt[2] = { + "Input A Select", + "Input B Select", +}; + +static const char * const lpf_freq_sel_txt[4] = { + "9-MHz LPF", + "16-MHz LPF", + "35-MHz LPF", + "Bypass LPF", +}; + +static const char * const in_bias_sel_dis_cont_txt[8] = { + "Disable Channel", + "Mute Function - No Output", + "DC Bias Select", + "DC Bias + 250 mV Offset Select", + "AC Bias Select", + "Sync Tip Clamp with low bias", + "Sync Tip Clamp with mid bias", + "Sync Tip Clamp with high bias", +}; + +static void ths7303_log_channel_status(struct v4l2_subdev *sd, u8 reg) +{ + u8 val = ths7303_read(sd, reg); + + if ((val & 0x7) == 0) { + v4l2_info(sd, "Channel %d Off\n", reg); + return; + } + + v4l2_info(sd, "Channel %d On\n", reg); + v4l2_info(sd, " value 0x%x\n", val); + v4l2_info(sd, " %s\n", stc_lpf_sel_txt[(val >> 6) & 0x3]); + v4l2_info(sd, " %s\n", in_mux_sel_txt[(val >> 5) & 0x1]); + v4l2_info(sd, " %s\n", lpf_freq_sel_txt[(val >> 3) & 0x3]); + v4l2_info(sd, " %s\n", in_bias_sel_dis_cont_txt[(val >> 0) & 0x7]); +} + +static int ths7303_log_status(struct v4l2_subdev *sd) +{ + struct ths7303_state *state = to_state(sd); + + v4l2_info(sd, "stream %s\n", state->stream_on ? "On" : "Off"); + + if (state->bt.pixelclock) { + struct v4l2_bt_timings *bt = bt = &state->bt; + u32 frame_width, frame_height; + + frame_width = bt->width + bt->hfrontporch + + bt->hsync + bt->hbackporch; + frame_height = bt->height + bt->vfrontporch + + bt->vsync + bt->vbackporch; + v4l2_info(sd, + "timings: %dx%d%s%d (%dx%d). Pix freq. = %d Hz. Polarities = 0x%x\n", + bt->width, bt->height, bt->interlaced ? "i" : "p", + (frame_height * frame_width) > 0 ? + (int)bt->pixelclock / + (frame_height * frame_width) : 0, + frame_width, frame_height, + (int)bt->pixelclock, bt->polarities); + } else { + v4l2_info(sd, "no timings set\n"); + } + + ths7303_log_channel_status(sd, THS7303_CHANNEL_1); + ths7303_log_channel_status(sd, THS7303_CHANNEL_2); + ths7303_log_channel_status(sd, THS7303_CHANNEL_3); + + return 0; +} + static const struct v4l2_subdev_core_ops ths7303_core_ops = { .g_chip_ident = ths7303_g_chip_ident, + .log_status = ths7303_log_status, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ths7303_g_register, + .s_register = ths7303_s_register, +#endif }; static const struct v4l2_subdev_ops ths7303_ops = { @@ -163,11 +353,38 @@ static const struct v4l2_subdev_ops ths7303_ops = { .video = &ths7303_video_ops, }; +static int ths7303_setup(struct v4l2_subdev *sd) +{ + struct ths7303_state *state = to_state(sd); + struct ths7303_platform_data *pdata = &state->pdata; + int ret; + u8 mask; + + state->stream_on = pdata->init_enable; + + mask = state->stream_on ? 0xff : 0xf8; + + ret = ths7303_write(sd, THS7303_CHANNEL_1, pdata->ch_1 & mask); + if (ret) + return ret; + + ret = ths7303_write(sd, THS7303_CHANNEL_2, pdata->ch_2 & mask); + if (ret) + return ret; + + ret = ths7303_write(sd, THS7303_CHANNEL_3, pdata->ch_3 & mask); + if (ret) + return ret; + + return 0; +} + static int ths7303_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct ths7303_platform_data *pdata = client->dev.platform_data; + struct ths7303_state *state; struct v4l2_subdev *sd; - v4l2_std_id std_id = V4L2_STD_NTSC; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV; @@ -175,13 +392,28 @@ static int ths7303_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - sd = devm_kzalloc(&client->dev, sizeof(struct v4l2_subdev), GFP_KERNEL); - if (sd == NULL) + state = devm_kzalloc(&client->dev, sizeof(struct ths7303_state), + GFP_KERNEL); + if (!state) return -ENOMEM; + if (!pdata) + v4l_warn(client, "No platform data, using default data!\n"); + else + state->pdata = *pdata; + + sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &ths7303_ops); - return ths7303_s_std_output(sd, std_id); + /* store the driver data to differntiate the chip */ + state->driver_data = (int)id->driver_data; + + if (ths7303_setup(sd) < 0) { + v4l_err(client, "init failed\n"); + return -EIO; + } + + return 0; } static int ths7303_remove(struct i2c_client *client) @@ -194,7 +426,8 @@ static int ths7303_remove(struct i2c_client *client) } static const struct i2c_device_id ths7303_id[] = { - {"ths7303", 0}, + {"ths7303", V4L2_IDENT_THS7303}, + {"ths7353", V4L2_IDENT_THS7353}, {}, }; @@ -203,7 +436,7 @@ MODULE_DEVICE_TABLE(i2c, ths7303_id); static struct i2c_driver ths7303_driver = { .driver = { .owner = THIS_MODULE, - .name = "ths7303", + .name = "ths73x3", }, .probe = ths7303_probe, .remove = ths7303_remove, diff --git a/include/media/ths7303.h b/include/media/ths7303.h new file mode 100644 index 000000000000..980ec51d574d --- /dev/null +++ b/include/media/ths7303.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2013 Texas Instruments Inc + * + * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. + * + * Contributors: + * Hans Verkuil + * Lad, Prabhakar + * Martin Bugge + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef THS7353_H +#define THS7353_H + +/** + * struct ths7303_platform_data - Platform dependent data + * @ch_1: Bias value for channel one. + * @ch_2: Bias value for channel two. + * @ch_3: Bias value for channel three. + * @init_enable: initalize on init. + */ +struct ths7303_platform_data { + u8 ch_1; + u8 ch_2; + u8 ch_3; + u8 init_enable; +}; + +#endif diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index b5996f959a31..c259b36bf1e9 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h @@ -188,6 +188,9 @@ enum { /* module adv7343: just ident 7343 */ V4L2_IDENT_ADV7343 = 7343, + /* module ths7353: just ident 7353 */ + V4L2_IDENT_THS7353 = 7353, + /* module adv7393: just ident 7393 */ V4L2_IDENT_ADV7393 = 7393, -- cgit v1.2.3 From 5b38b0f88d28bd1b492fe225b6d401b2e51fd8cc Mon Sep 17 00:00:00 2001 From: Manjunath Hadli Date: Fri, 8 Mar 2013 04:13:35 -0300 Subject: [media] media: tvp514x: enable TVP514X for media controller based usage add support for TVP514x as a media entity and support for pad operations. The decoder supports 1 output pad. The default format code was V4L2_MBUS_FMT_YUYV10_2X10 changed it to V4L2_MBUS_FMT_UYVY8_2X8. Signed-off-by: Manjunath Hadli Signed-off-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp514x.c | 163 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 154 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index aa94ebc2d755..ab8f3fee7e94 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -12,6 +12,7 @@ * Hardik Shah * Manjunath Hadli * Karicheri Muralidharan + * Prabhakar Lad * * This package is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -33,6 +34,7 @@ #include #include #include +#include #include #include @@ -40,12 +42,10 @@ #include #include #include +#include #include "tvp514x_regs.h" -/* Module Name */ -#define TVP514X_MODULE_NAME "tvp514x" - /* Private macros for TVP */ #define I2C_RETRY_COUNT (5) #define LOCK_RETRY_COUNT (5) @@ -91,6 +91,9 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable); * @pdata: Board specific * @ver: Chip version * @streaming: TVP5146/47 decoder streaming - enabled or disabled. + * @pix: Current pixel format + * @num_fmts: Number of formats + * @fmt_list: Format list * @current_std: Current standard * @num_stds: Number of standards * @std_list: Standards list @@ -106,12 +109,20 @@ struct tvp514x_decoder { int ver; int streaming; + struct v4l2_pix_format pix; + int num_fmts; + const struct v4l2_fmtdesc *fmt_list; + enum tvp514x_std current_std; int num_stds; const struct tvp514x_std_info *std_list; /* Input and Output Routing parameters */ u32 input; u32 output; + + /* mc related members */ + struct media_pad pad; + struct v4l2_mbus_framefmt format; }; /* TVP514x default register values */ @@ -199,6 +210,21 @@ static struct tvp514x_reg tvp514x_reg_list_default[] = { {TOK_TERM, 0, 0}, }; +/** + * List of image formats supported by TVP5146/47 decoder + * Currently we are using 8 bit mode only, but can be + * extended to 10/20 bit mode. + */ +static const struct v4l2_fmtdesc tvp514x_fmt_list[] = { + { + .index = 0, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = 0, + .description = "8-bit UYVY 4:2:2 Format", + .pixelformat = V4L2_PIX_FMT_UYVY, + }, +}; + /** * Supported standards - * @@ -733,7 +759,7 @@ tvp514x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, } /** - * tvp514x_mbus_fmt_cap() - V4L2 decoder interface handler for try/s/g_mbus_fmt + * tvp514x_mbus_fmt() - V4L2 decoder interface handler for try/s/g_mbus_fmt * @sd: pointer to standard V4L2 sub-device structure * @f: pointer to the mediabus format structure * @@ -751,12 +777,11 @@ tvp514x_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) /* Calculate height and width based on current standard */ current_std = decoder->current_std; - f->code = V4L2_MBUS_FMT_YUYV10_2X10; + f->code = V4L2_MBUS_FMT_YUYV8_2X8; f->width = decoder->std_list[current_std].width; f->height = decoder->std_list[current_std].height; f->field = V4L2_FIELD_INTERLACED; f->colorspace = V4L2_COLORSPACE_SMPTE170M; - v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d\n", f->width, f->height); return 0; @@ -892,6 +917,88 @@ static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = { .s_ctrl = tvp514x_s_ctrl, }; +/** + * tvp514x_enum_mbus_code() - V4L2 decoder interface handler for enum_mbus_code + * @sd: pointer to standard V4L2 sub-device structure + * @fh: file handle + * @code: pointer to v4l2_subdev_mbus_code_enum structure + * + * Enumertaes mbus codes supported + */ +static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + u32 pad = code->pad; + u32 index = code->index; + + memset(code, 0, sizeof(*code)); + code->index = index; + code->pad = pad; + + if (index != 0) + return -EINVAL; + + code->code = V4L2_MBUS_FMT_YUYV8_2X8; + + return 0; +} + +/** + * tvp514x_get_pad_format() - V4L2 decoder interface handler for get pad format + * @sd: pointer to standard V4L2 sub-device structure + * @fh: file handle + * @format: pointer to v4l2_subdev_format structure + * + * Retrieves pad format which is active or tried based on requirement + */ +static int tvp514x_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *format) +{ + struct tvp514x_decoder *decoder = to_decoder(sd); + __u32 which = format->which; + + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { + format->format = decoder->format; + return 0; + } + + format->format.code = V4L2_MBUS_FMT_YUYV8_2X8; + format->format.width = tvp514x_std_list[decoder->current_std].width; + format->format.height = tvp514x_std_list[decoder->current_std].height; + format->format.colorspace = V4L2_COLORSPACE_SMPTE170M; + format->format.field = V4L2_FIELD_INTERLACED; + + return 0; +} + +/** + * tvp514x_set_pad_format() - V4L2 decoder interface handler for set pad format + * @sd: pointer to standard V4L2 sub-device structure + * @fh: file handle + * @format: pointer to v4l2_subdev_format structure + * + * Set pad format for the output pad + */ +static int tvp514x_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct tvp514x_decoder *decoder = to_decoder(sd); + + if (fmt->format.field != V4L2_FIELD_INTERLACED || + fmt->format.code != V4L2_MBUS_FMT_YUYV8_2X8 || + fmt->format.colorspace != V4L2_COLORSPACE_SMPTE170M || + fmt->format.width != tvp514x_std_list[decoder->current_std].width || + fmt->format.height != tvp514x_std_list[decoder->current_std].height) + return -EINVAL; + + decoder->format = fmt->format; + + return 0; +} + static const struct v4l2_subdev_core_ops tvp514x_core_ops = { .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, @@ -915,13 +1022,33 @@ static const struct v4l2_subdev_video_ops tvp514x_video_ops = { .s_stream = tvp514x_s_stream, }; +static const struct v4l2_subdev_pad_ops tvp514x_pad_ops = { + .enum_mbus_code = tvp514x_enum_mbus_code, + .get_fmt = tvp514x_get_pad_format, + .set_fmt = tvp514x_set_pad_format, +}; + static const struct v4l2_subdev_ops tvp514x_ops = { .core = &tvp514x_core_ops, .video = &tvp514x_video_ops, + .pad = &tvp514x_pad_ops, }; static struct tvp514x_decoder tvp514x_dev = { .streaming = 0, + .fmt_list = tvp514x_fmt_list, + .num_fmts = ARRAY_SIZE(tvp514x_fmt_list), + .pix = { + /* Default to NTSC 8-bit YUV 422 */ + .width = NTSC_NUM_ACTIVE_PIXELS, + .height = NTSC_NUM_ACTIVE_LINES, + .pixelformat = V4L2_PIX_FMT_UYVY, + .field = V4L2_FIELD_INTERLACED, + .bytesperline = NTSC_NUM_ACTIVE_PIXELS * 2, + .sizeimage = NTSC_NUM_ACTIVE_PIXELS * 2 * + NTSC_NUM_ACTIVE_LINES, + .colorspace = V4L2_COLORSPACE_SMPTE170M, + }, .current_std = STD_NTSC_MJ, .std_list = tvp514x_std_list, .num_stds = ARRAY_SIZE(tvp514x_std_list), @@ -941,6 +1068,7 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tvp514x_decoder *decoder; struct v4l2_subdev *sd; + int ret; /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) @@ -981,7 +1109,21 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) /* Register with V4L2 layer as slave device */ sd = &decoder->sd; v4l2_i2c_subdev_init(sd, client, &tvp514x_ops); - + strlcpy(sd->name, TVP514X_MODULE_NAME, sizeof(sd->name)); + +#if defined(CONFIG_MEDIA_CONTROLLER) + decoder->pad.flags = MEDIA_PAD_FL_SOURCE; + decoder->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + decoder->sd.entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER; + + ret = media_entity_init(&decoder->sd.entity, 1, &decoder->pad, 0); + if (ret < 0) { + v4l2_err(sd, "%s decoder driver failed to register !!\n", + sd->name); + kfree(decoder); + return ret; + } +#endif v4l2_ctrl_handler_init(&decoder->hdl, 5); v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops, V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); @@ -995,10 +1137,10 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) V4L2_CID_AUTOGAIN, 0, 1, 1, 1); sd->ctrl_handler = &decoder->hdl; if (decoder->hdl.error) { - int err = decoder->hdl.error; + ret = decoder->hdl.error; v4l2_ctrl_handler_free(&decoder->hdl); - return err; + return ret; } v4l2_ctrl_handler_setup(&decoder->hdl); @@ -1021,6 +1163,9 @@ static int tvp514x_remove(struct i2c_client *client) struct tvp514x_decoder *decoder = to_decoder(sd); v4l2_device_unregister_subdev(sd); +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&decoder->sd.entity); +#endif v4l2_ctrl_handler_free(&decoder->hdl); return 0; } -- cgit v1.2.3 From d65fcbb0007bd8f0bcb93d1acd7970eea2aa06fc Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Mon, 11 Mar 2013 11:31:39 -0300 Subject: [media] ts2020: use customise option correctly The Kconfig entry for "TS2020 based tuners" defaults to modular if DVB_FE_CUSTOMISE is set. But that Kconfig symbol was replaced with MEDIA_SUBDRV_AUTOSELECT as of v3.7. So use the new symbol. And negate the logic, so we are in line with all the similar entries in this file. Signed-off-by: Paul Bolle Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 6f809a70c78e..0e2ec6f73b05 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -210,7 +210,7 @@ config DVB_SI21XX config DVB_TS2020 tristate "Montage Tehnology TS2020 based tuners" depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE + default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-S/S2 silicon tuner. Say Y when you want to support this tuner. -- cgit v1.2.3 From cbaa5c54cb73897ed6c2544a60ed52aa3215b0f6 Mon Sep 17 00:00:00 2001 From: Benoît Thébaudeau Date: Tue, 26 Feb 2013 15:32:49 -0300 Subject: [media] soc-camera: mt9m111: Fix auto-exposure control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit f9bd5843658e18a7097fc7258c60fb840109eaa8 changed V4L2_CID_EXPOSURE_AUTO from boolean to enum, and commit af8425c54beb3c32cbb503a379132b3975535289 changed the creation of this control into a menu for the mt9m111. However, mt9m111_set_autoexposure() is still interpreting the value set for this control as a boolean, which also conflicts with the default value of this control set to V4L2_EXPOSURE_AUTO (0). This patch makes mt9m111_set_autoexposure() interpret the value set for V4L2_CID_EXPOSURE_AUTO as defined by enum v4l2_exposure_auto_type. Signed-off-by: Benoît Thébaudeau Tested-by: Javier Martin Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/mt9m111.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index bbc4ff99603c..0b0ebaa68602 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/soc_camera/mt9m111.c @@ -701,11 +701,11 @@ static int mt9m111_set_global_gain(struct mt9m111 *mt9m111, int gain) return reg_write(GLOBAL_GAIN, val); } -static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int on) +static int mt9m111_set_autoexposure(struct mt9m111 *mt9m111, int val) { struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); - if (on) + if (val == V4L2_EXPOSURE_AUTO) return reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); } -- cgit v1.2.3 From 4a1313c447ffb67125802d20653959ac46b0b4ef Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 12 Mar 2013 08:40:37 -0300 Subject: [media] mt9m111: fix Oops - initialise context before dereferencing A recent commit "[media] soc-camera: Push probe-time power management to drivers" causes an Oops during mt9m111 driver probing because its .ctx private data field is now dereferenced before it is initialised. Fix this by initialising the field earlier. Reported-by: Javier Martin Signed-off-by: Guennadi Liakhovetski Tested-by: Javier Martin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/mt9m111.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index 0b0ebaa68602..2902ba633da6 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/soc_camera/mt9m111.c @@ -785,8 +785,6 @@ static int mt9m111_init(struct mt9m111 *mt9m111) struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); int ret; - /* Default HIGHPOWER context */ - mt9m111->ctx = &context_b; ret = mt9m111_enable(mt9m111); if (!ret) ret = mt9m111_reset(mt9m111); @@ -975,6 +973,9 @@ static int mt9m111_probe(struct i2c_client *client, if (!mt9m111) return -ENOMEM; + /* Default HIGHPOWER context */ + mt9m111->ctx = &context_b; + v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); v4l2_ctrl_handler_init(&mt9m111->hdl, 5); v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, -- cgit v1.2.3 From bff7993936a1617f7502ddd2a09d37767fc8c929 Mon Sep 17 00:00:00 2001 From: Andrei Andreyanau Date: Wed, 6 Feb 2013 11:29:18 -0300 Subject: [media] mt9v022 driver: send valid HORIZONTAL_BLANKING values to mt9v024 soc camera This patch fixes the issue that appears when mt9v024 camera is used with the mt9v022 soc camera driver. The minimum total row time is 690 columns (horizontal width + horizontal blanking). The minimum horizontal blanking is 61. Thus, when the window width is set below 627, horizontal blanking must be increased. For the mt9v024 camera the values above are correct and for the mt9v022 camera the correct values are in the existing kernel driver. Signed-off-by: Andrei Andreyanau Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/mt9v022.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index a5e65d6a0781..53eaf899d3b6 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -275,6 +275,7 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9v022 *mt9v022 = to_mt9v022(client); struct v4l2_rect rect = a->c; + int min_row, min_blank; int ret; /* Bayer format - even size lengths */ @@ -310,13 +311,21 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) ret = reg_write(client, MT9V022_COLUMN_START, rect.left); if (!ret) ret = reg_write(client, MT9V022_ROW_START, rect.top); + /* + * mt9v022: min total row time is 660 columns, min blanking is 43 + * mt9v024: min total row time is 690 columns, min blanking is 61 + */ + if (is_mt9v024(mt9v022->chip_version)) { + min_row = 690; + min_blank = 61; + } else { + min_row = 660; + min_blank = 43; + } if (!ret) - /* - * Default 94, Phytec driver says: - * "width + horizontal blank >= 660" - */ ret = v4l2_ctrl_s_ctrl(mt9v022->hblank, - rect.width > 660 - 43 ? 43 : 660 - rect.width); + rect.width > min_row - min_blank ? + min_blank : min_row - rect.width); if (!ret) ret = v4l2_ctrl_s_ctrl(mt9v022->vblank, 45); if (!ret) -- cgit v1.2.3 From 15a0934201780f7a95d9fa3b910e19bf89ab25d5 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 4 Mar 2013 05:15:20 -0300 Subject: [media] soc_camera/sh_mobile_ceu_camera: Convert to devm_ioremap_resource() Use the newly introduced devm_ioremap_resource() instead of devm_request_and_ioremap() which provides more consistent error handling. devm_ioremap_resource() provides its own error messages; so all explicit error messages can be removed from the failure code paths. Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 973e72b24fa8..d7294efc3199 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -2111,11 +2112,9 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev) pcdev->max_width = pcdev->pdata->max_width ? : 2560; pcdev->max_height = pcdev->pdata->max_height ? : 1920; - base = devm_request_and_ioremap(&pdev->dev, res); - if (!base) { - dev_err(&pdev->dev, "Unable to ioremap CEU registers.\n"); - return -ENXIO; - } + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); pcdev->irq = irq; pcdev->base = base; -- cgit v1.2.3 From 2e2d612d80c1cb829769d413a8e8bf64f64197f8 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 4 Mar 2013 05:15:21 -0300 Subject: [media] soc_camera/sh_mobile_csi2: Convert to devm_ioremap_resource() Use the newly introduced devm_ioremap_resource() instead of devm_request_and_ioremap() which provides more consistent error handling. devm_ioremap_resource() provides its own error messages; so all explicit error messages can be removed from the failure code paths. Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/sh_mobile_csi2.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c index 42c559eb4937..09cb4fc88f34 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_csi2.c +++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -324,11 +325,9 @@ static int sh_csi2_probe(struct platform_device *pdev) priv->irq = irq; - priv->base = devm_request_and_ioremap(&pdev->dev, res); - if (!priv->base) { - dev_err(&pdev->dev, "Unable to ioremap CSI2 registers.\n"); - return -ENXIO; - } + priv->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); priv->pdev = pdev; platform_set_drvdata(pdev, priv); -- cgit v1.2.3 From 8efdb13543909af277a93bab17730e92b552b7c9 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 4 Mar 2013 05:15:19 -0300 Subject: [media] soc_camera/pxa_camera: Convert to devm_ioremap_resource() Use the newly introduced devm_ioremap_resource() instead of devm_request_and_ioremap() which provides more consistent error handling. Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/pxa_camera.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index 395e2e043615..42abbce650f7 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -1710,9 +1711,10 @@ static int pxa_camera_probe(struct platform_device *pdev) /* * Request the regions. */ - base = devm_request_and_ioremap(&pdev->dev, res); - if (!base) - return -ENOMEM; + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + pcdev->irq = irq; pcdev->base = base; -- cgit v1.2.3 From f2b4dc1a0fc8f52e06025497ce9bb252ff51f15f Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 4 Mar 2013 05:15:18 -0300 Subject: [media] sh_veu.c: Convert to devm_ioremap_resource() Use the newly introduced devm_ioremap_resource() instead of devm_request_and_ioremap() which provides more consistent error handling. Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_veu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index cb54c69d5748..362d88ec6ea1 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation */ +#include #include #include #include @@ -1164,9 +1165,9 @@ static int sh_veu_probe(struct platform_device *pdev) veu->is_2h = resource_size(reg_res) == 0x22c; - veu->base = devm_request_and_ioremap(&pdev->dev, reg_res); - if (!veu->base) - return -ENOMEM; + veu->base = devm_ioremap_resource(&pdev->dev, reg_res); + if (IS_ERR(veu->base)) + return PTR_ERR(veu->base); ret = devm_request_threaded_irq(&pdev->dev, irq, sh_veu_isr, sh_veu_bh, 0, "veu", veu); -- cgit v1.2.3 From bd3b4a3fde243d2870c703ed92c86d7026517569 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 5 Mar 2013 01:53:38 -0300 Subject: [media] soc_camera/mx1_camera: Use module_platform_driver_probe macro module_platform_driver_probe() eliminates the boilerplate and simplifies the code. Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/mx1_camera.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/mx1_camera.c b/drivers/media/platform/soc_camera/mx1_camera.c index 25b2a285dc86..4389f43dd03c 100644 --- a/drivers/media/platform/soc_camera/mx1_camera.c +++ b/drivers/media/platform/soc_camera/mx1_camera.c @@ -859,18 +859,7 @@ static struct platform_driver mx1_camera_driver = { .remove = __exit_p(mx1_camera_remove), }; -static int __init mx1_camera_init(void) -{ - return platform_driver_probe(&mx1_camera_driver, mx1_camera_probe); -} - -static void __exit mx1_camera_exit(void) -{ - return platform_driver_unregister(&mx1_camera_driver); -} - -module_init(mx1_camera_init); -module_exit(mx1_camera_exit); +module_platform_driver_probe(mx1_camera_driver, mx1_camera_probe); MODULE_DESCRIPTION("i.MX1/i.MXL SoC Camera Host driver"); MODULE_AUTHOR("Paulius Zaleckas "); -- cgit v1.2.3 From 6647b9c003f3c5de786a6eeb6c91b9481e543382 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 5 Mar 2013 01:53:36 -0300 Subject: [media] sh_veu: Use module_platform_driver_probe macro module_platform_driver_probe() eliminates the boilerplate and simplifies the code. Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_veu.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index 362d88ec6ea1..0b32cc3f6a47 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -1249,18 +1249,7 @@ static struct platform_driver __refdata sh_veu_pdrv = { }, }; -static int __init sh_veu_init(void) -{ - return platform_driver_probe(&sh_veu_pdrv, sh_veu_probe); -} - -static void __exit sh_veu_exit(void) -{ - platform_driver_unregister(&sh_veu_pdrv); -} - -module_init(sh_veu_init); -module_exit(sh_veu_exit); +module_platform_driver_probe(sh_veu_pdrv, sh_veu_probe); MODULE_DESCRIPTION("sh-mobile VEU mem2mem driver"); MODULE_AUTHOR("Guennadi Liakhovetski, "); -- cgit v1.2.3 From b3fd87bc35a2cdc743b0d7f0b0a3aff18784ec58 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 5 Mar 2013 01:53:37 -0300 Subject: [media] sh_vou: Use module_platform_driver_probe macro module_platform_driver_probe() eliminates the boilerplate and simplifies the code. Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 66c8da18df84..d853162586fa 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -1485,18 +1485,7 @@ static struct platform_driver __refdata sh_vou = { }, }; -static int __init sh_vou_init(void) -{ - return platform_driver_probe(&sh_vou, sh_vou_probe); -} - -static void __exit sh_vou_exit(void) -{ - platform_driver_unregister(&sh_vou); -} - -module_init(sh_vou_init); -module_exit(sh_vou_exit); +module_platform_driver_probe(sh_vou, sh_vou_probe); MODULE_DESCRIPTION("SuperH VOU driver"); MODULE_AUTHOR("Guennadi Liakhovetski "); -- cgit v1.2.3 From b3d9a15d9af9bba65ac7cd7c196268046470643d Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Mon, 11 Mar 2013 18:30:03 -0300 Subject: [media] soc_camera: remove two outdated selects Release v2.6.30 removed the MT9M001_PCA9536_SWITCH and MT9V022_PCA9536_SWITCH Kconfig symbols, in commits 36034dc325ecab63c8cfb992fbf9a1a8e94738a2 ("V4L/DVB (11032): mt9m001: allow setting of bus width from board code") and e958e27adeade7fa085dd396a8a0dfaef7e338c1 ("V4L/DVB (11033): mt9v022: allow setting of bus width from board code"). These two commits removed all gpio related code from these two drivers. But they skipped removing their two selects of GPIO_PCA953X. Remove these now as they are outdated. Their dependencies can never evaluate to true anyhow. Signed-off-by: Paul Bolle Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/Kconfig | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig index 6dff2b7ad520..23d352f0adf0 100644 --- a/drivers/media/i2c/soc_camera/Kconfig +++ b/drivers/media/i2c/soc_camera/Kconfig @@ -9,7 +9,6 @@ config SOC_CAMERA_IMX074 config SOC_CAMERA_MT9M001 tristate "mt9m001 support" depends on SOC_CAMERA && I2C - select GPIO_PCA953X if MT9M001_PCA9536_SWITCH help This driver supports MT9M001 cameras from Micron, monochrome and colour models. @@ -36,7 +35,6 @@ config SOC_CAMERA_MT9T112 config SOC_CAMERA_MT9V022 tristate "mt9v022 and mt9v024 support" depends on SOC_CAMERA && I2C - select GPIO_PCA953X if MT9V022_PCA9536_SWITCH help This driver supports MT9V022 cameras from Micron -- cgit v1.2.3 From 01ae72866d31de9291039b6030d021c004f5bfed Mon Sep 17 00:00:00 2001 From: Dmitri Belimov Date: Wed, 13 Mar 2013 00:23:36 -0300 Subject: [media] xc5000: fix incorrect debug printnk I found very small bug in xc5000 source. When set option debug=1 and listen a radio we see in dmesg xc5000: xc_SetTVStandard() Standard = M/N-NTSC/PAL-BTSC at all times. However, it should be, instead "FM Radio-INPUT1_MONO". That happens because xc5000_set_radio_freq() gets the correct value for VideoMode and AudioMode for radio and calls xc_SetTVStandard() where name of standard comes from the incorrect place priv->video_standard. This incorrect debug message makes debugging a little difficult. Signed-off-by: Dmitry Belimov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/xc5000.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index d6be1b613c52..5cd09a681b6a 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -422,13 +422,19 @@ static int xc_initialize(struct xc5000_priv *priv) } static int xc_SetTVStandard(struct xc5000_priv *priv, - u16 VideoMode, u16 AudioMode) + u16 VideoMode, u16 AudioMode, u8 RadioMode) { int ret; dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode); - dprintk(1, "%s() Standard = %s\n", - __func__, - XC5000_Standard[priv->video_standard].Name); + if (RadioMode) { + dprintk(1, "%s() Standard = %s\n", + __func__, + XC5000_Standard[RadioMode].Name); + } else { + dprintk(1, "%s() Standard = %s\n", + __func__, + XC5000_Standard[priv->video_standard].Name); + } ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode); if (ret == XC_RESULT_SUCCESS) @@ -824,7 +830,7 @@ static int xc5000_set_params(struct dvb_frontend *fe) ret = xc_SetTVStandard(priv, XC5000_Standard[priv->video_standard].VideoMode, - XC5000_Standard[priv->video_standard].AudioMode); + XC5000_Standard[priv->video_standard].AudioMode, 0); if (ret != XC_RESULT_SUCCESS) { printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); return -EREMOTEIO; @@ -940,7 +946,7 @@ tune_channel: ret = xc_SetTVStandard(priv, XC5000_Standard[priv->video_standard].VideoMode, - XC5000_Standard[priv->video_standard].AudioMode); + XC5000_Standard[priv->video_standard].AudioMode, 0); if (ret != XC_RESULT_SUCCESS) { printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); return -EREMOTEIO; @@ -1003,7 +1009,7 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe, priv->rf_mode = XC_RF_MODE_AIR; ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode, - XC5000_Standard[radio_input].AudioMode); + XC5000_Standard[radio_input].AudioMode, radio_input); if (ret != XC_RESULT_SUCCESS) { printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); -- cgit v1.2.3 From 15170025ee26946dc61f3c21e54652c6db4a0326 Mon Sep 17 00:00:00 2001 From: Federico Fuga Date: Fri, 24 Aug 2012 11:54:11 -0300 Subject: [media] Corrected Oops on omap_vout when no manager is connected If no manager is connected to the vout device, the omapvid_init() function fails. No error condition is checked, and the device is started. Later on, when irq is serviced, a NULL pointer dereference occurs. Also, the isr routine must be registered only if no error occurs, otherwise the isr triggers without the proper setup, and the kernel oops again. To prevent this, the error condition is checked, and the streamon function exits with error. Also the isr registration call is moved after the setup procedure is completed. Reviewed-by: Prabhakar Lad Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/omap_vout.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 96c4a17e4280..477268a2415f 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -648,9 +648,12 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) /* First save the configuration in ovelray structure */ ret = omapvid_init(vout, addr); - if (ret) + if (ret) { printk(KERN_ERR VOUT_NAME "failed to set overlay info\n"); + goto vout_isr_err; + } + /* Enable the pipeline and set the Go bit */ ret = omapvid_apply_changes(vout); if (ret) @@ -1660,13 +1663,16 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2; - omap_dispc_register_isr(omap_vout_isr, vout, mask); - /* First save the configuration in ovelray structure */ ret = omapvid_init(vout, addr); - if (ret) + if (ret) { v4l2_err(&vout->vid_dev->v4l2_dev, "failed to set overlay info\n"); + goto streamon_err1; + } + + omap_dispc_register_isr(omap_vout_isr, vout, mask); + /* Enable the pipeline and set the Go bit */ ret = omapvid_apply_changes(vout); if (ret) -- cgit v1.2.3 From 26ccbec44a7c62de4fef4f33bb858963e501921d Mon Sep 17 00:00:00 2001 From: Kevin Baradon Date: Mon, 18 Feb 2013 14:42:47 -0300 Subject: [media] media/rc/imon.c: make send_packet() delay larger for 15c2:0036 Some imon devices (like 15c2:0036) need a higher delay between send_packet calls. Default value is still 5ms to avoid regressions on already working hardware. Also use interruptible wait to avoid load average going too high (and let caller handle signals). Signed-off-by: Kevin Baradon Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index dec203bb06f6..178b94660b58 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -112,6 +112,7 @@ struct imon_context { bool tx_control; unsigned char usb_rx_buf[8]; unsigned char usb_tx_buf[8]; + unsigned int send_packet_delay; struct tx_t { unsigned char data_buf[35]; /* user data buffer */ @@ -185,6 +186,10 @@ enum { IMON_KEY_PANEL = 2, }; +enum { + IMON_NEED_20MS_PKT_DELAY = 1 +}; + /* * USB Device ID for iMON USB Control Boards * @@ -215,7 +220,7 @@ static struct usb_device_id imon_usb_id_table[] = { /* SoundGraph iMON OEM Touch LCD (IR & 4.3" VGA LCD) */ { USB_DEVICE(0x15c2, 0x0035) }, /* SoundGraph iMON OEM VFD (IR & VFD) */ - { USB_DEVICE(0x15c2, 0x0036) }, + { USB_DEVICE(0x15c2, 0x0036), .driver_info = IMON_NEED_20MS_PKT_DELAY }, /* device specifics unknown */ { USB_DEVICE(0x15c2, 0x0037) }, /* SoundGraph iMON OEM LCD (IR & LCD) */ @@ -535,12 +540,12 @@ static int send_packet(struct imon_context *ictx) kfree(control_req); /* - * Induce a mandatory 5ms delay before returning, as otherwise, + * Induce a mandatory delay before returning, as otherwise, * send_packet can get called so rapidly as to overwhelm the device, * particularly on faster systems and/or those with quirky usb. */ - timeout = msecs_to_jiffies(5); - set_current_state(TASK_UNINTERRUPTIBLE); + timeout = msecs_to_jiffies(ictx->send_packet_delay); + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(timeout); return retval; @@ -2335,6 +2340,10 @@ static int imon_probe(struct usb_interface *interface, } + /* default send_packet delay is 5ms but some devices need more */ + ictx->send_packet_delay = id->driver_info & IMON_NEED_20MS_PKT_DELAY ? + 20 : 5; + usb_set_intfdata(interface, ictx); if (ifnum == 0) { -- cgit v1.2.3 From e9e7a16d6da4af030ccb117079dcf1ef66bd5804 Mon Sep 17 00:00:00 2001 From: Kevin Baradon Date: Mon, 18 Feb 2013 15:10:22 -0300 Subject: [media] media/rc/imon.c: avoid flooding syslog with "unknown keypress" when keypad is pressed My 15c2:0036 device floods syslog when a keypad key is pressed: Feb 18 19:00:57 homeserver kernel: imon 5-1:1.0: imon_incoming_packet: unknown keypress, code 0x100fff2 Feb 18 19:00:57 homeserver kernel: imon 5-1:1.0: imon_incoming_packet: unknown keypress, code 0x100fef2 Feb 18 19:00:57 homeserver kernel: imon 5-1:1.0: imon_incoming_packet: unknown keypress, code 0x100fff2 Feb 18 19:00:57 homeserver kernel: imon 5-1:1.0: imon_incoming_packet: unknown keypress, code 0x100fff2 Feb 18 19:00:57 homeserver kernel: imon 5-1:1.0: imon_incoming_packet: unknown keypress, code 0x100fff2 This patch removes those messages from imon, following suggestion from Mauro. Unknown keys shall be correctly handled by rc/input layer. Signed-off-by: Kevin Baradon Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 178b94660b58..b8f9f85a11c9 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1573,11 +1573,6 @@ static void imon_incoming_packet(struct imon_context *ictx, if (press_type < 0) goto not_input_data; - spin_lock_irqsave(&ictx->kc_lock, flags); - if (ictx->kc == KEY_UNKNOWN) - goto unknown_key; - spin_unlock_irqrestore(&ictx->kc_lock, flags); - if (ktype != IMON_KEY_PANEL) { if (press_type == 0) rc_keyup(ictx->rdev); @@ -1620,12 +1615,6 @@ static void imon_incoming_packet(struct imon_context *ictx, return; -unknown_key: - spin_unlock_irqrestore(&ictx->kc_lock, flags); - dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__, - (long long)scancode); - return; - not_input_data: if (len != 8) { dev_warn(dev, "imon %s: invalid incoming packet " -- cgit v1.2.3 From 88b38befc0d8b7590f0b083dc4c8e4cee0b84788 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 7 Jan 2013 09:37:30 -0300 Subject: [media] ITE IT913X silicon tuner driver It is tuner driver for tuner integrated to the ITE IT9135 and IT9137 chips. I split it out from the current it913x-fe driver. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/Kconfig | 7 + drivers/media/tuners/Makefile | 1 + drivers/media/tuners/it913x.c | 584 +++++++++++++++++++++++++ drivers/media/tuners/it913x.h | 55 +++ drivers/media/tuners/it913x_priv.h | 867 +++++++++++++++++++++++++++++++++++++ 5 files changed, 1514 insertions(+) create mode 100644 drivers/media/tuners/it913x.c create mode 100644 drivers/media/tuners/it913x.h create mode 100644 drivers/media/tuners/it913x_priv.h (limited to 'drivers/media') diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index e8fdf713fce8..ffabd66dd14d 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -241,4 +241,11 @@ config MEDIA_TUNER_TUA9001 default m if !MEDIA_SUBDRV_AUTOSELECT help Infineon TUA 9001 silicon tuner driver. + +config MEDIA_TUNER_IT913X + tristate "ITE Tech IT913x silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + ITE Tech IT913x silicon tuner driver. endmenu diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile index 5e569b1083cf..f136a6d83120 100644 --- a/drivers/media/tuners/Makefile +++ b/drivers/media/tuners/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o +obj-$(CONFIG_MEDIA_TUNER_IT913X) += it913x.o ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c new file mode 100644 index 000000000000..6ee4f97f586e --- /dev/null +++ b/drivers/media/tuners/it913x.c @@ -0,0 +1,584 @@ +/* + * ITE Tech IT9137 silicon tuner driver + * + * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) + * IT9137 Copyright (C) ITE Tech Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#include "it913x_priv.h" + +struct it913x_fe_state { + struct dvb_frontend frontend; + struct i2c_adapter *i2c_adap; + struct ite_config *config; + u8 i2c_addr; + u32 frequency; + fe_modulation_t constellation; + fe_transmit_mode_t transmission_mode; + u8 priority; + u32 crystalFrequency; + u32 adcFrequency; + u8 tuner_type; + struct adctable *table; + fe_status_t it913x_status; + u16 tun_xtal; + u8 tun_fdiv; + u8 tun_clk_mode; + u32 tun_fn_min; + u32 ucblocks; +}; + + +static int it913x_read_reg(struct it913x_fe_state *state, + u32 reg, u8 *data, u8 count) +{ + int ret; + u8 b[3]; + struct i2c_msg msg[2] = { + { .addr = state->i2c_addr, .flags = 0, + .buf = b, .len = sizeof(b) }, + { .addr = state->i2c_addr, .flags = I2C_M_RD, + .buf = data, .len = count } + }; + b[0] = (u8)(reg >> 16) & 0xff; + b[1] = (u8)(reg >> 8) & 0xff; + b[2] = (u8) reg & 0xff; + b[0] |= 0x80; /* All reads from demodulator */ + + ret = i2c_transfer(state->i2c_adap, msg, 2); + + return ret; +} + +static int it913x_read_reg_u8(struct it913x_fe_state *state, u32 reg) +{ + int ret; + u8 b[1]; + ret = it913x_read_reg(state, reg, &b[0], sizeof(b)); + return (ret < 0) ? -ENODEV : b[0]; +} + +static int it913x_write(struct it913x_fe_state *state, + u8 pro, u32 reg, u8 buf[], u8 count) +{ + u8 b[256]; + struct i2c_msg msg[1] = { + { .addr = state->i2c_addr, .flags = 0, + .buf = b, .len = 3 + count } + }; + int ret; + b[0] = (u8)(reg >> 16) & 0xff; + b[1] = (u8)(reg >> 8) & 0xff; + b[2] = (u8) reg & 0xff; + memcpy(&b[3], buf, count); + + if (pro == PRO_DMOD) + b[0] |= 0x80; + + ret = i2c_transfer(state->i2c_adap, msg, 1); + + if (ret < 0) + return -EIO; + + return 0; +} + +static int it913x_write_reg(struct it913x_fe_state *state, + u8 pro, u32 reg, u32 data) +{ + int ret; + u8 b[4]; + u8 s; + + b[0] = data >> 24; + b[1] = (data >> 16) & 0xff; + b[2] = (data >> 8) & 0xff; + b[3] = data & 0xff; + /* expand write as needed */ + if (data < 0x100) + s = 3; + else if (data < 0x1000) + s = 2; + else if (data < 0x100000) + s = 1; + else + s = 0; + + ret = it913x_write(state, pro, reg, &b[s], sizeof(b) - s); + + return ret; +} + +static int it913x_fe_script_loader(struct it913x_fe_state *state, + struct it913xset *loadscript) +{ + int ret, i; + if (loadscript == NULL) + return -EINVAL; + + for (i = 0; i < 1000; ++i) { + if (loadscript[i].pro == 0xff) + break; + ret = it913x_write(state, loadscript[i].pro, + loadscript[i].address, + loadscript[i].reg, loadscript[i].count); + if (ret < 0) + return -ENODEV; + } + return 0; +} + +static int it913x_init_tuner(struct dvb_frontend *fe) +{ + struct it913x_fe_state *state = fe->tuner_priv; + int ret, i, reg; + u8 val, nv_val; + u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; + u8 b[2]; + + reg = it913x_read_reg_u8(state, 0xec86); + switch (reg) { + case 0: + state->tun_clk_mode = reg; + state->tun_xtal = 2000; + state->tun_fdiv = 3; + val = 16; + break; + case -ENODEV: + return -ENODEV; + case 1: + default: + state->tun_clk_mode = reg; + state->tun_xtal = 640; + state->tun_fdiv = 1; + val = 6; + break; + } + + reg = it913x_read_reg_u8(state, 0xed03); + + if (reg < 0) + return -ENODEV; + else if (reg < ARRAY_SIZE(nv)) + nv_val = nv[reg]; + else + nv_val = 2; + + for (i = 0; i < 50; i++) { + ret = it913x_read_reg(state, 0xed23, &b[0], sizeof(b)); + reg = (b[1] << 8) + b[0]; + if (reg > 0) + break; + if (ret < 0) + return -ENODEV; + udelay(2000); + } + state->tun_fn_min = state->tun_xtal * reg; + state->tun_fn_min /= (state->tun_fdiv * nv_val); + pr_debug("Tuner fn_min %d\n", state->tun_fn_min); + + if (state->config->chip_ver > 1) + msleep(50); + else { + for (i = 0; i < 50; i++) { + reg = it913x_read_reg_u8(state, 0xec82); + if (reg > 0) + break; + if (reg < 0) + return -ENODEV; + udelay(2000); + } + } + + return it913x_write_reg(state, PRO_DMOD, 0xed81, val); +} + +static int it9137_set_tuner(struct dvb_frontend *fe) +{ + struct it913x_fe_state *state = fe->tuner_priv; + struct it913xset *set_tuner = set_it9137_template; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 bandwidth = p->bandwidth_hz; + u32 frequency_m = p->frequency; + int ret, reg; + u32 frequency = frequency_m / 1000; + u32 freq, temp_f, tmp; + u16 iqik_m_cal; + u16 n_div; + u8 n; + u8 l_band; + u8 lna_band; + u8 bw; + + if (state->config->firmware_ver == 1) + set_tuner = set_it9135_template; + else + set_tuner = set_it9137_template; + + pr_debug("Tuner Frequency %d Bandwidth %d\n", frequency, bandwidth); + + if (frequency >= 51000 && frequency <= 440000) { + l_band = 0; + lna_band = 0; + } else if (frequency > 440000 && frequency <= 484000) { + l_band = 1; + lna_band = 1; + } else if (frequency > 484000 && frequency <= 533000) { + l_band = 1; + lna_band = 2; + } else if (frequency > 533000 && frequency <= 587000) { + l_band = 1; + lna_band = 3; + } else if (frequency > 587000 && frequency <= 645000) { + l_band = 1; + lna_band = 4; + } else if (frequency > 645000 && frequency <= 710000) { + l_band = 1; + lna_band = 5; + } else if (frequency > 710000 && frequency <= 782000) { + l_band = 1; + lna_band = 6; + } else if (frequency > 782000 && frequency <= 860000) { + l_band = 1; + lna_band = 7; + } else if (frequency > 1450000 && frequency <= 1492000) { + l_band = 1; + lna_band = 0; + } else if (frequency > 1660000 && frequency <= 1685000) { + l_band = 1; + lna_band = 1; + } else + return -EINVAL; + set_tuner[0].reg[0] = lna_band; + + switch (bandwidth) { + case 5000000: + bw = 0; + break; + case 6000000: + bw = 2; + break; + case 7000000: + bw = 4; + break; + default: + case 8000000: + bw = 6; + break; + } + + set_tuner[1].reg[0] = bw; + set_tuner[2].reg[0] = 0xa0 | (l_band << 3); + + if (frequency > 53000 && frequency <= 74000) { + n_div = 48; + n = 0; + } else if (frequency > 74000 && frequency <= 111000) { + n_div = 32; + n = 1; + } else if (frequency > 111000 && frequency <= 148000) { + n_div = 24; + n = 2; + } else if (frequency > 148000 && frequency <= 222000) { + n_div = 16; + n = 3; + } else if (frequency > 222000 && frequency <= 296000) { + n_div = 12; + n = 4; + } else if (frequency > 296000 && frequency <= 445000) { + n_div = 8; + n = 5; + } else if (frequency > 445000 && frequency <= state->tun_fn_min) { + n_div = 6; + n = 6; + } else if (frequency > state->tun_fn_min && frequency <= 950000) { + n_div = 4; + n = 7; + } else if (frequency > 1450000 && frequency <= 1680000) { + n_div = 2; + n = 0; + } else + return -EINVAL; + + reg = it913x_read_reg_u8(state, 0xed81); + iqik_m_cal = (u16)reg * n_div; + + if (reg < 0x20) { + if (state->tun_clk_mode == 0) + iqik_m_cal = (iqik_m_cal * 9) >> 5; + else + iqik_m_cal >>= 1; + } else { + iqik_m_cal = 0x40 - iqik_m_cal; + if (state->tun_clk_mode == 0) + iqik_m_cal = ~((iqik_m_cal * 9) >> 5); + else + iqik_m_cal = ~(iqik_m_cal >> 1); + } + + temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv; + freq = temp_f / state->tun_xtal; + tmp = freq * state->tun_xtal; + + if ((temp_f - tmp) >= (state->tun_xtal >> 1)) + freq++; + + freq += (u32) n << 13; + /* Frequency OMEGA_IQIK_M_CAL_MID*/ + temp_f = freq + (u32)iqik_m_cal; + + set_tuner[3].reg[0] = temp_f & 0xff; + set_tuner[4].reg[0] = (temp_f >> 8) & 0xff; + + pr_debug("High Frequency = %04x\n", temp_f); + + /* Lower frequency */ + set_tuner[5].reg[0] = freq & 0xff; + set_tuner[6].reg[0] = (freq >> 8) & 0xff; + + pr_debug("low Frequency = %04x\n", freq); + + ret = it913x_fe_script_loader(state, set_tuner); + + return (ret < 0) ? -ENODEV : 0; +} + +static int it913x_fe_suspend(struct it913x_fe_state *state) +{ + int ret = 0; +#if 0 + int ret, i; + u8 b; + + ret = it913x_write_reg(state, PRO_DMOD, SUSPEND_FLAG, 0x1); + + ret |= it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0); + + for (i = 0; i < 128; i++) { + ret = it913x_read_reg(state, SUSPEND_FLAG, &b, 1); + if (ret < 0) + return -ENODEV; + if (b == 0) + break; + + } + + ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x8); + /* Turn LED off */ + ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0); +#endif + ret |= it913x_fe_script_loader(state, it9137_tuner_off); + + return (ret < 0) ? -ENODEV : 0; +} + +/* Power sequence */ +/* Power Up Tuner on -> Frontend suspend off -> Tuner clk on */ +/* Power Down Frontend suspend on -> Tuner clk off -> Tuner off */ + +static int it913x_fe_sleep(struct dvb_frontend *fe) +{ + struct it913x_fe_state *state = fe->tuner_priv; + return it913x_fe_suspend(state); +} + +static int it913x_fe_start(struct dvb_frontend *fe) +{ + struct it913x_fe_state *state = fe->tuner_priv; + struct it913xset *set_lna; +// struct it913xset *set_mode; + int ret; +// u8 adf = (state->config->adf & 0xf); +// u32 adc, xtal; +// u8 b[4]; + + if (state->config->chip_ver == 1) + ret = it913x_init_tuner(fe); + +#if 0 + pr_info("ADF table value :%02x\n", adf); + + if (adf < 10) { + state->crystalFrequency = fe_clockTable[adf].xtal ; + state->table = fe_clockTable[adf].table; + state->adcFrequency = state->table->adcFrequency; + + adc = compute_div(state->adcFrequency, 1000000ul, 19ul); + xtal = compute_div(state->crystalFrequency, 1000000ul, 19ul); + + } else + return -EINVAL; + + /* Set LED indicator on GPIOH3 */ + ret = it913x_write_reg(state, PRO_LINK, GPIOH3_EN, 0x1); + ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_ON, 0x1); + ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1); + + ret |= it913x_write_reg(state, PRO_LINK, 0xf641, state->tuner_type); + ret |= it913x_write_reg(state, PRO_DMOD, 0xf5ca, 0x01); + ret |= it913x_write_reg(state, PRO_DMOD, 0xf715, 0x01); + + b[0] = xtal & 0xff; + b[1] = (xtal >> 8) & 0xff; + b[2] = (xtal >> 16) & 0xff; + b[3] = (xtal >> 24); + ret |= it913x_write(state, PRO_DMOD, XTAL_CLK, b , 4); + + b[0] = adc & 0xff; + b[1] = (adc >> 8) & 0xff; + b[2] = (adc >> 16) & 0xff; + ret |= it913x_write(state, PRO_DMOD, ADC_FREQ, b, 3); + + if (state->config->adc_x2) + ret |= it913x_write_reg(state, PRO_DMOD, ADC_X_2, 0x01); + b[0] = 0; + b[1] = 0; + b[2] = 0; + ret |= it913x_write(state, PRO_DMOD, 0x0029, b, 3); + + pr_info("Crystal Frequency :%d Adc Frequency :%d ADC X2: %02x\n", + state->crystalFrequency, state->adcFrequency, + state->config->adc_x2); + pr_debug("Xtal value :%04x Adc value :%04x\n", xtal, adc); + + if (ret < 0) + return -ENODEV; +#endif + + /* v1 or v2 tuner script */ + if (state->config->chip_ver > 1) + ret = it913x_fe_script_loader(state, it9135_v2); + else + ret = it913x_fe_script_loader(state, it9135_v1); + if (ret < 0) + return ret; + + /* LNA Scripts */ + switch (state->tuner_type) { + case IT9135_51: + set_lna = it9135_51; + break; + case IT9135_52: + set_lna = it9135_52; + break; + case IT9135_60: + set_lna = it9135_60; + break; + case IT9135_61: + set_lna = it9135_61; + break; + case IT9135_62: + set_lna = it9135_62; + break; + case IT9135_38: + default: + set_lna = it9135_38; + } + pr_info("Tuner LNA type :%02x\n", state->tuner_type); + + ret = it913x_fe_script_loader(state, set_lna); + if (ret < 0) + return ret; + + if (state->config->chip_ver == 2) { + ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1); + ret |= it913x_write_reg(state, PRO_LINK, PADODPU, 0x0); + ret |= it913x_write_reg(state, PRO_LINK, AGC_O_D, 0x0); + ret |= it913x_init_tuner(fe); + } + if (ret < 0) + return -ENODEV; + + /* Always solo frontend */ +// set_mode = set_solo_fe; +// ret |= it913x_fe_script_loader(state, set_mode); + + ret |= it913x_fe_suspend(state); + return (ret < 0) ? -ENODEV : 0; +} + +static int it913x_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + return 0; +} + +static const struct dvb_tuner_ops it913x_tuner_ops = { + .info = { + .name = "ITE Tech IT913X", + .frequency_min = 174000000, + .frequency_max = 862000000, + }, + + .release = it913x_release, + + .init = it913x_init_tuner, + .sleep = it913x_fe_sleep, + .set_params = it9137_set_tuner, +}; + +struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, u8 i2c_addr, struct ite_config *config) +{ + struct it913x_fe_state *state = NULL; + int ret; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct it913x_fe_state), GFP_KERNEL); + if (state == NULL) + return NULL; + if (config == NULL) + goto error; + + state->i2c_adap = i2c_adap; + state->i2c_addr = i2c_addr; + state->config = config; + + switch (state->config->tuner_id_0) { + case IT9135_51: + case IT9135_52: + case IT9135_60: + case IT9135_61: + case IT9135_62: + state->tuner_type = state->config->tuner_id_0; + break; + default: + case IT9135_38: + state->tuner_type = IT9135_38; + } + + fe->tuner_priv = state; + memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + ret = it913x_fe_start(fe); + if (ret < 0) + goto error; + + pr_info("%s: ITE Tech IT913X attached\n", KBUILD_MODNAME); + + return fe; +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(it913x_attach); + +MODULE_DESCRIPTION("ITE Tech IT913X silicon tuner driver"); +MODULE_AUTHOR("Antti Palosaari "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/it913x.h b/drivers/media/tuners/it913x.h new file mode 100644 index 000000000000..3583e56625f1 --- /dev/null +++ b/drivers/media/tuners/it913x.h @@ -0,0 +1,55 @@ +/* + * ITE Tech IT9137 silicon tuner driver + * + * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) + * IT9137 Copyright (C) ITE Tech Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef IT913X_H +#define IT913X_H + +#include "dvb_frontend.h" + +struct ite_config { + u8 chip_ver; + u16 chip_type; + u32 firmware; + u8 firmware_ver; + u8 adc_x2; + u8 tuner_id_0; + u8 tuner_id_1; + u8 dual_mode; + u8 adf; + /* option to read SIGNAL_LEVEL */ + u8 read_slevel; +}; + +#if defined(CONFIG_MEDIA_TUNER_IT913X) || \ + (defined(CONFIG_MEDIA_TUNER_IT913X_MODULE) && defined(MODULE)) +extern struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, u8 i2c_addr, struct ite_config *config); +#else +static inline struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, u8 i2c_addr, struct ite_config *config) +{ + pr_warn("%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff --git a/drivers/media/tuners/it913x_priv.h b/drivers/media/tuners/it913x_priv.h new file mode 100644 index 000000000000..e4a0136efc3d --- /dev/null +++ b/drivers/media/tuners/it913x_priv.h @@ -0,0 +1,867 @@ +/* + * ITE Tech IT9137 silicon tuner driver + * + * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) + * IT9137 Copyright (C) ITE Tech Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef IT913X_PRIV_H +#define IT913X_PRIV_H + +#include "it913x.h" + +/* Build in tuner types */ +#define IT9137 0x38 +#define IT9135_38 0x38 +#define IT9135_51 0x51 +#define IT9135_52 0x52 +#define IT9135_60 0x60 +#define IT9135_61 0x61 +#define IT9135_62 0x62 + +#define I2C_BASE_ADDR 0x10 +#define DEV_0 0x0 +#define DEV_1 0x10 +#define PRO_LINK 0x0 +#define PRO_DMOD 0x1 +#define DEV_0_DMOD (PRO_DMOD << 0x7) +#define DEV_1_DMOD (DEV_0_DMOD | DEV_1) +#define CHIP2_I2C_ADDR 0x3a + +#define PADODPU 0xd827 +#define THIRDODPU 0xd828 +#define AGC_O_D 0xd829 + +#define TRIGGER_OFSM 0x0000 + + +struct it913xset { u32 pro; + u32 address; + u8 reg[15]; + u8 count; +}; + +/* Version 1 types */ +static struct it913xset it9135_v1[] = { + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a}, 0x01}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a}, 0x01}, + {PRO_DMOD, 0x008a, {0x01}, 0x01}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06}, 0x01}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009f, {0xe1}, 0x01}, + {PRO_DMOD, 0x00a0, {0xcf}, 0x01}, + {PRO_DMOD, 0x00a3, {0x01}, 0x01}, + {PRO_DMOD, 0x00a5, {0x01}, 0x01}, + {PRO_DMOD, 0x00a6, {0x01}, 0x01}, + {PRO_DMOD, 0x00a9, {0x00}, 0x01}, + {PRO_DMOD, 0x00aa, {0x01}, 0x01}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00c2, {0x05}, 0x01}, + {PRO_DMOD, 0x00c6, {0x19}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf016, {0x10}, 0x01}, + {PRO_DMOD, 0xf017, {0x04}, 0x01}, + {PRO_DMOD, 0xf018, {0x05}, 0x01}, + {PRO_DMOD, 0xf019, {0x04}, 0x01}, + {PRO_DMOD, 0xf01a, {0x05}, 0x01}, + {PRO_DMOD, 0xf021, {0x03}, 0x01}, + {PRO_DMOD, 0xf022, {0x0a}, 0x01}, + {PRO_DMOD, 0xf023, {0x0a}, 0x01}, + {PRO_DMOD, 0xf02b, {0x00}, 0x01}, + {PRO_DMOD, 0xf02c, {0x01}, 0x01}, + {PRO_DMOD, 0xf064, {0x03}, 0x01}, + {PRO_DMOD, 0xf065, {0xf9}, 0x01}, + {PRO_DMOD, 0xf066, {0x03}, 0x01}, + {PRO_DMOD, 0xf067, {0x01}, 0x01}, + {PRO_DMOD, 0xf06f, {0xe0}, 0x01}, + {PRO_DMOD, 0xf070, {0x03}, 0x01}, + {PRO_DMOD, 0xf072, {0x0f}, 0x01}, + {PRO_DMOD, 0xf073, {0x03}, 0x01}, + {PRO_DMOD, 0xf078, {0x00}, 0x01}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f}, 0x01}, + {PRO_DMOD, 0xf09c, {0x00}, 0x01}, + {PRO_DMOD, 0xf09d, {0x20}, 0x01}, + {PRO_DMOD, 0xf09e, {0x00}, 0x01}, + {PRO_DMOD, 0xf09f, {0x0c}, 0x01}, + {PRO_DMOD, 0xf0a0, {0x00}, 0x01}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00}, 0x01}, + {PRO_DMOD, 0xf14d, {0x00}, 0x01}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00}, 0x01}, + {PRO_DMOD, 0xf15b, {0x08}, 0x01}, + {PRO_DMOD, 0xf15d, {0x03}, 0x01}, + {PRO_DMOD, 0xf15e, {0x05}, 0x01}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01}, 0x01}, + {PRO_DMOD, 0xf167, {0x40}, 0x01}, + {PRO_DMOD, 0xf168, {0x0f}, 0x01}, + {PRO_DMOD, 0xf17a, {0x00}, 0x01}, + {PRO_DMOD, 0xf17b, {0x00}, 0x01}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36}, 0x01}, + {PRO_DMOD, 0xf1bd, {0x00}, 0x01}, + {PRO_DMOD, 0xf1cb, {0xa0}, 0x01}, + {PRO_DMOD, 0xf1cc, {0x01}, 0x01}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf40e, {0x0a}, 0x01}, + {PRO_DMOD, 0xf40f, {0x40}, 0x01}, + {PRO_DMOD, 0xf410, {0x08}, 0x01}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15}, 0x01}, + {PRO_DMOD, 0xf562, {0x20}, 0x01}, + {PRO_DMOD, 0xf5df, {0xfb}, 0x01}, + {PRO_DMOD, 0xf5e0, {0x00}, 0x01}, + {PRO_DMOD, 0xf5e3, {0x09}, 0x01}, + {PRO_DMOD, 0xf5e4, {0x01}, 0x01}, + {PRO_DMOD, 0xf5e5, {0x01}, 0x01}, + {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, + {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, + {PRO_DMOD, 0xf600, {0x05}, 0x01}, + {PRO_DMOD, 0xf601, {0x08}, 0x01}, + {PRO_DMOD, 0xf602, {0x0b}, 0x01}, + {PRO_DMOD, 0xf603, {0x0e}, 0x01}, + {PRO_DMOD, 0xf604, {0x11}, 0x01}, + {PRO_DMOD, 0xf605, {0x14}, 0x01}, + {PRO_DMOD, 0xf606, {0x17}, 0x01}, + {PRO_DMOD, 0xf607, {0x1f}, 0x01}, + {PRO_DMOD, 0xf60e, {0x00}, 0x01}, + {PRO_DMOD, 0xf60f, {0x04}, 0x01}, + {PRO_DMOD, 0xf610, {0x32}, 0x01}, + {PRO_DMOD, 0xf611, {0x10}, 0x01}, + {PRO_DMOD, 0xf707, {0xfc}, 0x01}, + {PRO_DMOD, 0xf708, {0x00}, 0x01}, + {PRO_DMOD, 0xf709, {0x37}, 0x01}, + {PRO_DMOD, 0xf70a, {0x00}, 0x01}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40}, 0x01}, + {PRO_DMOD, 0xf810, {0x54}, 0x01}, + {PRO_DMOD, 0xf811, {0x5a}, 0x01}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_38[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x38}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x0a}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02}, + {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc8, 0xb8, + 0xd0, 0xc3, 0x01}, 0x0a}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x32}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03}, + {PRO_DMOD, 0x00c4, {0x00}, 0x01}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03}, + {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x02, 0x02, 0x02, 0x09, 0x50, 0x7b, 0x77, + 0x00, 0x02, 0xc8, 0x05, 0x7b}, 0x0c}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04}, + {PRO_DMOD, 0x011a, {0xc8, 0x7b, 0x8a, 0xa0}, 0x04}, + {PRO_DMOD, 0x0122, {0x02, 0x18, 0xc3}, 0x03}, + {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02}, + {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, + {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05}, + {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8, 0x59}, 0x05}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf085, {0x00, 0x02, 0x00}, 0x03}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, + {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, + {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, + 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_51[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x51}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x0a}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x06, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02}, + {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc0, 0x96, + 0xcf, 0xc3, 0x01}, 0x0a}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03}, + {PRO_DMOD, 0x00c4, {0x00}, 0x01}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03}, + {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x03, 0x02, 0x02, 0x09, 0x50, 0x7a, 0x77, + 0x01, 0x02, 0xb0, 0x02, 0x7a}, 0x0c}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04}, + {PRO_DMOD, 0x011a, {0xc0, 0x7a, 0xac, 0x8c}, 0x04}, + {PRO_DMOD, 0x0122, {0x02, 0x70, 0xa4}, 0x03}, + {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02}, + {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, + {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05}, + {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc0, 0x59}, 0x05}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, + {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, + {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, + 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_52[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x52}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x10}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xa0, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02}, + {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x03, 0x0a, 0x03, 0xb3, 0x97, + 0xc0, 0x9e, 0x01}, 0x0a}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03}, + {PRO_DMOD, 0x00c4, {0x00}, 0x01}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03}, + {PRO_DMOD, 0x00f3, {0x05, 0x91, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x03, 0x02, 0x02, 0x09, 0x50, 0x74, 0x77, + 0x02, 0x02, 0xae, 0x02, 0x6e}, 0x0c}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04}, + {PRO_DMOD, 0x011a, {0xcd, 0x62, 0xa4, 0x8c}, 0x04}, + {PRO_DMOD, 0x0122, {0x03, 0x18, 0x9e}, 0x03}, + {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02}, + {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, + {PRO_DMOD, 0x0137, {0x00, 0x00, 0x07, 0x00, 0x06}, 0x05}, + {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xb6, 0x59}, 0x05}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, + {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, + {PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, + 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +/* Version 2 types */ +static struct it913xset it9135_v2[] = { + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a}, 0x01}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a}, 0x01}, + {PRO_DMOD, 0x008a, {0x01}, 0x01}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06}, 0x01}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009f, {0xe1}, 0x01}, + {PRO_DMOD, 0x00a0, {0xcf}, 0x01}, + {PRO_DMOD, 0x00a3, {0x01}, 0x01}, + {PRO_DMOD, 0x00a5, {0x01}, 0x01}, + {PRO_DMOD, 0x00a6, {0x01}, 0x01}, + {PRO_DMOD, 0x00a9, {0x00}, 0x01}, + {PRO_DMOD, 0x00aa, {0x01}, 0x01}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00c2, {0x05}, 0x01}, + {PRO_DMOD, 0x00c6, {0x19}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf02b, {0x00}, 0x01}, + {PRO_DMOD, 0xf064, {0x03}, 0x01}, + {PRO_DMOD, 0xf065, {0xf9}, 0x01}, + {PRO_DMOD, 0xf066, {0x03}, 0x01}, + {PRO_DMOD, 0xf067, {0x01}, 0x01}, + {PRO_DMOD, 0xf06f, {0xe0}, 0x01}, + {PRO_DMOD, 0xf070, {0x03}, 0x01}, + {PRO_DMOD, 0xf072, {0x0f}, 0x01}, + {PRO_DMOD, 0xf073, {0x03}, 0x01}, + {PRO_DMOD, 0xf078, {0x00}, 0x01}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f}, 0x01}, + {PRO_DMOD, 0xf09c, {0x00}, 0x01}, + {PRO_DMOD, 0xf09d, {0x20}, 0x01}, + {PRO_DMOD, 0xf09e, {0x00}, 0x01}, + {PRO_DMOD, 0xf09f, {0x0c}, 0x01}, + {PRO_DMOD, 0xf0a0, {0x00}, 0x01}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00}, 0x01}, + {PRO_DMOD, 0xf14d, {0x00}, 0x01}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00}, 0x01}, + {PRO_DMOD, 0xf15b, {0x08}, 0x01}, + {PRO_DMOD, 0xf15d, {0x03}, 0x01}, + {PRO_DMOD, 0xf15e, {0x05}, 0x01}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01}, 0x01}, + {PRO_DMOD, 0xf167, {0x40}, 0x01}, + {PRO_DMOD, 0xf168, {0x0f}, 0x01}, + {PRO_DMOD, 0xf17a, {0x00}, 0x01}, + {PRO_DMOD, 0xf17b, {0x00}, 0x01}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36}, 0x01}, + {PRO_DMOD, 0xf1bd, {0x00}, 0x01}, + {PRO_DMOD, 0xf1cb, {0xa0}, 0x01}, + {PRO_DMOD, 0xf1cc, {0x01}, 0x01}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf40e, {0x0a}, 0x01}, + {PRO_DMOD, 0xf40f, {0x40}, 0x01}, + {PRO_DMOD, 0xf410, {0x08}, 0x01}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15}, 0x01}, + {PRO_DMOD, 0xf562, {0x20}, 0x01}, + {PRO_DMOD, 0xf5e3, {0x09}, 0x01}, + {PRO_DMOD, 0xf5e4, {0x01}, 0x01}, + {PRO_DMOD, 0xf5e5, {0x01}, 0x01}, + {PRO_DMOD, 0xf600, {0x05}, 0x01}, + {PRO_DMOD, 0xf601, {0x08}, 0x01}, + {PRO_DMOD, 0xf602, {0x0b}, 0x01}, + {PRO_DMOD, 0xf603, {0x0e}, 0x01}, + {PRO_DMOD, 0xf604, {0x11}, 0x01}, + {PRO_DMOD, 0xf605, {0x14}, 0x01}, + {PRO_DMOD, 0xf606, {0x17}, 0x01}, + {PRO_DMOD, 0xf607, {0x1f}, 0x01}, + {PRO_DMOD, 0xf60e, {0x00}, 0x01}, + {PRO_DMOD, 0xf60f, {0x04}, 0x01}, + {PRO_DMOD, 0xf610, {0x32}, 0x01}, + {PRO_DMOD, 0xf611, {0x10}, 0x01}, + {PRO_DMOD, 0xf707, {0xfc}, 0x01}, + {PRO_DMOD, 0xf708, {0x00}, 0x01}, + {PRO_DMOD, 0xf709, {0x37}, 0x01}, + {PRO_DMOD, 0xf70a, {0x00}, 0x01}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40}, 0x01}, + {PRO_DMOD, 0xf810, {0x54}, 0x01}, + {PRO_DMOD, 0xf811, {0x5a}, 0x01}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_60[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x60}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x0a}, 0x01}, + {PRO_DMOD, 0x006a, {0x03}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02}, + {PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbe, 0xa0, 0xc6, 0xb6, 0x01}, 0x07}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04}, + {PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x03, 0x03, 0x02, 0x0a, 0x50, 0x7b, 0x8c, + 0x00, 0x02, 0xbe, 0x00}, 0x0b}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, + {PRO_DMOD, 0x011a, {0xbe}, 0x01}, + {PRO_DMOD, 0x0124, {0xae}, 0x01}, + {PRO_DMOD, 0x0127, {0x00}, 0x01}, + {PRO_DMOD, 0x012a, {0x56, 0x50, 0x47, 0x42}, 0x04}, + {PRO_DMOD, 0x0137, {0x00}, 0x01}, + {PRO_DMOD, 0x013b, {0x08}, 0x01}, + {PRO_DMOD, 0x013f, {0x5b}, 0x01}, + {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x19, 0x19, 0x8c, 0x8c, 0x8c, + 0x6e, 0x8c, 0x50, 0x8c, 0x8c, 0xac, 0xc6, + 0x33}, 0x0f}, + {PRO_DMOD, 0x0151, {0x28}, 0x01}, + {PRO_DMOD, 0x0153, {0xbc}, 0x01}, + {PRO_DMOD, 0x0178, {0x09}, 0x01}, + {PRO_DMOD, 0x0181, {0x94, 0x6e}, 0x02}, + {PRO_DMOD, 0x0185, {0x24}, 0x01}, + {PRO_DMOD, 0x0187, {0x00, 0x00, 0xbe, 0x02, 0x80}, 0x05}, + {PRO_DMOD, 0xed02, {0xff}, 0x01}, + {PRO_DMOD, 0xee42, {0xff}, 0x01}, + {PRO_DMOD, 0xee82, {0xff}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17 + , 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_61[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x61}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x06}, 0x01}, + {PRO_DMOD, 0x006a, {0x03}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x90, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02}, + {PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbc, 0x9c, 0xcc, 0xa8, 0x01}, 0x07}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04}, + {PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x03, 0x03, 0x02, 0x08, 0x50, 0x7b, 0x8c, + 0x01, 0x02, 0xc8, 0x00}, 0x0b}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, + {PRO_DMOD, 0x011a, {0xc6}, 0x01}, + {PRO_DMOD, 0x0124, {0xa8}, 0x01}, + {PRO_DMOD, 0x0127, {0x00}, 0x01}, + {PRO_DMOD, 0x012a, {0x59, 0x50, 0x47, 0x42}, 0x04}, + {PRO_DMOD, 0x0137, {0x00}, 0x01}, + {PRO_DMOD, 0x013b, {0x05}, 0x01}, + {PRO_DMOD, 0x013f, {0x5b}, 0x01}, + {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x59, 0x59, 0x8c, 0x8c, 0x8c, + 0x7b, 0x8c, 0x50, 0x8c, 0x8c, 0xa8, 0xc6, + 0x33}, 0x0f}, + {PRO_DMOD, 0x0151, {0x28}, 0x01}, + {PRO_DMOD, 0x0153, {0xcc}, 0x01}, + {PRO_DMOD, 0x0178, {0x09}, 0x01}, + {PRO_DMOD, 0x0181, {0x9c, 0x76}, 0x02}, + {PRO_DMOD, 0x0185, {0x28}, 0x01}, + {PRO_DMOD, 0x0187, {0x01, 0x00, 0xaa, 0x02, 0x80}, 0x05}, + {PRO_DMOD, 0xed02, {0xff}, 0x01}, + {PRO_DMOD, 0xee42, {0xff}, 0x01}, + {PRO_DMOD, 0xee82, {0xff}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, + 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +static struct it913xset it9135_62[] = { + {PRO_DMOD, 0x0043, {0x00}, 0x01}, + {PRO_DMOD, 0x0046, {0x62}, 0x01}, + {PRO_DMOD, 0x0051, {0x01}, 0x01}, + {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0x0068, {0x0a}, 0x01}, + {PRO_DMOD, 0x006a, {0x03}, 0x01}, + {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, + {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05}, + {PRO_DMOD, 0x007e, {0x04}, 0x01}, + {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02}, + {PRO_DMOD, 0x0084, { 0x0a, 0x33, 0xb8, 0x9c, 0xb2, 0xa6, 0x01}, + 0x07}, + {PRO_DMOD, 0x008e, {0x01}, 0x01}, + {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, + {PRO_DMOD, 0x0099, {0x01}, 0x01}, + {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, + {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, + {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, + {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, + {PRO_DMOD, 0x00b0, {0x01}, 0x01}, + {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02}, + {PRO_DMOD, 0x00b6, {0x14}, 0x01}, + {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05}, + {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, + {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04}, + {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03}, + {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, + {PRO_DMOD, 0x00fc, { 0x02, 0x03, 0x02, 0x09, 0x50, 0x6e, 0x8c, + 0x02, 0x02, 0xc2, 0x00}, 0x0b}, + {PRO_DMOD, 0x0109, {0x02}, 0x01}, + {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, + {PRO_DMOD, 0x011a, {0xb8}, 0x01}, + {PRO_DMOD, 0x0124, {0xa8}, 0x01}, + {PRO_DMOD, 0x0127, {0x00}, 0x01}, + {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, + {PRO_DMOD, 0x0137, {0x00}, 0x01}, + {PRO_DMOD, 0x013b, {0x05}, 0x01}, + {PRO_DMOD, 0x013f, {0x5b}, 0x01}, + {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x59, 0x19, 0x8c, 0x8c, 0x8c, + 0x7b, 0x8c, 0x50, 0x70, 0x8c, 0x96, 0xd0, + 0x33}, 0x0f}, + {PRO_DMOD, 0x0151, {0x28}, 0x01}, + {PRO_DMOD, 0x0153, {0xb2}, 0x01}, + {PRO_DMOD, 0x0178, {0x09}, 0x01}, + {PRO_DMOD, 0x0181, {0x9c, 0x6e}, 0x02}, + {PRO_DMOD, 0x0185, {0x24}, 0x01}, + {PRO_DMOD, 0x0187, {0x00, 0x00, 0xb8, 0x02, 0x80}, 0x05}, + {PRO_DMOD, 0xed02, {0xff}, 0x01}, + {PRO_DMOD, 0xee42, {0xff}, 0x01}, + {PRO_DMOD, 0xee82, {0xff}, 0x01}, + {PRO_DMOD, 0xf000, {0x0f}, 0x01}, + {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02}, + {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03}, + {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, + {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, + {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, + {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, + {PRO_DMOD, 0xf087, {0x00}, 0x01}, + {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, + {PRO_DMOD, 0xf130, {0x04}, 0x01}, + {PRO_DMOD, 0xf132, {0x04}, 0x01}, + {PRO_DMOD, 0xf144, {0x1a}, 0x01}, + {PRO_DMOD, 0xf146, {0x00}, 0x01}, + {PRO_DMOD, 0xf14a, {0x01}, 0x01}, + {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf14f, {0x04}, 0x01}, + {PRO_DMOD, 0xf158, {0x7f}, 0x01}, + {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, + {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, + {PRO_DMOD, 0xf163, {0x05}, 0x01}, + {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, + {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, + {PRO_DMOD, 0xf183, {0x01}, 0x01}, + {PRO_DMOD, 0xf19d, {0x40}, 0x01}, + {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, + {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, + {PRO_DMOD, 0xf204, {0x10}, 0x01}, + {PRO_DMOD, 0xf214, {0x00}, 0x01}, + {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, + {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, + {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, + {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, + {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, + {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, + {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, + {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, + 0x1f}, 0x08}, + {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, + {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, + {PRO_DMOD, 0xf78b, {0x01}, 0x01}, + {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, + {PRO_DMOD, 0xf905, {0x01}, 0x01}, + {PRO_DMOD, 0xfb06, {0x03}, 0x01}, + {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ +}; + +/* Tuner setting scripts (still keeping it9137) */ +static struct it913xset it9137_tuner_off[] = { + {PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off */ + {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */ + {PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04}, + {PRO_DMOD, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, 0x0c}, + {PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04}, + {PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00}, 0x09}, + {PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00}, 0x0a}, + {PRO_DMOD, 0xec20, {0x00}, 0x01}, + {PRO_DMOD, 0xec3f, {0x01}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; + +static struct it913xset set_it9135_template[] = { + {PRO_DMOD, 0xee06, {0x00}, 0x01}, + {PRO_DMOD, 0xec56, {0x00}, 0x01}, + {PRO_DMOD, 0xec4c, {0x00}, 0x01}, + {PRO_DMOD, 0xec4d, {0x00}, 0x01}, + {PRO_DMOD, 0xec4e, {0x00}, 0x01}, + {PRO_DMOD, 0x011e, {0x00}, 0x01}, /* Older Devices */ + {PRO_DMOD, 0x011f, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; + +static struct it913xset set_it9137_template[] = { + {PRO_DMOD, 0xee06, {0x00}, 0x01}, + {PRO_DMOD, 0xec56, {0x00}, 0x01}, + {PRO_DMOD, 0xec4c, {0x00}, 0x01}, + {PRO_DMOD, 0xec4d, {0x00}, 0x01}, + {PRO_DMOD, 0xec4e, {0x00}, 0x01}, + {PRO_DMOD, 0xec4f, {0x00}, 0x01}, + {PRO_DMOD, 0xec50, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; + +#endif -- cgit v1.2.3 From 4902bb39b643437a4c0a339dbf8f3ceb14540be5 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 7 Jan 2013 09:48:03 -0300 Subject: [media] af9033: support for it913x tuners Add support for tuners integrated to the IT9135 and IT9137. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 34 +++++++++++++++++++++------------- drivers/media/dvb-frontends/af9033.h | 15 +++++++++++++++ 2 files changed, 36 insertions(+), 13 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index c9cad989b8b9..dece775836ac 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -223,6 +223,7 @@ static int af9033_init(struct dvb_frontend *fe) { 0x80f986, state->ts_mode_parallel, 0x01 }, { 0x00d827, 0x00, 0xff }, { 0x00d829, 0x00, 0xff }, + { 0x800045, state->cfg.adc_multiplier, 0xff }, }; /* program clock control */ @@ -322,6 +323,14 @@ static int af9033_init(struct dvb_frontend *fe) len = ARRAY_SIZE(tuner_init_fc0012); init = tuner_init_fc0012; break; + case AF9033_TUNER_IT9135_38: + case AF9033_TUNER_IT9135_51: + case AF9033_TUNER_IT9135_52: + case AF9033_TUNER_IT9135_60: + case AF9033_TUNER_IT9135_61: + case AF9033_TUNER_IT9135_62: + len = 0; + break; default: dev_dbg(&state->i2c->dev, "%s: unsupported tuner ID=%d\n", __func__, state->cfg.tuner); @@ -498,12 +507,7 @@ static int af9033_set_frontend(struct dvb_frontend *fe) if (spec_inv == -1) freq_cw = 0x800000 - freq_cw; - /* get adc multiplies */ - ret = af9033_rd_reg(state, 0x800045, &tmp); - if (ret < 0) - goto err; - - if (tmp == 1) + if (state->cfg.adc_multiplier == AF9033_ADC_MULTIPLIER_2X) freq_cw /= 2; buf[0] = (freq_cw >> 0) & 0xff; @@ -933,14 +937,18 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, "OFDM=%d.%d.%d.%d\n", KBUILD_MODNAME, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); - /* sleep */ - ret = af9033_wr_reg(state, 0x80004c, 1); - if (ret < 0) - goto err; - ret = af9033_wr_reg(state, 0x800000, 0); - if (ret < 0) - goto err; + /* FIXME: Do not abuse adc_multiplier for detecting IT9135 */ + if (state->cfg.adc_multiplier != AF9033_ADC_MULTIPLIER_2X) { + /* sleep */ + ret = af9033_wr_reg(state, 0x80004c, 1); + if (ret < 0) + goto err; + + ret = af9033_wr_reg(state, 0x800000, 0); + if (ret < 0) + goto err; + } /* configure internal TS mode */ switch (state->cfg.ts_mode) { diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h index 82bd8c1513b6..53fd3040c5f0 100644 --- a/drivers/media/dvb-frontends/af9033.h +++ b/drivers/media/dvb-frontends/af9033.h @@ -35,6 +35,13 @@ struct af9033_config { */ u32 clock; + /* + * ADC multiplier + */ +#define AF9033_ADC_MULTIPLIER_1X 0 +#define AF9033_ADC_MULTIPLIER_2X 1 + u8 adc_multiplier; + /* * tuner */ @@ -44,6 +51,14 @@ struct af9033_config { #define AF9033_TUNER_MXL5007T 0xa0 /* MaxLinear MxL5007T */ #define AF9033_TUNER_TDA18218 0xa1 /* NXP TDA 18218HN */ #define AF9033_TUNER_FC2580 0x32 /* FCI FC2580 */ +/* 50-5f Omega */ +#define AF9033_TUNER_IT9135_38 0x38 /* Omega */ +#define AF9033_TUNER_IT9135_51 0x51 /* Omega LNA config 1 */ +#define AF9033_TUNER_IT9135_52 0x52 /* Omega LNA config 2 */ +/* 60-6f Omega v2 */ +#define AF9033_TUNER_IT9135_60 0x60 /* Omega v2 */ +#define AF9033_TUNER_IT9135_61 0x61 /* Omega v2 LNA config 1 */ +#define AF9033_TUNER_IT9135_62 0x62 /* Omega v2 LNA config 2 */ u8 tuner; /* -- cgit v1.2.3 From ac77fb0f0ce9f77f465692d590b9615b95a99fb2 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 7 Jan 2013 09:51:13 -0300 Subject: [media] af9035: add support for 1st gen it9135 Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/Kconfig | 1 + drivers/media/usb/dvb-usb-v2/af9035.c | 24 +++++++++++++++++++++++- drivers/media/usb/dvb-usb-v2/af9035.h | 1 + 3 files changed, 25 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 692224d97d06..2d4abfa75043 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -41,6 +41,7 @@ config DVB_USB_AF9035 select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18218 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_IT913X if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Afatech AF9035 based DVB USB receiver. diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 66f65197c40d..f43e83c4122a 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -652,6 +652,10 @@ static int af9035_read_config_it9135(struct dvb_usb_device *d) int ret, i; u8 tmp; + /* demod I2C "address" */ + state->af9033_config[0].i2c_addr = 0x38; + state->af9033_config[0].tuner = AF9033_TUNER_IT9135_38; + state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X; state->dual_mode = false; /* get demod clock */ @@ -920,6 +924,20 @@ static const struct fc0012_config af9035_fc0012_config[] = { } }; +static struct ite_config af9035_it913x_config = { + .chip_ver = 0x01, + .chip_type = 0x9135, + .firmware = 0x00000000, + .firmware_ver = 1, + .adc_x2 = 1, + .tuner_id_0 = AF9033_TUNER_IT9135_38, + .tuner_id_1 = 0x00, + .dual_mode = 0x00, + .adf = 0x00, + /* option to read SIGNAL_LEVEL */ + .read_slevel = 0, +}; + static int af9035_tuner_attach(struct dvb_usb_adapter *adap) { struct state *state = adap_to_priv(adap); @@ -1082,6 +1100,11 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) fe = dvb_attach(fc0012_attach, adap->fe[0], &d->i2c_adap, &af9035_fc0012_config[adap->id]); break; + case AF9033_TUNER_IT9135_38: + /* attach tuner */ + fe = dvb_attach(it913x_attach, adap->fe[0], + &d->i2c_adap, 0x38, &af9035_it913x_config); + break; default: fe = NULL; } @@ -1275,7 +1298,6 @@ static const struct dvb_usb_device_properties it9135_props = { .frontend_attach = af9035_frontend_attach, .tuner_attach = af9035_tuner_attach, .init = af9035_init, - .get_rc_config = af9035_get_rc_config, .num_adapters = 1, .adapter = { diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index 6d098a93d5ab..1b2f69f594f3 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -30,6 +30,7 @@ #include "mxl5007t.h" #include "tda18218.h" #include "fc2580.h" +#include "it913x.h" struct reg_val { u32 reg; -- cgit v1.2.3 From 74c1883a56369d5e323c712a6c81b869e3bcb113 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 7 Jan 2013 15:16:54 -0300 Subject: [media] af9035: add auto configuration heuristic for it9135 Detect automatically multiple chip versions and select configuration according to that. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 116 ++++++++++++++++++++++++---------- drivers/media/usb/dvb-usb-v2/af9035.h | 6 +- 2 files changed, 88 insertions(+), 34 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index f43e83c4122a..2c5b01d9dc23 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -292,12 +292,38 @@ static struct i2c_algorithm af9035_i2c_algo = { static int af9035_identify_state(struct dvb_usb_device *d, const char **name) { + struct state *state = d_to_priv(d); int ret; u8 wbuf[1] = { 1 }; u8 rbuf[4]; struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf, sizeof(rbuf), rbuf }; + ret = af9035_rd_regs(d, 0x1222, rbuf, 3); + if (ret < 0) + goto err; + + state->chip_version = rbuf[0]; + state->chip_type = rbuf[2] << 8 | rbuf[1] << 0; + + ret = af9035_rd_reg(d, 0x384f, &state->prechip_version); + if (ret < 0) + goto err; + + dev_info(&d->udev->dev, + "%s: prechip_version=%02x chip_version=%02x chip_type=%04x\n", + __func__, state->prechip_version, state->chip_version, + state->chip_type); + + if (state->chip_type == 0x9135) { + if (state->chip_version == 2) + *name = AF9035_FIRMWARE_IT9135_V2; + else + *name = AF9035_FIRMWARE_IT9135_V1; + } else { + *name = AF9035_FIRMWARE_AF9035; + } + ret = af9035_ctrl_msg(d, &req); if (ret < 0) goto err; @@ -316,7 +342,7 @@ err: return ret; } -static int af9035_download_firmware(struct dvb_usb_device *d, +static int af9035_download_firmware_af9035(struct dvb_usb_device *d, const struct firmware *fw) { int ret, i, j, len; @@ -543,7 +569,18 @@ err: return ret; } -static int af9035_read_config(struct dvb_usb_device *d) +static int af9035_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + struct state *state = d_to_priv(d); + + if (state->chip_type == 0x9135) + return af9035_download_firmware_it9135(d, fw); + else + return af9035_download_firmware_af9035(d, fw); +} + +static int af9035_read_config_af9035(struct dvb_usb_device *d) { struct state *state = d_to_priv(d); int ret, i, eeprom_shift = 0; @@ -658,6 +695,27 @@ static int af9035_read_config_it9135(struct dvb_usb_device *d) state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X; state->dual_mode = false; + /* check if eeprom exists */ + if (state->chip_version == 2) + ret = af9035_rd_reg(d, 0x00461d, &tmp); + else + ret = af9035_rd_reg(d, 0x00461b, &tmp); + if (ret < 0) + goto err; + + if (tmp) { + /* tuner */ + ret = af9035_rd_reg(d, 0x0049d0, &tmp); + if (ret < 0) + goto err; + + dev_dbg(&d->udev->dev, "%s: [%d]tuner=%02x\n", + __func__, 0, tmp); + + if (tmp) + state->af9033_config[0].tuner = tmp; + } + /* get demod clock */ ret = af9035_rd_reg(d, 0x00d800, &tmp); if (ret < 0) @@ -676,6 +734,16 @@ err: return ret; } +static int af9035_read_config(struct dvb_usb_device *d) +{ + struct state *state = d_to_priv(d); + + if (state->chip_type == 0x9135) + return af9035_read_config_it9135(d); + else + return af9035_read_config_af9035(d); +} + static int af9035_tua9001_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) { @@ -1101,7 +1169,13 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) &af9035_fc0012_config[adap->id]); break; case AF9033_TUNER_IT9135_38: + case AF9033_TUNER_IT9135_51: + case AF9033_TUNER_IT9135_52: + case AF9033_TUNER_IT9135_60: + case AF9033_TUNER_IT9135_61: + case AF9033_TUNER_IT9135_62: /* attach tuner */ + af9035_it913x_config.tuner_id_0 = state->af9033_config[0].tuner; fe = dvb_attach(it913x_attach, adap->fe[0], &d->i2c_adap, 0x38, &af9035_it913x_config); break; @@ -1202,9 +1276,14 @@ err: static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { + struct state *state = d_to_priv(d); int ret; u8 tmp; + /* TODO: IT9135 remote control support */ + if (state->chip_type == 0x9135) + return 0; + ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp); if (ret < 0) goto err; @@ -1260,7 +1339,6 @@ static const struct dvb_usb_device_properties af9035_props = { .generic_bulk_ctrl_endpoint_response = 0x81, .identify_state = af9035_identify_state, - .firmware = AF9035_FIRMWARE_AF9035, .download_firmware = af9035_download_firmware, .i2c_algo = &af9035_i2c_algo, @@ -1280,35 +1358,6 @@ static const struct dvb_usb_device_properties af9035_props = { }, }; -static const struct dvb_usb_device_properties it9135_props = { - .driver_name = KBUILD_MODNAME, - .owner = THIS_MODULE, - .adapter_nr = adapter_nr, - .size_of_priv = sizeof(struct state), - - .generic_bulk_ctrl_endpoint = 0x02, - .generic_bulk_ctrl_endpoint_response = 0x81, - - .identify_state = af9035_identify_state, - .firmware = AF9035_FIRMWARE_IT9135, - .download_firmware = af9035_download_firmware_it9135, - - .i2c_algo = &af9035_i2c_algo, - .read_config = af9035_read_config_it9135, - .frontend_attach = af9035_frontend_attach, - .tuner_attach = af9035_tuner_attach, - .init = af9035_init, - - .num_adapters = 1, - .adapter = { - { - .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), - }, { - .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), - }, - }, -}; - static const struct usb_device_id af9035_id_table[] = { { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035, &af9035_props, "Afatech AF9035 reference design", NULL) }, @@ -1358,4 +1407,5 @@ MODULE_AUTHOR("Antti Palosaari "); MODULE_DESCRIPTION("Afatech AF9035 driver"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(AF9035_FIRMWARE_AF9035); -MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135); +MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V1); +MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V2); diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index 1b2f69f594f3..4465f858eb03 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -57,6 +57,9 @@ struct state { u8 buf[BUF_LEN]; u8 seq; /* packet sequence number */ bool dual_mode; + u8 prechip_version; + u8 chip_version; + u16 chip_type; struct af9033_config af9033_config[2]; }; @@ -89,7 +92,8 @@ u32 clock_lut_it9135[] = { }; #define AF9035_FIRMWARE_AF9035 "dvb-usb-af9035-02.fw" -#define AF9035_FIRMWARE_IT9135 "dvb-usb-it9135-01.fw" +#define AF9035_FIRMWARE_IT9135_V1 "dvb-usb-it9135-01.fw" +#define AF9035_FIRMWARE_IT9135_V2 "dvb-usb-it9135-02.fw" /* EEPROM locations */ #define EEPROM_IR_MODE 0x430d -- cgit v1.2.3 From 0d94d6a04b503bed97911d80963ff8e63deee60e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 7 Jan 2013 15:26:05 -0300 Subject: [media] af9035: fix af9033 demod sampling frequency ADC needs to be also multiplied to 2 as it9135. Fixes bug I introduced few commits ago. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 2c5b01d9dc23..1a4aeefefb6a 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -589,6 +589,7 @@ static int af9035_read_config_af9035(struct dvb_usb_device *d) /* demod I2C "address" */ state->af9033_config[0].i2c_addr = 0x38; + state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X; /* check if there is dual tuners */ ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp); -- cgit v1.2.3 From e8c7aab50ddcb84f164422b5c8e0042a6fec6649 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Mon, 7 Jan 2013 16:29:13 -0300 Subject: [media] af9015: reject device TerraTec Cinergy T Stick Dual RC (rev. 2) That same USB ID is used both AF9015 and AF9035 driver. iManufacturer is only thing we can select correct driver without a I/O. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9015.c | 40 ++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 2fa7c6ee5a70..d556042cf312 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -1320,6 +1320,43 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) #define af9015_get_rc_config NULL #endif +static int af9015_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + char manufacturer[sizeof("ITE Technologies, Inc.")]; + + memset(manufacturer, 0, sizeof(manufacturer)); + usb_string(udev, udev->descriptor.iManufacturer, + manufacturer, sizeof(manufacturer)); + /* + * There is two devices having same ID but different chipset. One uses + * AF9015 and the other IT9135 chipset. Only difference seen on lsusb + * is iManufacturer string. + * + * idVendor 0x0ccd TerraTec Electronic GmbH + * idProduct 0x0099 + * bcdDevice 2.00 + * iManufacturer 1 Afatech + * iProduct 2 DVB-T 2 + * + * idVendor 0x0ccd TerraTec Electronic GmbH + * idProduct 0x0099 + * bcdDevice 2.00 + * iManufacturer 1 ITE Technologies, Inc. + * iProduct 2 DVB-T TV Stick + */ + if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VID_TERRATEC) && + (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) { + if (!strcmp("ITE Technologies, Inc.", manufacturer)) { + dev_dbg(&udev->dev, "%s: rejecting device\n", __func__); + return -ENODEV; + } + } + + return dvb_usbv2_probe(intf, id); +} + /* interface 0 is used by DVB-T receiver and interface 1 is for remote controller (HID) */ static struct dvb_usb_device_properties af9015_props = { @@ -1428,6 +1465,7 @@ static const struct usb_device_id af9015_id_table[] = { &af9015_props, "AverMedia AVerTV Volar M (A815Mac)", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC, &af9015_props, "TerraTec Cinergy T Stick RC", RC_MAP_TERRATEC_SLIM_2) }, + /* XXX: that same ID [0ccd:0099] is used by af9035 driver too */ { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC, &af9015_props, "TerraTec Cinergy T Stick Dual RC", RC_MAP_TERRATEC_SLIM) }, { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T, @@ -1444,7 +1482,7 @@ MODULE_DEVICE_TABLE(usb, af9015_id_table); static struct usb_driver af9015_usb_driver = { .name = KBUILD_MODNAME, .id_table = af9015_id_table, - .probe = dvb_usbv2_probe, + .probe = af9015_probe, .disconnect = dvb_usbv2_disconnect, .suspend = dvb_usbv2_suspend, .resume = dvb_usbv2_resume, -- cgit v1.2.3 From b799b8102baa8e63139f0eadef00d75701328775 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 11 Jan 2013 16:22:07 -0300 Subject: [media] af9035: [0ccd:0099] TerraTec Cinergy T Stick Dual RC (rev. 2) That same USB ID is used both AF9015 and AF9035 driver. iManufacturer is only thing we can select correct driver without a I/O. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 42 ++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 1a4aeefefb6a..ad66ac4b3913 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -1328,6 +1328,43 @@ err: #define af9035_get_rc_config NULL #endif +static int af9035_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + char manufacturer[sizeof("Afatech")]; + + memset(manufacturer, 0, sizeof(manufacturer)); + usb_string(udev, udev->descriptor.iManufacturer, + manufacturer, sizeof(manufacturer)); + /* + * There is two devices having same ID but different chipset. One uses + * AF9015 and the other IT9135 chipset. Only difference seen on lsusb + * is iManufacturer string. + * + * idVendor 0x0ccd TerraTec Electronic GmbH + * idProduct 0x0099 + * bcdDevice 2.00 + * iManufacturer 1 Afatech + * iProduct 2 DVB-T 2 + * + * idVendor 0x0ccd TerraTec Electronic GmbH + * idProduct 0x0099 + * bcdDevice 2.00 + * iManufacturer 1 ITE Technologies, Inc. + * iProduct 2 DVB-T TV Stick + */ + if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VID_TERRATEC) && + (le16_to_cpu(udev->descriptor.idProduct) == 0x0099)) { + if (!strcmp("Afatech", manufacturer)) { + dev_dbg(&udev->dev, "%s: rejecting device\n", __func__); + return -ENODEV; + } + } + + return dvb_usbv2_probe(intf, id); +} + /* interface 0 is used by DVB-T receiver and interface 1 is for remote controller (HID) */ static const struct dvb_usb_device_properties af9035_props = { @@ -1386,6 +1423,9 @@ static const struct usb_device_id af9035_id_table[] = { &af9035_props, "Asus U3100Mini Plus", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00aa, &af9035_props, "TerraTec Cinergy T Stick (rev. 2)", NULL) }, + /* XXX: that same ID [0ccd:0099] is used by af9015 driver too */ + { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099, + &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, af9035_id_table); @@ -1393,7 +1433,7 @@ MODULE_DEVICE_TABLE(usb, af9035_id_table); static struct usb_driver af9035_usb_driver = { .name = KBUILD_MODNAME, .id_table = af9035_id_table, - .probe = dvb_usbv2_probe, + .probe = af9035_probe, .disconnect = dvb_usbv2_disconnect, .suspend = dvb_usbv2_suspend, .resume = dvb_usbv2_resume, -- cgit v1.2.3 From a7816b7667d227e97d91e4dee4657862affea7a1 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 11 Jan 2013 16:34:06 -0300 Subject: [media] af9035: constify clock tables Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index 4465f858eb03..f126eeabf0ba 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -63,7 +63,7 @@ struct state { struct af9033_config af9033_config[2]; }; -u32 clock_lut[] = { +static const u32 clock_lut[] = { 20480000, /* FPGA */ 16384000, /* 16.38 MHz */ 20480000, /* 20.48 MHz */ @@ -78,7 +78,7 @@ u32 clock_lut[] = { 12000000, /* 12.00 MHz */ }; -u32 clock_lut_it9135[] = { +static const u32 clock_lut_it9135[] = { 12000000, /* 12.00 MHz */ 20480000, /* 20.48 MHz */ 36000000, /* 36.00 MHz */ -- cgit v1.2.3 From bada342e0845f459f0abd80cf7c86ec871980c1a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 11 Jan 2013 20:45:11 -0300 Subject: [media] af9035: USB1.1 support (== PID filters) Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 85 +++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index ad66ac4b3913..3f00f0bee0ce 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -894,7 +894,12 @@ static int af9035_frontend_callback(void *adapter_priv, int component, static int af9035_get_adapter_count(struct dvb_usb_device *d) { struct state *state = d_to_priv(d); - return state->dual_mode + 1; + + /* disable 2nd adapter as we don't have PID filters implemented */ + if (d->udev->speed == USB_SPEED_FULL) + return 1; + else + return state->dual_mode + 1; } static int af9035_frontend_attach(struct dvb_usb_adapter *adap) @@ -1201,8 +1206,8 @@ static int af9035_init(struct dvb_usb_device *d) { struct state *state = d_to_priv(d); int ret, i; - u16 frame_size = 87 * 188 / 4; - u8 packet_size = 512 / 4; + u16 frame_size = (d->udev->speed == USB_SPEED_FULL ? 5 : 87) * 188 / 4; + u8 packet_size = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4; struct reg_val_mask tab[] = { { 0x80f99d, 0x01, 0x01 }, { 0x80f9a4, 0x01, 0x01 }, @@ -1328,6 +1333,72 @@ err: #define af9035_get_rc_config NULL #endif +static int af9035_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, + struct usb_data_stream_properties *stream) +{ + struct dvb_usb_device *d = fe_to_d(fe); + dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, fe_to_adap(fe)->id); + + if (d->udev->speed == USB_SPEED_FULL) + stream->u.bulk.buffersize = 5 * 188; + + return 0; +} + +/* + * FIXME: PID filter is property of demodulator and should be moved to the + * correct driver. Also we support only adapter #0 PID filter and will + * disable adapter #1 if USB1.1 is used. + */ +static int af9035_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) +{ + struct dvb_usb_device *d = adap_to_d(adap); + int ret; + + dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); + + ret = af9035_wr_reg_mask(d, 0x80f993, onoff, 0x01); + if (ret < 0) + goto err; + + return 0; + +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, + int onoff) +{ + struct dvb_usb_device *d = adap_to_d(adap); + int ret; + u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff}; + + dev_dbg(&d->udev->dev, "%s: index=%d pid=%04x onoff=%d\n", + __func__, index, pid, onoff); + + ret = af9035_wr_regs(d, 0x80f996, wbuf, 2); + if (ret < 0) + goto err; + + ret = af9035_wr_reg(d, 0x80f994, onoff); + if (ret < 0) + goto err; + + ret = af9035_wr_reg(d, 0x80f995, index); + if (ret < 0) + goto err; + + return 0; + +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} + static int af9035_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1385,10 +1456,18 @@ static const struct dvb_usb_device_properties af9035_props = { .tuner_attach = af9035_tuner_attach, .init = af9035_init, .get_rc_config = af9035_get_rc_config, + .get_stream_config = af9035_get_stream_config, .get_adapter_count = af9035_get_adapter_count, .adapter = { { + .caps = DVB_USB_ADAP_HAS_PID_FILTER | + DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, + + .pid_filter_count = 32, + .pid_filter_ctrl = af9035_pid_filter_ctrl, + .pid_filter = af9035_pid_filter, + .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188), }, { .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188), -- cgit v1.2.3 From 9ea3681db4c9cd3995595aa9c3e4f1defb8a700b Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 11 Jan 2013 22:16:25 -0300 Subject: [media] af9035: merge af9035 and it9135 eeprom read routines Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 139 ++++++++++++++-------------------- drivers/media/usb/dvb-usb-v2/af9035.h | 27 ++++--- 2 files changed, 73 insertions(+), 93 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 3f00f0bee0ce..44a1196c7f3f 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -362,7 +362,7 @@ static int af9035_download_firmware_af9035(struct dvb_usb_device *d, * which is done by master demod. * Master feeds also clock and controls power via GPIO. */ - ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp); + ret = af9035_rd_reg(d, EEPROM_BASE_AF9035 + EEPROM_DUAL_MODE, &tmp); if (ret < 0) goto err; @@ -387,7 +387,9 @@ static int af9035_download_firmware_af9035(struct dvb_usb_device *d, goto err; /* tell the slave I2C address */ - ret = af9035_rd_reg(d, EEPROM_2ND_DEMOD_ADDR, &tmp); + ret = af9035_rd_reg(d, + EEPROM_BASE_AF9035 + EEPROM_2ND_DEMOD_ADDR, + &tmp); if (ret < 0) goto err; @@ -580,19 +582,39 @@ static int af9035_download_firmware(struct dvb_usb_device *d, return af9035_download_firmware_af9035(d, fw); } -static int af9035_read_config_af9035(struct dvb_usb_device *d) +static int af9035_read_config(struct dvb_usb_device *d) { struct state *state = d_to_priv(d); - int ret, i, eeprom_shift = 0; + int ret, i; u8 tmp; - u16 tmp16; + u16 tmp16, addr; /* demod I2C "address" */ state->af9033_config[0].i2c_addr = 0x38; state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X; + /* eeprom memory mapped location */ + if (state->chip_type == 0x9135) { + /* check if eeprom exists */ + if (state->chip_version == 2) + ret = af9035_rd_reg(d, 0x00461d, &tmp); + else + ret = af9035_rd_reg(d, 0x00461b, &tmp); + if (ret < 0) + goto err; + + if (tmp) { + addr = EEPROM_BASE_IT9135; + } else { + state->af9033_config[0].tuner = AF9033_TUNER_IT9135_38; + goto skip_eeprom; + } + } else { + addr = EEPROM_BASE_AF9035; + } + /* check if there is dual tuners */ - ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp); + ret = af9035_rd_reg(d, addr + EEPROM_DUAL_MODE, &tmp); if (ret < 0) goto err; @@ -602,7 +624,7 @@ static int af9035_read_config_af9035(struct dvb_usb_device *d) if (state->dual_mode) { /* read 2nd demodulator I2C address */ - ret = af9035_rd_reg(d, EEPROM_2ND_DEMOD_ADDR, &tmp); + ret = af9035_rd_reg(d, addr + EEPROM_2ND_DEMOD_ADDR, &tmp); if (ret < 0) goto err; @@ -613,7 +635,7 @@ static int af9035_read_config_af9035(struct dvb_usb_device *d) for (i = 0; i < state->dual_mode + 1; i++) { /* tuner */ - ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp); + ret = af9035_rd_reg(d, addr + EEPROM_1_TUNER_ID, &tmp); if (ret < 0) goto err; @@ -621,7 +643,10 @@ static int af9035_read_config_af9035(struct dvb_usb_device *d) dev_dbg(&d->udev->dev, "%s: [%d]tuner=%02x\n", __func__, i, tmp); - switch (tmp) { + if (state->chip_type == 0x9135 && tmp == 0x00) + state->af9033_config[i].tuner = AF9033_TUNER_IT9135_38; + + switch (state->af9033_config[i].tuner) { case AF9033_TUNER_TUA9001: case AF9033_TUNER_FC0011: case AF9033_TUNER_MXL5007T: @@ -630,9 +655,16 @@ static int af9035_read_config_af9035(struct dvb_usb_device *d) case AF9033_TUNER_FC0012: state->af9033_config[i].spec_inv = 1; break; + case AF9033_TUNER_IT9135_38: + case AF9033_TUNER_IT9135_51: + case AF9033_TUNER_IT9135_52: + case AF9033_TUNER_IT9135_60: + case AF9033_TUNER_IT9135_61: + case AF9033_TUNER_IT9135_62: + break; default: - dev_warn(&d->udev->dev, "%s: tuner id=%02x not " \ - "supported, please report!", + dev_warn(&d->udev->dev, + "%s: tuner id=%02x not supported, please report!", KBUILD_MODNAME, tmp); } @@ -643,19 +675,19 @@ static int af9035_read_config_af9035(struct dvb_usb_device *d) break; default: state->dual_mode = false; - dev_info(&d->udev->dev, "%s: driver does not " \ - "support 2nd tuner and will " \ - "disable it", KBUILD_MODNAME); + dev_info(&d->udev->dev, + "%s: driver does not support 2nd tuner and will disable it", + KBUILD_MODNAME); } /* tuner IF frequency */ - ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp); + ret = af9035_rd_reg(d, addr + EEPROM_1_IF_L, &tmp); if (ret < 0) goto err; tmp16 = tmp; - ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp); + ret = af9035_rd_reg(d, addr + EEPROM_1_IF_H, &tmp); if (ret < 0) goto err; @@ -663,9 +695,10 @@ static int af9035_read_config_af9035(struct dvb_usb_device *d) dev_dbg(&d->udev->dev, "%s: [%d]IF=%d\n", __func__, i, tmp16); - eeprom_shift = 0x10; /* shift for the 2nd tuner params */ + addr += 0x10; /* shift for the 2nd tuner params */ } +skip_eeprom: /* get demod clock */ ret = af9035_rd_reg(d, 0x00d800, &tmp); if (ret < 0) @@ -673,60 +706,13 @@ static int af9035_read_config_af9035(struct dvb_usb_device *d) tmp = (tmp >> 0) & 0x0f; - for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) - state->af9033_config[i].clock = clock_lut[tmp]; - - return 0; - -err: - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9035_read_config_it9135(struct dvb_usb_device *d) -{ - struct state *state = d_to_priv(d); - int ret, i; - u8 tmp; - - /* demod I2C "address" */ - state->af9033_config[0].i2c_addr = 0x38; - state->af9033_config[0].tuner = AF9033_TUNER_IT9135_38; - state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X; - state->dual_mode = false; - - /* check if eeprom exists */ - if (state->chip_version == 2) - ret = af9035_rd_reg(d, 0x00461d, &tmp); - else - ret = af9035_rd_reg(d, 0x00461b, &tmp); - if (ret < 0) - goto err; - - if (tmp) { - /* tuner */ - ret = af9035_rd_reg(d, 0x0049d0, &tmp); - if (ret < 0) - goto err; - - dev_dbg(&d->udev->dev, "%s: [%d]tuner=%02x\n", - __func__, 0, tmp); - - if (tmp) - state->af9033_config[0].tuner = tmp; + for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) { + if (state->chip_type == 0x9135) + state->af9033_config[i].clock = clock_lut_it9135[tmp]; + else + state->af9033_config[i].clock = clock_lut_af9035[tmp]; } - /* get demod clock */ - ret = af9035_rd_reg(d, 0x00d800, &tmp); - if (ret < 0) - goto err; - - tmp = (tmp >> 0) & 0x0f; - - for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++) - state->af9033_config[i].clock = clock_lut_it9135[tmp]; - return 0; err: @@ -735,16 +721,6 @@ err: return ret; } -static int af9035_read_config(struct dvb_usb_device *d) -{ - struct state *state = d_to_priv(d); - - if (state->chip_type == 0x9135) - return af9035_read_config_it9135(d); - else - return af9035_read_config_af9035(d); -} - static int af9035_tua9001_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) { @@ -1290,7 +1266,7 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) if (state->chip_type == 0x9135) return 0; - ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp); + ret = af9035_rd_reg(d, EEPROM_BASE_AF9035 + EEPROM_IR_MODE, &tmp); if (ret < 0) goto err; @@ -1298,7 +1274,8 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) /* don't activate rc if in HID mode or if not available */ if (tmp == 5) { - ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp); + ret = af9035_rd_reg(d, EEPROM_BASE_AF9035 + EEPROM_IR_TYPE, + &tmp); if (ret < 0) goto err; diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index f126eeabf0ba..7e49e1ad2814 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -63,7 +63,7 @@ struct state { struct af9033_config af9033_config[2]; }; -static const u32 clock_lut[] = { +static const u32 clock_lut_af9035[] = { 20480000, /* FPGA */ 16384000, /* 16.38 MHz */ 20480000, /* 20.48 MHz */ @@ -95,17 +95,20 @@ static const u32 clock_lut_it9135[] = { #define AF9035_FIRMWARE_IT9135_V1 "dvb-usb-it9135-01.fw" #define AF9035_FIRMWARE_IT9135_V2 "dvb-usb-it9135-02.fw" -/* EEPROM locations */ -#define EEPROM_IR_MODE 0x430d -#define EEPROM_DUAL_MODE 0x4326 -#define EEPROM_2ND_DEMOD_ADDR 0x4327 -#define EEPROM_IR_TYPE 0x4329 -#define EEPROM_1_IFFREQ_L 0x432d -#define EEPROM_1_IFFREQ_H 0x432e -#define EEPROM_1_TUNER_ID 0x4331 -#define EEPROM_2_IFFREQ_L 0x433d -#define EEPROM_2_IFFREQ_H 0x433e -#define EEPROM_2_TUNER_ID 0x4341 +#define EEPROM_BASE_AF9035 0x42fd +#define EEPROM_BASE_IT9135 0x499c +#define EEPROM_SHIFT 0x10 + +#define EEPROM_IR_MODE 0x10 +#define EEPROM_DUAL_MODE 0x29 +#define EEPROM_2ND_DEMOD_ADDR 0x2a +#define EEPROM_IR_TYPE 0x2c +#define EEPROM_1_IF_L 0x30 +#define EEPROM_1_IF_H 0x31 +#define EEPROM_1_TUNER_ID 0x34 +#define EEPROM_2_IF_L 0x40 +#define EEPROM_2_IF_H 0x41 +#define EEPROM_2_TUNER_ID 0x44 /* USB commands */ #define CMD_MEM_RD 0x00 -- cgit v1.2.3 From bc3c9e10fcf1bf344a5d6d7e83c429a7c2e730c5 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 1 Feb 2013 22:23:07 -0300 Subject: [media] af9035: basic support for IT9135 v2 chips Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 43 ++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 13 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 44a1196c7f3f..f4f3a2109245 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -316,7 +316,7 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name) state->chip_type); if (state->chip_type == 0x9135) { - if (state->chip_version == 2) + if (state->chip_version == 0x02) *name = AF9035_FIRMWARE_IT9135_V2; else *name = AF9035_FIRMWARE_IT9135_V1; @@ -595,18 +595,23 @@ static int af9035_read_config(struct dvb_usb_device *d) /* eeprom memory mapped location */ if (state->chip_type == 0x9135) { + if (state->chip_version == 0x02) { + state->af9033_config[0].tuner = AF9033_TUNER_IT9135_60; + tmp16 = 0x00461d; + } else { + state->af9033_config[0].tuner = AF9033_TUNER_IT9135_38; + tmp16 = 0x00461b; + } + /* check if eeprom exists */ - if (state->chip_version == 2) - ret = af9035_rd_reg(d, 0x00461d, &tmp); - else - ret = af9035_rd_reg(d, 0x00461b, &tmp); + ret = af9035_rd_reg(d, tmp16, &tmp); if (ret < 0) goto err; if (tmp) { addr = EEPROM_BASE_IT9135; } else { - state->af9033_config[0].tuner = AF9033_TUNER_IT9135_38; + dev_dbg(&d->udev->dev, "%s: no eeprom\n", __func__); goto skip_eeprom; } } else { @@ -639,12 +644,15 @@ static int af9035_read_config(struct dvb_usb_device *d) if (ret < 0) goto err; - state->af9033_config[i].tuner = tmp; - dev_dbg(&d->udev->dev, "%s: [%d]tuner=%02x\n", - __func__, i, tmp); + if (tmp == 0x00) + dev_dbg(&d->udev->dev, + "%s: [%d]tuner not set, using default\n", + __func__, i); + else + state->af9033_config[i].tuner = tmp; - if (state->chip_type == 0x9135 && tmp == 0x00) - state->af9033_config[i].tuner = AF9033_TUNER_IT9135_38; + dev_dbg(&d->udev->dev, "%s: [%d]tuner=%02x\n", + __func__, i, state->af9033_config[i].tuner); switch (state->af9033_config[i].tuner) { case AF9033_TUNER_TUA9001: @@ -975,12 +983,12 @@ static const struct fc0012_config af9035_fc0012_config[] = { }; static struct ite_config af9035_it913x_config = { - .chip_ver = 0x01, + .chip_ver = 0x02, .chip_type = 0x9135, .firmware = 0x00000000, .firmware_ver = 1, .adc_x2 = 1, - .tuner_id_0 = AF9033_TUNER_IT9135_38, + .tuner_id_0 = 0x00, .tuner_id_1 = 0x00, .dual_mode = 0x00, .adf = 0x00, @@ -1153,6 +1161,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) case AF9033_TUNER_IT9135_38: case AF9033_TUNER_IT9135_51: case AF9033_TUNER_IT9135_52: + af9035_it913x_config.chip_ver = 0x01; case AF9033_TUNER_IT9135_60: case AF9033_TUNER_IT9135_61: case AF9033_TUNER_IT9135_62: @@ -1453,6 +1462,7 @@ static const struct dvb_usb_device_properties af9035_props = { }; static const struct usb_device_id af9035_id_table[] = { + /* AF9035 devices */ { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035, &af9035_props, "Afatech AF9035 reference design", NULL) }, { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000, @@ -1479,6 +1489,13 @@ static const struct usb_device_id af9035_id_table[] = { &af9035_props, "Asus U3100Mini Plus", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00aa, &af9035_props, "TerraTec Cinergy T Stick (rev. 2)", NULL) }, + /* IT9135 devices */ +#if 0 + { DVB_USB_DEVICE(0x048d, 0x9135, + &af9035_props, "IT9135 reference design", NULL) }, + { DVB_USB_DEVICE(0x048d, 0x9006, + &af9035_props, "IT9135 reference design", NULL) }, +#endif /* XXX: that same ID [0ccd:0099] is used by af9015 driver too */ { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099, &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)", NULL) }, -- cgit v1.2.3 From fe8eece1fdc7dd965ae2da5743730a261f022832 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 3 Feb 2013 13:39:55 -0300 Subject: [media] af9033: IT9135 v2 supported related changes Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index dece775836ac..f51022817fed 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -285,10 +285,29 @@ static int af9033_init(struct dvb_frontend *fe) goto err; } + /* + * FIXME: These inits are logically property of demodulator driver + * (that driver), but currently in case of IT9135 those are done by + * tuner driver. + */ + /* load OFSM settings */ dev_dbg(&state->i2c->dev, "%s: load ofsm settings\n", __func__); - len = ARRAY_SIZE(ofsm_init); - init = ofsm_init; + switch (state->cfg.tuner) { + case AF9033_TUNER_IT9135_38: + case AF9033_TUNER_IT9135_51: + case AF9033_TUNER_IT9135_52: + case AF9033_TUNER_IT9135_60: + case AF9033_TUNER_IT9135_61: + case AF9033_TUNER_IT9135_62: + len = 0; + break; + default: + len = ARRAY_SIZE(ofsm_init); + init = ofsm_init; + break; + } + for (i = 0; i < len; i++) { ret = af9033_wr_reg(state, init[i].reg, init[i].val); if (ret < 0) @@ -424,7 +443,8 @@ err: static int af9033_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *fesettings) { - fesettings->min_delay_ms = 800; + /* 800 => 2000 because IT9135 v2 is slow to gain lock */ + fesettings->min_delay_ms = 2000; fesettings->step_size = 0; fesettings->max_drift = 0; @@ -513,6 +533,11 @@ static int af9033_set_frontend(struct dvb_frontend *fe) buf[0] = (freq_cw >> 0) & 0xff; buf[1] = (freq_cw >> 8) & 0xff; buf[2] = (freq_cw >> 16) & 0x7f; + + /* FIXME: there seems to be calculation error here... */ + if (if_frequency == 0) + buf[2] = 0; + ret = af9033_wr_regs(state, 0x800029, buf, 3); if (ret < 0) goto err; -- cgit v1.2.3 From df8f1be14fa68f99b426c7c413a60fb368b8c522 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 3 Feb 2013 13:46:56 -0300 Subject: [media] af9035: IT9135 dual tuner related changes Now it supports IT9135 based dual tuner devices. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 201 +++++++++++++++++----------------- drivers/media/usb/dvb-usb-v2/af9035.h | 3 +- 2 files changed, 102 insertions(+), 102 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index f4f3a2109245..5c025f657144 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -320,8 +320,10 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name) *name = AF9035_FIRMWARE_IT9135_V2; else *name = AF9035_FIRMWARE_IT9135_V1; + state->eeprom_addr = EEPROM_BASE_IT9135; } else { *name = AF9035_FIRMWARE_AF9035; + state->eeprom_addr = EEPROM_BASE_AF9035; } ret = af9035_ctrl_msg(d, &req); @@ -347,62 +349,13 @@ static int af9035_download_firmware_af9035(struct dvb_usb_device *d, { int ret, i, j, len; u8 wbuf[1]; - u8 rbuf[4]; struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL }; - struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; - u8 hdr_core, tmp; + u8 hdr_core; u16 hdr_addr, hdr_data_len, hdr_checksum; #define MAX_DATA 58 #define HDR_SIZE 7 - /* - * In case of dual tuner configuration we need to do some extra - * initialization in order to download firmware to slave demod too, - * which is done by master demod. - * Master feeds also clock and controls power via GPIO. - */ - ret = af9035_rd_reg(d, EEPROM_BASE_AF9035 + EEPROM_DUAL_MODE, &tmp); - if (ret < 0) - goto err; - - if (tmp) { - /* configure gpioh1, reset & power slave demod */ - ret = af9035_wr_reg_mask(d, 0x00d8b0, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0x00d8b1, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0x00d8af, 0x00, 0x01); - if (ret < 0) - goto err; - - usleep_range(10000, 50000); - - ret = af9035_wr_reg_mask(d, 0x00d8af, 0x01, 0x01); - if (ret < 0) - goto err; - - /* tell the slave I2C address */ - ret = af9035_rd_reg(d, - EEPROM_BASE_AF9035 + EEPROM_2ND_DEMOD_ADDR, - &tmp); - if (ret < 0) - goto err; - - ret = af9035_wr_reg(d, 0x00417f, tmp); - if (ret < 0) - goto err; - - /* enable clock out */ - ret = af9035_wr_reg_mask(d, 0x00d81a, 0x01, 0x01); - if (ret < 0) - goto err; - } - /* * Thanks to Daniel Glöckner about that info! * @@ -469,28 +422,6 @@ static int af9035_download_firmware_af9035(struct dvb_usb_device *d, if (i) dev_warn(&d->udev->dev, "%s: bad firmware\n", KBUILD_MODNAME); - /* firmware loaded, request boot */ - req.cmd = CMD_FW_BOOT; - ret = af9035_ctrl_msg(d, &req); - if (ret < 0) - goto err; - - /* ensure firmware starts */ - wbuf[0] = 1; - ret = af9035_ctrl_msg(d, &req_fw_ver); - if (ret < 0) - goto err; - - if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) { - dev_err(&d->udev->dev, "%s: firmware did not run\n", - KBUILD_MODNAME); - ret = -ENODEV; - goto err; - } - - dev_info(&d->udev->dev, "%s: firmware version=%d.%d.%d.%d", - KBUILD_MODNAME, rbuf[0], rbuf[1], rbuf[2], rbuf[3]); - return 0; err: @@ -503,11 +434,7 @@ static int af9035_download_firmware_it9135(struct dvb_usb_device *d, const struct firmware *fw) { int ret, i, i_prev; - u8 wbuf[1]; - u8 rbuf[4]; - struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL }; - struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; #define HDR_SIZE 7 /* @@ -522,7 +449,6 @@ static int af9035_download_firmware_it9135(struct dvb_usb_device *d, * 5: addr LSB * 6: count of data bytes ? */ - for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) { if (i == fw->size || (fw->data[i + 0] == 0x03 && @@ -541,6 +467,86 @@ static int af9035_download_firmware_it9135(struct dvb_usb_device *d, } } + return 0; + +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9035_download_firmware(struct dvb_usb_device *d, + const struct firmware *fw) +{ + struct state *state = d_to_priv(d); + int ret; + u8 wbuf[1]; + u8 rbuf[4]; + u8 tmp; + struct usb_req req = { 0, 0, 0, NULL, 0, NULL }; + struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + + /* + * In case of dual tuner configuration we need to do some extra + * initialization in order to download firmware to slave demod too, + * which is done by master demod. + * Master feeds also clock and controls power via GPIO. + */ + ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_DUAL_MODE, &tmp); + if (ret < 0) + goto err; + + if (tmp) { + /* configure gpioh1, reset & power slave demod */ + ret = af9035_wr_reg_mask(d, 0x00d8b0, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0x00d8b1, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0x00d8af, 0x00, 0x01); + if (ret < 0) + goto err; + + usleep_range(10000, 50000); + + ret = af9035_wr_reg_mask(d, 0x00d8af, 0x01, 0x01); + if (ret < 0) + goto err; + + /* tell the slave I2C address */ + ret = af9035_rd_reg(d, + state->eeprom_addr + EEPROM_2ND_DEMOD_ADDR, + &tmp); + if (ret < 0) + goto err; + + if (state->chip_type == 0x9135) { + ret = af9035_wr_reg(d, 0x004bfb, tmp); + if (ret < 0) + goto err; + } else { + ret = af9035_wr_reg(d, 0x00417f, tmp); + if (ret < 0) + goto err; + + /* enable clock out */ + ret = af9035_wr_reg_mask(d, 0x00d81a, 0x01, 0x01); + if (ret < 0) + goto err; + } + } + + if (state->chip_type == 0x9135) + ret = af9035_download_firmware_it9135(d, fw); + else + ret = af9035_download_firmware_af9035(d, fw); + if (ret < 0) + goto err; + /* firmware loaded, request boot */ req.cmd = CMD_FW_BOOT; ret = af9035_ctrl_msg(d, &req); @@ -571,17 +577,6 @@ err: return ret; } -static int af9035_download_firmware(struct dvb_usb_device *d, - const struct firmware *fw) -{ - struct state *state = d_to_priv(d); - - if (state->chip_type == 0x9135) - return af9035_download_firmware_it9135(d, fw); - else - return af9035_download_firmware_af9035(d, fw); -} - static int af9035_read_config(struct dvb_usb_device *d) { struct state *state = d_to_priv(d); @@ -592,14 +587,17 @@ static int af9035_read_config(struct dvb_usb_device *d) /* demod I2C "address" */ state->af9033_config[0].i2c_addr = 0x38; state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X; + state->af9033_config[1].adc_multiplier = AF9033_ADC_MULTIPLIER_2X; /* eeprom memory mapped location */ if (state->chip_type == 0x9135) { if (state->chip_version == 0x02) { state->af9033_config[0].tuner = AF9033_TUNER_IT9135_60; + state->af9033_config[1].tuner = AF9033_TUNER_IT9135_60; tmp16 = 0x00461d; } else { state->af9033_config[0].tuner = AF9033_TUNER_IT9135_38; + state->af9033_config[1].tuner = AF9033_TUNER_IT9135_38; tmp16 = 0x00461b; } @@ -678,8 +676,14 @@ static int af9035_read_config(struct dvb_usb_device *d) /* disable dual mode if driver does not support it */ if (i == 1) - switch (tmp) { + switch (state->af9033_config[i].tuner) { case AF9033_TUNER_FC0012: + case AF9033_TUNER_IT9135_38: + case AF9033_TUNER_IT9135_51: + case AF9033_TUNER_IT9135_52: + case AF9033_TUNER_IT9135_60: + case AF9033_TUNER_IT9135_61: + case AF9033_TUNER_IT9135_62: break; default: state->dual_mode = false; @@ -891,6 +895,7 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap) struct state *state = adap_to_priv(adap); struct dvb_usb_device *d = adap_to_d(adap); int ret; + dev_dbg(&d->udev->dev, "%s:\n", __func__); if (!state->af9033_config[adap->id].tuner) { /* unsupported tuner */ @@ -901,15 +906,6 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap) if (adap->id == 0) { state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB; state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL; - - ret = af9035_wr_reg(d, 0x00417f, - state->af9033_config[1].i2c_addr); - if (ret < 0) - goto err; - - ret = af9035_wr_reg(d, 0x00d81a, state->dual_mode); - if (ret < 0) - goto err; } /* attach demodulator */ @@ -1004,6 +1000,8 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) struct dvb_frontend *fe; struct i2c_msg msg[1]; u8 tuner_addr; + dev_dbg(&d->udev->dev, "%s:\n", __func__); + /* * XXX: Hack used in that function: we abuse unused I2C address bit [7] * to carry info about used I2C bus for dual tuner configuration. @@ -1165,10 +1163,11 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) case AF9033_TUNER_IT9135_60: case AF9033_TUNER_IT9135_61: case AF9033_TUNER_IT9135_62: - /* attach tuner */ af9035_it913x_config.tuner_id_0 = state->af9033_config[0].tuner; - fe = dvb_attach(it913x_attach, adap->fe[0], - &d->i2c_adap, 0x38, &af9035_it913x_config); + /* attach tuner */ + fe = dvb_attach(it913x_attach, adap->fe[0], &d->i2c_adap, + state->af9033_config[adap->id].i2c_addr, + &af9035_it913x_config); break; default: fe = NULL; diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index 7e49e1ad2814..2f7d269c7d60 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -56,10 +56,11 @@ struct state { #define BUF_LEN 64 u8 buf[BUF_LEN]; u8 seq; /* packet sequence number */ - bool dual_mode; u8 prechip_version; u8 chip_version; u16 chip_type; + bool dual_mode; + u16 eeprom_addr; struct af9033_config af9033_config[2]; }; -- cgit v1.2.3 From ebb0662cee9e6d8f7110c1217a7bd14315fdd148 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Feb 2013 20:34:06 -0300 Subject: [media] it913x: merge it913x_fe_start() to it913x_init_tuner() Merge those functions to one and disable sleep. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 165 ++++++++++++------------------------------ 1 file changed, 45 insertions(+), 120 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 6ee4f97f586e..f1938a13eace 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -43,7 +43,6 @@ struct it913x_fe_state { u32 ucblocks; }; - static int it913x_read_reg(struct it913x_fe_state *state, u32 reg, u8 *data, u8 count) { @@ -147,10 +146,54 @@ static int it913x_init_tuner(struct dvb_frontend *fe) { struct it913x_fe_state *state = fe->tuner_priv; int ret, i, reg; + struct it913xset *set_lna; u8 val, nv_val; u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; u8 b[2]; + /* v1 or v2 tuner script */ + if (state->config->chip_ver > 1) + ret = it913x_fe_script_loader(state, it9135_v2); + else + ret = it913x_fe_script_loader(state, it9135_v1); + if (ret < 0) + return ret; + + /* LNA Scripts */ + switch (state->tuner_type) { + case IT9135_51: + set_lna = it9135_51; + break; + case IT9135_52: + set_lna = it9135_52; + break; + case IT9135_60: + set_lna = it9135_60; + break; + case IT9135_61: + set_lna = it9135_61; + break; + case IT9135_62: + set_lna = it9135_62; + break; + case IT9135_38: + default: + set_lna = it9135_38; + } + pr_info("Tuner LNA type :%02x\n", state->tuner_type); + + ret = it913x_fe_script_loader(state, set_lna); + if (ret < 0) + return ret; + + if (state->config->chip_ver == 2) { + ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1); + ret |= it913x_write_reg(state, PRO_LINK, PADODPU, 0x0); + ret |= it913x_write_reg(state, PRO_LINK, AGC_O_D, 0x0); + } + if (ret < 0) + return -ENODEV; + reg = it913x_read_reg_u8(state, 0xec86); switch (reg) { case 0: @@ -361,6 +404,7 @@ static int it9137_set_tuner(struct dvb_frontend *fe) static int it913x_fe_suspend(struct it913x_fe_state *state) { int ret = 0; + return 0; #if 0 int ret, i; u8 b; @@ -397,121 +441,6 @@ static int it913x_fe_sleep(struct dvb_frontend *fe) return it913x_fe_suspend(state); } -static int it913x_fe_start(struct dvb_frontend *fe) -{ - struct it913x_fe_state *state = fe->tuner_priv; - struct it913xset *set_lna; -// struct it913xset *set_mode; - int ret; -// u8 adf = (state->config->adf & 0xf); -// u32 adc, xtal; -// u8 b[4]; - - if (state->config->chip_ver == 1) - ret = it913x_init_tuner(fe); - -#if 0 - pr_info("ADF table value :%02x\n", adf); - - if (adf < 10) { - state->crystalFrequency = fe_clockTable[adf].xtal ; - state->table = fe_clockTable[adf].table; - state->adcFrequency = state->table->adcFrequency; - - adc = compute_div(state->adcFrequency, 1000000ul, 19ul); - xtal = compute_div(state->crystalFrequency, 1000000ul, 19ul); - - } else - return -EINVAL; - - /* Set LED indicator on GPIOH3 */ - ret = it913x_write_reg(state, PRO_LINK, GPIOH3_EN, 0x1); - ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_ON, 0x1); - ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1); - - ret |= it913x_write_reg(state, PRO_LINK, 0xf641, state->tuner_type); - ret |= it913x_write_reg(state, PRO_DMOD, 0xf5ca, 0x01); - ret |= it913x_write_reg(state, PRO_DMOD, 0xf715, 0x01); - - b[0] = xtal & 0xff; - b[1] = (xtal >> 8) & 0xff; - b[2] = (xtal >> 16) & 0xff; - b[3] = (xtal >> 24); - ret |= it913x_write(state, PRO_DMOD, XTAL_CLK, b , 4); - - b[0] = adc & 0xff; - b[1] = (adc >> 8) & 0xff; - b[2] = (adc >> 16) & 0xff; - ret |= it913x_write(state, PRO_DMOD, ADC_FREQ, b, 3); - - if (state->config->adc_x2) - ret |= it913x_write_reg(state, PRO_DMOD, ADC_X_2, 0x01); - b[0] = 0; - b[1] = 0; - b[2] = 0; - ret |= it913x_write(state, PRO_DMOD, 0x0029, b, 3); - - pr_info("Crystal Frequency :%d Adc Frequency :%d ADC X2: %02x\n", - state->crystalFrequency, state->adcFrequency, - state->config->adc_x2); - pr_debug("Xtal value :%04x Adc value :%04x\n", xtal, adc); - - if (ret < 0) - return -ENODEV; -#endif - - /* v1 or v2 tuner script */ - if (state->config->chip_ver > 1) - ret = it913x_fe_script_loader(state, it9135_v2); - else - ret = it913x_fe_script_loader(state, it9135_v1); - if (ret < 0) - return ret; - - /* LNA Scripts */ - switch (state->tuner_type) { - case IT9135_51: - set_lna = it9135_51; - break; - case IT9135_52: - set_lna = it9135_52; - break; - case IT9135_60: - set_lna = it9135_60; - break; - case IT9135_61: - set_lna = it9135_61; - break; - case IT9135_62: - set_lna = it9135_62; - break; - case IT9135_38: - default: - set_lna = it9135_38; - } - pr_info("Tuner LNA type :%02x\n", state->tuner_type); - - ret = it913x_fe_script_loader(state, set_lna); - if (ret < 0) - return ret; - - if (state->config->chip_ver == 2) { - ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1); - ret |= it913x_write_reg(state, PRO_LINK, PADODPU, 0x0); - ret |= it913x_write_reg(state, PRO_LINK, AGC_O_D, 0x0); - ret |= it913x_init_tuner(fe); - } - if (ret < 0) - return -ENODEV; - - /* Always solo frontend */ -// set_mode = set_solo_fe; -// ret |= it913x_fe_script_loader(state, set_mode); - - ret |= it913x_fe_suspend(state); - return (ret < 0) ? -ENODEV : 0; -} - static int it913x_release(struct dvb_frontend *fe) { kfree(fe->tuner_priv); @@ -566,10 +495,6 @@ struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops, sizeof(struct dvb_tuner_ops)); - ret = it913x_fe_start(fe); - if (ret < 0) - goto error; - pr_info("%s: ITE Tech IT913X attached\n", KBUILD_MODNAME); return fe; -- cgit v1.2.3 From 8c1285a28084b5fa07a7842dd72a561f5c3b913e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Feb 2013 20:42:21 -0300 Subject: [media] it913x: merge it913x_fe_suspend() to it913x_fe_sleep() Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index f1938a13eace..6eb3afa32db6 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -401,36 +401,6 @@ static int it9137_set_tuner(struct dvb_frontend *fe) return (ret < 0) ? -ENODEV : 0; } -static int it913x_fe_suspend(struct it913x_fe_state *state) -{ - int ret = 0; - return 0; -#if 0 - int ret, i; - u8 b; - - ret = it913x_write_reg(state, PRO_DMOD, SUSPEND_FLAG, 0x1); - - ret |= it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0); - - for (i = 0; i < 128; i++) { - ret = it913x_read_reg(state, SUSPEND_FLAG, &b, 1); - if (ret < 0) - return -ENODEV; - if (b == 0) - break; - - } - - ret |= it913x_write_reg(state, PRO_DMOD, AFE_MEM0, 0x8); - /* Turn LED off */ - ret |= it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0); -#endif - ret |= it913x_fe_script_loader(state, it9137_tuner_off); - - return (ret < 0) ? -ENODEV : 0; -} - /* Power sequence */ /* Power Up Tuner on -> Frontend suspend off -> Tuner clk on */ /* Power Down Frontend suspend on -> Tuner clk off -> Tuner off */ @@ -438,7 +408,7 @@ static int it913x_fe_suspend(struct it913x_fe_state *state) static int it913x_fe_sleep(struct dvb_frontend *fe) { struct it913x_fe_state *state = fe->tuner_priv; - return it913x_fe_suspend(state); + return it913x_fe_script_loader(state, it9137_tuner_off); } static int it913x_release(struct dvb_frontend *fe) -- cgit v1.2.3 From 42432b3ce89eaf817284f0c6ff81dfd7b4ed35b3 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 26 Feb 2013 20:57:01 -0300 Subject: [media] it913x: rename functions and variables Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 72 +++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 34 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 6eb3afa32db6..82cc053bc998 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -22,7 +22,7 @@ #include "it913x_priv.h" -struct it913x_fe_state { +struct it913x_state { struct dvb_frontend frontend; struct i2c_adapter *i2c_adap; struct ite_config *config; @@ -43,7 +43,8 @@ struct it913x_fe_state { u32 ucblocks; }; -static int it913x_read_reg(struct it913x_fe_state *state, +/* read multiple registers */ +static int it913x_rd_regs(struct it913x_state *state, u32 reg, u8 *data, u8 count) { int ret; @@ -64,15 +65,17 @@ static int it913x_read_reg(struct it913x_fe_state *state, return ret; } -static int it913x_read_reg_u8(struct it913x_fe_state *state, u32 reg) +/* read single register */ +static int it913x_rd_reg(struct it913x_state *state, u32 reg) { int ret; u8 b[1]; - ret = it913x_read_reg(state, reg, &b[0], sizeof(b)); + ret = it913x_rd_regs(state, reg, &b[0], sizeof(b)); return (ret < 0) ? -ENODEV : b[0]; } -static int it913x_write(struct it913x_fe_state *state, +/* write multiple registers */ +static int it913x_wr_regs(struct it913x_state *state, u8 pro, u32 reg, u8 buf[], u8 count) { u8 b[256]; @@ -97,7 +100,8 @@ static int it913x_write(struct it913x_fe_state *state, return 0; } -static int it913x_write_reg(struct it913x_fe_state *state, +/* write single register */ +static int it913x_wr_reg(struct it913x_state *state, u8 pro, u32 reg, u32 data) { int ret; @@ -118,12 +122,12 @@ static int it913x_write_reg(struct it913x_fe_state *state, else s = 0; - ret = it913x_write(state, pro, reg, &b[s], sizeof(b) - s); + ret = it913x_wr_regs(state, pro, reg, &b[s], sizeof(b) - s); return ret; } -static int it913x_fe_script_loader(struct it913x_fe_state *state, +static int it913x_script_loader(struct it913x_state *state, struct it913xset *loadscript) { int ret, i; @@ -133,7 +137,7 @@ static int it913x_fe_script_loader(struct it913x_fe_state *state, for (i = 0; i < 1000; ++i) { if (loadscript[i].pro == 0xff) break; - ret = it913x_write(state, loadscript[i].pro, + ret = it913x_wr_regs(state, loadscript[i].pro, loadscript[i].address, loadscript[i].reg, loadscript[i].count); if (ret < 0) @@ -142,9 +146,9 @@ static int it913x_fe_script_loader(struct it913x_fe_state *state, return 0; } -static int it913x_init_tuner(struct dvb_frontend *fe) +static int it913x_init(struct dvb_frontend *fe) { - struct it913x_fe_state *state = fe->tuner_priv; + struct it913x_state *state = fe->tuner_priv; int ret, i, reg; struct it913xset *set_lna; u8 val, nv_val; @@ -153,9 +157,9 @@ static int it913x_init_tuner(struct dvb_frontend *fe) /* v1 or v2 tuner script */ if (state->config->chip_ver > 1) - ret = it913x_fe_script_loader(state, it9135_v2); + ret = it913x_script_loader(state, it9135_v2); else - ret = it913x_fe_script_loader(state, it9135_v1); + ret = it913x_script_loader(state, it9135_v1); if (ret < 0) return ret; @@ -182,19 +186,19 @@ static int it913x_init_tuner(struct dvb_frontend *fe) } pr_info("Tuner LNA type :%02x\n", state->tuner_type); - ret = it913x_fe_script_loader(state, set_lna); + ret = it913x_script_loader(state, set_lna); if (ret < 0) return ret; if (state->config->chip_ver == 2) { - ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1); - ret |= it913x_write_reg(state, PRO_LINK, PADODPU, 0x0); - ret |= it913x_write_reg(state, PRO_LINK, AGC_O_D, 0x0); + ret = it913x_wr_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1); + ret |= it913x_wr_reg(state, PRO_LINK, PADODPU, 0x0); + ret |= it913x_wr_reg(state, PRO_LINK, AGC_O_D, 0x0); } if (ret < 0) return -ENODEV; - reg = it913x_read_reg_u8(state, 0xec86); + reg = it913x_rd_reg(state, 0xec86); switch (reg) { case 0: state->tun_clk_mode = reg; @@ -213,7 +217,7 @@ static int it913x_init_tuner(struct dvb_frontend *fe) break; } - reg = it913x_read_reg_u8(state, 0xed03); + reg = it913x_rd_reg(state, 0xed03); if (reg < 0) return -ENODEV; @@ -223,7 +227,7 @@ static int it913x_init_tuner(struct dvb_frontend *fe) nv_val = 2; for (i = 0; i < 50; i++) { - ret = it913x_read_reg(state, 0xed23, &b[0], sizeof(b)); + ret = it913x_rd_regs(state, 0xed23, &b[0], sizeof(b)); reg = (b[1] << 8) + b[0]; if (reg > 0) break; @@ -239,7 +243,7 @@ static int it913x_init_tuner(struct dvb_frontend *fe) msleep(50); else { for (i = 0; i < 50; i++) { - reg = it913x_read_reg_u8(state, 0xec82); + reg = it913x_rd_reg(state, 0xec82); if (reg > 0) break; if (reg < 0) @@ -248,12 +252,12 @@ static int it913x_init_tuner(struct dvb_frontend *fe) } } - return it913x_write_reg(state, PRO_DMOD, 0xed81, val); + return it913x_wr_reg(state, PRO_DMOD, 0xed81, val); } -static int it9137_set_tuner(struct dvb_frontend *fe) +static int it9137_set_params(struct dvb_frontend *fe) { - struct it913x_fe_state *state = fe->tuner_priv; + struct it913x_state *state = fe->tuner_priv; struct it913xset *set_tuner = set_it9137_template; struct dtv_frontend_properties *p = &fe->dtv_property_cache; u32 bandwidth = p->bandwidth_hz; @@ -358,7 +362,7 @@ static int it9137_set_tuner(struct dvb_frontend *fe) } else return -EINVAL; - reg = it913x_read_reg_u8(state, 0xed81); + reg = it913x_rd_reg(state, 0xed81); iqik_m_cal = (u16)reg * n_div; if (reg < 0x20) { @@ -396,7 +400,7 @@ static int it9137_set_tuner(struct dvb_frontend *fe) pr_debug("low Frequency = %04x\n", freq); - ret = it913x_fe_script_loader(state, set_tuner); + ret = it913x_script_loader(state, set_tuner); return (ret < 0) ? -ENODEV : 0; } @@ -405,10 +409,10 @@ static int it9137_set_tuner(struct dvb_frontend *fe) /* Power Up Tuner on -> Frontend suspend off -> Tuner clk on */ /* Power Down Frontend suspend on -> Tuner clk off -> Tuner off */ -static int it913x_fe_sleep(struct dvb_frontend *fe) +static int it913x_sleep(struct dvb_frontend *fe) { - struct it913x_fe_state *state = fe->tuner_priv; - return it913x_fe_script_loader(state, it9137_tuner_off); + struct it913x_state *state = fe->tuner_priv; + return it913x_script_loader(state, it9137_tuner_off); } static int it913x_release(struct dvb_frontend *fe) @@ -426,19 +430,19 @@ static const struct dvb_tuner_ops it913x_tuner_ops = { .release = it913x_release, - .init = it913x_init_tuner, - .sleep = it913x_fe_sleep, - .set_params = it9137_set_tuner, + .init = it913x_init, + .sleep = it913x_sleep, + .set_params = it9137_set_params, }; struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr, struct ite_config *config) { - struct it913x_fe_state *state = NULL; + struct it913x_state *state = NULL; int ret; /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct it913x_fe_state), GFP_KERNEL); + state = kzalloc(sizeof(struct it913x_state), GFP_KERNEL); if (state == NULL) return NULL; if (config == NULL) -- cgit v1.2.3 From d19812eb5f1efed3fa0ba5d752da5f24d8c89701 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 27 Feb 2013 23:29:02 -0300 Subject: [media] it913x: tuner power up routines Copy forgotten power up registers from it913x-fe driver. Remove two demod registers as those are already written by af9033 driver. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 82cc053bc998..de20da1548aa 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -192,11 +192,9 @@ static int it913x_init(struct dvb_frontend *fe) if (state->config->chip_ver == 2) { ret = it913x_wr_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1); - ret |= it913x_wr_reg(state, PRO_LINK, PADODPU, 0x0); - ret |= it913x_wr_reg(state, PRO_LINK, AGC_O_D, 0x0); + if (ret < 0) + return -ENODEV; } - if (ret < 0) - return -ENODEV; reg = it913x_rd_reg(state, 0xec86); switch (reg) { @@ -252,6 +250,12 @@ static int it913x_init(struct dvb_frontend *fe) } } + /* Power Up Tuner - common all versions */ + ret = it913x_wr_reg(state, PRO_DMOD, 0xec40, 0x1); + ret |= it913x_wr_reg(state, PRO_DMOD, 0xfba8, 0x0); + ret |= it913x_wr_reg(state, PRO_DMOD, 0xec57, 0x0); + ret |= it913x_wr_reg(state, PRO_DMOD, 0xec58, 0x0); + return it913x_wr_reg(state, PRO_DMOD, 0xed81, val); } -- cgit v1.2.3 From 44af747f4e0174d5dbc8c565a4d329dbcf599921 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 28 Feb 2013 00:14:06 -0300 Subject: [media] it913x: get rid of it913x config struct We don't need it. Tuner ID and device address are enough. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 38 +++++++++++++++++++++-------------- drivers/media/tuners/it913x.h | 22 ++++++-------------- drivers/media/usb/dvb-usb-v2/af9035.c | 18 +---------------- 3 files changed, 30 insertions(+), 48 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index de20da1548aa..66d4b72d97ab 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -25,7 +25,8 @@ struct it913x_state { struct dvb_frontend frontend; struct i2c_adapter *i2c_adap; - struct ite_config *config; + u8 chip_ver; + u8 firmware_ver; u8 i2c_addr; u32 frequency; fe_modulation_t constellation; @@ -156,7 +157,7 @@ static int it913x_init(struct dvb_frontend *fe) u8 b[2]; /* v1 or v2 tuner script */ - if (state->config->chip_ver > 1) + if (state->chip_ver > 1) ret = it913x_script_loader(state, it9135_v2); else ret = it913x_script_loader(state, it9135_v1); @@ -190,7 +191,7 @@ static int it913x_init(struct dvb_frontend *fe) if (ret < 0) return ret; - if (state->config->chip_ver == 2) { + if (state->chip_ver == 2) { ret = it913x_wr_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1); if (ret < 0) return -ENODEV; @@ -237,7 +238,7 @@ static int it913x_init(struct dvb_frontend *fe) state->tun_fn_min /= (state->tun_fdiv * nv_val); pr_debug("Tuner fn_min %d\n", state->tun_fn_min); - if (state->config->chip_ver > 1) + if (state->chip_ver > 1) msleep(50); else { for (i = 0; i < 50; i++) { @@ -276,7 +277,7 @@ static int it9137_set_params(struct dvb_frontend *fe) u8 lna_band; u8 bw; - if (state->config->firmware_ver == 1) + if (state->firmware_ver == 1) set_tuner = set_it9135_template; else set_tuner = set_it9137_template; @@ -440,40 +441,47 @@ static const struct dvb_tuner_ops it913x_tuner_ops = { }; struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, u8 i2c_addr, struct ite_config *config) + struct i2c_adapter *i2c_adap, u8 i2c_addr, u8 config) { struct it913x_state *state = NULL; - int ret; /* allocate memory for the internal state */ state = kzalloc(sizeof(struct it913x_state), GFP_KERNEL); if (state == NULL) return NULL; - if (config == NULL) - goto error; state->i2c_adap = i2c_adap; state->i2c_addr = i2c_addr; - state->config = config; - switch (state->config->tuner_id_0) { + switch (config) { + case IT9135_38: case IT9135_51: case IT9135_52: + state->chip_ver = 0x01; + break; case IT9135_60: case IT9135_61: case IT9135_62: - state->tuner_type = state->config->tuner_id_0; + state->chip_ver = 0x02; break; default: - case IT9135_38: - state->tuner_type = IT9135_38; + dev_dbg(&i2c_adap->dev, + "%s: invalid config=%02x\n", __func__, config); + goto error; } + state->tuner_type = config; + state->firmware_ver = 1; + fe->tuner_priv = state; memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops, sizeof(struct dvb_tuner_ops)); - pr_info("%s: ITE Tech IT913X attached\n", KBUILD_MODNAME); + dev_info(&i2c_adap->dev, + "%s: ITE Tech IT913X successfully attached\n", + KBUILD_MODNAME); + dev_dbg(&i2c_adap->dev, "%s: config=%02x chip_ver=%02x\n", + __func__, config, state->chip_ver); return fe; error: diff --git a/drivers/media/tuners/it913x.h b/drivers/media/tuners/it913x.h index 3583e56625f1..12dd36bd9e79 100644 --- a/drivers/media/tuners/it913x.h +++ b/drivers/media/tuners/it913x.h @@ -25,27 +25,17 @@ #include "dvb_frontend.h" -struct ite_config { - u8 chip_ver; - u16 chip_type; - u32 firmware; - u8 firmware_ver; - u8 adc_x2; - u8 tuner_id_0; - u8 tuner_id_1; - u8 dual_mode; - u8 adf; - /* option to read SIGNAL_LEVEL */ - u8 read_slevel; -}; - #if defined(CONFIG_MEDIA_TUNER_IT913X) || \ (defined(CONFIG_MEDIA_TUNER_IT913X_MODULE) && defined(MODULE)) extern struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, u8 i2c_addr, struct ite_config *config); + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + u8 config); #else static inline struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, u8 i2c_addr, struct ite_config *config) + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + u8 config) { pr_warn("%s: driver disabled by Kconfig\n", __func__); return NULL; diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 5c025f657144..ce8cccb8946a 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -978,20 +978,6 @@ static const struct fc0012_config af9035_fc0012_config[] = { } }; -static struct ite_config af9035_it913x_config = { - .chip_ver = 0x02, - .chip_type = 0x9135, - .firmware = 0x00000000, - .firmware_ver = 1, - .adc_x2 = 1, - .tuner_id_0 = 0x00, - .tuner_id_1 = 0x00, - .dual_mode = 0x00, - .adf = 0x00, - /* option to read SIGNAL_LEVEL */ - .read_slevel = 0, -}; - static int af9035_tuner_attach(struct dvb_usb_adapter *adap) { struct state *state = adap_to_priv(adap); @@ -1159,15 +1145,13 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap) case AF9033_TUNER_IT9135_38: case AF9033_TUNER_IT9135_51: case AF9033_TUNER_IT9135_52: - af9035_it913x_config.chip_ver = 0x01; case AF9033_TUNER_IT9135_60: case AF9033_TUNER_IT9135_61: case AF9033_TUNER_IT9135_62: - af9035_it913x_config.tuner_id_0 = state->af9033_config[0].tuner; /* attach tuner */ fe = dvb_attach(it913x_attach, adap->fe[0], &d->i2c_adap, state->af9033_config[adap->id].i2c_addr, - &af9035_it913x_config); + state->af9033_config[0].tuner); break; default: fe = NULL; -- cgit v1.2.3 From 108597979297c75646889e307e276db57aa6d5b8 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 28 Feb 2013 19:02:19 -0300 Subject: [media] it913x: remove unused variables Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 14 ++------------ drivers/media/tuners/it913x_priv.h | 12 ------------ 2 files changed, 2 insertions(+), 24 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 66d4b72d97ab..6ae9d5ae9654 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -23,25 +23,15 @@ #include "it913x_priv.h" struct it913x_state { - struct dvb_frontend frontend; struct i2c_adapter *i2c_adap; - u8 chip_ver; - u8 firmware_ver; u8 i2c_addr; - u32 frequency; - fe_modulation_t constellation; - fe_transmit_mode_t transmission_mode; - u8 priority; - u32 crystalFrequency; - u32 adcFrequency; + u8 chip_ver; u8 tuner_type; - struct adctable *table; - fe_status_t it913x_status; + u8 firmware_ver; u16 tun_xtal; u8 tun_fdiv; u8 tun_clk_mode; u32 tun_fn_min; - u32 ucblocks; }; /* read multiple registers */ diff --git a/drivers/media/tuners/it913x_priv.h b/drivers/media/tuners/it913x_priv.h index e4a0136efc3d..315ff6c72c53 100644 --- a/drivers/media/tuners/it913x_priv.h +++ b/drivers/media/tuners/it913x_priv.h @@ -34,22 +34,10 @@ #define IT9135_61 0x61 #define IT9135_62 0x62 -#define I2C_BASE_ADDR 0x10 -#define DEV_0 0x0 -#define DEV_1 0x10 #define PRO_LINK 0x0 #define PRO_DMOD 0x1 -#define DEV_0_DMOD (PRO_DMOD << 0x7) -#define DEV_1_DMOD (DEV_0_DMOD | DEV_1) -#define CHIP2_I2C_ADDR 0x3a - -#define PADODPU 0xd827 -#define THIRDODPU 0xd828 -#define AGC_O_D 0xd829 - #define TRIGGER_OFSM 0x0000 - struct it913xset { u32 pro; u32 address; u8 reg[15]; -- cgit v1.2.3 From c0d300a66979c7a836c75f6e2d33727543245368 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 28 Feb 2013 20:14:38 -0300 Subject: [media] it913x: include tuner IDs from af9033.h Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 24 ++++++++++++------------ drivers/media/tuners/it913x_priv.h | 10 +--------- 2 files changed, 13 insertions(+), 21 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 6ae9d5ae9654..1cb97092f562 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -156,22 +156,22 @@ static int it913x_init(struct dvb_frontend *fe) /* LNA Scripts */ switch (state->tuner_type) { - case IT9135_51: + case AF9033_TUNER_IT9135_51: set_lna = it9135_51; break; - case IT9135_52: + case AF9033_TUNER_IT9135_52: set_lna = it9135_52; break; - case IT9135_60: + case AF9033_TUNER_IT9135_60: set_lna = it9135_60; break; - case IT9135_61: + case AF9033_TUNER_IT9135_61: set_lna = it9135_61; break; - case IT9135_62: + case AF9033_TUNER_IT9135_62: set_lna = it9135_62; break; - case IT9135_38: + case AF9033_TUNER_IT9135_38: default: set_lna = it9135_38; } @@ -444,14 +444,14 @@ struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, state->i2c_addr = i2c_addr; switch (config) { - case IT9135_38: - case IT9135_51: - case IT9135_52: + case AF9033_TUNER_IT9135_38: + case AF9033_TUNER_IT9135_51: + case AF9033_TUNER_IT9135_52: state->chip_ver = 0x01; break; - case IT9135_60: - case IT9135_61: - case IT9135_62: + case AF9033_TUNER_IT9135_60: + case AF9033_TUNER_IT9135_61: + case AF9033_TUNER_IT9135_62: state->chip_ver = 0x02; break; default: diff --git a/drivers/media/tuners/it913x_priv.h b/drivers/media/tuners/it913x_priv.h index 315ff6c72c53..1491bf85dc34 100644 --- a/drivers/media/tuners/it913x_priv.h +++ b/drivers/media/tuners/it913x_priv.h @@ -24,15 +24,7 @@ #define IT913X_PRIV_H #include "it913x.h" - -/* Build in tuner types */ -#define IT9137 0x38 -#define IT9135_38 0x38 -#define IT9135_51 0x51 -#define IT9135_52 0x52 -#define IT9135_60 0x60 -#define IT9135_61 0x61 -#define IT9135_62 0x62 +#include "af9033.h" #define PRO_LINK 0x0 #define PRO_DMOD 0x1 -- cgit v1.2.3 From cfd08f0fb9b761c44e4d853c5b38f7fc7c3f5325 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 28 Feb 2013 20:54:44 -0300 Subject: [media] it913x: use dev_foo() logging Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 1cb97092f562..66e003f5316e 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -175,7 +175,9 @@ static int it913x_init(struct dvb_frontend *fe) default: set_lna = it9135_38; } - pr_info("Tuner LNA type :%02x\n", state->tuner_type); + + dev_dbg(&state->i2c_adap->dev, "%s: Tuner LNA type :%02x\n", + KBUILD_MODNAME, state->tuner_type); ret = it913x_script_loader(state, set_lna); if (ret < 0) @@ -226,7 +228,8 @@ static int it913x_init(struct dvb_frontend *fe) } state->tun_fn_min = state->tun_xtal * reg; state->tun_fn_min /= (state->tun_fdiv * nv_val); - pr_debug("Tuner fn_min %d\n", state->tun_fn_min); + dev_dbg(&state->i2c_adap->dev, "%s: Tuner fn_min %d\n", __func__, + state->tun_fn_min); if (state->chip_ver > 1) msleep(50); @@ -272,7 +275,8 @@ static int it9137_set_params(struct dvb_frontend *fe) else set_tuner = set_it9137_template; - pr_debug("Tuner Frequency %d Bandwidth %d\n", frequency, bandwidth); + dev_dbg(&state->i2c_adap->dev, "%s: Tuner Frequency %d Bandwidth %d\n", + __func__, frequency, bandwidth); if (frequency >= 51000 && frequency <= 440000) { l_band = 0; @@ -387,13 +391,15 @@ static int it9137_set_params(struct dvb_frontend *fe) set_tuner[3].reg[0] = temp_f & 0xff; set_tuner[4].reg[0] = (temp_f >> 8) & 0xff; - pr_debug("High Frequency = %04x\n", temp_f); + dev_dbg(&state->i2c_adap->dev, "%s: High Frequency = %04x\n", + __func__, temp_f); /* Lower frequency */ set_tuner[5].reg[0] = freq & 0xff; set_tuner[6].reg[0] = (freq >> 8) & 0xff; - pr_debug("low Frequency = %04x\n", freq); + dev_dbg(&state->i2c_adap->dev, "%s: low Frequency = %04x\n", + __func__, freq); ret = it913x_script_loader(state, set_tuner); -- cgit v1.2.3 From 463c399c2a8a9a465ebc17524a14616a49106689 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 00:03:06 -0300 Subject: [media] af9033: add IT9135 demod reg init tables Dumped out from Windows driver version 12.07.06.1, 07/06/2012. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 6 +- drivers/media/dvb-frontends/af9033_priv.h | 209 ++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index f51022817fed..23690aa36460 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -297,10 +297,14 @@ static int af9033_init(struct dvb_frontend *fe) case AF9033_TUNER_IT9135_38: case AF9033_TUNER_IT9135_51: case AF9033_TUNER_IT9135_52: + len = ARRAY_SIZE(ofsm_init_it9135_v1); + init = ofsm_init_it9135_v1; + break; case AF9033_TUNER_IT9135_60: case AF9033_TUNER_IT9135_61: case AF9033_TUNER_IT9135_62: - len = 0; + len = ARRAY_SIZE(ofsm_init_it9135_v2); + init = ofsm_init_it9135_v2; break; default: len = ARRAY_SIZE(ofsm_init); diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h index e9bd78265543..0808319d4324 100644 --- a/drivers/media/dvb-frontends/af9033_priv.h +++ b/drivers/media/dvb-frontends/af9033_priv.h @@ -547,5 +547,214 @@ static const struct reg_val tuner_init_fc2580[] = { { 0x80f1e6, 0x01 }, }; +static const struct reg_val ofsm_init_it9135_v1[] = { + { 0x800051, 0x01 }, + { 0x800070, 0x0a }, + { 0x80007e, 0x04 }, + { 0x800081, 0x0a }, + { 0x80008a, 0x01 }, + { 0x80008e, 0x01 }, + { 0x800092, 0x06 }, + { 0x800099, 0x01 }, + { 0x80009f, 0xe1 }, + { 0x8000a0, 0xcf }, + { 0x8000a3, 0x01 }, + { 0x8000a5, 0x01 }, + { 0x8000a6, 0x01 }, + { 0x8000a9, 0x00 }, + { 0x8000aa, 0x01 }, + { 0x8000b0, 0x01 }, + { 0x8000c2, 0x05 }, + { 0x8000c6, 0x19 }, + { 0x80f000, 0x0f }, + { 0x80f016, 0x10 }, + { 0x80f017, 0x04 }, + { 0x80f018, 0x05 }, + { 0x80f019, 0x04 }, + { 0x80f01a, 0x05 }, + { 0x80f021, 0x03 }, + { 0x80f022, 0x0a }, + { 0x80f023, 0x0a }, + { 0x80f02b, 0x00 }, + { 0x80f02c, 0x01 }, + { 0x80f064, 0x03 }, + { 0x80f065, 0xf9 }, + { 0x80f066, 0x03 }, + { 0x80f067, 0x01 }, + { 0x80f06f, 0xe0 }, + { 0x80f070, 0x03 }, + { 0x80f072, 0x0f }, + { 0x80f073, 0x03 }, + { 0x80f078, 0x00 }, + { 0x80f087, 0x00 }, + { 0x80f09b, 0x3f }, + { 0x80f09c, 0x00 }, + { 0x80f09d, 0x20 }, + { 0x80f09e, 0x00 }, + { 0x80f09f, 0x0c }, + { 0x80f0a0, 0x00 }, + { 0x80f130, 0x04 }, + { 0x80f132, 0x04 }, + { 0x80f144, 0x1a }, + { 0x80f146, 0x00 }, + { 0x80f14a, 0x01 }, + { 0x80f14c, 0x00 }, + { 0x80f14d, 0x00 }, + { 0x80f14f, 0x04 }, + { 0x80f158, 0x7f }, + { 0x80f15a, 0x00 }, + { 0x80f15b, 0x08 }, + { 0x80f15d, 0x03 }, + { 0x80f15e, 0x05 }, + { 0x80f163, 0x05 }, + { 0x80f166, 0x01 }, + { 0x80f167, 0x40 }, + { 0x80f168, 0x0f }, + { 0x80f17a, 0x00 }, + { 0x80f17b, 0x00 }, + { 0x80f183, 0x01 }, + { 0x80f19d, 0x40 }, + { 0x80f1bc, 0x36 }, + { 0x80f1bd, 0x00 }, + { 0x80f1cb, 0xa0 }, + { 0x80f1cc, 0x01 }, + { 0x80f204, 0x10 }, + { 0x80f214, 0x00 }, + { 0x80f40e, 0x0a }, + { 0x80f40f, 0x40 }, + { 0x80f410, 0x08 }, + { 0x80f55f, 0x0a }, + { 0x80f561, 0x15 }, + { 0x80f562, 0x20 }, + { 0x80f5df, 0xfb }, + { 0x80f5e0, 0x00 }, + { 0x80f5e3, 0x09 }, + { 0x80f5e4, 0x01 }, + { 0x80f5e5, 0x01 }, + { 0x80f5f8, 0x01 }, + { 0x80f5fd, 0x01 }, + { 0x80f600, 0x05 }, + { 0x80f601, 0x08 }, + { 0x80f602, 0x0b }, + { 0x80f603, 0x0e }, + { 0x80f604, 0x11 }, + { 0x80f605, 0x14 }, + { 0x80f606, 0x17 }, + { 0x80f607, 0x1f }, + { 0x80f60e, 0x00 }, + { 0x80f60f, 0x04 }, + { 0x80f610, 0x32 }, + { 0x80f611, 0x10 }, + { 0x80f707, 0xfc }, + { 0x80f708, 0x00 }, + { 0x80f709, 0x37 }, + { 0x80f70a, 0x00 }, + { 0x80f78b, 0x01 }, + { 0x80f80f, 0x40 }, + { 0x80f810, 0x54 }, + { 0x80f811, 0x5a }, + { 0x80f905, 0x01 }, + { 0x80fb06, 0x03 }, + { 0x80fd8b, 0x00 }, +}; + +static const struct reg_val ofsm_init_it9135_v2[] = { + { 0x800051, 0x01 }, + { 0x800070, 0x0a }, + { 0x80007e, 0x04 }, + { 0x800081, 0x0a }, + { 0x80008a, 0x01 }, + { 0x80008e, 0x01 }, + { 0x800092, 0x06 }, + { 0x800099, 0x01 }, + { 0x80009f, 0xe1 }, + { 0x8000a0, 0xcf }, + { 0x8000a3, 0x01 }, + { 0x8000a5, 0x01 }, + { 0x8000a6, 0x01 }, + { 0x8000a9, 0x00 }, + { 0x8000aa, 0x01 }, + { 0x8000b0, 0x01 }, + { 0x8000c2, 0x05 }, + { 0x8000c6, 0x19 }, + { 0x80f000, 0x0f }, + { 0x80f02b, 0x00 }, + { 0x80f064, 0x03 }, + { 0x80f065, 0xf9 }, + { 0x80f066, 0x03 }, + { 0x80f067, 0x01 }, + { 0x80f06f, 0xe0 }, + { 0x80f070, 0x03 }, + { 0x80f072, 0x0f }, + { 0x80f073, 0x03 }, + { 0x80f078, 0x00 }, + { 0x80f087, 0x00 }, + { 0x80f09b, 0x3f }, + { 0x80f09c, 0x00 }, + { 0x80f09d, 0x20 }, + { 0x80f09e, 0x00 }, + { 0x80f09f, 0x0c }, + { 0x80f0a0, 0x00 }, + { 0x80f130, 0x04 }, + { 0x80f132, 0x04 }, + { 0x80f144, 0x1a }, + { 0x80f146, 0x00 }, + { 0x80f14a, 0x01 }, + { 0x80f14c, 0x00 }, + { 0x80f14d, 0x00 }, + { 0x80f14f, 0x04 }, + { 0x80f158, 0x7f }, + { 0x80f15a, 0x00 }, + { 0x80f15b, 0x08 }, + { 0x80f15d, 0x03 }, + { 0x80f15e, 0x05 }, + { 0x80f163, 0x05 }, + { 0x80f166, 0x01 }, + { 0x80f167, 0x40 }, + { 0x80f168, 0x0f }, + { 0x80f17a, 0x00 }, + { 0x80f17b, 0x00 }, + { 0x80f183, 0x01 }, + { 0x80f19d, 0x40 }, + { 0x80f1bc, 0x36 }, + { 0x80f1bd, 0x00 }, + { 0x80f1cb, 0xa0 }, + { 0x80f1cc, 0x01 }, + { 0x80f204, 0x10 }, + { 0x80f214, 0x00 }, + { 0x80f40e, 0x0a }, + { 0x80f40f, 0x40 }, + { 0x80f410, 0x08 }, + { 0x80f55f, 0x0a }, + { 0x80f561, 0x15 }, + { 0x80f562, 0x20 }, + { 0x80f5e3, 0x09 }, + { 0x80f5e4, 0x01 }, + { 0x80f5e5, 0x01 }, + { 0x80f600, 0x05 }, + { 0x80f601, 0x08 }, + { 0x80f602, 0x0b }, + { 0x80f603, 0x0e }, + { 0x80f604, 0x11 }, + { 0x80f605, 0x14 }, + { 0x80f606, 0x17 }, + { 0x80f607, 0x1f }, + { 0x80f60e, 0x00 }, + { 0x80f60f, 0x04 }, + { 0x80f610, 0x32 }, + { 0x80f611, 0x10 }, + { 0x80f707, 0xfc }, + { 0x80f708, 0x00 }, + { 0x80f709, 0x37 }, + { 0x80f70a, 0x00 }, + { 0x80f78b, 0x01 }, + { 0x80f80f, 0x40 }, + { 0x80f810, 0x54 }, + { 0x80f811, 0x5a }, + { 0x80f905, 0x01 }, + { 0x80fb06, 0x03 }, + { 0x80fd8b, 0x00 }, +}; + #endif /* AF9033_PRIV_H */ -- cgit v1.2.3 From 9d7b848e4311a77a9c62df481278e6efb23cba4a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 00:09:36 -0300 Subject: [media] it913x: remove demod init reg tables These are demod inits and are already done by af9033 demod driver. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/it913x.c | 8 -- drivers/media/tuners/it913x_priv.h | 211 ------------------------------------- 2 files changed, 219 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 66e003f5316e..ec4964ce8a58 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -146,14 +146,6 @@ static int it913x_init(struct dvb_frontend *fe) u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; u8 b[2]; - /* v1 or v2 tuner script */ - if (state->chip_ver > 1) - ret = it913x_script_loader(state, it9135_v2); - else - ret = it913x_script_loader(state, it9135_v1); - if (ret < 0) - return ret; - /* LNA Scripts */ switch (state->tuner_type) { case AF9033_TUNER_IT9135_51: diff --git a/drivers/media/tuners/it913x_priv.h b/drivers/media/tuners/it913x_priv.h index 1491bf85dc34..7d0e29268a0b 100644 --- a/drivers/media/tuners/it913x_priv.h +++ b/drivers/media/tuners/it913x_priv.h @@ -37,118 +37,6 @@ struct it913xset { u32 pro; }; /* Version 1 types */ -static struct it913xset it9135_v1[] = { - {PRO_DMOD, 0x0051, {0x01}, 0x01}, - {PRO_DMOD, 0x0070, {0x0a}, 0x01}, - {PRO_DMOD, 0x007e, {0x04}, 0x01}, - {PRO_DMOD, 0x0081, {0x0a}, 0x01}, - {PRO_DMOD, 0x008a, {0x01}, 0x01}, - {PRO_DMOD, 0x008e, {0x01}, 0x01}, - {PRO_DMOD, 0x0092, {0x06}, 0x01}, - {PRO_DMOD, 0x0099, {0x01}, 0x01}, - {PRO_DMOD, 0x009f, {0xe1}, 0x01}, - {PRO_DMOD, 0x00a0, {0xcf}, 0x01}, - {PRO_DMOD, 0x00a3, {0x01}, 0x01}, - {PRO_DMOD, 0x00a5, {0x01}, 0x01}, - {PRO_DMOD, 0x00a6, {0x01}, 0x01}, - {PRO_DMOD, 0x00a9, {0x00}, 0x01}, - {PRO_DMOD, 0x00aa, {0x01}, 0x01}, - {PRO_DMOD, 0x00b0, {0x01}, 0x01}, - {PRO_DMOD, 0x00c2, {0x05}, 0x01}, - {PRO_DMOD, 0x00c6, {0x19}, 0x01}, - {PRO_DMOD, 0xf000, {0x0f}, 0x01}, - {PRO_DMOD, 0xf016, {0x10}, 0x01}, - {PRO_DMOD, 0xf017, {0x04}, 0x01}, - {PRO_DMOD, 0xf018, {0x05}, 0x01}, - {PRO_DMOD, 0xf019, {0x04}, 0x01}, - {PRO_DMOD, 0xf01a, {0x05}, 0x01}, - {PRO_DMOD, 0xf021, {0x03}, 0x01}, - {PRO_DMOD, 0xf022, {0x0a}, 0x01}, - {PRO_DMOD, 0xf023, {0x0a}, 0x01}, - {PRO_DMOD, 0xf02b, {0x00}, 0x01}, - {PRO_DMOD, 0xf02c, {0x01}, 0x01}, - {PRO_DMOD, 0xf064, {0x03}, 0x01}, - {PRO_DMOD, 0xf065, {0xf9}, 0x01}, - {PRO_DMOD, 0xf066, {0x03}, 0x01}, - {PRO_DMOD, 0xf067, {0x01}, 0x01}, - {PRO_DMOD, 0xf06f, {0xe0}, 0x01}, - {PRO_DMOD, 0xf070, {0x03}, 0x01}, - {PRO_DMOD, 0xf072, {0x0f}, 0x01}, - {PRO_DMOD, 0xf073, {0x03}, 0x01}, - {PRO_DMOD, 0xf078, {0x00}, 0x01}, - {PRO_DMOD, 0xf087, {0x00}, 0x01}, - {PRO_DMOD, 0xf09b, {0x3f}, 0x01}, - {PRO_DMOD, 0xf09c, {0x00}, 0x01}, - {PRO_DMOD, 0xf09d, {0x20}, 0x01}, - {PRO_DMOD, 0xf09e, {0x00}, 0x01}, - {PRO_DMOD, 0xf09f, {0x0c}, 0x01}, - {PRO_DMOD, 0xf0a0, {0x00}, 0x01}, - {PRO_DMOD, 0xf130, {0x04}, 0x01}, - {PRO_DMOD, 0xf132, {0x04}, 0x01}, - {PRO_DMOD, 0xf144, {0x1a}, 0x01}, - {PRO_DMOD, 0xf146, {0x00}, 0x01}, - {PRO_DMOD, 0xf14a, {0x01}, 0x01}, - {PRO_DMOD, 0xf14c, {0x00}, 0x01}, - {PRO_DMOD, 0xf14d, {0x00}, 0x01}, - {PRO_DMOD, 0xf14f, {0x04}, 0x01}, - {PRO_DMOD, 0xf158, {0x7f}, 0x01}, - {PRO_DMOD, 0xf15a, {0x00}, 0x01}, - {PRO_DMOD, 0xf15b, {0x08}, 0x01}, - {PRO_DMOD, 0xf15d, {0x03}, 0x01}, - {PRO_DMOD, 0xf15e, {0x05}, 0x01}, - {PRO_DMOD, 0xf163, {0x05}, 0x01}, - {PRO_DMOD, 0xf166, {0x01}, 0x01}, - {PRO_DMOD, 0xf167, {0x40}, 0x01}, - {PRO_DMOD, 0xf168, {0x0f}, 0x01}, - {PRO_DMOD, 0xf17a, {0x00}, 0x01}, - {PRO_DMOD, 0xf17b, {0x00}, 0x01}, - {PRO_DMOD, 0xf183, {0x01}, 0x01}, - {PRO_DMOD, 0xf19d, {0x40}, 0x01}, - {PRO_DMOD, 0xf1bc, {0x36}, 0x01}, - {PRO_DMOD, 0xf1bd, {0x00}, 0x01}, - {PRO_DMOD, 0xf1cb, {0xa0}, 0x01}, - {PRO_DMOD, 0xf1cc, {0x01}, 0x01}, - {PRO_DMOD, 0xf204, {0x10}, 0x01}, - {PRO_DMOD, 0xf214, {0x00}, 0x01}, - {PRO_DMOD, 0xf40e, {0x0a}, 0x01}, - {PRO_DMOD, 0xf40f, {0x40}, 0x01}, - {PRO_DMOD, 0xf410, {0x08}, 0x01}, - {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, - {PRO_DMOD, 0xf561, {0x15}, 0x01}, - {PRO_DMOD, 0xf562, {0x20}, 0x01}, - {PRO_DMOD, 0xf5df, {0xfb}, 0x01}, - {PRO_DMOD, 0xf5e0, {0x00}, 0x01}, - {PRO_DMOD, 0xf5e3, {0x09}, 0x01}, - {PRO_DMOD, 0xf5e4, {0x01}, 0x01}, - {PRO_DMOD, 0xf5e5, {0x01}, 0x01}, - {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, - {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, - {PRO_DMOD, 0xf600, {0x05}, 0x01}, - {PRO_DMOD, 0xf601, {0x08}, 0x01}, - {PRO_DMOD, 0xf602, {0x0b}, 0x01}, - {PRO_DMOD, 0xf603, {0x0e}, 0x01}, - {PRO_DMOD, 0xf604, {0x11}, 0x01}, - {PRO_DMOD, 0xf605, {0x14}, 0x01}, - {PRO_DMOD, 0xf606, {0x17}, 0x01}, - {PRO_DMOD, 0xf607, {0x1f}, 0x01}, - {PRO_DMOD, 0xf60e, {0x00}, 0x01}, - {PRO_DMOD, 0xf60f, {0x04}, 0x01}, - {PRO_DMOD, 0xf610, {0x32}, 0x01}, - {PRO_DMOD, 0xf611, {0x10}, 0x01}, - {PRO_DMOD, 0xf707, {0xfc}, 0x01}, - {PRO_DMOD, 0xf708, {0x00}, 0x01}, - {PRO_DMOD, 0xf709, {0x37}, 0x01}, - {PRO_DMOD, 0xf70a, {0x00}, 0x01}, - {PRO_DMOD, 0xf78b, {0x01}, 0x01}, - {PRO_DMOD, 0xf80f, {0x40}, 0x01}, - {PRO_DMOD, 0xf810, {0x54}, 0x01}, - {PRO_DMOD, 0xf811, {0x5a}, 0x01}, - {PRO_DMOD, 0xf905, {0x01}, 0x01}, - {PRO_DMOD, 0xfb06, {0x03}, 0x01}, - {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ -}; - static struct it913xset it9135_38[] = { {PRO_DMOD, 0x0043, {0x00}, 0x01}, {PRO_DMOD, 0x0046, {0x38}, 0x01}, @@ -414,105 +302,6 @@ static struct it913xset it9135_52[] = { }; /* Version 2 types */ -static struct it913xset it9135_v2[] = { - {PRO_DMOD, 0x0051, {0x01}, 0x01}, - {PRO_DMOD, 0x0070, {0x0a}, 0x01}, - {PRO_DMOD, 0x007e, {0x04}, 0x01}, - {PRO_DMOD, 0x0081, {0x0a}, 0x01}, - {PRO_DMOD, 0x008a, {0x01}, 0x01}, - {PRO_DMOD, 0x008e, {0x01}, 0x01}, - {PRO_DMOD, 0x0092, {0x06}, 0x01}, - {PRO_DMOD, 0x0099, {0x01}, 0x01}, - {PRO_DMOD, 0x009f, {0xe1}, 0x01}, - {PRO_DMOD, 0x00a0, {0xcf}, 0x01}, - {PRO_DMOD, 0x00a3, {0x01}, 0x01}, - {PRO_DMOD, 0x00a5, {0x01}, 0x01}, - {PRO_DMOD, 0x00a6, {0x01}, 0x01}, - {PRO_DMOD, 0x00a9, {0x00}, 0x01}, - {PRO_DMOD, 0x00aa, {0x01}, 0x01}, - {PRO_DMOD, 0x00b0, {0x01}, 0x01}, - {PRO_DMOD, 0x00c2, {0x05}, 0x01}, - {PRO_DMOD, 0x00c6, {0x19}, 0x01}, - {PRO_DMOD, 0xf000, {0x0f}, 0x01}, - {PRO_DMOD, 0xf02b, {0x00}, 0x01}, - {PRO_DMOD, 0xf064, {0x03}, 0x01}, - {PRO_DMOD, 0xf065, {0xf9}, 0x01}, - {PRO_DMOD, 0xf066, {0x03}, 0x01}, - {PRO_DMOD, 0xf067, {0x01}, 0x01}, - {PRO_DMOD, 0xf06f, {0xe0}, 0x01}, - {PRO_DMOD, 0xf070, {0x03}, 0x01}, - {PRO_DMOD, 0xf072, {0x0f}, 0x01}, - {PRO_DMOD, 0xf073, {0x03}, 0x01}, - {PRO_DMOD, 0xf078, {0x00}, 0x01}, - {PRO_DMOD, 0xf087, {0x00}, 0x01}, - {PRO_DMOD, 0xf09b, {0x3f}, 0x01}, - {PRO_DMOD, 0xf09c, {0x00}, 0x01}, - {PRO_DMOD, 0xf09d, {0x20}, 0x01}, - {PRO_DMOD, 0xf09e, {0x00}, 0x01}, - {PRO_DMOD, 0xf09f, {0x0c}, 0x01}, - {PRO_DMOD, 0xf0a0, {0x00}, 0x01}, - {PRO_DMOD, 0xf130, {0x04}, 0x01}, - {PRO_DMOD, 0xf132, {0x04}, 0x01}, - {PRO_DMOD, 0xf144, {0x1a}, 0x01}, - {PRO_DMOD, 0xf146, {0x00}, 0x01}, - {PRO_DMOD, 0xf14a, {0x01}, 0x01}, - {PRO_DMOD, 0xf14c, {0x00}, 0x01}, - {PRO_DMOD, 0xf14d, {0x00}, 0x01}, - {PRO_DMOD, 0xf14f, {0x04}, 0x01}, - {PRO_DMOD, 0xf158, {0x7f}, 0x01}, - {PRO_DMOD, 0xf15a, {0x00}, 0x01}, - {PRO_DMOD, 0xf15b, {0x08}, 0x01}, - {PRO_DMOD, 0xf15d, {0x03}, 0x01}, - {PRO_DMOD, 0xf15e, {0x05}, 0x01}, - {PRO_DMOD, 0xf163, {0x05}, 0x01}, - {PRO_DMOD, 0xf166, {0x01}, 0x01}, - {PRO_DMOD, 0xf167, {0x40}, 0x01}, - {PRO_DMOD, 0xf168, {0x0f}, 0x01}, - {PRO_DMOD, 0xf17a, {0x00}, 0x01}, - {PRO_DMOD, 0xf17b, {0x00}, 0x01}, - {PRO_DMOD, 0xf183, {0x01}, 0x01}, - {PRO_DMOD, 0xf19d, {0x40}, 0x01}, - {PRO_DMOD, 0xf1bc, {0x36}, 0x01}, - {PRO_DMOD, 0xf1bd, {0x00}, 0x01}, - {PRO_DMOD, 0xf1cb, {0xa0}, 0x01}, - {PRO_DMOD, 0xf1cc, {0x01}, 0x01}, - {PRO_DMOD, 0xf204, {0x10}, 0x01}, - {PRO_DMOD, 0xf214, {0x00}, 0x01}, - {PRO_DMOD, 0xf40e, {0x0a}, 0x01}, - {PRO_DMOD, 0xf40f, {0x40}, 0x01}, - {PRO_DMOD, 0xf410, {0x08}, 0x01}, - {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, - {PRO_DMOD, 0xf561, {0x15}, 0x01}, - {PRO_DMOD, 0xf562, {0x20}, 0x01}, - {PRO_DMOD, 0xf5e3, {0x09}, 0x01}, - {PRO_DMOD, 0xf5e4, {0x01}, 0x01}, - {PRO_DMOD, 0xf5e5, {0x01}, 0x01}, - {PRO_DMOD, 0xf600, {0x05}, 0x01}, - {PRO_DMOD, 0xf601, {0x08}, 0x01}, - {PRO_DMOD, 0xf602, {0x0b}, 0x01}, - {PRO_DMOD, 0xf603, {0x0e}, 0x01}, - {PRO_DMOD, 0xf604, {0x11}, 0x01}, - {PRO_DMOD, 0xf605, {0x14}, 0x01}, - {PRO_DMOD, 0xf606, {0x17}, 0x01}, - {PRO_DMOD, 0xf607, {0x1f}, 0x01}, - {PRO_DMOD, 0xf60e, {0x00}, 0x01}, - {PRO_DMOD, 0xf60f, {0x04}, 0x01}, - {PRO_DMOD, 0xf610, {0x32}, 0x01}, - {PRO_DMOD, 0xf611, {0x10}, 0x01}, - {PRO_DMOD, 0xf707, {0xfc}, 0x01}, - {PRO_DMOD, 0xf708, {0x00}, 0x01}, - {PRO_DMOD, 0xf709, {0x37}, 0x01}, - {PRO_DMOD, 0xf70a, {0x00}, 0x01}, - {PRO_DMOD, 0xf78b, {0x01}, 0x01}, - {PRO_DMOD, 0xf80f, {0x40}, 0x01}, - {PRO_DMOD, 0xf810, {0x54}, 0x01}, - {PRO_DMOD, 0xf811, {0x5a}, 0x01}, - {PRO_DMOD, 0xf905, {0x01}, 0x01}, - {PRO_DMOD, 0xfb06, {0x03}, 0x01}, - {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ -}; - static struct it913xset it9135_60[] = { {PRO_DMOD, 0x0043, {0x00}, 0x01}, {PRO_DMOD, 0x0046, {0x60}, 0x01}, -- cgit v1.2.3 From 8229da506488ec67a051593fe452ee54e91c70cf Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 17:59:55 -0300 Subject: [media] af9035: select firmware loader according to firmware AF9035 and IT9135 supports two different firmware format. Select correct loader according to first byte of firmware file. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index ce8cccb8946a..75d99aec10b6 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -344,7 +344,7 @@ err: return ret; } -static int af9035_download_firmware_af9035(struct dvb_usb_device *d, +static int af9035_download_firmware_old(struct dvb_usb_device *d, const struct firmware *fw) { int ret, i, j, len; @@ -430,7 +430,7 @@ err: return ret; } -static int af9035_download_firmware_it9135(struct dvb_usb_device *d, +static int af9035_download_firmware_new(struct dvb_usb_device *d, const struct firmware *fw) { int ret, i, i_prev; @@ -540,10 +540,10 @@ static int af9035_download_firmware(struct dvb_usb_device *d, } } - if (state->chip_type == 0x9135) - ret = af9035_download_firmware_it9135(d, fw); + if (fw->data[0] == 0x01) + ret = af9035_download_firmware_old(d, fw); else - ret = af9035_download_firmware_af9035(d, fw); + ret = af9035_download_firmware_new(d, fw); if (ret < 0) goto err; -- cgit v1.2.3 From 431a6d4ab9cfc41dd541544f8afdd517090e49b1 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 18:28:25 -0300 Subject: [media] af9035: use already detected eeprom base addr eeprom memory mapped base address is detected at the very first. Use it everywhere. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 75d99aec10b6..1ccc9ce02d8c 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -606,18 +606,14 @@ static int af9035_read_config(struct dvb_usb_device *d) if (ret < 0) goto err; - if (tmp) { - addr = EEPROM_BASE_IT9135; - } else { + if (tmp == 0x00) { dev_dbg(&d->udev->dev, "%s: no eeprom\n", __func__); goto skip_eeprom; } - } else { - addr = EEPROM_BASE_AF9035; } /* check if there is dual tuners */ - ret = af9035_rd_reg(d, addr + EEPROM_DUAL_MODE, &tmp); + ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_DUAL_MODE, &tmp); if (ret < 0) goto err; @@ -627,7 +623,9 @@ static int af9035_read_config(struct dvb_usb_device *d) if (state->dual_mode) { /* read 2nd demodulator I2C address */ - ret = af9035_rd_reg(d, addr + EEPROM_2ND_DEMOD_ADDR, &tmp); + ret = af9035_rd_reg(d, + state->eeprom_addr + EEPROM_2ND_DEMOD_ADDR, + &tmp); if (ret < 0) goto err; @@ -636,6 +634,8 @@ static int af9035_read_config(struct dvb_usb_device *d) __func__, tmp); } + addr = state->eeprom_addr; + for (i = 0; i < state->dual_mode + 1; i++) { /* tuner */ ret = af9035_rd_reg(d, addr + EEPROM_1_TUNER_ID, &tmp); @@ -1258,7 +1258,7 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) if (state->chip_type == 0x9135) return 0; - ret = af9035_rd_reg(d, EEPROM_BASE_AF9035 + EEPROM_IR_MODE, &tmp); + ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_IR_MODE, &tmp); if (ret < 0) goto err; @@ -1266,7 +1266,7 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) /* don't activate rc if in HID mode or if not available */ if (tmp == 5) { - ret = af9035_rd_reg(d, EEPROM_BASE_AF9035 + EEPROM_IR_TYPE, + ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_IR_TYPE, &tmp); if (ret < 0) goto err; -- cgit v1.2.3 From ab56ad6ada8c7ff56a4f4b032e79471cb1c3c0fc Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 18:43:51 -0300 Subject: [media] af9035: set demod TS mode config in read_config() Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 1ccc9ce02d8c..3efb79af4d9b 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -588,6 +588,8 @@ static int af9035_read_config(struct dvb_usb_device *d) state->af9033_config[0].i2c_addr = 0x38; state->af9033_config[0].adc_multiplier = AF9033_ADC_MULTIPLIER_2X; state->af9033_config[1].adc_multiplier = AF9033_ADC_MULTIPLIER_2X; + state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB; + state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL; /* eeprom memory mapped location */ if (state->chip_type == 0x9135) { @@ -903,11 +905,6 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap) goto err; } - if (adap->id == 0) { - state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB; - state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL; - } - /* attach demodulator */ adap->fe[0] = dvb_attach(af9033_attach, &state->af9033_config[adap->id], &d->i2c_adap); -- cgit v1.2.3 From 1c72fe2679996a125219caaede542ad6913a3539 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 19:03:06 -0300 Subject: [media] af9035: enable remote controller for IT9135 too There is no difference towards AF9035 remote controller, so enable it. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 3efb79af4d9b..735646d4f34a 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -1251,10 +1251,6 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) int ret; u8 tmp; - /* TODO: IT9135 remote control support */ - if (state->chip_type == 0x9135) - return 0; - ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_IR_MODE, &tmp); if (ret < 0) goto err; -- cgit v1.2.3 From 70375ecc452128d855f89e04b31a0961501cc153 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 19:22:52 -0300 Subject: [media] af9035: change dual mode boolean to bit field For some reason there seems to be value 0x03 in eeprom for dual mode (and 0x00 for single mode). Boolean is not always 1 bit wide - it could be 8 bit wide too. Storing number 0x03 to boolean causes driver to thing there is 4 tuners in some cases :o Add also some comments regarding to eeprom. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index 2f7d269c7d60..0f42b6cb3708 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -59,7 +59,7 @@ struct state { u8 prechip_version; u8 chip_version; u16 chip_type; - bool dual_mode; + u8 dual_mode:1; u16 eeprom_addr; struct af9033_config af9033_config[2]; }; @@ -96,6 +96,14 @@ static const u32 clock_lut_it9135[] = { #define AF9035_FIRMWARE_IT9135_V1 "dvb-usb-it9135-01.fw" #define AF9035_FIRMWARE_IT9135_V2 "dvb-usb-it9135-02.fw" +/* + * eeprom is memory mapped as read only. Writing that memory mapped address + * will not corrupt eeprom. + * + * eeprom has value 0x00 single mode and 0x03 for dual mode as far as I have + * seen to this day. + */ + #define EEPROM_BASE_AF9035 0x42fd #define EEPROM_BASE_IT9135 0x499c #define EEPROM_SHIFT 0x10 -- cgit v1.2.3 From a72cbb77c1f18e7e560afea9cba1159fa0968c50 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 21:17:55 -0300 Subject: [media] af9033: add IT9135 tuner config "38" init table Dumped out from the Windows driver version 12.07.06.1 Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 3 + drivers/media/dvb-frontends/af9033_priv.h | 217 ++++++++++++++++++++++++++++++ 2 files changed, 220 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 23690aa36460..1386d2968129 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -347,6 +347,9 @@ static int af9033_init(struct dvb_frontend *fe) init = tuner_init_fc0012; break; case AF9033_TUNER_IT9135_38: + len = ARRAY_SIZE(tuner_init_it9135_38); + init = tuner_init_it9135_38; + break; case AF9033_TUNER_IT9135_51: case AF9033_TUNER_IT9135_52: case AF9033_TUNER_IT9135_60: diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h index 0808319d4324..0dc13ebf4951 100644 --- a/drivers/media/dvb-frontends/af9033_priv.h +++ b/drivers/media/dvb-frontends/af9033_priv.h @@ -658,6 +658,223 @@ static const struct reg_val ofsm_init_it9135_v1[] = { { 0x80fd8b, 0x00 }, }; +/* ITE Tech IT9135 Omega tuner init + AF9033_TUNER_IT9135_38 = 0x38 */ +static const struct reg_val tuner_init_it9135_38[] = { + { 0x800043, 0x00 }, + { 0x800046, 0x38 }, + { 0x800051, 0x01 }, + { 0x80005f, 0x00 }, + { 0x800060, 0x00 }, + { 0x800068, 0x0a }, + { 0x800070, 0x0a }, + { 0x800071, 0x05 }, + { 0x800072, 0x02 }, + { 0x800075, 0x8c }, + { 0x800076, 0x8c }, + { 0x800077, 0x8c }, + { 0x800078, 0xc8 }, + { 0x800079, 0x01 }, + { 0x80007e, 0x04 }, + { 0x80007f, 0x00 }, + { 0x800081, 0x0a }, + { 0x800082, 0x12 }, + { 0x800083, 0x02 }, + { 0x800084, 0x0a }, + { 0x800085, 0x03 }, + { 0x800086, 0xc8 }, + { 0x800087, 0xb8 }, + { 0x800088, 0xd0 }, + { 0x800089, 0xc3 }, + { 0x80008a, 0x01 }, + { 0x80008e, 0x01 }, + { 0x800092, 0x06 }, + { 0x800093, 0x00 }, + { 0x800094, 0x00 }, + { 0x800095, 0x00 }, + { 0x800096, 0x00 }, + { 0x800099, 0x01 }, + { 0x80009b, 0x3c }, + { 0x80009c, 0x28 }, + { 0x80009f, 0xe1 }, + { 0x8000a0, 0xcf }, + { 0x8000a3, 0x01 }, + { 0x8000a4, 0x5a }, + { 0x8000a5, 0x01 }, + { 0x8000a6, 0x01 }, + { 0x8000a9, 0x00 }, + { 0x8000aa, 0x01 }, + { 0x8000b0, 0x01 }, + { 0x8000b3, 0x02 }, + { 0x8000b4, 0x32 }, + { 0x8000b6, 0x14 }, + { 0x8000c0, 0x11 }, + { 0x8000c1, 0x00 }, + { 0x8000c2, 0x05 }, + { 0x8000c4, 0x00 }, + { 0x8000c6, 0x19 }, + { 0x8000c7, 0x00 }, + { 0x8000cc, 0x2e }, + { 0x8000cd, 0x51 }, + { 0x8000ce, 0x33 }, + { 0x8000f3, 0x05 }, + { 0x8000f4, 0x8c }, + { 0x8000f5, 0x8c }, + { 0x8000f8, 0x03 }, + { 0x8000f9, 0x06 }, + { 0x8000fa, 0x06 }, + { 0x8000fc, 0x02 }, + { 0x8000fd, 0x02 }, + { 0x8000fe, 0x02 }, + { 0x8000ff, 0x09 }, + { 0x800100, 0x50 }, + { 0x800101, 0x7b }, + { 0x800102, 0x77 }, + { 0x800103, 0x00 }, + { 0x800104, 0x02 }, + { 0x800105, 0xc8 }, + { 0x800106, 0x05 }, + { 0x800107, 0x7b }, + { 0x800109, 0x02 }, + { 0x800115, 0x0a }, + { 0x800116, 0x03 }, + { 0x800117, 0x02 }, + { 0x800118, 0x80 }, + { 0x80011a, 0xc8 }, + { 0x80011b, 0x7b }, + { 0x80011c, 0x8a }, + { 0x80011d, 0xa0 }, + { 0x800122, 0x02 }, + { 0x800123, 0x18 }, + { 0x800124, 0xc3 }, + { 0x800127, 0x00 }, + { 0x800128, 0x07 }, + { 0x80012a, 0x53 }, + { 0x80012b, 0x51 }, + { 0x80012c, 0x4e }, + { 0x80012d, 0x43 }, + { 0x800137, 0x01 }, + { 0x800138, 0x00 }, + { 0x800139, 0x07 }, + { 0x80013a, 0x00 }, + { 0x80013b, 0x06 }, + { 0x80013d, 0x00 }, + { 0x80013e, 0x01 }, + { 0x80013f, 0x5b }, + { 0x800140, 0xc8 }, + { 0x800141, 0x59 }, + { 0x80f000, 0x0f }, + { 0x80f016, 0x10 }, + { 0x80f017, 0x04 }, + { 0x80f018, 0x05 }, + { 0x80f019, 0x04 }, + { 0x80f01a, 0x05 }, + { 0x80f01f, 0x8c }, + { 0x80f020, 0x00 }, + { 0x80f021, 0x03 }, + { 0x80f022, 0x0a }, + { 0x80f023, 0x0a }, + { 0x80f029, 0x8c }, + { 0x80f02a, 0x00 }, + { 0x80f02b, 0x00 }, + { 0x80f02c, 0x01 }, + { 0x80f064, 0x03 }, + { 0x80f065, 0xf9 }, + { 0x80f066, 0x03 }, + { 0x80f067, 0x01 }, + { 0x80f06f, 0xe0 }, + { 0x80f070, 0x03 }, + { 0x80f072, 0x0f }, + { 0x80f073, 0x03 }, + { 0x80f077, 0x01 }, + { 0x80f078, 0x00 }, + { 0x80f085, 0x00 }, + { 0x80f086, 0x02 }, + { 0x80f087, 0x00 }, + { 0x80f09b, 0x3f }, + { 0x80f09c, 0x00 }, + { 0x80f09d, 0x20 }, + { 0x80f09e, 0x00 }, + { 0x80f09f, 0x0c }, + { 0x80f0a0, 0x00 }, + { 0x80f130, 0x04 }, + { 0x80f132, 0x04 }, + { 0x80f144, 0x1a }, + { 0x80f146, 0x00 }, + { 0x80f14a, 0x01 }, + { 0x80f14c, 0x00 }, + { 0x80f14d, 0x00 }, + { 0x80f14f, 0x04 }, + { 0x80f158, 0x7f }, + { 0x80f15a, 0x00 }, + { 0x80f15b, 0x08 }, + { 0x80f15d, 0x03 }, + { 0x80f15e, 0x05 }, + { 0x80f163, 0x05 }, + { 0x80f166, 0x01 }, + { 0x80f167, 0x40 }, + { 0x80f168, 0x0f }, + { 0x80f17a, 0x00 }, + { 0x80f17b, 0x00 }, + { 0x80f183, 0x01 }, + { 0x80f19d, 0x40 }, + { 0x80f1bc, 0x36 }, + { 0x80f1bd, 0x00 }, + { 0x80f1cb, 0xa0 }, + { 0x80f1cc, 0x01 }, + { 0x80f204, 0x10 }, + { 0x80f214, 0x00 }, + { 0x80f24c, 0x88 }, + { 0x80f24d, 0x95 }, + { 0x80f24e, 0x9a }, + { 0x80f24f, 0x90 }, + { 0x80f25a, 0x07 }, + { 0x80f25b, 0xe8 }, + { 0x80f25c, 0x03 }, + { 0x80f25d, 0xb0 }, + { 0x80f25e, 0x04 }, + { 0x80f270, 0x01 }, + { 0x80f271, 0x02 }, + { 0x80f272, 0x01 }, + { 0x80f273, 0x02 }, + { 0x80f40e, 0x0a }, + { 0x80f40f, 0x40 }, + { 0x80f410, 0x08 }, + { 0x80f55f, 0x0a }, + { 0x80f561, 0x15 }, + { 0x80f562, 0x20 }, + { 0x80f5df, 0xfb }, + { 0x80f5e0, 0x00 }, + { 0x80f5e3, 0x09 }, + { 0x80f5e4, 0x01 }, + { 0x80f5e5, 0x01 }, + { 0x80f5f8, 0x01 }, + { 0x80f5fd, 0x01 }, + { 0x80f600, 0x05 }, + { 0x80f601, 0x08 }, + { 0x80f602, 0x0b }, + { 0x80f603, 0x0e }, + { 0x80f604, 0x11 }, + { 0x80f605, 0x14 }, + { 0x80f606, 0x17 }, + { 0x80f607, 0x1f }, + { 0x80f60e, 0x00 }, + { 0x80f60f, 0x04 }, + { 0x80f610, 0x32 }, + { 0x80f611, 0x10 }, + { 0x80f707, 0xfc }, + { 0x80f708, 0x00 }, + { 0x80f709, 0x37 }, + { 0x80f70a, 0x00 }, + { 0x80f78b, 0x01 }, + { 0x80f80f, 0x40 }, + { 0x80f810, 0x54 }, + { 0x80f811, 0x5a }, + { 0x80f905, 0x01 }, + { 0x80fb06, 0x03 }, + { 0x80fd8b, 0x00 }, +}; + static const struct reg_val ofsm_init_it9135_v2[] = { { 0x800051, 0x01 }, { 0x800070, 0x0a }, -- cgit v1.2.3 From bb2e12a6f983045f4452f7561c712162002ccf44 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 21:25:16 -0300 Subject: [media] af9033: add IT9135 tuner config "51" init table Dumped out from the Windows driver version 12.07.06.1 Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 3 + drivers/media/dvb-frontends/af9033_priv.h | 217 ++++++++++++++++++++++++++++++ 2 files changed, 220 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 1386d2968129..d6fc566669ea 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -351,6 +351,9 @@ static int af9033_init(struct dvb_frontend *fe) init = tuner_init_it9135_38; break; case AF9033_TUNER_IT9135_51: + len = ARRAY_SIZE(tuner_init_it9135_51); + init = tuner_init_it9135_51; + break; case AF9033_TUNER_IT9135_52: case AF9033_TUNER_IT9135_60: case AF9033_TUNER_IT9135_61: diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h index 0dc13ebf4951..5e35ef6c5825 100644 --- a/drivers/media/dvb-frontends/af9033_priv.h +++ b/drivers/media/dvb-frontends/af9033_priv.h @@ -875,6 +875,223 @@ static const struct reg_val tuner_init_it9135_38[] = { { 0x80fd8b, 0x00 }, }; +/* ITE Tech IT9135 Omega LNA config 1 tuner init + AF9033_TUNER_IT9135_51 = 0x51 */ +static const struct reg_val tuner_init_it9135_51[] = { + { 0x800043, 0x00 }, + { 0x800046, 0x51 }, + { 0x800051, 0x01 }, + { 0x80005f, 0x00 }, + { 0x800060, 0x00 }, + { 0x800068, 0x0a }, + { 0x800070, 0x0a }, + { 0x800071, 0x06 }, + { 0x800072, 0x02 }, + { 0x800075, 0x8c }, + { 0x800076, 0x8c }, + { 0x800077, 0x8c }, + { 0x800078, 0xc8 }, + { 0x800079, 0x01 }, + { 0x80007e, 0x04 }, + { 0x80007f, 0x00 }, + { 0x800081, 0x0a }, + { 0x800082, 0x12 }, + { 0x800083, 0x02 }, + { 0x800084, 0x0a }, + { 0x800085, 0x03 }, + { 0x800086, 0xc0 }, + { 0x800087, 0x96 }, + { 0x800088, 0xcf }, + { 0x800089, 0xc3 }, + { 0x80008a, 0x01 }, + { 0x80008e, 0x01 }, + { 0x800092, 0x06 }, + { 0x800093, 0x00 }, + { 0x800094, 0x00 }, + { 0x800095, 0x00 }, + { 0x800096, 0x00 }, + { 0x800099, 0x01 }, + { 0x80009b, 0x3c }, + { 0x80009c, 0x28 }, + { 0x80009f, 0xe1 }, + { 0x8000a0, 0xcf }, + { 0x8000a3, 0x01 }, + { 0x8000a4, 0x5a }, + { 0x8000a5, 0x01 }, + { 0x8000a6, 0x01 }, + { 0x8000a9, 0x00 }, + { 0x8000aa, 0x01 }, + { 0x8000b0, 0x01 }, + { 0x8000b3, 0x02 }, + { 0x8000b4, 0x3c }, + { 0x8000b6, 0x14 }, + { 0x8000c0, 0x11 }, + { 0x8000c1, 0x00 }, + { 0x8000c2, 0x05 }, + { 0x8000c4, 0x00 }, + { 0x8000c6, 0x19 }, + { 0x8000c7, 0x00 }, + { 0x8000cc, 0x2e }, + { 0x8000cd, 0x51 }, + { 0x8000ce, 0x33 }, + { 0x8000f3, 0x05 }, + { 0x8000f4, 0x8c }, + { 0x8000f5, 0x8c }, + { 0x8000f8, 0x03 }, + { 0x8000f9, 0x06 }, + { 0x8000fa, 0x06 }, + { 0x8000fc, 0x03 }, + { 0x8000fd, 0x02 }, + { 0x8000fe, 0x02 }, + { 0x8000ff, 0x09 }, + { 0x800100, 0x50 }, + { 0x800101, 0x7a }, + { 0x800102, 0x77 }, + { 0x800103, 0x01 }, + { 0x800104, 0x02 }, + { 0x800105, 0xb0 }, + { 0x800106, 0x02 }, + { 0x800107, 0x7a }, + { 0x800109, 0x02 }, + { 0x800115, 0x0a }, + { 0x800116, 0x03 }, + { 0x800117, 0x02 }, + { 0x800118, 0x80 }, + { 0x80011a, 0xc0 }, + { 0x80011b, 0x7a }, + { 0x80011c, 0xac }, + { 0x80011d, 0x8c }, + { 0x800122, 0x02 }, + { 0x800123, 0x70 }, + { 0x800124, 0xa4 }, + { 0x800127, 0x00 }, + { 0x800128, 0x07 }, + { 0x80012a, 0x53 }, + { 0x80012b, 0x51 }, + { 0x80012c, 0x4e }, + { 0x80012d, 0x43 }, + { 0x800137, 0x01 }, + { 0x800138, 0x00 }, + { 0x800139, 0x07 }, + { 0x80013a, 0x00 }, + { 0x80013b, 0x06 }, + { 0x80013d, 0x00 }, + { 0x80013e, 0x01 }, + { 0x80013f, 0x5b }, + { 0x800140, 0xc0 }, + { 0x800141, 0x59 }, + { 0x80f000, 0x0f }, + { 0x80f016, 0x10 }, + { 0x80f017, 0x04 }, + { 0x80f018, 0x05 }, + { 0x80f019, 0x04 }, + { 0x80f01a, 0x05 }, + { 0x80f01f, 0x8c }, + { 0x80f020, 0x00 }, + { 0x80f021, 0x03 }, + { 0x80f022, 0x0a }, + { 0x80f023, 0x0a }, + { 0x80f029, 0x8c }, + { 0x80f02a, 0x00 }, + { 0x80f02b, 0x00 }, + { 0x80f02c, 0x01 }, + { 0x80f064, 0x03 }, + { 0x80f065, 0xf9 }, + { 0x80f066, 0x03 }, + { 0x80f067, 0x01 }, + { 0x80f06f, 0xe0 }, + { 0x80f070, 0x03 }, + { 0x80f072, 0x0f }, + { 0x80f073, 0x03 }, + { 0x80f077, 0x01 }, + { 0x80f078, 0x00 }, + { 0x80f085, 0xc0 }, + { 0x80f086, 0x01 }, + { 0x80f087, 0x00 }, + { 0x80f09b, 0x3f }, + { 0x80f09c, 0x00 }, + { 0x80f09d, 0x20 }, + { 0x80f09e, 0x00 }, + { 0x80f09f, 0x0c }, + { 0x80f0a0, 0x00 }, + { 0x80f130, 0x04 }, + { 0x80f132, 0x04 }, + { 0x80f144, 0x1a }, + { 0x80f146, 0x00 }, + { 0x80f14a, 0x01 }, + { 0x80f14c, 0x00 }, + { 0x80f14d, 0x00 }, + { 0x80f14f, 0x04 }, + { 0x80f158, 0x7f }, + { 0x80f15a, 0x00 }, + { 0x80f15b, 0x08 }, + { 0x80f15d, 0x03 }, + { 0x80f15e, 0x05 }, + { 0x80f163, 0x05 }, + { 0x80f166, 0x01 }, + { 0x80f167, 0x40 }, + { 0x80f168, 0x0f }, + { 0x80f17a, 0x00 }, + { 0x80f17b, 0x00 }, + { 0x80f183, 0x01 }, + { 0x80f19d, 0x40 }, + { 0x80f1bc, 0x36 }, + { 0x80f1bd, 0x00 }, + { 0x80f1cb, 0xa0 }, + { 0x80f1cc, 0x01 }, + { 0x80f204, 0x10 }, + { 0x80f214, 0x00 }, + { 0x80f24c, 0x88 }, + { 0x80f24d, 0x95 }, + { 0x80f24e, 0x9a }, + { 0x80f24f, 0x90 }, + { 0x80f25a, 0x07 }, + { 0x80f25b, 0xe8 }, + { 0x80f25c, 0x03 }, + { 0x80f25d, 0xb0 }, + { 0x80f25e, 0x04 }, + { 0x80f270, 0x01 }, + { 0x80f271, 0x02 }, + { 0x80f272, 0x01 }, + { 0x80f273, 0x02 }, + { 0x80f40e, 0x0a }, + { 0x80f40f, 0x40 }, + { 0x80f410, 0x08 }, + { 0x80f55f, 0x0a }, + { 0x80f561, 0x15 }, + { 0x80f562, 0x20 }, + { 0x80f5df, 0xfb }, + { 0x80f5e0, 0x00 }, + { 0x80f5e3, 0x09 }, + { 0x80f5e4, 0x01 }, + { 0x80f5e5, 0x01 }, + { 0x80f5f8, 0x01 }, + { 0x80f5fd, 0x01 }, + { 0x80f600, 0x05 }, + { 0x80f601, 0x08 }, + { 0x80f602, 0x0b }, + { 0x80f603, 0x0e }, + { 0x80f604, 0x11 }, + { 0x80f605, 0x14 }, + { 0x80f606, 0x17 }, + { 0x80f607, 0x1f }, + { 0x80f60e, 0x00 }, + { 0x80f60f, 0x04 }, + { 0x80f610, 0x32 }, + { 0x80f611, 0x10 }, + { 0x80f707, 0xfc }, + { 0x80f708, 0x00 }, + { 0x80f709, 0x37 }, + { 0x80f70a, 0x00 }, + { 0x80f78b, 0x01 }, + { 0x80f80f, 0x40 }, + { 0x80f810, 0x54 }, + { 0x80f811, 0x5a }, + { 0x80f905, 0x01 }, + { 0x80fb06, 0x03 }, + { 0x80fd8b, 0x00 }, +}; + static const struct reg_val ofsm_init_it9135_v2[] = { { 0x800051, 0x01 }, { 0x800070, 0x0a }, -- cgit v1.2.3 From 22d729f30e6ffa2c28a704377a5e6689f33b3095 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 21:29:05 -0300 Subject: [media] af9033: add IT9135 tuner config "52" init table Dumped out from the Windows driver version 12.07.06.1 Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 3 + drivers/media/dvb-frontends/af9033_priv.h | 217 ++++++++++++++++++++++++++++++ 2 files changed, 220 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index d6fc566669ea..920c8758c696 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -355,6 +355,9 @@ static int af9033_init(struct dvb_frontend *fe) init = tuner_init_it9135_51; break; case AF9033_TUNER_IT9135_52: + len = ARRAY_SIZE(tuner_init_it9135_52); + init = tuner_init_it9135_52; + break; case AF9033_TUNER_IT9135_60: case AF9033_TUNER_IT9135_61: case AF9033_TUNER_IT9135_62: diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h index 5e35ef6c5825..01844d5b1563 100644 --- a/drivers/media/dvb-frontends/af9033_priv.h +++ b/drivers/media/dvb-frontends/af9033_priv.h @@ -1092,6 +1092,223 @@ static const struct reg_val tuner_init_it9135_51[] = { { 0x80fd8b, 0x00 }, }; +/* ITE Tech IT9135 Omega LNA config 2 tuner init + AF9033_TUNER_IT9135_52 = 0x52 */ +static const struct reg_val tuner_init_it9135_52[] = { + { 0x800043, 0x00 }, + { 0x800046, 0x52 }, + { 0x800051, 0x01 }, + { 0x80005f, 0x00 }, + { 0x800060, 0x00 }, + { 0x800068, 0x10 }, + { 0x800070, 0x0a }, + { 0x800071, 0x05 }, + { 0x800072, 0x02 }, + { 0x800075, 0x8c }, + { 0x800076, 0x8c }, + { 0x800077, 0x8c }, + { 0x800078, 0xa0 }, + { 0x800079, 0x01 }, + { 0x80007e, 0x04 }, + { 0x80007f, 0x00 }, + { 0x800081, 0x0a }, + { 0x800082, 0x17 }, + { 0x800083, 0x03 }, + { 0x800084, 0x0a }, + { 0x800085, 0x03 }, + { 0x800086, 0xb3 }, + { 0x800087, 0x97 }, + { 0x800088, 0xc0 }, + { 0x800089, 0x9e }, + { 0x80008a, 0x01 }, + { 0x80008e, 0x01 }, + { 0x800092, 0x06 }, + { 0x800093, 0x00 }, + { 0x800094, 0x00 }, + { 0x800095, 0x00 }, + { 0x800096, 0x00 }, + { 0x800099, 0x01 }, + { 0x80009b, 0x3c }, + { 0x80009c, 0x28 }, + { 0x80009f, 0xe1 }, + { 0x8000a0, 0xcf }, + { 0x8000a3, 0x01 }, + { 0x8000a4, 0x5c }, + { 0x8000a5, 0x01 }, + { 0x8000a6, 0x01 }, + { 0x8000a9, 0x00 }, + { 0x8000aa, 0x01 }, + { 0x8000b0, 0x01 }, + { 0x8000b3, 0x02 }, + { 0x8000b4, 0x3c }, + { 0x8000b6, 0x14 }, + { 0x8000c0, 0x11 }, + { 0x8000c1, 0x00 }, + { 0x8000c2, 0x05 }, + { 0x8000c4, 0x00 }, + { 0x8000c6, 0x19 }, + { 0x8000c7, 0x00 }, + { 0x8000cc, 0x2e }, + { 0x8000cd, 0x51 }, + { 0x8000ce, 0x33 }, + { 0x8000f3, 0x05 }, + { 0x8000f4, 0x91 }, + { 0x8000f5, 0x8c }, + { 0x8000f8, 0x03 }, + { 0x8000f9, 0x06 }, + { 0x8000fa, 0x06 }, + { 0x8000fc, 0x03 }, + { 0x8000fd, 0x02 }, + { 0x8000fe, 0x02 }, + { 0x8000ff, 0x09 }, + { 0x800100, 0x50 }, + { 0x800101, 0x74 }, + { 0x800102, 0x77 }, + { 0x800103, 0x02 }, + { 0x800104, 0x02 }, + { 0x800105, 0xa4 }, + { 0x800106, 0x02 }, + { 0x800107, 0x6e }, + { 0x800109, 0x02 }, + { 0x800115, 0x0a }, + { 0x800116, 0x03 }, + { 0x800117, 0x02 }, + { 0x800118, 0x80 }, + { 0x80011a, 0xcd }, + { 0x80011b, 0x62 }, + { 0x80011c, 0xa4 }, + { 0x80011d, 0x8c }, + { 0x800122, 0x03 }, + { 0x800123, 0x18 }, + { 0x800124, 0x9e }, + { 0x800127, 0x00 }, + { 0x800128, 0x07 }, + { 0x80012a, 0x53 }, + { 0x80012b, 0x51 }, + { 0x80012c, 0x4e }, + { 0x80012d, 0x43 }, + { 0x800137, 0x00 }, + { 0x800138, 0x00 }, + { 0x800139, 0x07 }, + { 0x80013a, 0x00 }, + { 0x80013b, 0x06 }, + { 0x80013d, 0x00 }, + { 0x80013e, 0x01 }, + { 0x80013f, 0x5b }, + { 0x800140, 0xb6 }, + { 0x800141, 0x59 }, + { 0x80f000, 0x0f }, + { 0x80f016, 0x10 }, + { 0x80f017, 0x04 }, + { 0x80f018, 0x05 }, + { 0x80f019, 0x04 }, + { 0x80f01a, 0x05 }, + { 0x80f01f, 0x8c }, + { 0x80f020, 0x00 }, + { 0x80f021, 0x03 }, + { 0x80f022, 0x0a }, + { 0x80f023, 0x0a }, + { 0x80f029, 0x8c }, + { 0x80f02a, 0x00 }, + { 0x80f02b, 0x00 }, + { 0x80f02c, 0x01 }, + { 0x80f064, 0x03 }, + { 0x80f065, 0xf9 }, + { 0x80f066, 0x03 }, + { 0x80f067, 0x01 }, + { 0x80f06f, 0xe0 }, + { 0x80f070, 0x03 }, + { 0x80f072, 0x0f }, + { 0x80f073, 0x03 }, + { 0x80f077, 0x01 }, + { 0x80f078, 0x00 }, + { 0x80f085, 0xc0 }, + { 0x80f086, 0x01 }, + { 0x80f087, 0x00 }, + { 0x80f09b, 0x3f }, + { 0x80f09c, 0x00 }, + { 0x80f09d, 0x20 }, + { 0x80f09e, 0x00 }, + { 0x80f09f, 0x0c }, + { 0x80f0a0, 0x00 }, + { 0x80f130, 0x04 }, + { 0x80f132, 0x04 }, + { 0x80f144, 0x1a }, + { 0x80f146, 0x00 }, + { 0x80f14a, 0x01 }, + { 0x80f14c, 0x00 }, + { 0x80f14d, 0x00 }, + { 0x80f14f, 0x04 }, + { 0x80f158, 0x7f }, + { 0x80f15a, 0x00 }, + { 0x80f15b, 0x08 }, + { 0x80f15d, 0x03 }, + { 0x80f15e, 0x05 }, + { 0x80f163, 0x05 }, + { 0x80f166, 0x01 }, + { 0x80f167, 0x40 }, + { 0x80f168, 0x0f }, + { 0x80f17a, 0x00 }, + { 0x80f17b, 0x00 }, + { 0x80f183, 0x01 }, + { 0x80f19d, 0x40 }, + { 0x80f1bc, 0x36 }, + { 0x80f1bd, 0x00 }, + { 0x80f1cb, 0xa0 }, + { 0x80f1cc, 0x01 }, + { 0x80f204, 0x10 }, + { 0x80f214, 0x00 }, + { 0x80f24c, 0x88 }, + { 0x80f24d, 0x95 }, + { 0x80f24e, 0x9a }, + { 0x80f24f, 0x90 }, + { 0x80f25a, 0x07 }, + { 0x80f25b, 0xe8 }, + { 0x80f25c, 0x03 }, + { 0x80f25d, 0xb0 }, + { 0x80f25e, 0x04 }, + { 0x80f270, 0x01 }, + { 0x80f271, 0x02 }, + { 0x80f272, 0x01 }, + { 0x80f273, 0x02 }, + { 0x80f40e, 0x0a }, + { 0x80f40f, 0x40 }, + { 0x80f410, 0x08 }, + { 0x80f55f, 0x0a }, + { 0x80f561, 0x15 }, + { 0x80f562, 0x20 }, + { 0x80f5df, 0xfb }, + { 0x80f5e0, 0x00 }, + { 0x80f5e3, 0x09 }, + { 0x80f5e4, 0x01 }, + { 0x80f5e5, 0x01 }, + { 0x80f5f8, 0x01 }, + { 0x80f5fd, 0x01 }, + { 0x80f600, 0x05 }, + { 0x80f601, 0x08 }, + { 0x80f602, 0x0b }, + { 0x80f603, 0x0e }, + { 0x80f604, 0x11 }, + { 0x80f605, 0x14 }, + { 0x80f606, 0x17 }, + { 0x80f607, 0x1f }, + { 0x80f60e, 0x00 }, + { 0x80f60f, 0x04 }, + { 0x80f610, 0x32 }, + { 0x80f611, 0x10 }, + { 0x80f707, 0xfc }, + { 0x80f708, 0x00 }, + { 0x80f709, 0x37 }, + { 0x80f70a, 0x00 }, + { 0x80f78b, 0x01 }, + { 0x80f80f, 0x40 }, + { 0x80f810, 0x54 }, + { 0x80f811, 0x5a }, + { 0x80f905, 0x01 }, + { 0x80fb06, 0x03 }, + { 0x80fd8b, 0x00 }, +}; + static const struct reg_val ofsm_init_it9135_v2[] = { { 0x800051, 0x01 }, { 0x800070, 0x0a }, -- cgit v1.2.3 From a49f53a0802959f81a9576a9c0f5164214598422 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 21:38:00 -0300 Subject: [media] af9033: add IT9135 tuner config "60" init table Dumped out from the Windows driver version 12.07.06.1 Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 3 + drivers/media/dvb-frontends/af9033_priv.h | 215 ++++++++++++++++++++++++++++++ 2 files changed, 218 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 920c8758c696..9359dbd0ceb8 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -359,6 +359,9 @@ static int af9033_init(struct dvb_frontend *fe) init = tuner_init_it9135_52; break; case AF9033_TUNER_IT9135_60: + len = ARRAY_SIZE(tuner_init_it9135_60); + init = tuner_init_it9135_60; + break; case AF9033_TUNER_IT9135_61: case AF9033_TUNER_IT9135_62: len = 0; diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h index 01844d5b1563..3b4ff8b334c8 100644 --- a/drivers/media/dvb-frontends/af9033_priv.h +++ b/drivers/media/dvb-frontends/af9033_priv.h @@ -1407,5 +1407,220 @@ static const struct reg_val ofsm_init_it9135_v2[] = { { 0x80fd8b, 0x00 }, }; +/* ITE Tech IT9135 Omega v2 tuner init + AF9033_TUNER_IT9135_60 = 0x60 */ +static const struct reg_val tuner_init_it9135_60[] = { + { 0x800043, 0x00 }, + { 0x800046, 0x60 }, + { 0x800051, 0x01 }, + { 0x80005f, 0x00 }, + { 0x800060, 0x00 }, + { 0x800068, 0x0a }, + { 0x80006a, 0x03 }, + { 0x800070, 0x0a }, + { 0x800071, 0x05 }, + { 0x800072, 0x02 }, + { 0x800075, 0x8c }, + { 0x800076, 0x8c }, + { 0x800077, 0x8c }, + { 0x800078, 0x8c }, + { 0x800079, 0x01 }, + { 0x80007e, 0x04 }, + { 0x800081, 0x0a }, + { 0x800082, 0x18 }, + { 0x800084, 0x0a }, + { 0x800085, 0x33 }, + { 0x800086, 0xbe }, + { 0x800087, 0xa0 }, + { 0x800088, 0xc6 }, + { 0x800089, 0xb6 }, + { 0x80008a, 0x01 }, + { 0x80008e, 0x01 }, + { 0x800092, 0x06 }, + { 0x800093, 0x00 }, + { 0x800094, 0x00 }, + { 0x800095, 0x00 }, + { 0x800096, 0x00 }, + { 0x800099, 0x01 }, + { 0x80009b, 0x3c }, + { 0x80009c, 0x28 }, + { 0x80009f, 0xe1 }, + { 0x8000a0, 0xcf }, + { 0x8000a3, 0x01 }, + { 0x8000a4, 0x5a }, + { 0x8000a5, 0x01 }, + { 0x8000a6, 0x01 }, + { 0x8000a9, 0x00 }, + { 0x8000aa, 0x01 }, + { 0x8000b0, 0x01 }, + { 0x8000b3, 0x02 }, + { 0x8000b4, 0x3a }, + { 0x8000b6, 0x14 }, + { 0x8000c0, 0x11 }, + { 0x8000c1, 0x00 }, + { 0x8000c2, 0x05 }, + { 0x8000c3, 0x01 }, + { 0x8000c4, 0x00 }, + { 0x8000c6, 0x19 }, + { 0x8000c7, 0x00 }, + { 0x8000cb, 0x32 }, + { 0x8000cc, 0x2c }, + { 0x8000cd, 0x4f }, + { 0x8000ce, 0x30 }, + { 0x8000f3, 0x05 }, + { 0x8000f4, 0xa0 }, + { 0x8000f5, 0x8c }, + { 0x8000f8, 0x03 }, + { 0x8000f9, 0x06 }, + { 0x8000fa, 0x06 }, + { 0x8000fc, 0x03 }, + { 0x8000fd, 0x03 }, + { 0x8000fe, 0x02 }, + { 0x8000ff, 0x0a }, + { 0x800100, 0x50 }, + { 0x800101, 0x7b }, + { 0x800102, 0x8c }, + { 0x800103, 0x00 }, + { 0x800104, 0x02 }, + { 0x800105, 0xbe }, + { 0x800106, 0x00 }, + { 0x800109, 0x02 }, + { 0x800115, 0x0a }, + { 0x800116, 0x03 }, + { 0x80011a, 0xbe }, + { 0x800124, 0xae }, + { 0x800127, 0x00 }, + { 0x80012a, 0x56 }, + { 0x80012b, 0x50 }, + { 0x80012c, 0x47 }, + { 0x80012d, 0x42 }, + { 0x800137, 0x00 }, + { 0x80013b, 0x08 }, + { 0x80013f, 0x5b }, + { 0x800141, 0x59 }, + { 0x800142, 0xf9 }, + { 0x800143, 0x19 }, + { 0x800144, 0x00 }, + { 0x800145, 0x8c }, + { 0x800146, 0x8c }, + { 0x800147, 0x8c }, + { 0x800148, 0x6e }, + { 0x800149, 0x8c }, + { 0x80014a, 0x50 }, + { 0x80014b, 0x8c }, + { 0x80014d, 0xac }, + { 0x80014e, 0xc6 }, + { 0x80014f, 0x03 }, + { 0x800151, 0x1e }, + { 0x800153, 0xbc }, + { 0x800178, 0x09 }, + { 0x800181, 0x94 }, + { 0x800182, 0x6e }, + { 0x800185, 0x24 }, + { 0x800189, 0xbe }, + { 0x80018c, 0x03 }, + { 0x80018d, 0x5f }, + { 0x80018f, 0xa0 }, + { 0x800190, 0x5a }, + { 0x80ed02, 0xff }, + { 0x80ee42, 0xff }, + { 0x80ee82, 0xff }, + { 0x80f000, 0x0f }, + { 0x80f01f, 0x8c }, + { 0x80f020, 0x00 }, + { 0x80f029, 0x8c }, + { 0x80f02a, 0x00 }, + { 0x80f02b, 0x00 }, + { 0x80f064, 0x03 }, + { 0x80f065, 0xf9 }, + { 0x80f066, 0x03 }, + { 0x80f067, 0x01 }, + { 0x80f06f, 0xe0 }, + { 0x80f070, 0x03 }, + { 0x80f072, 0x0f }, + { 0x80f073, 0x03 }, + { 0x80f077, 0x01 }, + { 0x80f078, 0x00 }, + { 0x80f087, 0x00 }, + { 0x80f09b, 0x3f }, + { 0x80f09c, 0x00 }, + { 0x80f09d, 0x20 }, + { 0x80f09e, 0x00 }, + { 0x80f09f, 0x0c }, + { 0x80f0a0, 0x00 }, + { 0x80f130, 0x04 }, + { 0x80f132, 0x04 }, + { 0x80f144, 0x1a }, + { 0x80f146, 0x00 }, + { 0x80f14a, 0x01 }, + { 0x80f14c, 0x00 }, + { 0x80f14d, 0x00 }, + { 0x80f14f, 0x04 }, + { 0x80f158, 0x7f }, + { 0x80f15a, 0x00 }, + { 0x80f15b, 0x08 }, + { 0x80f15d, 0x03 }, + { 0x80f15e, 0x05 }, + { 0x80f163, 0x05 }, + { 0x80f166, 0x01 }, + { 0x80f167, 0x40 }, + { 0x80f168, 0x0f }, + { 0x80f17a, 0x00 }, + { 0x80f17b, 0x00 }, + { 0x80f183, 0x01 }, + { 0x80f19d, 0x40 }, + { 0x80f1bc, 0x36 }, + { 0x80f1bd, 0x00 }, + { 0x80f1cb, 0xa0 }, + { 0x80f1cc, 0x01 }, + { 0x80f204, 0x10 }, + { 0x80f214, 0x00 }, + { 0x80f24c, 0x88 }, + { 0x80f24d, 0x95 }, + { 0x80f24e, 0x9a }, + { 0x80f24f, 0x90 }, + { 0x80f25a, 0x07 }, + { 0x80f25b, 0xe8 }, + { 0x80f25c, 0x03 }, + { 0x80f25d, 0xb0 }, + { 0x80f25e, 0x04 }, + { 0x80f270, 0x01 }, + { 0x80f271, 0x02 }, + { 0x80f272, 0x01 }, + { 0x80f273, 0x02 }, + { 0x80f40e, 0x0a }, + { 0x80f40f, 0x40 }, + { 0x80f410, 0x08 }, + { 0x80f55f, 0x0a }, + { 0x80f561, 0x15 }, + { 0x80f562, 0x20 }, + { 0x80f5e3, 0x09 }, + { 0x80f5e4, 0x01 }, + { 0x80f5e5, 0x01 }, + { 0x80f600, 0x05 }, + { 0x80f601, 0x08 }, + { 0x80f602, 0x0b }, + { 0x80f603, 0x0e }, + { 0x80f604, 0x11 }, + { 0x80f605, 0x14 }, + { 0x80f606, 0x17 }, + { 0x80f607, 0x1f }, + { 0x80f60e, 0x00 }, + { 0x80f60f, 0x04 }, + { 0x80f610, 0x32 }, + { 0x80f611, 0x10 }, + { 0x80f707, 0xfc }, + { 0x80f708, 0x00 }, + { 0x80f709, 0x37 }, + { 0x80f70a, 0x00 }, + { 0x80f78b, 0x01 }, + { 0x80f80f, 0x40 }, + { 0x80f810, 0x54 }, + { 0x80f811, 0x5a }, + { 0x80f905, 0x01 }, + { 0x80fb06, 0x03 }, + { 0x80fd8b, 0x00 }, +}; + #endif /* AF9033_PRIV_H */ -- cgit v1.2.3 From 85211323fa61d1eb9171e0cb6a9ca48490d03aaf Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 21:44:30 -0300 Subject: [media] af9033: add IT9135 tuner config "61" init table Dumped out from the Windows driver version 12.07.06.1 Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 3 + drivers/media/dvb-frontends/af9033_priv.h | 216 +++++++++++++++++++++++++++++- 2 files changed, 218 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 9359dbd0ceb8..c3c3a6d38a25 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -363,6 +363,9 @@ static int af9033_init(struct dvb_frontend *fe) init = tuner_init_it9135_60; break; case AF9033_TUNER_IT9135_61: + len = ARRAY_SIZE(tuner_init_it9135_61); + init = tuner_init_it9135_61; + break; case AF9033_TUNER_IT9135_62: len = 0; break; diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h index 3b4ff8b334c8..4a78b66b03dc 100644 --- a/drivers/media/dvb-frontends/af9033_priv.h +++ b/drivers/media/dvb-frontends/af9033_priv.h @@ -1622,5 +1622,219 @@ static const struct reg_val tuner_init_it9135_60[] = { { 0x80fd8b, 0x00 }, }; -#endif /* AF9033_PRIV_H */ +/* ITE Tech IT9135 Omega v2 LNA config 1 tuner init + AF9033_TUNER_IT9135_61 = 0x61 */ +static const struct reg_val tuner_init_it9135_61[] = { + { 0x800043, 0x00 }, + { 0x800046, 0x61 }, + { 0x800051, 0x01 }, + { 0x80005f, 0x00 }, + { 0x800060, 0x00 }, + { 0x800068, 0x06 }, + { 0x80006a, 0x03 }, + { 0x800070, 0x0a }, + { 0x800071, 0x05 }, + { 0x800072, 0x02 }, + { 0x800075, 0x8c }, + { 0x800076, 0x8c }, + { 0x800077, 0x8c }, + { 0x800078, 0x90 }, + { 0x800079, 0x01 }, + { 0x80007e, 0x04 }, + { 0x800081, 0x0a }, + { 0x800082, 0x12 }, + { 0x800084, 0x0a }, + { 0x800085, 0x33 }, + { 0x800086, 0xbc }, + { 0x800087, 0x9c }, + { 0x800088, 0xcc }, + { 0x800089, 0xa8 }, + { 0x80008a, 0x01 }, + { 0x80008e, 0x01 }, + { 0x800092, 0x06 }, + { 0x800093, 0x00 }, + { 0x800094, 0x00 }, + { 0x800095, 0x00 }, + { 0x800096, 0x00 }, + { 0x800099, 0x01 }, + { 0x80009b, 0x3c }, + { 0x80009c, 0x28 }, + { 0x80009f, 0xe1 }, + { 0x8000a0, 0xcf }, + { 0x8000a3, 0x01 }, + { 0x8000a4, 0x5c }, + { 0x8000a5, 0x01 }, + { 0x8000a6, 0x01 }, + { 0x8000a9, 0x00 }, + { 0x8000aa, 0x01 }, + { 0x8000b0, 0x01 }, + { 0x8000b3, 0x02 }, + { 0x8000b4, 0x3a }, + { 0x8000b6, 0x14 }, + { 0x8000c0, 0x11 }, + { 0x8000c1, 0x00 }, + { 0x8000c2, 0x05 }, + { 0x8000c3, 0x01 }, + { 0x8000c4, 0x00 }, + { 0x8000c6, 0x19 }, + { 0x8000c7, 0x00 }, + { 0x8000cb, 0x32 }, + { 0x8000cc, 0x2c }, + { 0x8000cd, 0x4f }, + { 0x8000ce, 0x30 }, + { 0x8000f3, 0x05 }, + { 0x8000f4, 0xa0 }, + { 0x8000f5, 0x8c }, + { 0x8000f8, 0x03 }, + { 0x8000f9, 0x06 }, + { 0x8000fa, 0x06 }, + { 0x8000fc, 0x03 }, + { 0x8000fd, 0x03 }, + { 0x8000fe, 0x02 }, + { 0x8000ff, 0x08 }, + { 0x800100, 0x50 }, + { 0x800101, 0x7b }, + { 0x800102, 0x8c }, + { 0x800103, 0x01 }, + { 0x800104, 0x02 }, + { 0x800105, 0xc8 }, + { 0x800106, 0x00 }, + { 0x800109, 0x02 }, + { 0x800115, 0x0a }, + { 0x800116, 0x03 }, + { 0x80011a, 0xc6 }, + { 0x800124, 0xa8 }, + { 0x800127, 0x00 }, + { 0x80012a, 0x59 }, + { 0x80012b, 0x50 }, + { 0x80012c, 0x47 }, + { 0x80012d, 0x42 }, + { 0x800137, 0x00 }, + { 0x80013b, 0x05 }, + { 0x80013f, 0x5b }, + { 0x800141, 0x59 }, + { 0x800142, 0xf9 }, + { 0x800143, 0x59 }, + { 0x800144, 0x01 }, + { 0x800145, 0x8c }, + { 0x800146, 0x8c }, + { 0x800147, 0x8c }, + { 0x800148, 0x7b }, + { 0x800149, 0x8c }, + { 0x80014a, 0x50 }, + { 0x80014b, 0x8c }, + { 0x80014d, 0xa8 }, + { 0x80014e, 0xc6 }, + { 0x80014f, 0x03 }, + { 0x800151, 0x28 }, + { 0x800153, 0xcc }, + { 0x800178, 0x09 }, + { 0x800181, 0x9c }, + { 0x800182, 0x76 }, + { 0x800185, 0x28 }, + { 0x800189, 0xaa }, + { 0x80018c, 0x03 }, + { 0x80018d, 0x5f }, + { 0x80018f, 0xfb }, + { 0x800190, 0x5c }, + { 0x80ed02, 0xff }, + { 0x80ee42, 0xff }, + { 0x80ee82, 0xff }, + { 0x80f000, 0x0f }, + { 0x80f01f, 0x8c }, + { 0x80f020, 0x00 }, + { 0x80f029, 0x8c }, + { 0x80f02a, 0x00 }, + { 0x80f02b, 0x00 }, + { 0x80f064, 0x03 }, + { 0x80f065, 0xf9 }, + { 0x80f066, 0x03 }, + { 0x80f067, 0x01 }, + { 0x80f06f, 0xe0 }, + { 0x80f070, 0x03 }, + { 0x80f072, 0x0f }, + { 0x80f073, 0x03 }, + { 0x80f077, 0x01 }, + { 0x80f078, 0x00 }, + { 0x80f087, 0x00 }, + { 0x80f09b, 0x3f }, + { 0x80f09c, 0x00 }, + { 0x80f09d, 0x20 }, + { 0x80f09e, 0x00 }, + { 0x80f09f, 0x0c }, + { 0x80f0a0, 0x00 }, + { 0x80f130, 0x04 }, + { 0x80f132, 0x04 }, + { 0x80f144, 0x1a }, + { 0x80f146, 0x00 }, + { 0x80f14a, 0x01 }, + { 0x80f14c, 0x00 }, + { 0x80f14d, 0x00 }, + { 0x80f14f, 0x04 }, + { 0x80f158, 0x7f }, + { 0x80f15a, 0x00 }, + { 0x80f15b, 0x08 }, + { 0x80f15d, 0x03 }, + { 0x80f15e, 0x05 }, + { 0x80f163, 0x05 }, + { 0x80f166, 0x01 }, + { 0x80f167, 0x40 }, + { 0x80f168, 0x0f }, + { 0x80f17a, 0x00 }, + { 0x80f17b, 0x00 }, + { 0x80f183, 0x01 }, + { 0x80f19d, 0x40 }, + { 0x80f1bc, 0x36 }, + { 0x80f1bd, 0x00 }, + { 0x80f1cb, 0xa0 }, + { 0x80f1cc, 0x01 }, + { 0x80f204, 0x10 }, + { 0x80f214, 0x00 }, + { 0x80f24c, 0x88 }, + { 0x80f24d, 0x95 }, + { 0x80f24e, 0x9a }, + { 0x80f24f, 0x90 }, + { 0x80f25a, 0x07 }, + { 0x80f25b, 0xe8 }, + { 0x80f25c, 0x03 }, + { 0x80f25d, 0xb0 }, + { 0x80f25e, 0x04 }, + { 0x80f270, 0x01 }, + { 0x80f271, 0x02 }, + { 0x80f272, 0x01 }, + { 0x80f273, 0x02 }, + { 0x80f40e, 0x0a }, + { 0x80f40f, 0x40 }, + { 0x80f410, 0x08 }, + { 0x80f55f, 0x0a }, + { 0x80f561, 0x15 }, + { 0x80f562, 0x20 }, + { 0x80f5e3, 0x09 }, + { 0x80f5e4, 0x01 }, + { 0x80f5e5, 0x01 }, + { 0x80f600, 0x05 }, + { 0x80f601, 0x08 }, + { 0x80f602, 0x0b }, + { 0x80f603, 0x0e }, + { 0x80f604, 0x11 }, + { 0x80f605, 0x14 }, + { 0x80f606, 0x17 }, + { 0x80f607, 0x1f }, + { 0x80f60e, 0x00 }, + { 0x80f60f, 0x04 }, + { 0x80f610, 0x32 }, + { 0x80f611, 0x10 }, + { 0x80f707, 0xfc }, + { 0x80f708, 0x00 }, + { 0x80f709, 0x37 }, + { 0x80f70a, 0x00 }, + { 0x80f78b, 0x01 }, + { 0x80f80f, 0x40 }, + { 0x80f810, 0x54 }, + { 0x80f811, 0x5a }, + { 0x80f905, 0x01 }, + { 0x80fb06, 0x03 }, + { 0x80fd8b, 0x00 }, +}; +#endif /* AF9033_PRIV_H */ -- cgit v1.2.3 From dc4a2c40f87327c5859edc20a5b6b2afa6071d49 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 21:47:20 -0300 Subject: [media] af9033: add IT9135 tuner config "62" init table Dumped out from the Windows driver version 12.07.06.1 Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 3 +- drivers/media/dvb-frontends/af9033_priv.h | 215 ++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index c3c3a6d38a25..847a9b6d3dcf 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -367,7 +367,8 @@ static int af9033_init(struct dvb_frontend *fe) init = tuner_init_it9135_61; break; case AF9033_TUNER_IT9135_62: - len = 0; + len = ARRAY_SIZE(tuner_init_it9135_62); + init = tuner_init_it9135_62; break; default: dev_dbg(&state->i2c->dev, "%s: unsupported tuner ID=%d\n", diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h index 4a78b66b03dc..fc2ad581e302 100644 --- a/drivers/media/dvb-frontends/af9033_priv.h +++ b/drivers/media/dvb-frontends/af9033_priv.h @@ -1837,4 +1837,219 @@ static const struct reg_val tuner_init_it9135_61[] = { { 0x80fd8b, 0x00 }, }; +/* ITE Tech IT9135 Omega v2 LNA config 2 tuner init + AF9033_TUNER_IT9135_62 = 0x62 */ +static const struct reg_val tuner_init_it9135_62[] = { + { 0x800043, 0x00 }, + { 0x800046, 0x62 }, + { 0x800051, 0x01 }, + { 0x80005f, 0x00 }, + { 0x800060, 0x00 }, + { 0x800068, 0x0a }, + { 0x80006a, 0x03 }, + { 0x800070, 0x0a }, + { 0x800071, 0x05 }, + { 0x800072, 0x02 }, + { 0x800075, 0x8c }, + { 0x800076, 0x8c }, + { 0x800077, 0x8c }, + { 0x800078, 0x8c }, + { 0x800079, 0x01 }, + { 0x80007e, 0x04 }, + { 0x800081, 0x0a }, + { 0x800082, 0x12 }, + { 0x800084, 0x0a }, + { 0x800085, 0x33 }, + { 0x800086, 0xb8 }, + { 0x800087, 0x9c }, + { 0x800088, 0xb2 }, + { 0x800089, 0xa6 }, + { 0x80008a, 0x01 }, + { 0x80008e, 0x01 }, + { 0x800092, 0x06 }, + { 0x800093, 0x00 }, + { 0x800094, 0x00 }, + { 0x800095, 0x00 }, + { 0x800096, 0x00 }, + { 0x800099, 0x01 }, + { 0x80009b, 0x3c }, + { 0x80009c, 0x28 }, + { 0x80009f, 0xe1 }, + { 0x8000a0, 0xcf }, + { 0x8000a3, 0x01 }, + { 0x8000a4, 0x5a }, + { 0x8000a5, 0x01 }, + { 0x8000a6, 0x01 }, + { 0x8000a9, 0x00 }, + { 0x8000aa, 0x01 }, + { 0x8000b0, 0x01 }, + { 0x8000b3, 0x02 }, + { 0x8000b4, 0x3a }, + { 0x8000b6, 0x14 }, + { 0x8000c0, 0x11 }, + { 0x8000c1, 0x00 }, + { 0x8000c2, 0x05 }, + { 0x8000c3, 0x01 }, + { 0x8000c4, 0x00 }, + { 0x8000c6, 0x19 }, + { 0x8000c7, 0x00 }, + { 0x8000cb, 0x32 }, + { 0x8000cc, 0x2c }, + { 0x8000cd, 0x4f }, + { 0x8000ce, 0x30 }, + { 0x8000f3, 0x05 }, + { 0x8000f4, 0x8c }, + { 0x8000f5, 0x8c }, + { 0x8000f8, 0x03 }, + { 0x8000f9, 0x06 }, + { 0x8000fa, 0x06 }, + { 0x8000fc, 0x02 }, + { 0x8000fd, 0x03 }, + { 0x8000fe, 0x02 }, + { 0x8000ff, 0x09 }, + { 0x800100, 0x50 }, + { 0x800101, 0x6e }, + { 0x800102, 0x8c }, + { 0x800103, 0x02 }, + { 0x800104, 0x02 }, + { 0x800105, 0xc2 }, + { 0x800106, 0x00 }, + { 0x800109, 0x02 }, + { 0x800115, 0x0a }, + { 0x800116, 0x03 }, + { 0x80011a, 0xb8 }, + { 0x800124, 0xa8 }, + { 0x800127, 0x00 }, + { 0x80012a, 0x53 }, + { 0x80012b, 0x51 }, + { 0x80012c, 0x4e }, + { 0x80012d, 0x43 }, + { 0x800137, 0x00 }, + { 0x80013b, 0x05 }, + { 0x80013f, 0x5b }, + { 0x800141, 0x59 }, + { 0x800142, 0xf9 }, + { 0x800143, 0x59 }, + { 0x800144, 0x00 }, + { 0x800145, 0x8c }, + { 0x800146, 0x8c }, + { 0x800147, 0x8c }, + { 0x800148, 0x7b }, + { 0x800149, 0x8c }, + { 0x80014a, 0x50 }, + { 0x80014b, 0x70 }, + { 0x80014d, 0x96 }, + { 0x80014e, 0xd0 }, + { 0x80014f, 0x03 }, + { 0x800151, 0x28 }, + { 0x800153, 0xb2 }, + { 0x800178, 0x09 }, + { 0x800181, 0x9c }, + { 0x800182, 0x6e }, + { 0x800185, 0x24 }, + { 0x800189, 0xb8 }, + { 0x80018c, 0x03 }, + { 0x80018d, 0x5f }, + { 0x80018f, 0xfb }, + { 0x800190, 0x5a }, + { 0x80ed02, 0xff }, + { 0x80ee42, 0xff }, + { 0x80ee82, 0xff }, + { 0x80f000, 0x0f }, + { 0x80f01f, 0x8c }, + { 0x80f020, 0x00 }, + { 0x80f029, 0x8c }, + { 0x80f02a, 0x00 }, + { 0x80f02b, 0x00 }, + { 0x80f064, 0x03 }, + { 0x80f065, 0xf9 }, + { 0x80f066, 0x03 }, + { 0x80f067, 0x01 }, + { 0x80f06f, 0xe0 }, + { 0x80f070, 0x03 }, + { 0x80f072, 0x0f }, + { 0x80f073, 0x03 }, + { 0x80f077, 0x01 }, + { 0x80f078, 0x00 }, + { 0x80f087, 0x00 }, + { 0x80f09b, 0x3f }, + { 0x80f09c, 0x00 }, + { 0x80f09d, 0x20 }, + { 0x80f09e, 0x00 }, + { 0x80f09f, 0x0c }, + { 0x80f0a0, 0x00 }, + { 0x80f130, 0x04 }, + { 0x80f132, 0x04 }, + { 0x80f144, 0x1a }, + { 0x80f146, 0x00 }, + { 0x80f14a, 0x01 }, + { 0x80f14c, 0x00 }, + { 0x80f14d, 0x00 }, + { 0x80f14f, 0x04 }, + { 0x80f158, 0x7f }, + { 0x80f15a, 0x00 }, + { 0x80f15b, 0x08 }, + { 0x80f15d, 0x03 }, + { 0x80f15e, 0x05 }, + { 0x80f163, 0x05 }, + { 0x80f166, 0x01 }, + { 0x80f167, 0x40 }, + { 0x80f168, 0x0f }, + { 0x80f17a, 0x00 }, + { 0x80f17b, 0x00 }, + { 0x80f183, 0x01 }, + { 0x80f19d, 0x40 }, + { 0x80f1bc, 0x36 }, + { 0x80f1bd, 0x00 }, + { 0x80f1cb, 0xa0 }, + { 0x80f1cc, 0x01 }, + { 0x80f204, 0x10 }, + { 0x80f214, 0x00 }, + { 0x80f24c, 0x88 }, + { 0x80f24d, 0x95 }, + { 0x80f24e, 0x9a }, + { 0x80f24f, 0x90 }, + { 0x80f25a, 0x07 }, + { 0x80f25b, 0xe8 }, + { 0x80f25c, 0x03 }, + { 0x80f25d, 0xb0 }, + { 0x80f25e, 0x04 }, + { 0x80f270, 0x01 }, + { 0x80f271, 0x02 }, + { 0x80f272, 0x01 }, + { 0x80f273, 0x02 }, + { 0x80f40e, 0x0a }, + { 0x80f40f, 0x40 }, + { 0x80f410, 0x08 }, + { 0x80f55f, 0x0a }, + { 0x80f561, 0x15 }, + { 0x80f562, 0x20 }, + { 0x80f5e3, 0x09 }, + { 0x80f5e4, 0x01 }, + { 0x80f5e5, 0x01 }, + { 0x80f600, 0x05 }, + { 0x80f601, 0x08 }, + { 0x80f602, 0x0b }, + { 0x80f603, 0x0e }, + { 0x80f604, 0x11 }, + { 0x80f605, 0x14 }, + { 0x80f606, 0x17 }, + { 0x80f607, 0x1f }, + { 0x80f60e, 0x00 }, + { 0x80f60f, 0x04 }, + { 0x80f610, 0x32 }, + { 0x80f611, 0x10 }, + { 0x80f707, 0xfc }, + { 0x80f708, 0x00 }, + { 0x80f709, 0x37 }, + { 0x80f70a, 0x00 }, + { 0x80f78b, 0x01 }, + { 0x80f80f, 0x40 }, + { 0x80f810, 0x54 }, + { 0x80f811, 0x5a }, + { 0x80f905, 0x01 }, + { 0x80fb06, 0x03 }, + { 0x80fd8b, 0x00 }, +}; + #endif /* AF9033_PRIV_H */ -- cgit v1.2.3 From d423e108c1d6ced41964fafc97c02e4b5d0597a1 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 21:59:41 -0300 Subject: [media] it913x: remove unused af9033 demod tuner config inits Those are demodulator init tables according to used tuner tuner config. af9033 demod driver does those inits currently and due to that these duplicate inits could be removed. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 6 - drivers/media/tuners/it913x.c | 30 -- drivers/media/tuners/it913x_priv.h | 558 ----------------------------------- 3 files changed, 594 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 847a9b6d3dcf..032074708d73 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -285,12 +285,6 @@ static int af9033_init(struct dvb_frontend *fe) goto err; } - /* - * FIXME: These inits are logically property of demodulator driver - * (that driver), but currently in case of IT9135 those are done by - * tuner driver. - */ - /* load OFSM settings */ dev_dbg(&state->i2c->dev, "%s: load ofsm settings\n", __func__); switch (state->cfg.tuner) { diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index ec4964ce8a58..2c60bf77ebfc 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -141,40 +141,10 @@ static int it913x_init(struct dvb_frontend *fe) { struct it913x_state *state = fe->tuner_priv; int ret, i, reg; - struct it913xset *set_lna; u8 val, nv_val; u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; u8 b[2]; - /* LNA Scripts */ - switch (state->tuner_type) { - case AF9033_TUNER_IT9135_51: - set_lna = it9135_51; - break; - case AF9033_TUNER_IT9135_52: - set_lna = it9135_52; - break; - case AF9033_TUNER_IT9135_60: - set_lna = it9135_60; - break; - case AF9033_TUNER_IT9135_61: - set_lna = it9135_61; - break; - case AF9033_TUNER_IT9135_62: - set_lna = it9135_62; - break; - case AF9033_TUNER_IT9135_38: - default: - set_lna = it9135_38; - } - - dev_dbg(&state->i2c_adap->dev, "%s: Tuner LNA type :%02x\n", - KBUILD_MODNAME, state->tuner_type); - - ret = it913x_script_loader(state, set_lna); - if (ret < 0) - return ret; - if (state->chip_ver == 2) { ret = it913x_wr_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1); if (ret < 0) diff --git a/drivers/media/tuners/it913x_priv.h b/drivers/media/tuners/it913x_priv.h index 7d0e29268a0b..00dcf3c27888 100644 --- a/drivers/media/tuners/it913x_priv.h +++ b/drivers/media/tuners/it913x_priv.h @@ -36,564 +36,6 @@ struct it913xset { u32 pro; u8 count; }; -/* Version 1 types */ -static struct it913xset it9135_38[] = { - {PRO_DMOD, 0x0043, {0x00}, 0x01}, - {PRO_DMOD, 0x0046, {0x38}, 0x01}, - {PRO_DMOD, 0x0051, {0x01}, 0x01}, - {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0x0068, {0x0a}, 0x01}, - {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, - {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05}, - {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02}, - {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc8, 0xb8, - 0xd0, 0xc3, 0x01}, 0x0a}, - {PRO_DMOD, 0x008e, {0x01}, 0x01}, - {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, - {PRO_DMOD, 0x0099, {0x01}, 0x01}, - {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, - {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, - {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, - {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, - {PRO_DMOD, 0x00b0, {0x01}, 0x01}, - {PRO_DMOD, 0x00b3, {0x02, 0x32}, 0x02}, - {PRO_DMOD, 0x00b6, {0x14}, 0x01}, - {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03}, - {PRO_DMOD, 0x00c4, {0x00}, 0x01}, - {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, - {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03}, - {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03}, - {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, - {PRO_DMOD, 0x00fc, { 0x02, 0x02, 0x02, 0x09, 0x50, 0x7b, 0x77, - 0x00, 0x02, 0xc8, 0x05, 0x7b}, 0x0c}, - {PRO_DMOD, 0x0109, {0x02}, 0x01}, - {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04}, - {PRO_DMOD, 0x011a, {0xc8, 0x7b, 0x8a, 0xa0}, 0x04}, - {PRO_DMOD, 0x0122, {0x02, 0x18, 0xc3}, 0x03}, - {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02}, - {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, - {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05}, - {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc8, 0x59}, 0x05}, - {PRO_DMOD, 0xf000, {0x0f}, 0x01}, - {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05}, - {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05}, - {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04}, - {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, - {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, - {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, - {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, - {PRO_DMOD, 0xf085, {0x00, 0x02, 0x00}, 0x03}, - {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, - {PRO_DMOD, 0xf130, {0x04}, 0x01}, - {PRO_DMOD, 0xf132, {0x04}, 0x01}, - {PRO_DMOD, 0xf144, {0x1a}, 0x01}, - {PRO_DMOD, 0xf146, {0x00}, 0x01}, - {PRO_DMOD, 0xf14a, {0x01}, 0x01}, - {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0xf14f, {0x04}, 0x01}, - {PRO_DMOD, 0xf158, {0x7f}, 0x01}, - {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, - {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, - {PRO_DMOD, 0xf163, {0x05}, 0x01}, - {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, - {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0xf183, {0x01}, 0x01}, - {PRO_DMOD, 0xf19d, {0x40}, 0x01}, - {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, - {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, - {PRO_DMOD, 0xf204, {0x10}, 0x01}, - {PRO_DMOD, 0xf214, {0x00}, 0x01}, - {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, - {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, - {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, - {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, - {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, - {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, - {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02}, - {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, - {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, - {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, - {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, - 0x1f}, 0x08}, - {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, - {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, - {PRO_DMOD, 0xf78b, {0x01}, 0x01}, - {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, - {PRO_DMOD, 0xf905, {0x01}, 0x01}, - {PRO_DMOD, 0xfb06, {0x03}, 0x01}, - {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ -}; - -static struct it913xset it9135_51[] = { - {PRO_DMOD, 0x0043, {0x00}, 0x01}, - {PRO_DMOD, 0x0046, {0x51}, 0x01}, - {PRO_DMOD, 0x0051, {0x01}, 0x01}, - {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0x0068, {0x0a}, 0x01}, - {PRO_DMOD, 0x0070, {0x0a, 0x06, 0x02}, 0x03}, - {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xc8, 0x01}, 0x05}, - {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02}, - {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x02, 0x0a, 0x03, 0xc0, 0x96, - 0xcf, 0xc3, 0x01}, 0x0a}, - {PRO_DMOD, 0x008e, {0x01}, 0x01}, - {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, - {PRO_DMOD, 0x0099, {0x01}, 0x01}, - {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, - {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, - {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, - {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, - {PRO_DMOD, 0x00b0, {0x01}, 0x01}, - {PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02}, - {PRO_DMOD, 0x00b6, {0x14}, 0x01}, - {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03}, - {PRO_DMOD, 0x00c4, {0x00}, 0x01}, - {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, - {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03}, - {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03}, - {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, - {PRO_DMOD, 0x00fc, { 0x03, 0x02, 0x02, 0x09, 0x50, 0x7a, 0x77, - 0x01, 0x02, 0xb0, 0x02, 0x7a}, 0x0c}, - {PRO_DMOD, 0x0109, {0x02}, 0x01}, - {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04}, - {PRO_DMOD, 0x011a, {0xc0, 0x7a, 0xac, 0x8c}, 0x04}, - {PRO_DMOD, 0x0122, {0x02, 0x70, 0xa4}, 0x03}, - {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02}, - {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, - {PRO_DMOD, 0x0137, {0x01, 0x00, 0x07, 0x00, 0x06}, 0x05}, - {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xc0, 0x59}, 0x05}, - {PRO_DMOD, 0xf000, {0x0f}, 0x01}, - {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05}, - {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05}, - {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04}, - {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, - {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, - {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, - {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, - {PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03}, - {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, - {PRO_DMOD, 0xf130, {0x04}, 0x01}, - {PRO_DMOD, 0xf132, {0x04}, 0x01}, - {PRO_DMOD, 0xf144, {0x1a}, 0x01}, - {PRO_DMOD, 0xf146, {0x00}, 0x01}, - {PRO_DMOD, 0xf14a, {0x01}, 0x01}, - {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0xf14f, {0x04}, 0x01}, - {PRO_DMOD, 0xf158, {0x7f}, 0x01}, - {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, - {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, - {PRO_DMOD, 0xf163, {0x05}, 0x01}, - {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, - {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0xf183, {0x01}, 0x01}, - {PRO_DMOD, 0xf19d, {0x40}, 0x01}, - {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, - {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, - {PRO_DMOD, 0xf204, {0x10}, 0x01}, - {PRO_DMOD, 0xf214, {0x00}, 0x01}, - {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, - {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, - {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, - {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, - {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, - {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, - {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02}, - {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, - {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, - {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, - {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, - 0x1f}, 0x08}, - {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, - {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, - {PRO_DMOD, 0xf78b, {0x01}, 0x01}, - {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, - {PRO_DMOD, 0xf905, {0x01}, 0x01}, - {PRO_DMOD, 0xfb06, {0x03}, 0x01}, - {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ -}; - -static struct it913xset it9135_52[] = { - {PRO_DMOD, 0x0043, {0x00}, 0x01}, - {PRO_DMOD, 0x0046, {0x52}, 0x01}, - {PRO_DMOD, 0x0051, {0x01}, 0x01}, - {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0x0068, {0x10}, 0x01}, - {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, - {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0xa0, 0x01}, 0x05}, - {PRO_DMOD, 0x007e, {0x04, 0x00}, 0x02}, - {PRO_DMOD, 0x0081, { 0x0a, 0x12, 0x03, 0x0a, 0x03, 0xb3, 0x97, - 0xc0, 0x9e, 0x01}, 0x0a}, - {PRO_DMOD, 0x008e, {0x01}, 0x01}, - {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, - {PRO_DMOD, 0x0099, {0x01}, 0x01}, - {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, - {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, - {PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04}, - {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, - {PRO_DMOD, 0x00b0, {0x01}, 0x01}, - {PRO_DMOD, 0x00b3, {0x02, 0x3c}, 0x02}, - {PRO_DMOD, 0x00b6, {0x14}, 0x01}, - {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05}, 0x03}, - {PRO_DMOD, 0x00c4, {0x00}, 0x01}, - {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, - {PRO_DMOD, 0x00cc, {0x2e, 0x51, 0x33}, 0x03}, - {PRO_DMOD, 0x00f3, {0x05, 0x91, 0x8c}, 0x03}, - {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, - {PRO_DMOD, 0x00fc, { 0x03, 0x02, 0x02, 0x09, 0x50, 0x74, 0x77, - 0x02, 0x02, 0xae, 0x02, 0x6e}, 0x0c}, - {PRO_DMOD, 0x0109, {0x02}, 0x01}, - {PRO_DMOD, 0x0115, {0x0a, 0x03, 0x02, 0x80}, 0x04}, - {PRO_DMOD, 0x011a, {0xcd, 0x62, 0xa4, 0x8c}, 0x04}, - {PRO_DMOD, 0x0122, {0x03, 0x18, 0x9e}, 0x03}, - {PRO_DMOD, 0x0127, {0x00, 0x07}, 0x02}, - {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, - {PRO_DMOD, 0x0137, {0x00, 0x00, 0x07, 0x00, 0x06}, 0x05}, - {PRO_DMOD, 0x013d, {0x00, 0x01, 0x5b, 0xb6, 0x59}, 0x05}, - {PRO_DMOD, 0xf000, {0x0f}, 0x01}, - {PRO_DMOD, 0xf016, {0x10, 0x04, 0x05, 0x04, 0x05}, 0x05}, - {PRO_DMOD, 0xf01f, {0x8c, 0x00, 0x03, 0x0a, 0x0a}, 0x05}, - {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00, 0x01}, 0x04}, - {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, - {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, - {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, - {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, - {PRO_DMOD, 0xf085, {0xc0, 0x01, 0x00}, 0x03}, - {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, - {PRO_DMOD, 0xf130, {0x04}, 0x01}, - {PRO_DMOD, 0xf132, {0x04}, 0x01}, - {PRO_DMOD, 0xf144, {0x1a}, 0x01}, - {PRO_DMOD, 0xf146, {0x00}, 0x01}, - {PRO_DMOD, 0xf14a, {0x01}, 0x01}, - {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0xf14f, {0x04}, 0x01}, - {PRO_DMOD, 0xf158, {0x7f}, 0x01}, - {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, - {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, - {PRO_DMOD, 0xf163, {0x05}, 0x01}, - {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, - {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0xf183, {0x01}, 0x01}, - {PRO_DMOD, 0xf19d, {0x40}, 0x01}, - {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, - {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, - {PRO_DMOD, 0xf204, {0x10}, 0x01}, - {PRO_DMOD, 0xf214, {0x00}, 0x01}, - {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, - {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, - {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, - {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, - {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, - {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, - {PRO_DMOD, 0xf5df, {0xfb, 0x00}, 0x02}, - {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, - {PRO_DMOD, 0xf5f8, {0x01}, 0x01}, - {PRO_DMOD, 0xf5fd, {0x01}, 0x01}, - {PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, - 0x1f}, 0x08}, - {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, - {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, - {PRO_DMOD, 0xf78b, {0x01}, 0x01}, - {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, - {PRO_DMOD, 0xf905, {0x01}, 0x01}, - {PRO_DMOD, 0xfb06, {0x03}, 0x01}, - {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ -}; - -/* Version 2 types */ -static struct it913xset it9135_60[] = { - {PRO_DMOD, 0x0043, {0x00}, 0x01}, - {PRO_DMOD, 0x0046, {0x60}, 0x01}, - {PRO_DMOD, 0x0051, {0x01}, 0x01}, - {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0x0068, {0x0a}, 0x01}, - {PRO_DMOD, 0x006a, {0x03}, 0x01}, - {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, - {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05}, - {PRO_DMOD, 0x007e, {0x04}, 0x01}, - {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02}, - {PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbe, 0xa0, 0xc6, 0xb6, 0x01}, 0x07}, - {PRO_DMOD, 0x008e, {0x01}, 0x01}, - {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, - {PRO_DMOD, 0x0099, {0x01}, 0x01}, - {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, - {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, - {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, - {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, - {PRO_DMOD, 0x00b0, {0x01}, 0x01}, - {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02}, - {PRO_DMOD, 0x00b6, {0x14}, 0x01}, - {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05}, - {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, - {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04}, - {PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03}, - {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, - {PRO_DMOD, 0x00fc, { 0x03, 0x03, 0x02, 0x0a, 0x50, 0x7b, 0x8c, - 0x00, 0x02, 0xbe, 0x00}, 0x0b}, - {PRO_DMOD, 0x0109, {0x02}, 0x01}, - {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, - {PRO_DMOD, 0x011a, {0xbe}, 0x01}, - {PRO_DMOD, 0x0124, {0xae}, 0x01}, - {PRO_DMOD, 0x0127, {0x00}, 0x01}, - {PRO_DMOD, 0x012a, {0x56, 0x50, 0x47, 0x42}, 0x04}, - {PRO_DMOD, 0x0137, {0x00}, 0x01}, - {PRO_DMOD, 0x013b, {0x08}, 0x01}, - {PRO_DMOD, 0x013f, {0x5b}, 0x01}, - {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x19, 0x19, 0x8c, 0x8c, 0x8c, - 0x6e, 0x8c, 0x50, 0x8c, 0x8c, 0xac, 0xc6, - 0x33}, 0x0f}, - {PRO_DMOD, 0x0151, {0x28}, 0x01}, - {PRO_DMOD, 0x0153, {0xbc}, 0x01}, - {PRO_DMOD, 0x0178, {0x09}, 0x01}, - {PRO_DMOD, 0x0181, {0x94, 0x6e}, 0x02}, - {PRO_DMOD, 0x0185, {0x24}, 0x01}, - {PRO_DMOD, 0x0187, {0x00, 0x00, 0xbe, 0x02, 0x80}, 0x05}, - {PRO_DMOD, 0xed02, {0xff}, 0x01}, - {PRO_DMOD, 0xee42, {0xff}, 0x01}, - {PRO_DMOD, 0xee82, {0xff}, 0x01}, - {PRO_DMOD, 0xf000, {0x0f}, 0x01}, - {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02}, - {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03}, - {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, - {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, - {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, - {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, - {PRO_DMOD, 0xf087, {0x00}, 0x01}, - {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, - {PRO_DMOD, 0xf130, {0x04}, 0x01}, - {PRO_DMOD, 0xf132, {0x04}, 0x01}, - {PRO_DMOD, 0xf144, {0x1a}, 0x01}, - {PRO_DMOD, 0xf146, {0x00}, 0x01}, - {PRO_DMOD, 0xf14a, {0x01}, 0x01}, - {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0xf14f, {0x04}, 0x01}, - {PRO_DMOD, 0xf158, {0x7f}, 0x01}, - {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, - {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, - {PRO_DMOD, 0xf163, {0x05}, 0x01}, - {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, - {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0xf183, {0x01}, 0x01}, - {PRO_DMOD, 0xf19d, {0x40}, 0x01}, - {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, - {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, - {PRO_DMOD, 0xf204, {0x10}, 0x01}, - {PRO_DMOD, 0xf214, {0x00}, 0x01}, - {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, - {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, - {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, - {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, - {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, - {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, - {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, - {PRO_DMOD, 0xf600, {0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17 - , 0x1f}, 0x08}, - {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, - {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, - {PRO_DMOD, 0xf78b, {0x01}, 0x01}, - {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, - {PRO_DMOD, 0xf905, {0x01}, 0x01}, - {PRO_DMOD, 0xfb06, {0x03}, 0x01}, - {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ -}; - -static struct it913xset it9135_61[] = { - {PRO_DMOD, 0x0043, {0x00}, 0x01}, - {PRO_DMOD, 0x0046, {0x61}, 0x01}, - {PRO_DMOD, 0x0051, {0x01}, 0x01}, - {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0x0068, {0x06}, 0x01}, - {PRO_DMOD, 0x006a, {0x03}, 0x01}, - {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, - {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x90, 0x01}, 0x05}, - {PRO_DMOD, 0x007e, {0x04}, 0x01}, - {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02}, - {PRO_DMOD, 0x0084, {0x0a, 0x33, 0xbc, 0x9c, 0xcc, 0xa8, 0x01}, 0x07}, - {PRO_DMOD, 0x008e, {0x01}, 0x01}, - {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, - {PRO_DMOD, 0x0099, {0x01}, 0x01}, - {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, - {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, - {PRO_DMOD, 0x00a3, {0x01, 0x5c, 0x01, 0x01}, 0x04}, - {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, - {PRO_DMOD, 0x00b0, {0x01}, 0x01}, - {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02}, - {PRO_DMOD, 0x00b6, {0x14}, 0x01}, - {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05}, - {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, - {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04}, - {PRO_DMOD, 0x00f3, {0x05, 0xa0, 0x8c}, 0x03}, - {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, - {PRO_DMOD, 0x00fc, { 0x03, 0x03, 0x02, 0x08, 0x50, 0x7b, 0x8c, - 0x01, 0x02, 0xc8, 0x00}, 0x0b}, - {PRO_DMOD, 0x0109, {0x02}, 0x01}, - {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, - {PRO_DMOD, 0x011a, {0xc6}, 0x01}, - {PRO_DMOD, 0x0124, {0xa8}, 0x01}, - {PRO_DMOD, 0x0127, {0x00}, 0x01}, - {PRO_DMOD, 0x012a, {0x59, 0x50, 0x47, 0x42}, 0x04}, - {PRO_DMOD, 0x0137, {0x00}, 0x01}, - {PRO_DMOD, 0x013b, {0x05}, 0x01}, - {PRO_DMOD, 0x013f, {0x5b}, 0x01}, - {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x59, 0x59, 0x8c, 0x8c, 0x8c, - 0x7b, 0x8c, 0x50, 0x8c, 0x8c, 0xa8, 0xc6, - 0x33}, 0x0f}, - {PRO_DMOD, 0x0151, {0x28}, 0x01}, - {PRO_DMOD, 0x0153, {0xcc}, 0x01}, - {PRO_DMOD, 0x0178, {0x09}, 0x01}, - {PRO_DMOD, 0x0181, {0x9c, 0x76}, 0x02}, - {PRO_DMOD, 0x0185, {0x28}, 0x01}, - {PRO_DMOD, 0x0187, {0x01, 0x00, 0xaa, 0x02, 0x80}, 0x05}, - {PRO_DMOD, 0xed02, {0xff}, 0x01}, - {PRO_DMOD, 0xee42, {0xff}, 0x01}, - {PRO_DMOD, 0xee82, {0xff}, 0x01}, - {PRO_DMOD, 0xf000, {0x0f}, 0x01}, - {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02}, - {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03}, - {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, - {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, - {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, - {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, - {PRO_DMOD, 0xf087, {0x00}, 0x01}, - {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, - {PRO_DMOD, 0xf130, {0x04}, 0x01}, - {PRO_DMOD, 0xf132, {0x04}, 0x01}, - {PRO_DMOD, 0xf144, {0x1a}, 0x01}, - {PRO_DMOD, 0xf146, {0x00}, 0x01}, - {PRO_DMOD, 0xf14a, {0x01}, 0x01}, - {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0xf14f, {0x04}, 0x01}, - {PRO_DMOD, 0xf158, {0x7f}, 0x01}, - {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, - {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, - {PRO_DMOD, 0xf163, {0x05}, 0x01}, - {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, - {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0xf183, {0x01}, 0x01}, - {PRO_DMOD, 0xf19d, {0x40}, 0x01}, - {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, - {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, - {PRO_DMOD, 0xf204, {0x10}, 0x01}, - {PRO_DMOD, 0xf214, {0x00}, 0x01}, - {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, - {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, - {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, - {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, - {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, - {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, - {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, - {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, - 0x1f}, 0x08}, - {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, - {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, - {PRO_DMOD, 0xf78b, {0x01}, 0x01}, - {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, - {PRO_DMOD, 0xf905, {0x01}, 0x01}, - {PRO_DMOD, 0xfb06, {0x03}, 0x01}, - {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ -}; - -static struct it913xset it9135_62[] = { - {PRO_DMOD, 0x0043, {0x00}, 0x01}, - {PRO_DMOD, 0x0046, {0x62}, 0x01}, - {PRO_DMOD, 0x0051, {0x01}, 0x01}, - {PRO_DMOD, 0x005f, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0x0068, {0x0a}, 0x01}, - {PRO_DMOD, 0x006a, {0x03}, 0x01}, - {PRO_DMOD, 0x0070, {0x0a, 0x05, 0x02}, 0x03}, - {PRO_DMOD, 0x0075, {0x8c, 0x8c, 0x8c, 0x8c, 0x01}, 0x05}, - {PRO_DMOD, 0x007e, {0x04}, 0x01}, - {PRO_DMOD, 0x0081, {0x0a, 0x12}, 0x02}, - {PRO_DMOD, 0x0084, { 0x0a, 0x33, 0xb8, 0x9c, 0xb2, 0xa6, 0x01}, - 0x07}, - {PRO_DMOD, 0x008e, {0x01}, 0x01}, - {PRO_DMOD, 0x0092, {0x06, 0x00, 0x00, 0x00, 0x00}, 0x05}, - {PRO_DMOD, 0x0099, {0x01}, 0x01}, - {PRO_DMOD, 0x009b, {0x3c, 0x28}, 0x02}, - {PRO_DMOD, 0x009f, {0xe1, 0xcf}, 0x02}, - {PRO_DMOD, 0x00a3, {0x01, 0x5a, 0x01, 0x01}, 0x04}, - {PRO_DMOD, 0x00a9, {0x00, 0x01}, 0x02}, - {PRO_DMOD, 0x00b0, {0x01}, 0x01}, - {PRO_DMOD, 0x00b3, {0x02, 0x3a}, 0x02}, - {PRO_DMOD, 0x00b6, {0x14}, 0x01}, - {PRO_DMOD, 0x00c0, {0x11, 0x00, 0x05, 0x01, 0x00}, 0x05}, - {PRO_DMOD, 0x00c6, {0x19, 0x00}, 0x02}, - {PRO_DMOD, 0x00cb, {0x32, 0x2c, 0x4f, 0x30}, 0x04}, - {PRO_DMOD, 0x00f3, {0x05, 0x8c, 0x8c}, 0x03}, - {PRO_DMOD, 0x00f8, {0x03, 0x06, 0x06}, 0x03}, - {PRO_DMOD, 0x00fc, { 0x02, 0x03, 0x02, 0x09, 0x50, 0x6e, 0x8c, - 0x02, 0x02, 0xc2, 0x00}, 0x0b}, - {PRO_DMOD, 0x0109, {0x02}, 0x01}, - {PRO_DMOD, 0x0115, {0x0a, 0x03}, 0x02}, - {PRO_DMOD, 0x011a, {0xb8}, 0x01}, - {PRO_DMOD, 0x0124, {0xa8}, 0x01}, - {PRO_DMOD, 0x0127, {0x00}, 0x01}, - {PRO_DMOD, 0x012a, {0x53, 0x51, 0x4e, 0x43}, 0x04}, - {PRO_DMOD, 0x0137, {0x00}, 0x01}, - {PRO_DMOD, 0x013b, {0x05}, 0x01}, - {PRO_DMOD, 0x013f, {0x5b}, 0x01}, - {PRO_DMOD, 0x0141, { 0x59, 0xf9, 0x59, 0x19, 0x8c, 0x8c, 0x8c, - 0x7b, 0x8c, 0x50, 0x70, 0x8c, 0x96, 0xd0, - 0x33}, 0x0f}, - {PRO_DMOD, 0x0151, {0x28}, 0x01}, - {PRO_DMOD, 0x0153, {0xb2}, 0x01}, - {PRO_DMOD, 0x0178, {0x09}, 0x01}, - {PRO_DMOD, 0x0181, {0x9c, 0x6e}, 0x02}, - {PRO_DMOD, 0x0185, {0x24}, 0x01}, - {PRO_DMOD, 0x0187, {0x00, 0x00, 0xb8, 0x02, 0x80}, 0x05}, - {PRO_DMOD, 0xed02, {0xff}, 0x01}, - {PRO_DMOD, 0xee42, {0xff}, 0x01}, - {PRO_DMOD, 0xee82, {0xff}, 0x01}, - {PRO_DMOD, 0xf000, {0x0f}, 0x01}, - {PRO_DMOD, 0xf01f, {0x8c, 0x00}, 0x02}, - {PRO_DMOD, 0xf029, {0x8c, 0x00, 0x00}, 0x03}, - {PRO_DMOD, 0xf064, {0x03, 0xf9, 0x03, 0x01}, 0x04}, - {PRO_DMOD, 0xf06f, {0xe0, 0x03}, 0x02}, - {PRO_DMOD, 0xf072, {0x0f, 0x03}, 0x02}, - {PRO_DMOD, 0xf077, {0x01, 0x00}, 0x02}, - {PRO_DMOD, 0xf087, {0x00}, 0x01}, - {PRO_DMOD, 0xf09b, {0x3f, 0x00, 0x20, 0x00, 0x0c, 0x00}, 0x06}, - {PRO_DMOD, 0xf130, {0x04}, 0x01}, - {PRO_DMOD, 0xf132, {0x04}, 0x01}, - {PRO_DMOD, 0xf144, {0x1a}, 0x01}, - {PRO_DMOD, 0xf146, {0x00}, 0x01}, - {PRO_DMOD, 0xf14a, {0x01}, 0x01}, - {PRO_DMOD, 0xf14c, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0xf14f, {0x04}, 0x01}, - {PRO_DMOD, 0xf158, {0x7f}, 0x01}, - {PRO_DMOD, 0xf15a, {0x00, 0x08}, 0x02}, - {PRO_DMOD, 0xf15d, {0x03, 0x05}, 0x02}, - {PRO_DMOD, 0xf163, {0x05}, 0x01}, - {PRO_DMOD, 0xf166, {0x01, 0x40, 0x0f}, 0x03}, - {PRO_DMOD, 0xf17a, {0x00, 0x00}, 0x02}, - {PRO_DMOD, 0xf183, {0x01}, 0x01}, - {PRO_DMOD, 0xf19d, {0x40}, 0x01}, - {PRO_DMOD, 0xf1bc, {0x36, 0x00}, 0x02}, - {PRO_DMOD, 0xf1cb, {0xa0, 0x01}, 0x02}, - {PRO_DMOD, 0xf204, {0x10}, 0x01}, - {PRO_DMOD, 0xf214, {0x00}, 0x01}, - {PRO_DMOD, 0xf24c, {0x88, 0x95, 0x9a, 0x90}, 0x04}, - {PRO_DMOD, 0xf25a, {0x07, 0xe8, 0x03, 0xb0, 0x04}, 0x05}, - {PRO_DMOD, 0xf270, {0x01, 0x02, 0x01, 0x02}, 0x04}, - {PRO_DMOD, 0xf40e, {0x0a, 0x40, 0x08}, 0x03}, - {PRO_DMOD, 0xf55f, {0x0a}, 0x01}, - {PRO_DMOD, 0xf561, {0x15, 0x20}, 0x02}, - {PRO_DMOD, 0xf5e3, {0x09, 0x01, 0x01}, 0x03}, - {PRO_DMOD, 0xf600, { 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x17, - 0x1f}, 0x08}, - {PRO_DMOD, 0xf60e, {0x00, 0x04, 0x32, 0x10}, 0x04}, - {PRO_DMOD, 0xf707, {0xfc, 0x00, 0x37, 0x00}, 0x04}, - {PRO_DMOD, 0xf78b, {0x01}, 0x01}, - {PRO_DMOD, 0xf80f, {0x40, 0x54, 0x5a}, 0x03}, - {PRO_DMOD, 0xf905, {0x01}, 0x01}, - {PRO_DMOD, 0xfb06, {0x03}, 0x01}, - {PRO_DMOD, 0xfd8b, {0x00}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00} /* Terminating Entry */ -}; - /* Tuner setting scripts (still keeping it9137) */ static struct it913xset it9137_tuner_off[] = { {PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off */ -- cgit v1.2.3 From 086991dd106bda1c43a294a874563322e0d777e4 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 22:18:56 -0300 Subject: [media] af9033: move code from it913x to af9033 That register is property of demodulator so move it correct place. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 9 +++++++++ drivers/media/tuners/it913x.c | 6 ------ 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 032074708d73..8e3a99d2b4bf 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -391,6 +391,15 @@ static int af9033_init(struct dvb_frontend *fe) goto err; } + switch (state->cfg.tuner) { + case AF9033_TUNER_IT9135_60: + case AF9033_TUNER_IT9135_61: + case AF9033_TUNER_IT9135_62: + ret = af9033_wr_reg(state, 0x800000, 0x01); + if (ret < 0) + goto err; + } + state->bandwidth_hz = 0; /* force to program all parameters */ return 0; diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 2c60bf77ebfc..4d7a24761050 100644 --- a/drivers/media/tuners/it913x.c +++ b/drivers/media/tuners/it913x.c @@ -145,12 +145,6 @@ static int it913x_init(struct dvb_frontend *fe) u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; u8 b[2]; - if (state->chip_ver == 2) { - ret = it913x_wr_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x1); - if (ret < 0) - return -ENODEV; - } - reg = it913x_rd_reg(state, 0xec86); switch (reg) { case 0: -- cgit v1.2.3 From 0c13c54d8527df03decf7c522f35886fb721f282 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 7 Mar 2013 23:13:31 -0300 Subject: [media] af9033: sleep on attach() Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 8e3a99d2b4bf..2dba516d5680 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -985,10 +985,17 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, "OFDM=%d.%d.%d.%d\n", KBUILD_MODNAME, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); - - /* FIXME: Do not abuse adc_multiplier for detecting IT9135 */ - if (state->cfg.adc_multiplier != AF9033_ADC_MULTIPLIER_2X) { - /* sleep */ + /* sleep */ + switch (state->cfg.tuner) { + case AF9033_TUNER_IT9135_38: + case AF9033_TUNER_IT9135_51: + case AF9033_TUNER_IT9135_52: + case AF9033_TUNER_IT9135_60: + case AF9033_TUNER_IT9135_61: + case AF9033_TUNER_IT9135_62: + /* IT9135 did not like to sleep at that early */ + break; + default: ret = af9033_wr_reg(state, 0x80004c, 1); if (ret < 0) goto err; -- cgit v1.2.3 From 3bf5e55299ac5a389a4e6b9991f900579a765172 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 8 Mar 2013 16:54:09 -0300 Subject: [media] af9033: implement i/o optimized reg table writer Use register address auto increment to reduce I/O when large register / values tables are written. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/af9033.c | 47 ++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 2dba516d5680..a777b4b944eb 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -156,6 +156,37 @@ static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val, return 0; } +/* write reg val table using reg addr auto increment */ +static int af9033_wr_reg_val_tab(struct af9033_state *state, + const struct reg_val *tab, int tab_len) +{ + int ret, i, j; + u8 buf[tab_len]; + + dev_dbg(&state->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len); + + for (i = 0, j = 0; i < tab_len; i++) { + buf[j] = tab[i].val; + + if (i == tab_len - 1 || tab[i].reg != tab[i + 1].reg - 1) { + ret = af9033_wr_regs(state, tab[i].reg - j, buf, j + 1); + if (ret < 0) + goto err; + + j = 0; + } else { + j++; + } + } + + return 0; + +err: + dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} + static u32 af9033_div(struct af9033_state *state, u32 a, u32 b, u32 x) { u32 r = 0, c = 0, i; @@ -306,11 +337,9 @@ static int af9033_init(struct dvb_frontend *fe) break; } - for (i = 0; i < len; i++) { - ret = af9033_wr_reg(state, init[i].reg, init[i].val); - if (ret < 0) - goto err; - } + ret = af9033_wr_reg_val_tab(state, init, len); + if (ret < 0) + goto err; /* load tuner specific settings */ dev_dbg(&state->i2c->dev, "%s: load tuner specific settings\n", @@ -371,11 +400,9 @@ static int af9033_init(struct dvb_frontend *fe) goto err; } - for (i = 0; i < len; i++) { - ret = af9033_wr_reg(state, init[i].reg, init[i].val); - if (ret < 0) - goto err; - } + ret = af9033_wr_reg_val_tab(state, init, len); + if (ret < 0) + goto err; if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) { ret = af9033_wr_reg_mask(state, 0x00d91c, 0x01, 0x01); -- cgit v1.2.3 From 1bfd5294ddb8b3d3ac05f609334070454b5ef96f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 8 Mar 2013 17:39:12 -0300 Subject: [media] af9035: check I/O errors on IR polling Use more careful error checks. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 735646d4f34a..5d6b3713e035 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -100,6 +100,10 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) /* check status */ if (state->buf[2]) { + /* fw returns status 1 when IR code was not received */ + if (req->cmd == CMD_IR_GET || state->buf[2] == 1) + return 1; + dev_dbg(&d->udev->dev, "%s: command=%02x failed fw error=%d\n", __func__, req->cmd, state->buf[2]); ret = -EIO; @@ -1223,7 +1227,9 @@ static int af9035_rc_query(struct dvb_usb_device *d) struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b }; ret = af9035_ctrl_msg(d, &req); - if (ret < 0) + if (ret == 1) + return 0; + else if (ret < 0) goto err; if ((b[2] + b[3]) == 0xff) { @@ -1240,9 +1246,12 @@ static int af9035_rc_query(struct dvb_usb_device *d) rc_keydown(d->rc_dev, key, 0); -err: - /* ignore errors */ return 0; + +err: + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + + return ret; } static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) -- cgit v1.2.3 From 75cd5886ed45b4173aa29bc66e7814a820b4fbf7 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 8 Mar 2013 17:50:21 -0300 Subject: [media] af9035: style changes for remote controller polling Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 5d6b3713e035..bc26b52e9887 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -1221,10 +1221,10 @@ err: #if IS_ENABLED(CONFIG_RC_CORE) static int af9035_rc_query(struct dvb_usb_device *d) { - unsigned int key; - unsigned char b[4]; int ret; - struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b }; + u32 key; + u8 buf[4]; + struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, buf }; ret = af9035_ctrl_msg(d, &req); if (ret == 1) @@ -1232,18 +1232,21 @@ static int af9035_rc_query(struct dvb_usb_device *d) else if (ret < 0) goto err; - if ((b[2] + b[3]) == 0xff) { - if ((b[0] + b[1]) == 0xff) { - /* NEC */ - key = b[0] << 8 | b[2]; + if ((buf[2] + buf[3]) == 0xff) { + if ((buf[0] + buf[1]) == 0xff) { + /* NEC standard 16bit */ + key = buf[0] << 8 | buf[2]; } else { - /* ext. NEC */ - key = b[0] << 16 | b[1] << 8 | b[2]; + /* NEC extended 24bit */ + key = buf[0] << 16 | buf[1] << 8 | buf[2]; } } else { - key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3]; + /* NEC full code 32bit */ + key = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; } + dev_dbg(&d->udev->dev, "%s: %*ph\n", __func__, 4, buf); + rc_keydown(d->rc_dev, key, 0); return 0; -- cgit v1.2.3 From f35d09db0e61009679e41cc5afa2d205b99c3816 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Mar 2013 06:22:45 -0300 Subject: [media] siano: use do_div() for 64-bits division MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As reported by Frank Schäfer : ERROR: "__divdi3" [drivers/media/common/siano/smsdvb.ko] undefined! Reported-by: Frank Schäfer Tested-by: Gianluca Gennari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb-main.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index d965a7ae5982..297f1b2f9a32 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -22,6 +22,7 @@ along with this program. If not, see . #include #include #include +#include #include "dmxdev.h" #include "dvbdev.h" @@ -244,6 +245,7 @@ static void smsdvb_update_per_slices(struct smsdvb_client_t *client, { struct dvb_frontend *fe = &client->frontend; struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u64 tmp; client->fe_status = sms_to_status(p->is_demod_locked, p->is_rf_locked); c->modulation = sms_to_modulation(p->constellation); @@ -272,8 +274,9 @@ static void smsdvb_update_per_slices(struct smsdvb_client_t *client, c->post_bit_count.stat[0].uvalue += p->ber_bit_count; /* Legacy PER/BER */ - client->legacy_per = (p->ets_packets * 65535) / - (p->ts_packets + p->ets_packets); + tmp = p->ets_packets * 65535; + do_div(tmp, p->ts_packets + p->ets_packets); + client->legacy_per = tmp; } static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client, @@ -803,7 +806,7 @@ static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr) rc = smsdvb_send_statistics_request(client); /* Preferred scale for SNR with legacy API: 0.1 dB */ - *snr = c->cnr.stat[0].svalue / 100; + *snr = ((u32)c->cnr.stat[0].svalue) / 100; led_feedback(client); -- cgit v1.2.3 From 48f72a1a4caaaac6cc22b6c4b6471286955a590d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Mar 2013 06:37:32 -0300 Subject: [media] drxk: fix CNR calculus Changeset 8f3741e accidentally broke the CNR estimation. It should be calculated as "a + b - c". However, previously, the subtraction by c only occurred if SNR would be positive, due to a bad binding to DVBv3 API. This also fixes the following warning: drivers/media/dvb-frontends/drxk_hard.c:2556:6: warning: variable 'c' set but not used [-Wunused-but-set-variable] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drxk_hard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index fc93bd396cf4..55a4c22ac2d4 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -2628,7 +2628,7 @@ static int GetDVBTSignalToNoise(struct drxk_state *state, /* log(x) x = (16bits + 16bits) << 15 ->32 bits */ c = Log10Times100(SqrErrIQ); - iMER = a + b; + iMER = a + b - c; } *pSignalToNoise = iMER; -- cgit v1.2.3 From 39ed1267d971d648886454b895852e46655bdcb6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Mar 2013 06:47:07 -0300 Subject: [media] siano: remove the ir protocol field This field is unused. Remove it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsir.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smsir.h b/drivers/media/common/siano/smsir.h index 69b59b9eee28..fc8b7925c532 100644 --- a/drivers/media/common/siano/smsir.h +++ b/drivers/media/common/siano/smsir.h @@ -40,7 +40,6 @@ struct ir_t { char phys[32]; char *rc_codes; - u64 protocol; u32 timeout; u32 controller; -- cgit v1.2.3 From 9dc033f1eaea01ed6701b16622744c4d57f108b7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 22 Mar 2013 06:51:06 -0300 Subject: [media] m5602_ov7660: return error at ov7660_init() It used to be a code that returns arror at ov7660_init. However, this was removed by changeset c84e412f: @@ -231,33 +116,40 @@ int ov7660_init(struct sd *sd) if (dump_sensor) ov7660_dump_registers(sd); - err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); - if (err < 0) - return err; + return 0; +} - err = ov7660_set_auto_white_balance(&sd->gspca_dev, - sensor_settings[AUTO_WHITE_BALANCE_IDX]); - if (err < 0) - return err; As complained by gcc: drivers/media/usb/gspca/m5602/m5602_ov7660.c: In function 'ov7660_init': drivers/media/usb/gspca/m5602/m5602_ov7660.c:99:9: warning: variable 'err' set but not used [-Wunused-but-set-variable] It should be noticed that the original error code was crappy, as it wasn't returning any error if sensor init fails. Fix it by returning an error if the sensor can't be initialized. Cc: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/m5602/m5602_ov7660.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/gspca/m5602/m5602_ov7660.c b/drivers/media/usb/gspca/m5602/m5602_ov7660.c index 4ac78893cc5f..64b3b03a9141 100644 --- a/drivers/media/usb/gspca/m5602/m5602_ov7660.c +++ b/drivers/media/usb/gspca/m5602/m5602_ov7660.c @@ -96,7 +96,7 @@ sensor_found: int ov7660_init(struct sd *sd) { - int i, err = 0; + int i, err; /* Init the sensor */ for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) { @@ -111,6 +111,8 @@ int ov7660_init(struct sd *sd) err = m5602_write_sensor(sd, init_ov7660[i][1], data, 1); } + if (err < 0) + return err; } if (dump_sensor) -- cgit v1.2.3 From 3190fbee0176a40a8dd13200862d39f956692f63 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Mar 2013 06:03:27 -0300 Subject: [media] em28xx: Only change I2C bus inside em28xx-i2c There's currently a bug on em28xx-i2c that makes it write the wrong values to register 06, that controlls the I2C bus speed and bus. Fix it to change only the I2C bus flag. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index de9b2086ab2d..9e2fa41044b3 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -284,6 +284,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, struct em28xx *dev = i2c_bus->dev; unsigned bus = i2c_bus->bus; int addr, rc, i, byte; + u8 reg; rc = rt_mutex_trylock(&dev->i2c_bus_lock); if (rc < 0) @@ -292,10 +293,11 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, /* Switch I2C bus if needed */ if (bus != dev->cur_i2c_bus) { if (bus == 1) - dev->cur_i2c_bus |= EM2874_I2C_SECONDARY_BUS_SELECT; + reg = EM2874_I2C_SECONDARY_BUS_SELECT; else - dev->cur_i2c_bus &= ~EM2874_I2C_SECONDARY_BUS_SELECT; - em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->cur_i2c_bus); + reg = 0; + em28xx_write_reg_bits(dev, EM28XX_R06_I2C_CLK, reg, + EM2874_I2C_SECONDARY_BUS_SELECT); dev->cur_i2c_bus = bus; } -- cgit v1.2.3 From bc3d292803409ce44febffb8e6839faae6e768fb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 22 Mar 2013 09:54:00 -0300 Subject: [media] em28xx: tuner setup is broken after algo_data change Commit aab3125c43d8fecc7134e5f1e729fabf4dd196da broke em28xx. I traced this eventually to the change in what algo_data points to. This pointer is also passed to em28xx_tuner_callback() through several hidden tuner layers (yuck!) and that callback was not updated. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 46fff5c3335b..cb7cdd322702 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2229,8 +2229,9 @@ static unsigned short msp3400_addrs[] = { int em28xx_tuner_callback(void *ptr, int component, int command, int arg) { + struct em28xx_i2c_bus *i2c_bus = ptr; + struct em28xx *dev = i2c_bus->dev; int rc = 0; - struct em28xx *dev = ptr; if (dev->tuner_type != TUNER_XC2028 && dev->tuner_type != TUNER_XC5000) return 0; -- cgit v1.2.3 From 13828c61e9d3fd293c284fd24077f1f7d0946458 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 21 Mar 2013 23:17:18 -0300 Subject: [media] dvb_usb_v2: make local function dvb_usb_v2_generic_io() static dvb_usb_v2_generic_io() was not declared. It should be static. Signed-off-by: Wei Yongjun Acked-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c index 74c911fa1fe6..aa0c35ef3179 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c @@ -21,7 +21,7 @@ #include "dvb_usb_common.h" -int dvb_usb_v2_generic_io(struct dvb_usb_device *d, +static int dvb_usb_v2_generic_io(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) { int ret, actual_length; -- cgit v1.2.3 From 54d80904b4c1f7aa1d569d07ca3e62fba0daf3a2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Mar 2013 15:46:18 -0300 Subject: [media] hdpvr-video: Use the proper check for I2C support As reported by Geert Uytterhoeven : drivers/media/usb/hdpvr/hdpvr-video.c: warning: "CONFIG_I2C_MODULE" is not defined [-Wundef] Reported-by: Geert Uytterhoeven Thanks-to: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-video.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index da6b77912222..6a15405360dc 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -1238,7 +1239,7 @@ static void hdpvr_device_release(struct video_device *vdev) v4l2_device_unregister(&dev->v4l2_dev); /* deregister I2C adapter */ -#if defined(CONFIG_I2C) || (CONFIG_I2C_MODULE) +#if IS_ENABLED(CONFIG_I2C) mutex_lock(&dev->i2c_mutex); i2c_del_adapter(&dev->i2c_adapter); mutex_unlock(&dev->i2c_mutex); -- cgit v1.2.3 From 782d8b743aad7dfffa4c01e9e8b57fd35247d70a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Mar 2013 16:11:54 -0300 Subject: [media] dvb-frontends: use IS_ENABLED Instead of checking everywhere there for 3 symbols, use instead IS_ENABLED macro. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/a8293.h | 5 +++-- drivers/media/dvb-frontends/af9013.h | 4 ++-- drivers/media/dvb-frontends/af9033.h | 5 +++-- drivers/media/dvb-frontends/atbm8830.h | 4 ++-- drivers/media/dvb-frontends/au8522.h | 4 ++-- drivers/media/dvb-frontends/cx22702.h | 4 ++-- drivers/media/dvb-frontends/cx24113.h | 5 +++-- drivers/media/dvb-frontends/cx24116.h | 4 ++-- drivers/media/dvb-frontends/cx24123.h | 4 ++-- drivers/media/dvb-frontends/cxd2820r.h | 4 ++-- drivers/media/dvb-frontends/dib3000mc.h | 5 +++-- drivers/media/dvb-frontends/dib7000m.h | 5 +++-- drivers/media/dvb-frontends/dib7000p.h | 5 +++-- drivers/media/dvb-frontends/drxd.h | 4 ++-- drivers/media/dvb-frontends/drxk.h | 4 ++-- drivers/media/dvb-frontends/ds3000.h | 4 ++-- drivers/media/dvb-frontends/dvb_dummy_fe.h | 4 ++-- drivers/media/dvb-frontends/ec100.h | 4 ++-- drivers/media/dvb-frontends/hd29l2.h | 4 ++-- drivers/media/dvb-frontends/it913x-fe.h | 4 ++-- drivers/media/dvb-frontends/ix2505v.h | 4 ++-- drivers/media/dvb-frontends/lg2160.h | 4 ++-- drivers/media/dvb-frontends/lgdt3305.h | 4 ++-- drivers/media/dvb-frontends/lgs8gl5.h | 4 ++-- drivers/media/dvb-frontends/lgs8gxx.h | 4 ++-- drivers/media/dvb-frontends/lnbh24.h | 5 +++-- drivers/media/dvb-frontends/lnbp21.h | 5 +++-- drivers/media/dvb-frontends/lnbp22.h | 5 +++-- drivers/media/dvb-frontends/m88rs2000.h | 4 ++-- drivers/media/dvb-frontends/mb86a20s.h | 4 ++-- drivers/media/dvb-frontends/rtl2830.h | 4 ++-- drivers/media/dvb-frontends/rtl2832.h | 4 ++-- drivers/media/dvb-frontends/s5h1409.h | 4 ++-- drivers/media/dvb-frontends/s5h1411.h | 4 ++-- drivers/media/dvb-frontends/s5h1432.h | 4 ++-- drivers/media/dvb-frontends/s921.h | 4 ++-- drivers/media/dvb-frontends/si21xx.h | 4 ++-- drivers/media/dvb-frontends/stb6000.h | 4 ++-- drivers/media/dvb-frontends/stv0288.h | 4 ++-- drivers/media/dvb-frontends/stv0367.h | 4 ++-- drivers/media/dvb-frontends/stv0900.h | 4 ++-- drivers/media/dvb-frontends/stv6110.h | 4 ++-- drivers/media/dvb-frontends/tda10048.h | 4 ++-- drivers/media/dvb-frontends/tda10071.h | 4 ++-- drivers/media/dvb-frontends/tda18271c2dd.h | 6 ++++-- drivers/media/dvb-frontends/ts2020.h | 4 ++-- drivers/media/dvb-frontends/zl10036.h | 4 ++-- drivers/media/dvb-frontends/zl10039.h | 5 +++-- 48 files changed, 108 insertions(+), 96 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/a8293.h b/drivers/media/dvb-frontends/a8293.h index ed29e5504f76..b6ef6427cfa5 100644 --- a/drivers/media/dvb-frontends/a8293.h +++ b/drivers/media/dvb-frontends/a8293.h @@ -21,12 +21,13 @@ #ifndef A8293_H #define A8293_H +#include + struct a8293_config { u8 i2c_addr; }; -#if defined(CONFIG_DVB_A8293) || \ - (defined(CONFIG_DVB_A8293_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_A8293) extern struct dvb_frontend *a8293_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct a8293_config *cfg); #else diff --git a/drivers/media/dvb-frontends/af9013.h b/drivers/media/dvb-frontends/af9013.h index dc837d91327a..09273b2cd310 100644 --- a/drivers/media/dvb-frontends/af9013.h +++ b/drivers/media/dvb-frontends/af9013.h @@ -25,6 +25,7 @@ #ifndef AF9013_H #define AF9013_H +#include #include /* AF9013/5 GPIOs (mostly guessed) @@ -102,8 +103,7 @@ struct af9013_config { u8 gpio[4]; }; -#if defined(CONFIG_DVB_AF9013) || \ - (defined(CONFIG_DVB_AF9013_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_AF9013) extern struct dvb_frontend *af9013_attach(const struct af9013_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h index 53fd3040c5f0..c286e8f1ec02 100644 --- a/drivers/media/dvb-frontends/af9033.h +++ b/drivers/media/dvb-frontends/af9033.h @@ -22,6 +22,8 @@ #ifndef AF9033_H #define AF9033_H +#include + struct af9033_config { /* * I2C address @@ -76,8 +78,7 @@ struct af9033_config { }; -#if defined(CONFIG_DVB_AF9033) || \ - (defined(CONFIG_DVB_AF9033_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_AF9033) extern struct dvb_frontend *af9033_attach(const struct af9033_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/atbm8830.h b/drivers/media/dvb-frontends/atbm8830.h index 024273374bd8..8e0ac98f8d08 100644 --- a/drivers/media/dvb-frontends/atbm8830.h +++ b/drivers/media/dvb-frontends/atbm8830.h @@ -22,6 +22,7 @@ #ifndef __ATBM8830_H__ #define __ATBM8830_H__ +#include #include #include @@ -60,8 +61,7 @@ struct atbm8830_config { u8 agc_hold_loop; }; -#if defined(CONFIG_DVB_ATBM8830) || \ - (defined(CONFIG_DVB_ATBM8830_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_ATBM8830) extern struct dvb_frontend *atbm8830_attach(const struct atbm8830_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/au8522.h b/drivers/media/dvb-frontends/au8522.h index 565dcf31af57..f2111e0fefda 100644 --- a/drivers/media/dvb-frontends/au8522.h +++ b/drivers/media/dvb-frontends/au8522.h @@ -22,6 +22,7 @@ #ifndef __AU8522_H__ #define __AU8522_H__ +#include #include enum au8522_if_freq { @@ -60,8 +61,7 @@ struct au8522_config { enum au8522_if_freq qam_if; }; -#if defined(CONFIG_DVB_AU8522) || \ - (defined(CONFIG_DVB_AU8522_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_AU8522) extern struct dvb_frontend *au8522_attach(const struct au8522_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/cx22702.h b/drivers/media/dvb-frontends/cx22702.h index f154e1f428eb..0b1a6c2f9d5f 100644 --- a/drivers/media/dvb-frontends/cx22702.h +++ b/drivers/media/dvb-frontends/cx22702.h @@ -28,6 +28,7 @@ #ifndef CX22702_H #define CX22702_H +#include #include struct cx22702_config { @@ -40,8 +41,7 @@ struct cx22702_config { u8 output_mode; }; -#if defined(CONFIG_DVB_CX22702) || (defined(CONFIG_DVB_CX22702_MODULE) \ - && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_CX22702) extern struct dvb_frontend *cx22702_attach( const struct cx22702_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/cx24113.h b/drivers/media/dvb-frontends/cx24113.h index 01eb7b9c28f4..782711ba1a32 100644 --- a/drivers/media/dvb-frontends/cx24113.h +++ b/drivers/media/dvb-frontends/cx24113.h @@ -22,6 +22,8 @@ #ifndef CX24113_H #define CX24113_H +#include + struct dvb_frontend; struct cx24113_config { @@ -30,8 +32,7 @@ struct cx24113_config { u32 xtal_khz; }; -#if defined(CONFIG_DVB_TUNER_CX24113) || \ - (defined(CONFIG_DVB_TUNER_CX24113_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_TUNER_CX24113) extern struct dvb_frontend *cx24113_attach(struct dvb_frontend *, const struct cx24113_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/cx24116.h b/drivers/media/dvb-frontends/cx24116.h index 7d90ab949c03..2ec84fae3f9f 100644 --- a/drivers/media/dvb-frontends/cx24116.h +++ b/drivers/media/dvb-frontends/cx24116.h @@ -21,6 +21,7 @@ #ifndef CX24116_H #define CX24116_H +#include #include struct cx24116_config { @@ -40,8 +41,7 @@ struct cx24116_config { u16 i2c_wr_max; }; -#if defined(CONFIG_DVB_CX24116) || \ - (defined(CONFIG_DVB_CX24116_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_CX24116) extern struct dvb_frontend *cx24116_attach( const struct cx24116_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/cx24123.h b/drivers/media/dvb-frontends/cx24123.h index 51ae866e9fed..102e70d17c43 100644 --- a/drivers/media/dvb-frontends/cx24123.h +++ b/drivers/media/dvb-frontends/cx24123.h @@ -21,6 +21,7 @@ #ifndef CX24123_H #define CX24123_H +#include #include struct cx24123_config { @@ -38,8 +39,7 @@ struct cx24123_config { void (*agc_callback) (struct dvb_frontend *); }; -#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) \ - && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_CX24123) extern struct dvb_frontend *cx24123_attach(const struct cx24123_config *config, struct i2c_adapter *i2c); extern struct i2c_adapter *cx24123_get_tuner_i2c_adapter(struct dvb_frontend *); diff --git a/drivers/media/dvb-frontends/cxd2820r.h b/drivers/media/dvb-frontends/cxd2820r.h index 6acc21c581c5..82b3d93718f8 100644 --- a/drivers/media/dvb-frontends/cxd2820r.h +++ b/drivers/media/dvb-frontends/cxd2820r.h @@ -22,6 +22,7 @@ #ifndef CXD2820R_H #define CXD2820R_H +#include #include #define CXD2820R_GPIO_D (0 << 0) /* disable */ @@ -65,8 +66,7 @@ struct cxd2820r_config { }; -#if defined(CONFIG_DVB_CXD2820R) || \ - (defined(CONFIG_DVB_CXD2820R_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_CXD2820R) extern struct dvb_frontend *cxd2820r_attach( const struct cxd2820r_config *config, struct i2c_adapter *i2c, diff --git a/drivers/media/dvb-frontends/dib3000mc.h b/drivers/media/dvb-frontends/dib3000mc.h index d75ffad2d752..129d1425516a 100644 --- a/drivers/media/dvb-frontends/dib3000mc.h +++ b/drivers/media/dvb-frontends/dib3000mc.h @@ -13,6 +13,8 @@ #ifndef DIB3000MC_H #define DIB3000MC_H +#include + #include "dibx000_common.h" struct dib3000mc_config { @@ -39,8 +41,7 @@ struct dib3000mc_config { #define DEFAULT_DIB3000MC_I2C_ADDRESS 16 #define DEFAULT_DIB3000P_I2C_ADDRESS 24 -#if defined(CONFIG_DVB_DIB3000MC) || (defined(CONFIG_DVB_DIB3000MC_MODULE) && \ - defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_DIB3000MC) extern struct dvb_frontend *dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg); diff --git a/drivers/media/dvb-frontends/dib7000m.h b/drivers/media/dvb-frontends/dib7000m.h index 81fcf2241c64..b585413f9a29 100644 --- a/drivers/media/dvb-frontends/dib7000m.h +++ b/drivers/media/dvb-frontends/dib7000m.h @@ -1,6 +1,8 @@ #ifndef DIB7000M_H #define DIB7000M_H +#include + #include "dibx000_common.h" struct dib7000m_config { @@ -38,8 +40,7 @@ struct dib7000m_config { #define DEFAULT_DIB7000M_I2C_ADDRESS 18 -#if defined(CONFIG_DVB_DIB7000M) || (defined(CONFIG_DVB_DIB7000M_MODULE) && \ - defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_DIB7000M) extern struct dvb_frontend *dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg); diff --git a/drivers/media/dvb-frontends/dib7000p.h b/drivers/media/dvb-frontends/dib7000p.h index b61b03a6e1ed..cf5e77956a1f 100644 --- a/drivers/media/dvb-frontends/dib7000p.h +++ b/drivers/media/dvb-frontends/dib7000p.h @@ -1,6 +1,8 @@ #ifndef DIB7000P_H #define DIB7000P_H +#include + #include "dibx000_common.h" struct dib7000p_config { @@ -44,8 +46,7 @@ struct dib7000p_config { #define DEFAULT_DIB7000P_I2C_ADDRESS 18 -#if defined(CONFIG_DVB_DIB7000P) || (defined(CONFIG_DVB_DIB7000P_MODULE) && \ - defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_DIB7000P) extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); diff --git a/drivers/media/dvb-frontends/drxd.h b/drivers/media/dvb-frontends/drxd.h index 216c8c3702f8..5f1d6b5f1685 100644 --- a/drivers/media/dvb-frontends/drxd.h +++ b/drivers/media/dvb-frontends/drxd.h @@ -24,6 +24,7 @@ #ifndef _DRXD_H_ #define _DRXD_H_ +#include #include #include @@ -51,8 +52,7 @@ struct drxd_config { s16(*osc_deviation) (void *priv, s16 dev, int flag); }; -#if defined(CONFIG_DVB_DRXD) || \ - (defined(CONFIG_DVB_DRXD_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_DRXD) extern struct dvb_frontend *drxd_attach(const struct drxd_config *config, void *priv, struct i2c_adapter *i2c, diff --git a/drivers/media/dvb-frontends/drxk.h b/drivers/media/dvb-frontends/drxk.h index 94fecfbf14c1..e6667189ddce 100644 --- a/drivers/media/dvb-frontends/drxk.h +++ b/drivers/media/dvb-frontends/drxk.h @@ -1,6 +1,7 @@ #ifndef _DRXK_H_ #define _DRXK_H_ +#include #include #include @@ -52,8 +53,7 @@ struct drxk_config { int qam_demod_parameter_count; }; -#if defined(CONFIG_DVB_DRXK) || (defined(CONFIG_DVB_DRXK_MODULE) \ - && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_DRXK) extern struct dvb_frontend *drxk_attach(const struct drxk_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/ds3000.h b/drivers/media/dvb-frontends/ds3000.h index 478ad66c63d7..f9c21fb7af13 100644 --- a/drivers/media/dvb-frontends/ds3000.h +++ b/drivers/media/dvb-frontends/ds3000.h @@ -22,6 +22,7 @@ #ifndef DS3000_H #define DS3000_H +#include #include struct ds3000_config { @@ -34,8 +35,7 @@ struct ds3000_config { void (*set_lock_led)(struct dvb_frontend *fe, int offon); }; -#if defined(CONFIG_DVB_DS3000) || \ - (defined(CONFIG_DVB_DS3000_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_DS3000) extern struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/dvb_dummy_fe.h b/drivers/media/dvb-frontends/dvb_dummy_fe.h index 1fcb987d6386..0cbf96105631 100644 --- a/drivers/media/dvb-frontends/dvb_dummy_fe.h +++ b/drivers/media/dvb-frontends/dvb_dummy_fe.h @@ -22,11 +22,11 @@ #ifndef DVB_DUMMY_FE_H #define DVB_DUMMY_FE_H +#include #include #include "dvb_frontend.h" -#if defined(CONFIG_DVB_DUMMY_FE) || (defined(CONFIG_DVB_DUMMY_FE_MODULE) && \ -defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_DUMMY_FE) extern struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void); extern struct dvb_frontend* dvb_dummy_fe_qpsk_attach(void); extern struct dvb_frontend* dvb_dummy_fe_qam_attach(void); diff --git a/drivers/media/dvb-frontends/ec100.h b/drivers/media/dvb-frontends/ec100.h index b8479719d7f1..37558403068d 100644 --- a/drivers/media/dvb-frontends/ec100.h +++ b/drivers/media/dvb-frontends/ec100.h @@ -22,6 +22,7 @@ #ifndef EC100_H #define EC100_H +#include #include struct ec100_config { @@ -30,8 +31,7 @@ struct ec100_config { }; -#if defined(CONFIG_DVB_EC100) || \ - (defined(CONFIG_DVB_EC100_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_EC100) extern struct dvb_frontend *ec100_attach(const struct ec100_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/hd29l2.h b/drivers/media/dvb-frontends/hd29l2.h index 4ad00d79aa77..05cd13028a91 100644 --- a/drivers/media/dvb-frontends/hd29l2.h +++ b/drivers/media/dvb-frontends/hd29l2.h @@ -23,6 +23,7 @@ #ifndef HD29L2_H #define HD29L2_H +#include #include struct hd29l2_config { @@ -50,8 +51,7 @@ struct hd29l2_config { }; -#if defined(CONFIG_DVB_HD29L2) || \ - (defined(CONFIG_DVB_HD29L2_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_HD29L2) extern struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/it913x-fe.h b/drivers/media/dvb-frontends/it913x-fe.h index 07fa4594c12b..df0ad4207343 100644 --- a/drivers/media/dvb-frontends/it913x-fe.h +++ b/drivers/media/dvb-frontends/it913x-fe.h @@ -21,6 +21,7 @@ #ifndef IT913X_FE_H #define IT913X_FE_H +#include #include #include "dvb_frontend.h" @@ -38,8 +39,7 @@ struct ite_config { u8 read_slevel; }; -#if defined(CONFIG_DVB_IT913X_FE) || (defined(CONFIG_DVB_IT913X_FE_MODULE) && \ -defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_IT913X_FE) extern struct dvb_frontend *it913x_fe_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct ite_config *config); #else diff --git a/drivers/media/dvb-frontends/ix2505v.h b/drivers/media/dvb-frontends/ix2505v.h index 67e89d616d50..1a735a75aa98 100644 --- a/drivers/media/dvb-frontends/ix2505v.h +++ b/drivers/media/dvb-frontends/ix2505v.h @@ -20,6 +20,7 @@ #ifndef DVB_IX2505V_H #define DVB_IX2505V_H +#include #include #include "dvb_frontend.h" @@ -48,8 +49,7 @@ struct ix2505v_config { }; -#if defined(CONFIG_DVB_IX2505V) || \ - (defined(CONFIG_DVB_IX2505V_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_IX2505V) extern struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe, const struct ix2505v_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/lg2160.h b/drivers/media/dvb-frontends/lg2160.h index 9e2c0f41199a..a5f036824d68 100644 --- a/drivers/media/dvb-frontends/lg2160.h +++ b/drivers/media/dvb-frontends/lg2160.h @@ -22,6 +22,7 @@ #ifndef _LG2160_H_ #define _LG2160_H_ +#include #include #include "dvb_frontend.h" @@ -66,8 +67,7 @@ struct lg2160_config { enum lg_chip_type lg_chip; }; -#if defined(CONFIG_DVB_LG2160) || (defined(CONFIG_DVB_LG2160_MODULE) && \ - defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_LG2160) extern struct dvb_frontend *lg2160_attach(const struct lg2160_config *config, struct i2c_adapter *i2c_adap); diff --git a/drivers/media/dvb-frontends/lgdt3305.h b/drivers/media/dvb-frontends/lgdt3305.h index 02172eca4d47..d9ab556c1b27 100644 --- a/drivers/media/dvb-frontends/lgdt3305.h +++ b/drivers/media/dvb-frontends/lgdt3305.h @@ -22,6 +22,7 @@ #ifndef _LGDT3305_H_ #define _LGDT3305_H_ +#include #include #include "dvb_frontend.h" @@ -73,8 +74,7 @@ struct lgdt3305_config { enum lgdt_demod_chip_type demod_chip; }; -#if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \ - defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_LGDT3305) extern struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, struct i2c_adapter *i2c_adap); diff --git a/drivers/media/dvb-frontends/lgs8gl5.h b/drivers/media/dvb-frontends/lgs8gl5.h index d14176787a7d..c2da59614727 100644 --- a/drivers/media/dvb-frontends/lgs8gl5.h +++ b/drivers/media/dvb-frontends/lgs8gl5.h @@ -23,6 +23,7 @@ #ifndef LGS8GL5_H #define LGS8GL5_H +#include #include struct lgs8gl5_config { @@ -30,8 +31,7 @@ struct lgs8gl5_config { u8 demod_address; }; -#if defined(CONFIG_DVB_LGS8GL5) || \ - (defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_LGS8GL5) extern struct dvb_frontend *lgs8gl5_attach( const struct lgs8gl5_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/lgs8gxx.h b/drivers/media/dvb-frontends/lgs8gxx.h index 33c3c5e162fa..dadb78bf61a9 100644 --- a/drivers/media/dvb-frontends/lgs8gxx.h +++ b/drivers/media/dvb-frontends/lgs8gxx.h @@ -26,6 +26,7 @@ #ifndef __LGS8GXX_H__ #define __LGS8GXX_H__ +#include #include #include @@ -79,8 +80,7 @@ struct lgs8gxx_config { u8 tuner_address; }; -#if defined(CONFIG_DVB_LGS8GXX) || \ - (defined(CONFIG_DVB_LGS8GXX_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_LGS8GXX) extern struct dvb_frontend *lgs8gxx_attach(const struct lgs8gxx_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/lnbh24.h b/drivers/media/dvb-frontends/lnbh24.h index c059b165318f..b327a4f31d16 100644 --- a/drivers/media/dvb-frontends/lnbh24.h +++ b/drivers/media/dvb-frontends/lnbh24.h @@ -23,6 +23,8 @@ #ifndef _LNBH24_H #define _LNBH24_H +#include + /* system register bits */ #define LNBH24_OLF 0x01 #define LNBH24_OTF 0x02 @@ -35,8 +37,7 @@ #include -#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \ - && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_LNBP21) /* override_set and override_clear control which system register bits (above) to always set & clear */ extern struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/lnbp21.h b/drivers/media/dvb-frontends/lnbp21.h index fcdf1c650dde..dbcbcc2f20a3 100644 --- a/drivers/media/dvb-frontends/lnbp21.h +++ b/drivers/media/dvb-frontends/lnbp21.h @@ -27,6 +27,8 @@ #ifndef _LNBP21_H #define _LNBP21_H +#include + /* system register bits */ /* [RO] 0=OK; 1=over current limit flag */ #define LNBP21_OLF 0x01 @@ -55,8 +57,7 @@ #include -#if defined(CONFIG_DVB_LNBP21) || (defined(CONFIG_DVB_LNBP21_MODULE) \ - && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_LNBP21) /* override_set and override_clear control which system register bits (above) to always set & clear */ extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/lnbp22.h b/drivers/media/dvb-frontends/lnbp22.h index 63e2dec7e68a..63861b311dd8 100644 --- a/drivers/media/dvb-frontends/lnbp22.h +++ b/drivers/media/dvb-frontends/lnbp22.h @@ -28,6 +28,8 @@ #ifndef _LNBP22_H #define _LNBP22_H +#include + /* Enable */ #define LNBP22_EN 0x10 /* Voltage selection */ @@ -37,8 +39,7 @@ #include -#if defined(CONFIG_DVB_LNBP22) || \ - (defined(CONFIG_DVB_LNBP22_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_LNBP22) /* * override_set and override_clear control which system register bits (above) * to always set & clear diff --git a/drivers/media/dvb-frontends/m88rs2000.h b/drivers/media/dvb-frontends/m88rs2000.h index 5a8023e5a4b8..14ce31e76ae6 100644 --- a/drivers/media/dvb-frontends/m88rs2000.h +++ b/drivers/media/dvb-frontends/m88rs2000.h @@ -20,6 +20,7 @@ #ifndef M88RS2000_H #define M88RS2000_H +#include #include #include "dvb_frontend.h" @@ -40,8 +41,7 @@ enum { CALL_IS_READ, }; -#if defined(CONFIG_DVB_M88RS2000) || (defined(CONFIG_DVB_M88RS2000_MODULE) && \ - defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_M88RS2000) extern struct dvb_frontend *m88rs2000_attach( const struct m88rs2000_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/mb86a20s.h b/drivers/media/dvb-frontends/mb86a20s.h index 1a7dea2b237a..6627a3976087 100644 --- a/drivers/media/dvb-frontends/mb86a20s.h +++ b/drivers/media/dvb-frontends/mb86a20s.h @@ -16,6 +16,7 @@ #ifndef MB86A20S_H #define MB86A20S_H +#include #include /** @@ -33,8 +34,7 @@ struct mb86a20s_config { bool is_serial; }; -#if defined(CONFIG_DVB_MB86A20S) || (defined(CONFIG_DVB_MB86A20S_MODULE) \ - && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_MB86A20S) extern struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, struct i2c_adapter *i2c); extern struct i2c_adapter *mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *); diff --git a/drivers/media/dvb-frontends/rtl2830.h b/drivers/media/dvb-frontends/rtl2830.h index f4349a1fc03e..3313847fb0be 100644 --- a/drivers/media/dvb-frontends/rtl2830.h +++ b/drivers/media/dvb-frontends/rtl2830.h @@ -21,6 +21,7 @@ #ifndef RTL2830_H #define RTL2830_H +#include #include struct rtl2830_config { @@ -59,8 +60,7 @@ struct rtl2830_config { u8 agc_targ_val; }; -#if defined(CONFIG_DVB_RTL2830) || \ - (defined(CONFIG_DVB_RTL2830_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_RTL2830) extern struct dvb_frontend *rtl2830_attach( const struct rtl2830_config *config, struct i2c_adapter *i2c diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h index 785a466eb065..fefba0e9ba30 100644 --- a/drivers/media/dvb-frontends/rtl2832.h +++ b/drivers/media/dvb-frontends/rtl2832.h @@ -21,6 +21,7 @@ #ifndef RTL2832_H #define RTL2832_H +#include #include struct rtl2832_config { @@ -54,8 +55,7 @@ struct rtl2832_config { u8 tuner; }; -#if defined(CONFIG_DVB_RTL2832) || \ - (defined(CONFIG_DVB_RTL2832_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_RTL2832) extern struct dvb_frontend *rtl2832_attach( const struct rtl2832_config *cfg, struct i2c_adapter *i2c diff --git a/drivers/media/dvb-frontends/s5h1409.h b/drivers/media/dvb-frontends/s5h1409.h index 91f2ebd1a534..63b1e0a34e4e 100644 --- a/drivers/media/dvb-frontends/s5h1409.h +++ b/drivers/media/dvb-frontends/s5h1409.h @@ -22,6 +22,7 @@ #ifndef __S5H1409_H__ #define __S5H1409_H__ +#include #include struct s5h1409_config { @@ -66,8 +67,7 @@ struct s5h1409_config { u8 hvr1600_opt; }; -#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) \ - && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_S5H1409) extern struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/s5h1411.h b/drivers/media/dvb-frontends/s5h1411.h index 45ec0f82989c..e4f56871f982 100644 --- a/drivers/media/dvb-frontends/s5h1411.h +++ b/drivers/media/dvb-frontends/s5h1411.h @@ -22,6 +22,7 @@ #ifndef __S5H1411_H__ #define __S5H1411_H__ +#include #include #define S5H1411_I2C_TOP_ADDR (0x32 >> 1) @@ -68,8 +69,7 @@ struct s5h1411_config { u8 status_mode; }; -#if defined(CONFIG_DVB_S5H1411) || \ - (defined(CONFIG_DVB_S5H1411_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_S5H1411) extern struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/s5h1432.h b/drivers/media/dvb-frontends/s5h1432.h index b57438c32546..70917dd2533a 100644 --- a/drivers/media/dvb-frontends/s5h1432.h +++ b/drivers/media/dvb-frontends/s5h1432.h @@ -22,6 +22,7 @@ #ifndef __S5H1432_H__ #define __S5H1432_H__ +#include #include #define S5H1432_I2C_TOP_ADDR (0x02 >> 1) @@ -74,8 +75,7 @@ struct s5h1432_config { u8 status_mode; }; -#if defined(CONFIG_DVB_S5H1432) || \ - (defined(CONFIG_DVB_S5H1432_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_S5H1432) extern struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/s921.h b/drivers/media/dvb-frontends/s921.h index f220d8299c81..8d5e2a6e187c 100644 --- a/drivers/media/dvb-frontends/s921.h +++ b/drivers/media/dvb-frontends/s921.h @@ -17,6 +17,7 @@ #ifndef S921_H #define S921_H +#include #include struct s921_config { @@ -24,8 +25,7 @@ struct s921_config { u8 demod_address; }; -#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) \ - && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_S921) extern struct dvb_frontend *s921_attach(const struct s921_config *config, struct i2c_adapter *i2c); extern struct i2c_adapter *s921_get_tuner_i2c_adapter(struct dvb_frontend *); diff --git a/drivers/media/dvb-frontends/si21xx.h b/drivers/media/dvb-frontends/si21xx.h index 141b5b8a5f63..1509fed44a3a 100644 --- a/drivers/media/dvb-frontends/si21xx.h +++ b/drivers/media/dvb-frontends/si21xx.h @@ -1,6 +1,7 @@ #ifndef SI21XX_H #define SI21XX_H +#include #include #include "dvb_frontend.h" @@ -12,8 +13,7 @@ struct si21xx_config { int min_delay_ms; }; -#if defined(CONFIG_DVB_SI21XX) || \ - (defined(CONFIG_DVB_SI21XX_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_SI21XX) extern struct dvb_frontend *si21xx_attach(const struct si21xx_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/stb6000.h b/drivers/media/dvb-frontends/stb6000.h index 7be479c22d5b..a768189bfaad 100644 --- a/drivers/media/dvb-frontends/stb6000.h +++ b/drivers/media/dvb-frontends/stb6000.h @@ -23,6 +23,7 @@ #ifndef __DVB_STB6000_H__ #define __DVB_STB6000_H__ +#include #include #include "dvb_frontend.h" @@ -34,8 +35,7 @@ * @param i2c i2c adapter to use. * @return FE pointer on success, NULL on failure. */ -#if defined(CONFIG_DVB_STB6000) || (defined(CONFIG_DVB_STB6000_MODULE) \ - && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_STB6000) extern struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/stv0288.h b/drivers/media/dvb-frontends/stv0288.h index f2b53db0606d..a0bd93107154 100644 --- a/drivers/media/dvb-frontends/stv0288.h +++ b/drivers/media/dvb-frontends/stv0288.h @@ -27,6 +27,7 @@ #ifndef STV0288_H #define STV0288_H +#include #include #include "dvb_frontend.h" @@ -42,8 +43,7 @@ struct stv0288_config { int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); }; -#if defined(CONFIG_DVB_STV0288) || (defined(CONFIG_DVB_STV0288_MODULE) && \ - defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_STV0288) extern struct dvb_frontend *stv0288_attach(const struct stv0288_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/stv0367.h b/drivers/media/dvb-frontends/stv0367.h index 93cc4a57eea0..ea80b341f094 100644 --- a/drivers/media/dvb-frontends/stv0367.h +++ b/drivers/media/dvb-frontends/stv0367.h @@ -26,6 +26,7 @@ #ifndef STV0367_H #define STV0367_H +#include #include #include "dvb_frontend.h" @@ -38,8 +39,7 @@ struct stv0367_config { int clk_pol; }; -#if defined(CONFIG_DVB_STV0367) || (defined(CONFIG_DVB_STV0367_MODULE) \ - && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_STV0367) extern struct dvb_frontend *stv0367ter_attach(const struct stv0367_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/stv0900.h b/drivers/media/dvb-frontends/stv0900.h index 91c7ee8b2313..e2a6dc69ecb4 100644 --- a/drivers/media/dvb-frontends/stv0900.h +++ b/drivers/media/dvb-frontends/stv0900.h @@ -26,6 +26,7 @@ #ifndef STV0900_H #define STV0900_H +#include #include #include "dvb_frontend.h" @@ -57,8 +58,7 @@ struct stv0900_config { void (*set_lock_led)(struct dvb_frontend *fe, int offon); }; -#if defined(CONFIG_DVB_STV0900) || (defined(CONFIG_DVB_STV0900_MODULE) \ - && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_STV0900) extern struct dvb_frontend *stv0900_attach(const struct stv0900_config *config, struct i2c_adapter *i2c, int demod); #else diff --git a/drivers/media/dvb-frontends/stv6110.h b/drivers/media/dvb-frontends/stv6110.h index fe71bba6a26e..8fa07e6a6745 100644 --- a/drivers/media/dvb-frontends/stv6110.h +++ b/drivers/media/dvb-frontends/stv6110.h @@ -25,6 +25,7 @@ #ifndef __DVB_STV6110_H__ #define __DVB_STV6110_H__ +#include #include #include "dvb_frontend.h" @@ -45,8 +46,7 @@ struct stv6110_config { u8 clk_div; /* divisor value for the output clock */ }; -#if defined(CONFIG_DVB_STV6110) || (defined(CONFIG_DVB_STV6110_MODULE) \ - && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_STV6110) extern struct dvb_frontend *stv6110_attach(struct dvb_frontend *fe, const struct stv6110_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/tda10048.h b/drivers/media/dvb-frontends/tda10048.h index fb2ef5ac9487..5e7bf4e47cb3 100644 --- a/drivers/media/dvb-frontends/tda10048.h +++ b/drivers/media/dvb-frontends/tda10048.h @@ -22,6 +22,7 @@ #ifndef TDA10048_H #define TDA10048_H +#include #include #include @@ -72,8 +73,7 @@ struct tda10048_config { u8 pll_n; }; -#if defined(CONFIG_DVB_TDA10048) || \ - (defined(CONFIG_DVB_TDA10048_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_TDA10048) extern struct dvb_frontend *tda10048_attach( const struct tda10048_config *config, struct i2c_adapter *i2c); diff --git a/drivers/media/dvb-frontends/tda10071.h b/drivers/media/dvb-frontends/tda10071.h index bff1c38df802..f9542f68fe78 100644 --- a/drivers/media/dvb-frontends/tda10071.h +++ b/drivers/media/dvb-frontends/tda10071.h @@ -21,6 +21,7 @@ #ifndef TDA10071_H #define TDA10071_H +#include #include struct tda10071_config { @@ -71,8 +72,7 @@ struct tda10071_config { }; -#if defined(CONFIG_DVB_TDA10071) || \ - (defined(CONFIG_DVB_TDA10071_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_TDA10071) extern struct dvb_frontend *tda10071_attach( const struct tda10071_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/tda18271c2dd.h b/drivers/media/dvb-frontends/tda18271c2dd.h index 1389c74e12ce..dd84f7b69bec 100644 --- a/drivers/media/dvb-frontends/tda18271c2dd.h +++ b/drivers/media/dvb-frontends/tda18271c2dd.h @@ -1,7 +1,9 @@ #ifndef _TDA18271C2DD_H_ #define _TDA18271C2DD_H_ -#if defined(CONFIG_DVB_TDA18271C2DD) || (defined(CONFIG_DVB_TDA18271C2DD_MODULE) \ - && defined(MODULE)) + +#include + +#if IS_ENABLED(CONFIG_DVB_TDA18271C2DD) struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 adr); #else diff --git a/drivers/media/dvb-frontends/ts2020.h b/drivers/media/dvb-frontends/ts2020.h index c7e64afa614a..5bcb9a71ca80 100644 --- a/drivers/media/dvb-frontends/ts2020.h +++ b/drivers/media/dvb-frontends/ts2020.h @@ -22,6 +22,7 @@ #ifndef TS2020_H #define TS2020_H +#include #include struct ts2020_config { @@ -29,8 +30,7 @@ struct ts2020_config { u8 clk_out_div; }; -#if defined(CONFIG_DVB_TS2020) || \ - (defined(CONFIG_DVB_TS2020_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_TS2020) extern struct dvb_frontend *ts2020_attach( struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/zl10036.h b/drivers/media/dvb-frontends/zl10036.h index d84b8f8215e9..5f1e8217eeb6 100644 --- a/drivers/media/dvb-frontends/zl10036.h +++ b/drivers/media/dvb-frontends/zl10036.h @@ -21,6 +21,7 @@ #ifndef DVB_ZL10036_H #define DVB_ZL10036_H +#include #include #include "dvb_frontend.h" @@ -37,8 +38,7 @@ struct zl10036_config { int rf_loop_enable; }; -#if defined(CONFIG_DVB_ZL10036) || \ - (defined(CONFIG_DVB_ZL10036_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_ZL10036) extern struct dvb_frontend *zl10036_attach(struct dvb_frontend *fe, const struct zl10036_config *config, struct i2c_adapter *i2c); #else diff --git a/drivers/media/dvb-frontends/zl10039.h b/drivers/media/dvb-frontends/zl10039.h index 5eee7ea162a1..750b9bca9d02 100644 --- a/drivers/media/dvb-frontends/zl10039.h +++ b/drivers/media/dvb-frontends/zl10039.h @@ -22,8 +22,9 @@ #ifndef ZL10039_H #define ZL10039_H -#if defined(CONFIG_DVB_ZL10039) || (defined(CONFIG_DVB_ZL10039_MODULE) \ - && defined(MODULE)) +#include + +#if IS_ENABLED(CONFIG_DVB_ZL10039) struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, u8 i2c_addr, struct i2c_adapter *i2c); -- cgit v1.2.3 From 9dc353c67cbe3150d3a6b293662d5a33028adec4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Mar 2013 16:24:09 -0300 Subject: [media] tuners: use IS_ENABLED Instead of checking everywhere there for 3 symbols, use instead IS_ENABLED macro. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/e4000.h | 4 ++-- drivers/media/tuners/fc0011.h | 4 ++-- drivers/media/tuners/fc0012.h | 4 ++-- drivers/media/tuners/fc0013.h | 4 ++-- drivers/media/tuners/fc2580.h | 4 ++-- drivers/media/tuners/max2165.h | 5 +++-- drivers/media/tuners/mc44s803.h | 5 +++-- drivers/media/tuners/mxl5005s.h | 5 +++-- drivers/media/tuners/tda18212.h | 4 ++-- drivers/media/tuners/tda18218.h | 4 ++-- drivers/media/tuners/tua9001.h | 4 ++-- drivers/media/tuners/xc5000.h | 4 ++-- 12 files changed, 27 insertions(+), 24 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/e4000.h b/drivers/media/tuners/e4000.h index 71b1935eb3d2..3783a0bdf855 100644 --- a/drivers/media/tuners/e4000.h +++ b/drivers/media/tuners/e4000.h @@ -21,6 +21,7 @@ #ifndef E4000_H #define E4000_H +#include #include "dvb_frontend.h" struct e4000_config { @@ -36,8 +37,7 @@ struct e4000_config { u32 clock; }; -#if defined(CONFIG_MEDIA_TUNER_E4000) || \ - (defined(CONFIG_MEDIA_TUNER_E4000_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_MEDIA_TUNER_E4000) extern struct dvb_frontend *e4000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct e4000_config *cfg); #else diff --git a/drivers/media/tuners/fc0011.h b/drivers/media/tuners/fc0011.h index 0ee581f122d2..43ec893a6877 100644 --- a/drivers/media/tuners/fc0011.h +++ b/drivers/media/tuners/fc0011.h @@ -1,6 +1,7 @@ #ifndef LINUX_FC0011_H_ #define LINUX_FC0011_H_ +#include #include "dvb_frontend.h" @@ -22,8 +23,7 @@ enum fc0011_fe_callback_commands { FC0011_FE_CALLBACK_RESET, }; -#if defined(CONFIG_MEDIA_TUNER_FC0011) ||\ - defined(CONFIG_MEDIA_TUNER_FC0011_MODULE) +#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0011) struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct fc0011_config *config); diff --git a/drivers/media/tuners/fc0012.h b/drivers/media/tuners/fc0012.h index 54508fcc3469..1d08057e3275 100644 --- a/drivers/media/tuners/fc0012.h +++ b/drivers/media/tuners/fc0012.h @@ -21,6 +21,7 @@ #ifndef _FC0012_H_ #define _FC0012_H_ +#include #include "dvb_frontend.h" #include "fc001x-common.h" @@ -48,8 +49,7 @@ struct fc0012_config { bool clock_out; }; -#if defined(CONFIG_MEDIA_TUNER_FC0012) || \ - (defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0012) extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct fc0012_config *cfg); diff --git a/drivers/media/tuners/fc0013.h b/drivers/media/tuners/fc0013.h index 594efd64aeec..d65d5b37f56e 100644 --- a/drivers/media/tuners/fc0013.h +++ b/drivers/media/tuners/fc0013.h @@ -22,11 +22,11 @@ #ifndef _FC0013_H_ #define _FC0013_H_ +#include #include "dvb_frontend.h" #include "fc001x-common.h" -#if defined(CONFIG_MEDIA_TUNER_FC0013) || \ - (defined(CONFIG_MEDIA_TUNER_FC0013_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC0013) extern struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_address, int dual_master, diff --git a/drivers/media/tuners/fc2580.h b/drivers/media/tuners/fc2580.h index 222601e5d23b..9c43c1cc82d9 100644 --- a/drivers/media/tuners/fc2580.h +++ b/drivers/media/tuners/fc2580.h @@ -21,6 +21,7 @@ #ifndef FC2580_H #define FC2580_H +#include #include "dvb_frontend.h" struct fc2580_config { @@ -36,8 +37,7 @@ struct fc2580_config { u32 clock; }; -#if defined(CONFIG_MEDIA_TUNER_FC2580) || \ - (defined(CONFIG_MEDIA_TUNER_FC2580_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_MEDIA_TUNER_FC2580) extern struct dvb_frontend *fc2580_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct fc2580_config *cfg); #else diff --git a/drivers/media/tuners/max2165.h b/drivers/media/tuners/max2165.h index c063c36a93d3..26e1dc64bb67 100644 --- a/drivers/media/tuners/max2165.h +++ b/drivers/media/tuners/max2165.h @@ -22,6 +22,8 @@ #ifndef __MAX2165_H__ #define __MAX2165_H__ +#include + struct dvb_frontend; struct i2c_adapter; @@ -30,8 +32,7 @@ struct max2165_config { u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */ }; -#if defined(CONFIG_MEDIA_TUNER_MAX2165) || \ - (defined(CONFIG_MEDIA_TUNER_MAX2165_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_MEDIA_TUNER_MAX2165) extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct max2165_config *cfg); diff --git a/drivers/media/tuners/mc44s803.h b/drivers/media/tuners/mc44s803.h index 34f3892d3f6d..9aae50aca2b7 100644 --- a/drivers/media/tuners/mc44s803.h +++ b/drivers/media/tuners/mc44s803.h @@ -22,6 +22,8 @@ #ifndef MC44S803_H #define MC44S803_H +#include + struct dvb_frontend; struct i2c_adapter; @@ -30,8 +32,7 @@ struct mc44s803_config { u8 dig_out; }; -#if defined(CONFIG_MEDIA_TUNER_MC44S803) || \ - (defined(CONFIG_MEDIA_TUNER_MC44S803_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_MEDIA_TUNER_MC44S803) extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mc44s803_config *cfg); #else diff --git a/drivers/media/tuners/mxl5005s.h b/drivers/media/tuners/mxl5005s.h index fc8a1ffc53b4..ae8db885ad87 100644 --- a/drivers/media/tuners/mxl5005s.h +++ b/drivers/media/tuners/mxl5005s.h @@ -23,6 +23,8 @@ #ifndef __MXL5005S_H #define __MXL5005S_H +#include + #include #include "dvb_frontend.h" @@ -116,8 +118,7 @@ struct mxl5005s_config { u8 AgcMasterByte; }; -#if defined(CONFIG_MEDIA_TUNER_MXL5005S) || \ - (defined(CONFIG_MEDIA_TUNER_MXL5005S_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_MEDIA_TUNER_MXL5005S) extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mxl5005s_config *config); diff --git a/drivers/media/tuners/tda18212.h b/drivers/media/tuners/tda18212.h index 9bd5da4aabb7..7e0d503baf05 100644 --- a/drivers/media/tuners/tda18212.h +++ b/drivers/media/tuners/tda18212.h @@ -21,6 +21,7 @@ #ifndef TDA18212_H #define TDA18212_H +#include #include "dvb_frontend.h" struct tda18212_config { @@ -36,8 +37,7 @@ struct tda18212_config { u16 if_dvbc; }; -#if defined(CONFIG_MEDIA_TUNER_TDA18212) || \ - (defined(CONFIG_MEDIA_TUNER_TDA18212_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18212) extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct tda18212_config *cfg); #else diff --git a/drivers/media/tuners/tda18218.h b/drivers/media/tuners/tda18218.h index b4180d180029..366410e0cc9a 100644 --- a/drivers/media/tuners/tda18218.h +++ b/drivers/media/tuners/tda18218.h @@ -21,6 +21,7 @@ #ifndef TDA18218_H #define TDA18218_H +#include #include "dvb_frontend.h" struct tda18218_config { @@ -29,8 +30,7 @@ struct tda18218_config { u8 loop_through:1; }; -#if defined(CONFIG_MEDIA_TUNER_TDA18218) || \ - (defined(CONFIG_MEDIA_TUNER_TDA18218_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA18218) extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct tda18218_config *cfg); #else diff --git a/drivers/media/tuners/tua9001.h b/drivers/media/tuners/tua9001.h index cf5b815feff9..26358da1c100 100644 --- a/drivers/media/tuners/tua9001.h +++ b/drivers/media/tuners/tua9001.h @@ -21,6 +21,7 @@ #ifndef TUA9001_H #define TUA9001_H +#include #include "dvb_frontend.h" struct tua9001_config { @@ -50,8 +51,7 @@ struct tua9001_config { #define TUA9001_CMD_RESETN 1 #define TUA9001_CMD_RXEN 2 -#if defined(CONFIG_MEDIA_TUNER_TUA9001) || \ - (defined(CONFIG_MEDIA_TUNER_TUA9001_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_MEDIA_TUNER_TUA9001) extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct tua9001_config *cfg); #else diff --git a/drivers/media/tuners/xc5000.h b/drivers/media/tuners/xc5000.h index b1a547494625..7245cae19f0c 100644 --- a/drivers/media/tuners/xc5000.h +++ b/drivers/media/tuners/xc5000.h @@ -22,6 +22,7 @@ #ifndef __XC5000_H__ #define __XC5000_H__ +#include #include struct dvb_frontend; @@ -56,8 +57,7 @@ struct xc5000_config { * it's passed back to a bridge during tuner_callback(). */ -#if defined(CONFIG_MEDIA_TUNER_XC5000) || \ - (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_MEDIA_TUNER_XC5000) extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, const struct xc5000_config *cfg); -- cgit v1.2.3 From 1c59390b3b551524d4c8415bd39c9c788705c7c0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Mar 2013 16:29:08 -0300 Subject: [media] cx23885: use IS_ENABLED Instead of checking everywhere there for 3 symbols, use instead IS_ENABLED macro. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/altera-ci.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h index 70e4fd69ad9e..4998c96caebe 100644 --- a/drivers/media/pci/cx23885/altera-ci.h +++ b/drivers/media/pci/cx23885/altera-ci.h @@ -24,6 +24,8 @@ #ifndef __ALTERA_CI_H #define __ALTERA_CI_H +#include + #define ALT_DATA 0x000000ff #define ALT_TDI 0x00008000 #define ALT_TDO 0x00004000 @@ -41,8 +43,7 @@ struct altera_ci_config { int (*fpga_rw) (void *dev, int ad_rg, int val, int rw); }; -#if defined(CONFIG_MEDIA_ALTERA_CI) || (defined(CONFIG_MEDIA_ALTERA_CI_MODULE) \ - && defined(MODULE)) +#if IS_ENABLED(CONFIG_MEDIA_ALTERA_CI) extern int altera_ci_init(struct altera_ci_config *config, int ci_nr); extern void altera_ci_release(void *dev, int ci_nr); -- cgit v1.2.3 From 028c70ff42783509d3a7c7fa0faf900446a2657a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 21 Mar 2013 16:29:36 -0300 Subject: [media] dvb-usb/dvb-usb-v2: use IS_ENABLED Instead of checking everywhere there for 3 symbols, use instead IS_ENABLED macro. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h | 4 ++-- drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h | 5 ++--- drivers/media/usb/dvb-usb/dibusb-common.c | 5 +++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h index 432706ae5274..3f3f8bfd190b 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h @@ -21,6 +21,7 @@ #ifndef __MXL111SF_DEMOD_H__ #define __MXL111SF_DEMOD_H__ +#include #include "dvb_frontend.h" #include "mxl111sf.h" @@ -31,8 +32,7 @@ struct mxl111sf_demod_config { struct mxl111sf_reg_ctrl_info *ctrl_reg_info); }; -#if defined(CONFIG_DVB_USB_MXL111SF) || \ - (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_USB_MXL111SF) extern struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state, struct mxl111sf_demod_config *cfg); diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h index ff333960b184..90f583e5d6a6 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h @@ -21,8 +21,8 @@ #ifndef __MXL111SF_TUNER_H__ #define __MXL111SF_TUNER_H__ +#include #include "dvb_frontend.h" - #include "mxl111sf.h" enum mxl_if_freq { @@ -60,8 +60,7 @@ struct mxl111sf_tuner_config { /* ------------------------------------------------------------------------ */ -#if defined(CONFIG_DVB_USB_MXL111SF) || \ - (defined(CONFIG_DVB_USB_MXL111SF_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_USB_MXL111SF) extern struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe, struct mxl111sf_state *mxl_state, diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c index af0d4321845b..c2dded92f1d3 100644 --- a/drivers/media/usb/dvb-usb/dibusb-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-common.c @@ -8,6 +8,8 @@ * * see Documentation/dvb/README.dvb-usb for more information */ + +#include #include "dibusb.h" static int debug; @@ -232,8 +234,7 @@ static struct dibx000_agc_config dib3000p_panasonic_agc_config = { .agc2_slope2 = 0x1e, }; -#if defined(CONFIG_DVB_DIB3000MC) || \ - (defined(CONFIG_DVB_DIB3000MC_MODULE) && defined(MODULE)) +#if IS_ENABLED(CONFIG_DVB_DIB3000MC) static struct dib3000mc_config mod3000p_dib3000p_config = { &dib3000p_panasonic_agc_config, -- cgit v1.2.3 From bdecbe43e345d1e5a0fa82625d7beb7c3371763e Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Mar 2013 00:16:32 -0300 Subject: [media] dvb_usb_v2: replace Kernel userspace lock with wait queue There was sync mutex which was held over userspace. That is very wrong and could cause deadlock if different userspace process is used to "unlock". Wait queue seems to be correct solution for that kind of synchronizing issue so use it instead. lock debug gives following bug report: ================================================ [ BUG: lock held when returning to user space! ] 3.9.0-rc1+ #38 Tainted: G O ------------------------------------------------ tzap/4614 is leaving the kernel with locks still held! 1 lock held by tzap/4614: Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvb_usb.h | 5 ++- drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 53 ++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index 42801f8ecaa8..658c6d47fdff 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -329,13 +329,16 @@ struct dvb_usb_adapter { u8 feed_count; u8 max_feed_count; s8 active_fe; +#define ADAP_INIT 0 +#define ADAP_SLEEP 1 +#define ADAP_STREAMING 2 + unsigned long state_bits; /* dvb */ struct dvb_adapter dvb_adap; struct dmxdev dmxdev; struct dvb_demux demux; struct dvb_net dvb_net; - struct mutex sync_mutex; struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP]; int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *); diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 086792055912..c91da3c4d332 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -253,6 +253,13 @@ static int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) return usb_urb_exitv2(&adap->stream); } +static int wait_schedule(void *ptr) +{ + schedule(); + + return 0; +} + static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int count) { @@ -266,6 +273,9 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, dvbdmxfeed->pid, dvbdmxfeed->index, (count == 1) ? "on" : "off"); + wait_on_bit(&adap->state_bits, ADAP_INIT, wait_schedule, + TASK_UNINTERRUPTIBLE); + if (adap->active_fe == -1) return -EINVAL; @@ -283,11 +293,14 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, "failed=%d\n", KBUILD_MODNAME, ret); usb_urb_killv2(&adap->stream); - goto err_mutex_unlock; + goto err_clear_wait; } } usb_urb_killv2(&adap->stream); - mutex_unlock(&adap->sync_mutex); + + clear_bit(ADAP_STREAMING, &adap->state_bits); + smp_mb__after_clear_bit(); + wake_up_bit(&adap->state_bits, ADAP_STREAMING); } /* activate the pid on the device pid filter */ @@ -303,7 +316,7 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, /* start feeding if it is first pid */ if (adap->feed_count == 1 && count == 1) { struct usb_data_stream_properties stream_props; - mutex_lock(&adap->sync_mutex); + set_bit(ADAP_STREAMING, &adap->state_bits); dev_dbg(&d->udev->dev, "%s: start feeding\n", __func__); /* resolve input and output streaming paramters */ @@ -314,7 +327,7 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, adap->fe[adap->active_fe], &adap->ts_type, &stream_props); if (ret < 0) - goto err_mutex_unlock; + goto err_clear_wait; } else { stream_props = adap->props->stream; } @@ -344,7 +357,7 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, dev_err(&d->udev->dev, "%s: " \ "pid_filter_ctrl() failed=%d\n", KBUILD_MODNAME, ret); - goto err_mutex_unlock; + goto err_clear_wait; } } @@ -355,14 +368,16 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, dev_err(&d->udev->dev, "%s: streaming_ctrl() " \ "failed=%d\n", KBUILD_MODNAME, ret); - goto err_mutex_unlock; + goto err_clear_wait; } } } return 0; -err_mutex_unlock: - mutex_unlock(&adap->sync_mutex); +err_clear_wait: + clear_bit(ADAP_STREAMING, &adap->state_bits); + smp_mb__after_clear_bit(); + wake_up_bit(&adap->state_bits, ADAP_STREAMING); dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } @@ -435,8 +450,6 @@ static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) goto err_dvb_net_init; } - mutex_init(&adap->sync_mutex); - return 0; err_dvb_net_init: dvb_dmxdev_release(&adap->dmxdev); @@ -500,7 +513,7 @@ static int dvb_usb_fe_init(struct dvb_frontend *fe) if (!adap->suspend_resume_active) { adap->active_fe = fe->id; - mutex_lock(&adap->sync_mutex); + set_bit(ADAP_INIT, &adap->state_bits); } ret = dvb_usbv2_device_power_ctrl(d, 1); @@ -519,8 +532,11 @@ static int dvb_usb_fe_init(struct dvb_frontend *fe) goto err; } err: - if (!adap->suspend_resume_active) - mutex_unlock(&adap->sync_mutex); + if (!adap->suspend_resume_active) { + clear_bit(ADAP_INIT, &adap->state_bits); + smp_mb__after_clear_bit(); + wake_up_bit(&adap->state_bits, ADAP_INIT); + } dev_dbg(&d->udev->dev, "%s: ret=%d\n", __func__, ret); return ret; @@ -534,8 +550,11 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id, fe->id); - if (!adap->suspend_resume_active) - mutex_lock(&adap->sync_mutex); + if (!adap->suspend_resume_active) { + set_bit(ADAP_SLEEP, &adap->state_bits); + wait_on_bit(&adap->state_bits, ADAP_STREAMING, wait_schedule, + TASK_UNINTERRUPTIBLE); + } if (adap->fe_sleep[fe->id]) { ret = adap->fe_sleep[fe->id](fe); @@ -555,7 +574,9 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) err: if (!adap->suspend_resume_active) { adap->active_fe = -1; - mutex_unlock(&adap->sync_mutex); + clear_bit(ADAP_SLEEP, &adap->state_bits); + smp_mb__after_clear_bit(); + wake_up_bit(&adap->state_bits, ADAP_SLEEP); } dev_dbg(&d->udev->dev, "%s: ret=%d\n", __func__, ret); -- cgit v1.2.3 From 6d7cfec4130fdbe4b74277c91b6ba91f56eaca03 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Mar 2013 11:36:35 -0300 Subject: [media] dvb_usb_v2: make checkpatch.pl happy New checkpatch version likes to see strings not to split multiple lines even those are exceeding 80 line length. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 81 +++++++++++++++-------------- drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c | 5 +- drivers/media/usb/dvb-usb-v2/usb_urb.c | 36 +++++++------ 3 files changed, 65 insertions(+), 57 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index c91da3c4d332..9b24a0e9675a 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -28,10 +28,11 @@ MODULE_PARM_DESC(disable_rc_polling, static int dvb_usb_force_pid_filter_usage; module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444); -MODULE_PARM_DESC(force_pid_filter_usage, "force all DVB USB devices to use a " \ - "PID filter, if any (default: 0)"); +MODULE_PARM_DESC(force_pid_filter_usage, + "force all DVB USB devices to use a PID filter, if any (default: 0)"); -static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *name) +static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, + const char *name) { int ret; const struct firmware *fw; @@ -44,10 +45,9 @@ static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *nam ret = request_firmware(&fw, name, &d->udev->dev); if (ret < 0) { - dev_err(&d->udev->dev, "%s: Did not find the firmware file "\ - "'%s'. Please see linux/Documentation/dvb/ " \ - "for more details on firmware-problems. " \ - "Status %d\n", KBUILD_MODNAME, name, ret); + dev_err(&d->udev->dev, + "%s: Did not find the firmware file '%s'. Please see linux/Documentation/dvb/ for more details on firmware-problems. Status %d\n", + KBUILD_MODNAME, name, ret); goto err; } @@ -181,9 +181,9 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d) /* initialize a work queue for handling polling */ INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control); - dev_info(&d->udev->dev, "%s: schedule remote query interval " \ - "to %d msecs\n", KBUILD_MODNAME, - d->rc.interval); + dev_info(&d->udev->dev, + "%s: schedule remote query interval to %d msecs\n", + KBUILD_MODNAME, d->rc.interval); schedule_delayed_work(&d->rc_query_work, msecs_to_jiffies(d->rc.interval)); d->rc_polling_active = true; @@ -266,8 +266,7 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; struct dvb_usb_device *d = adap_to_d(adap); int ret; - dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d " \ - "setting pid [%s]: %04x (%04d) at index %d '%s'\n", + dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: %04x (%04d) at index %d '%s'\n", __func__, adap->id, adap->active_fe, dvbdmxfeed->type, adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, dvbdmxfeed->pid, dvbdmxfeed->index, @@ -289,9 +288,9 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, ret = d->props->streaming_ctrl( adap->fe[adap->active_fe], 0); if (ret < 0) { - dev_err(&d->udev->dev, "%s: streaming_ctrl() " \ - "failed=%d\n", KBUILD_MODNAME, - ret); + dev_err(&d->udev->dev, + "%s: streaming_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); usb_urb_killv2(&adap->stream); goto err_clear_wait; } @@ -354,8 +353,8 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, ret = adap->props->pid_filter_ctrl(adap, adap->pid_filtering); if (ret < 0) { - dev_err(&d->udev->dev, "%s: " \ - "pid_filter_ctrl() failed=%d\n", + dev_err(&d->udev->dev, + "%s: pid_filter_ctrl() failed=%d\n", KBUILD_MODNAME, ret); goto err_clear_wait; } @@ -365,9 +364,9 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, ret = d->props->streaming_ctrl( adap->fe[adap->active_fe], 1); if (ret < 0) { - dev_err(&d->udev->dev, "%s: streaming_ctrl() " \ - "failed=%d\n", KBUILD_MODNAME, - ret); + dev_err(&d->udev->dev, + "%s: streaming_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); goto err_clear_wait; } } @@ -595,8 +594,9 @@ static int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) if (d->props->frontend_attach) { ret = d->props->frontend_attach(adap); if (ret < 0) { - dev_dbg(&d->udev->dev, "%s: frontend_attach() " \ - "failed=%d\n", __func__, ret); + dev_dbg(&d->udev->dev, + "%s: frontend_attach() failed=%d\n", + __func__, ret); goto err_dvb_frontend_detach; } } else { @@ -616,8 +616,9 @@ static int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]); if (ret < 0) { - dev_err(&d->udev->dev, "%s: frontend%d registration " \ - "failed\n", KBUILD_MODNAME, i); + dev_err(&d->udev->dev, + "%s: frontend%d registration failed\n", + KBUILD_MODNAME, i); goto err_dvb_unregister_frontend; } @@ -691,33 +692,33 @@ static int dvb_usbv2_adapter_init(struct dvb_usb_device *d) /* speed - when running at FULL speed we need a HW PID filter */ if (d->udev->speed == USB_SPEED_FULL && !(adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) { - dev_err(&d->udev->dev, "%s: this USB2.0 device " \ - "cannot be run on a USB1.1 port (it " \ - "lacks a hardware PID filter)\n", + dev_err(&d->udev->dev, + "%s: this USB2.0 device cannot be run on a USB1.1 port (it lacks a hardware PID filter)\n", KBUILD_MODNAME); ret = -ENODEV; goto err; } else if ((d->udev->speed == USB_SPEED_FULL && adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) || (adap->props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) { - dev_info(&d->udev->dev, "%s: will use the device's " \ - "hardware PID filter " \ - "(table count: %d)\n", KBUILD_MODNAME, + dev_info(&d->udev->dev, + "%s: will use the device's hardware PID filter (table count: %d)\n", + KBUILD_MODNAME, adap->props->pid_filter_count); adap->pid_filtering = 1; adap->max_feed_count = adap->props->pid_filter_count; } else { - dev_info(&d->udev->dev, "%s: will pass the complete " \ - "MPEG2 transport stream to the " \ - "software demuxer\n", KBUILD_MODNAME); + dev_info(&d->udev->dev, + "%s: will pass the complete MPEG2 transport stream to the software demuxer\n", + KBUILD_MODNAME); adap->pid_filtering = 0; adap->max_feed_count = 255; } if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage && adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) { - dev_info(&d->udev->dev, "%s: PID filter enabled by " \ - "module option\n", KBUILD_MODNAME); + dev_info(&d->udev->dev, + "%s: PID filter enabled by module option\n", + KBUILD_MODNAME); adap->pid_filtering = 1; adap->max_feed_count = adap->props->pid_filter_count; } @@ -846,8 +847,9 @@ static void dvb_usbv2_init_work(struct work_struct *work) if (ret == 0) { ; } else if (ret == COLD) { - dev_info(&d->udev->dev, "%s: found a '%s' in cold " \ - "state\n", KBUILD_MODNAME, d->name); + dev_info(&d->udev->dev, + "%s: found a '%s' in cold state\n", + KBUILD_MODNAME, d->name); if (!name) name = d->props->firmware; @@ -889,8 +891,9 @@ static void dvb_usbv2_init_work(struct work_struct *work) if (ret < 0) goto err_usb_driver_release_interface; - dev_info(&d->udev->dev, "%s: '%s' successfully initialized and " \ - "connected\n", KBUILD_MODNAME, d->name); + dev_info(&d->udev->dev, + "%s: '%s' successfully initialized and connected\n", + KBUILD_MODNAME, d->name); return; err_usb_driver_release_interface: diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c index aa0c35ef3179..33ff97e708e3 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c @@ -54,8 +54,9 @@ static int dvb_usb_v2_generic_io(struct dvb_usb_device *d, d->props->generic_bulk_ctrl_endpoint_response), rbuf, rlen, &actual_length, 2000); if (ret) - dev_err(&d->udev->dev, "%s: 2nd usb_bulk_msg() " \ - "failed=%d\n", KBUILD_MODNAME, ret); + dev_err(&d->udev->dev, + "%s: 2nd usb_bulk_msg() failed=%d\n", + KBUILD_MODNAME, ret); dev_dbg(&d->udev->dev, "%s: <<< %*ph\n", __func__, actual_length, rbuf); diff --git a/drivers/media/usb/dvb-usb-v2/usb_urb.c b/drivers/media/usb/dvb-usb-v2/usb_urb.c index 7346f85f3f2f..ca8f3c2b1082 100644 --- a/drivers/media/usb/dvb-usb-v2/usb_urb.c +++ b/drivers/media/usb/dvb-usb-v2/usb_urb.c @@ -22,8 +22,8 @@ static void usb_urb_complete(struct urb *urb) int i; u8 *b; - dev_dbg_ratelimited(&stream->udev->dev, "%s: %s urb completed " \ - "status=%d length=%d/%d pack_num=%d errors=%d\n", + dev_dbg_ratelimited(&stream->udev->dev, + "%s: %s urb completed status=%d length=%d/%d pack_num=%d errors=%d\n", __func__, ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", urb->status, urb->actual_length, urb->transfer_buffer_length, @@ -49,8 +49,8 @@ static void usb_urb_complete(struct urb *urb) case PIPE_ISOCHRONOUS: for (i = 0; i < urb->number_of_packets; i++) { if (urb->iso_frame_desc[i].status != 0) - dev_dbg(&stream->udev->dev, "%s: iso frame " \ - "descriptor has an error=%d\n", + dev_dbg(&stream->udev->dev, + "%s: iso frame descriptor has an error=%d\n", __func__, urb->iso_frame_desc[i].status); else if (urb->iso_frame_desc[i].actual_length > 0) @@ -67,8 +67,9 @@ static void usb_urb_complete(struct urb *urb) stream->complete(stream, b, urb->actual_length); break; default: - dev_err(&stream->udev->dev, "%s: unknown endpoint type in " \ - "completition handler\n", KBUILD_MODNAME); + dev_err(&stream->udev->dev, + "%s: unknown endpoint type in completition handler\n", + KBUILD_MODNAME); return; } usb_submit_urb(urb, GFP_ATOMIC); @@ -101,8 +102,8 @@ int usb_urb_submitv2(struct usb_data_stream *stream, dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i); ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC); if (ret) { - dev_err(&stream->udev->dev, "%s: could not submit " \ - "urb no. %d - get them all back\n", + dev_err(&stream->udev->dev, + "%s: could not submit urb no. %d - get them all back\n", KBUILD_MODNAME, i); usb_urb_killv2(stream); return ret; @@ -229,8 +230,9 @@ static int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num, stream->buf_num = 0; stream->buf_size = size; - dev_dbg(&stream->udev->dev, "%s: all in all I will use %lu bytes for " \ - "streaming\n", __func__, num * size); + dev_dbg(&stream->udev->dev, + "%s: all in all I will use %lu bytes for streaming\n", + __func__, num * size); for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) { stream->buf_list[stream->buf_num] = usb_alloc_coherent( @@ -274,8 +276,8 @@ int usb_urb_reconfig(struct usb_data_stream *stream, } if (stream->buf_num < props->count || stream->buf_size < buf_size) { - dev_err(&stream->udev->dev, "%s: cannot reconfigure as " \ - "allocated buffers are too small\n", + dev_err(&stream->udev->dev, + "%s: cannot reconfigure as allocated buffers are too small\n", KBUILD_MODNAME); return -EINVAL; } @@ -321,8 +323,9 @@ int usb_urb_initv2(struct usb_data_stream *stream, memcpy(&stream->props, props, sizeof(*props)); if (!stream->complete) { - dev_err(&stream->udev->dev, "%s: there is no data callback - " \ - "this doesn't make sense\n", KBUILD_MODNAME); + dev_err(&stream->udev->dev, + "%s: there is no data callback - this doesn't make sense\n", + KBUILD_MODNAME); return -EINVAL; } @@ -343,8 +346,9 @@ int usb_urb_initv2(struct usb_data_stream *stream, return usb_urb_alloc_isoc_urbs(stream); default: - dev_err(&stream->udev->dev, "%s: unknown urb-type for data " \ - "transfer\n", KBUILD_MODNAME); + dev_err(&stream->udev->dev, + "%s: unknown urb-type for data transfer\n", + KBUILD_MODNAME); return -EINVAL; } } -- cgit v1.2.3 From 61356eea6742ad38ad9ecfd5c65e2662e4c9d8ab Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Mar 2013 11:38:41 -0300 Subject: [media] cypress_firmware: make checkpatch.pl happy New checkpatch version likes to see strings not to split multiple lines even those are exceeding 80 line length. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/cypress_firmware.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.c b/drivers/media/usb/dvb-usb-v2/cypress_firmware.c index 211df549f26a..cfb1733519c2 100644 --- a/drivers/media/usb/dvb-usb-v2/cypress_firmware.c +++ b/drivers/media/usb/dvb-usb-v2/cypress_firmware.c @@ -71,9 +71,8 @@ int usbv2_cypress_load_firmware(struct usb_device *udev, if (ret < 0) { goto err_kfree; } else if (ret != hx->len) { - dev_err(&udev->dev, "%s: error while transferring " \ - "firmware (transferred size=%d, " \ - "block size=%d)\n", + dev_err(&udev->dev, + "%s: error while transferring firmware (transferred size=%d, block size=%d)\n", KBUILD_MODNAME, ret, hx->len); ret = -EIO; goto err_kfree; -- cgit v1.2.3 From 96d7ca5ec9baac231ab3dfd62abcb75141d80626 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Mar 2013 16:10:55 -0300 Subject: [media] dvb_usb_v2: rework USB streaming logic Control flow order changed a little bit. HW PID filter is now disabled also when streaming is stopped - earlier it was just set only when streaming was started. Control flow is now: * set streaming status bit * submit USB streaming packets * enable HW PID filter * ask device to start streaming * N x add PID to device HW PID filter ... streaming video ... * N x remove PID from device HW PID filter * ask device to stop streaming * disable HW PID filter * kill USB streaming packets * clear streaming status bit Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 215 +++++++++++++++------------- 1 file changed, 116 insertions(+), 99 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 9b24a0e9675a..19f6737d9817 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -260,135 +260,152 @@ static int wait_schedule(void *ptr) return 0; } -static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, - int count) +static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; struct dvb_usb_device *d = adap_to_d(adap); - int ret; - dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: %04x (%04d) at index %d '%s'\n", + int ret = 0; + struct usb_data_stream_properties stream_props; + dev_dbg(&d->udev->dev, + "%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: %04x (%04d) at index %d\n", __func__, adap->id, adap->active_fe, dvbdmxfeed->type, adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, - dvbdmxfeed->pid, dvbdmxfeed->index, - (count == 1) ? "on" : "off"); + dvbdmxfeed->pid, dvbdmxfeed->index); + /* wait init is done */ wait_on_bit(&adap->state_bits, ADAP_INIT, wait_schedule, TASK_UNINTERRUPTIBLE); if (adap->active_fe == -1) return -EINVAL; - adap->feed_count += count; - - /* stop feeding if it is last pid */ - if (adap->feed_count == 0) { - dev_dbg(&d->udev->dev, "%s: stop feeding\n", __func__); - - if (d->props->streaming_ctrl) { - ret = d->props->streaming_ctrl( - adap->fe[adap->active_fe], 0); - if (ret < 0) { - dev_err(&d->udev->dev, - "%s: streaming_ctrl() failed=%d\n", - KBUILD_MODNAME, ret); - usb_urb_killv2(&adap->stream); - goto err_clear_wait; - } - } - usb_urb_killv2(&adap->stream); + /* skip feed setup if we are already feeding */ + if (adap->feed_count++ > 0) + goto skip_feed_start; - clear_bit(ADAP_STREAMING, &adap->state_bits); - smp_mb__after_clear_bit(); - wake_up_bit(&adap->state_bits, ADAP_STREAMING); + /* set 'streaming' status bit */ + set_bit(ADAP_STREAMING, &adap->state_bits); + + /* resolve input and output streaming parameters */ + if (d->props->get_stream_config) { + memcpy(&stream_props, &adap->props->stream, + sizeof(struct usb_data_stream_properties)); + ret = d->props->get_stream_config(adap->fe[adap->active_fe], + &adap->ts_type, &stream_props); + if (ret) + dev_err(&d->udev->dev, + "%s: get_stream_config() failed=%d\n", + KBUILD_MODNAME, ret); + } else { + stream_props = adap->props->stream; + } + + switch (adap->ts_type) { + case DVB_USB_FE_TS_TYPE_204: + adap->stream.complete = dvb_usb_data_complete_204; + break; + case DVB_USB_FE_TS_TYPE_RAW: + adap->stream.complete = dvb_usb_data_complete_raw; + break; + case DVB_USB_FE_TS_TYPE_188: + default: + adap->stream.complete = dvb_usb_data_complete; + break; + } + + /* submit USB streaming packets */ + usb_urb_submitv2(&adap->stream, &stream_props); + + /* enable HW PID filter */ + if (adap->pid_filtering && adap->props->pid_filter_ctrl) { + ret = adap->props->pid_filter_ctrl(adap, 1); + if (ret) + dev_err(&d->udev->dev, + "%s: pid_filter_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); } - /* activate the pid on the device pid filter */ - if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->pid_filtering && adap->props->pid_filter) { + /* ask device to start streaming */ + if (d->props->streaming_ctrl) { + ret = d->props->streaming_ctrl(adap->fe[adap->active_fe], 1); + if (ret) + dev_err(&d->udev->dev, + "%s: streaming_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); + } +skip_feed_start: + + /* add PID to device HW PID filter */ + if (adap->pid_filtering && adap->props->pid_filter) { ret = adap->props->pid_filter(adap, dvbdmxfeed->index, - dvbdmxfeed->pid, (count == 1) ? 1 : 0); - if (ret < 0) + dvbdmxfeed->pid, 1); + if (ret) dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n", KBUILD_MODNAME, ret); } - /* start feeding if it is first pid */ - if (adap->feed_count == 1 && count == 1) { - struct usb_data_stream_properties stream_props; - set_bit(ADAP_STREAMING, &adap->state_bits); - dev_dbg(&d->udev->dev, "%s: start feeding\n", __func__); + if (ret) + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} - /* resolve input and output streaming paramters */ - if (d->props->get_stream_config) { - memcpy(&stream_props, &adap->props->stream, - sizeof(struct usb_data_stream_properties)); - ret = d->props->get_stream_config( - adap->fe[adap->active_fe], - &adap->ts_type, &stream_props); - if (ret < 0) - goto err_clear_wait; - } else { - stream_props = adap->props->stream; - } +static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv; + struct dvb_usb_device *d = adap_to_d(adap); + int ret = 0; + dev_dbg(&d->udev->dev, + "%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: %04x (%04d) at index %d\n", + __func__, adap->id, adap->active_fe, dvbdmxfeed->type, + adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid, + dvbdmxfeed->pid, dvbdmxfeed->index); - switch (adap->ts_type) { - case DVB_USB_FE_TS_TYPE_204: - adap->stream.complete = dvb_usb_data_complete_204; - break; - case DVB_USB_FE_TS_TYPE_RAW: - adap->stream.complete = dvb_usb_data_complete_raw; - break; - case DVB_USB_FE_TS_TYPE_188: - default: - adap->stream.complete = dvb_usb_data_complete; - break; - } + if (adap->active_fe == -1) + return -EINVAL; - usb_urb_submitv2(&adap->stream, &stream_props); - - if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->props->caps & - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF && - adap->props->pid_filter_ctrl) { - ret = adap->props->pid_filter_ctrl(adap, - adap->pid_filtering); - if (ret < 0) { - dev_err(&d->udev->dev, - "%s: pid_filter_ctrl() failed=%d\n", - KBUILD_MODNAME, ret); - goto err_clear_wait; - } - } + /* remove PID from device HW PID filter */ + if (adap->pid_filtering && adap->props->pid_filter) { + ret = adap->props->pid_filter(adap, dvbdmxfeed->index, + dvbdmxfeed->pid, 0); + if (ret) + dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n", + KBUILD_MODNAME, ret); + } - if (d->props->streaming_ctrl) { - ret = d->props->streaming_ctrl( - adap->fe[adap->active_fe], 1); - if (ret < 0) { - dev_err(&d->udev->dev, - "%s: streaming_ctrl() failed=%d\n", - KBUILD_MODNAME, ret); - goto err_clear_wait; - } - } + /* we cannot stop streaming until last PID is removed */ + if (--adap->feed_count > 0) + goto skip_feed_stop; + + /* ask device to stop streaming */ + if (d->props->streaming_ctrl) { + ret = d->props->streaming_ctrl(adap->fe[adap->active_fe], 0); + if (ret) + dev_err(&d->udev->dev, + "%s: streaming_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); } - return 0; -err_clear_wait: + /* disable HW PID filter */ + if (adap->pid_filtering && adap->props->pid_filter_ctrl) { + ret = adap->props->pid_filter_ctrl(adap, 0); + if (ret) + dev_err(&d->udev->dev, + "%s: pid_filter_ctrl() failed=%d\n", + KBUILD_MODNAME, ret); + } + + /* kill USB streaming packets */ + usb_urb_killv2(&adap->stream); + + /* clear 'streaming' status bit */ clear_bit(ADAP_STREAMING, &adap->state_bits); smp_mb__after_clear_bit(); wake_up_bit(&adap->state_bits, ADAP_STREAMING); - dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); - return ret; -} - -static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - return dvb_usb_ctrl_feed(dvbdmxfeed, 1); -} +skip_feed_stop: -static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - return dvb_usb_ctrl_feed(dvbdmxfeed, -1); + if (ret) + dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); + return ret; } static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) -- cgit v1.2.3 From b09e71a8de288bbd2e8ad48e6537d64214aad51b Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Mar 2013 21:10:14 -0300 Subject: [media] it913x: fix pid filter I just made commit: "dvb_usb_v2: rework USB streaming logic" that breaks that driver PID filter. it913x driver checks use of PID filter directly from DVB USB v2 core internal variable "adap->pid_filtering" and stores it to own state. Calling order of .pid_filter_ctrl() and .pid_filter() was changed and due to that state was updated too late. Update state earlier. TODO: checking PID filter usage from DVB USB v2 is not very good idea as PID filter callbacks are called only when PID filter is enabled. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/it913x.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/it913x.c b/drivers/media/usb/dvb-usb-v2/it913x.c index 833847995c65..e48cdeb9df41 100644 --- a/drivers/media/usb/dvb-usb-v2/it913x.c +++ b/drivers/media/usb/dvb-usb-v2/it913x.c @@ -218,6 +218,7 @@ static int it913x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff) deb_info(1, "PID_C (%02x)", onoff); + st->pid_filter_onoff = adap->pid_filtering; ret = it913x_wr_reg(d, pro, PID_EN, st->pid_filter_onoff); mutex_unlock(&d->i2c_mutex); -- cgit v1.2.3 From 385624a8e74374f19a3db4f066dd21f213447a7a Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Tue, 19 Mar 2013 11:41:31 -0300 Subject: [media] media: radio: CodingStyle changes on si4713 Minor changes to make alignment match on open parenthesis. Signed-off-by: Eduardo Valentin Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si4713.c | 53 +++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 27 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 8ae8442d6f97..1e0d6faff9a4 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -94,7 +94,7 @@ static int radio_si4713_querycap(struct file *file, void *priv, { strlcpy(capability->driver, "radio-si4713", sizeof(capability->driver)); strlcpy(capability->card, "Silicon Labs Si4713 Modulator", - sizeof(capability->card)); + sizeof(capability->card)); capability->capabilities = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT; return 0; @@ -102,7 +102,7 @@ static int radio_si4713_querycap(struct file *file, void *priv, /* radio_si4713_queryctrl - enumerate control items */ static int radio_si4713_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) + struct v4l2_queryctrl *qc) { /* Must be sorted from low to high control ID! */ static const u32 user_ctrls[] = { @@ -152,7 +152,7 @@ static int radio_si4713_queryctrl(struct file *file, void *priv, return v4l2_ctrl_query_fill(qc, 0, 0, 0, 0); return v4l2_device_call_until_err(&rsdev->v4l2_dev, 0, core, - queryctrl, qc); + queryctrl, qc); } /* @@ -165,66 +165,66 @@ static inline struct v4l2_device *get_v4l2_dev(struct file *file) } static int radio_si4713_g_ext_ctrls(struct file *file, void *p, - struct v4l2_ext_controls *vecs) + struct v4l2_ext_controls *vecs) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, - g_ext_ctrls, vecs); + g_ext_ctrls, vecs); } static int radio_si4713_s_ext_ctrls(struct file *file, void *p, - struct v4l2_ext_controls *vecs) + struct v4l2_ext_controls *vecs) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, - s_ext_ctrls, vecs); + s_ext_ctrls, vecs); } static int radio_si4713_g_ctrl(struct file *file, void *p, - struct v4l2_control *vc) + struct v4l2_control *vc) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, - g_ctrl, vc); + g_ctrl, vc); } static int radio_si4713_s_ctrl(struct file *file, void *p, - struct v4l2_control *vc) + struct v4l2_control *vc) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, - s_ctrl, vc); + s_ctrl, vc); } static int radio_si4713_g_modulator(struct file *file, void *p, - struct v4l2_modulator *vm) + struct v4l2_modulator *vm) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, - g_modulator, vm); + g_modulator, vm); } static int radio_si4713_s_modulator(struct file *file, void *p, - const struct v4l2_modulator *vm) + const struct v4l2_modulator *vm) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, - s_modulator, vm); + s_modulator, vm); } static int radio_si4713_g_frequency(struct file *file, void *p, - struct v4l2_frequency *vf) + struct v4l2_frequency *vf) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, - g_frequency, vf); + g_frequency, vf); } static int radio_si4713_s_frequency(struct file *file, void *p, - struct v4l2_frequency *vf) + struct v4l2_frequency *vf) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, - s_frequency, vf); + s_frequency, vf); } static long radio_si4713_default(struct file *file, void *p, - bool valid_prio, int cmd, void *arg) + bool valid_prio, int cmd, void *arg) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, - ioctl, cmd, arg); + ioctl, cmd, arg); } static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = { @@ -285,13 +285,13 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev) adapter = i2c_get_adapter(pdata->i2c_bus); if (!adapter) { dev_err(&pdev->dev, "Cannot get i2c adapter %d\n", - pdata->i2c_bus); + pdata->i2c_bus); rval = -ENODEV; goto unregister_v4l2_dev; } sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, - pdata->subdev_board_info, NULL); + pdata->subdev_board_info, NULL); if (!sd) { dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n"); rval = -ENODEV; @@ -306,7 +306,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev) } memcpy(rsdev->radio_dev, &radio_si4713_vdev_template, - sizeof(radio_si4713_vdev_template)); + sizeof(radio_si4713_vdev_template)); video_set_drvdata(rsdev->radio_dev, rsdev); if (video_register_device(rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) { dev_err(&pdev->dev, "Could not register video device.\n"); @@ -331,13 +331,12 @@ exit: static int radio_si4713_pdriver_remove(struct platform_device *pdev) { struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); - struct radio_si4713_device *rsdev = container_of(v4l2_dev, - struct radio_si4713_device, - v4l2_dev); struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next, struct v4l2_subdev, list); struct i2c_client *client = v4l2_get_subdevdata(sd); + struct radio_si4713_device *rsdev; + rsdev = container_of(v4l2_dev, struct radio_si4713_device, v4l2_dev); video_unregister_device(rsdev->radio_dev); i2c_put_adapter(client->adapter); v4l2_device_unregister(&rsdev->v4l2_dev); -- cgit v1.2.3 From a782ae09b709c21d872f23da3c12063d1f7fe61d Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Tue, 19 Mar 2013 11:41:32 -0300 Subject: [media] media: radio: correct module license (==> GPL v2) As per code header comment, changing the driver license entry to match the correct version. Signed-off-by: Eduardo Valentin Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si4713.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 1e0d6faff9a4..e025c39c8c48 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -39,7 +39,7 @@ module_param(radio_nr, int, 0); MODULE_PARM_DESC(radio_nr, "Minor number for radio device (-1 ==> auto assign)"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Eduardo Valentin "); MODULE_DESCRIPTION("Platform driver for Si4713 FM Radio Transmitter"); MODULE_VERSION("0.0.1"); -- cgit v1.2.3 From 04edd7b0382ccf059c316d28522a1215ca230420 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Tue, 19 Mar 2013 11:41:33 -0300 Subject: [media] media: radio: add driver owner entry for radio-si4713 Simple addition of platform_driver->driver->owner for radio-si4713. Signed-off-by: Eduardo Valentin Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si4713.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index e025c39c8c48..7b6601302413 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -347,6 +347,7 @@ static int radio_si4713_pdriver_remove(struct platform_device *pdev) static struct platform_driver radio_si4713_pdriver = { .driver = { .name = "radio-si4713", + .owner = THIS_MODULE, }, .probe = radio_si4713_pdriver_probe, .remove = radio_si4713_pdriver_remove, -- cgit v1.2.3 From 04e1ac04e54e420908c9ac3e09025f8266dcdf57 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Tue, 19 Mar 2013 11:41:34 -0300 Subject: [media] media: radio: add module alias entry for radio-si4713 Add MODULE_ALIAS entry for radio-si4713 platform driver. Signed-off-by: Eduardo Valentin Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si4713.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 7b6601302413..3df4339460d2 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -43,6 +43,7 @@ MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Eduardo Valentin "); MODULE_DESCRIPTION("Platform driver for Si4713 FM Radio Transmitter"); MODULE_VERSION("0.0.1"); +MODULE_ALIAS("platform:radio-si4713"); /* Driver state struct */ struct radio_si4713_device { -- cgit v1.2.3 From ced9b21ff626b6e6a23c06520ecb943f8d6ffa01 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Wed, 20 Mar 2013 01:28:27 -0300 Subject: [media] davinci: vpif: Fix module build for capture and display export the symbols which are used by two modules vpif_capture and vpif_display. renamed "ch_params" to "vpif_ch_params" so as to avoid name collision. This patch fixes following error: ERROR: "ch_params" [drivers/media/platform/davinci/vpif_display.ko] undefined! ERROR: "vpif_ch_params_count" [drivers/media/platform/davinci/vpif_display.ko] undefined! ERROR: "vpif_base" [drivers/media/platform/davinci/vpif_display.ko] undefined! ERROR: "ch_params" [drivers/media/platform/davinci/vpif_capture.ko] undefined! ERROR: "vpif_ch_params_count" [drivers/media/platform/davinci/vpif_capture.ko] undefined! ERROR: "vpif_base" [drivers/media/platform/davinci/vpif_capture.ko] undefined! make[1]: *** [__modpost] Error 1 Reported-by: Sekhar Nori Signed-off-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif.c | 10 +++++++--- drivers/media/platform/davinci/vpif.h | 2 +- drivers/media/platform/davinci/vpif_capture.c | 2 +- drivers/media/platform/davinci/vpif_display.c | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c index 28638a86f129..3bc4db8f0f27 100644 --- a/drivers/media/platform/davinci/vpif.c +++ b/drivers/media/platform/davinci/vpif.c @@ -44,13 +44,15 @@ static struct resource *res; spinlock_t vpif_lock; void __iomem *vpif_base; +EXPORT_SYMBOL_GPL(vpif_base); + struct clk *vpif_clk; /** - * ch_params: video standard configuration parameters for vpif + * vpif_ch_params: video standard configuration parameters for vpif * The table must include all presets from supported subdevices. */ -const struct vpif_channel_config_params ch_params[] = { +const struct vpif_channel_config_params vpif_ch_params[] = { /* HDTV formats */ { .name = "480p59_94", @@ -220,8 +222,10 @@ const struct vpif_channel_config_params ch_params[] = { .stdid = V4L2_STD_625_50, }, }; +EXPORT_SYMBOL_GPL(vpif_ch_params); -const unsigned int vpif_ch_params_count = ARRAY_SIZE(ch_params); +const unsigned int vpif_ch_params_count = ARRAY_SIZE(vpif_ch_params); +EXPORT_SYMBOL_GPL(vpif_ch_params_count); static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val) { diff --git a/drivers/media/platform/davinci/vpif.h b/drivers/media/platform/davinci/vpif.h index a1ab6a0f4e9e..9956e6788693 100644 --- a/drivers/media/platform/davinci/vpif.h +++ b/drivers/media/platform/davinci/vpif.h @@ -638,7 +638,7 @@ struct vpif_channel_config_params { }; extern const unsigned int vpif_ch_params_count; -extern const struct vpif_channel_config_params ch_params[]; +extern const struct vpif_channel_config_params vpif_ch_params[]; struct vpif_video_params; struct vpif_params; diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 1943e41f3866..d869c8e868ee 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -563,7 +563,7 @@ static int vpif_update_std_info(struct channel_obj *ch) vpif_dbg(2, debug, "vpif_update_std_info\n"); for (index = 0; index < vpif_ch_params_count; index++) { - config = &ch_params[index]; + config = &vpif_ch_params[index]; if (config->hd_sd == 0) { vpif_dbg(2, debug, "SD format\n"); if (config->stdid & vid_ch->stdid) { diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 5477c2cb8653..3bb187c9402b 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -511,7 +511,7 @@ static int vpif_update_std_info(struct channel_obj *ch) int i; for (i = 0; i < vpif_ch_params_count; i++) { - config = &ch_params[i]; + config = &vpif_ch_params[i]; if (config->hd_sd == 0) { vpif_dbg(2, debug, "SD format\n"); if (config->stdid & vid_ch->stdid) { -- cgit v1.2.3 From a3ad56d0aba738298338895b937359d57f40438b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 20 Mar 2013 12:43:21 +0000 Subject: [media] drxk_hard: Drop unused parameter Last parameter of function GetLockStatus() isn't used so drop it. Signed-off-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drxk_hard.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 55a4c22ac2d4..ec24d71e153d 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -1947,8 +1947,7 @@ static int ShutDown(struct drxk_state *state) return 0; } -static int GetLockStatus(struct drxk_state *state, u32 *pLockStatus, - u32 Time) +static int GetLockStatus(struct drxk_state *state, u32 *pLockStatus) { int status = -EINVAL; @@ -6488,7 +6487,7 @@ static int drxk_get_stats(struct dvb_frontend *fe) /* get status */ state->fe_status = 0; - GetLockStatus(state, &stat, 0); + GetLockStatus(state, &stat); if (stat == MPEG_LOCK) state->fe_status |= 0x1f; if (stat == FEC_LOCK) -- cgit v1.2.3 From 8b2c3da108b08751ac65911e1797ef9a5342c727 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 20 Mar 2013 11:30:46 -0300 Subject: [media] gspca: remove needless check before usb_free_coherent() usb_free_coherent() is safe with NULL addr and this check is not required. Signed-off-by: Wei Yongjun Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/gspca.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 5800d65f9144..924e032461d0 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -567,11 +567,10 @@ static void destroy_urbs(struct gspca_dev *gspca_dev) gspca_dev->urb[i] = NULL; usb_kill_urb(urb); - if (urb->transfer_buffer != NULL) - usb_free_coherent(gspca_dev->dev, - urb->transfer_buffer_length, - urb->transfer_buffer, - urb->transfer_dma); + usb_free_coherent(gspca_dev->dev, + urb->transfer_buffer_length, + urb->transfer_buffer, + urb->transfer_dma); usb_free_urb(urb); } } -- cgit v1.2.3 From 8cf2f7ad9749980a455d61b5664ccb553c12fd0e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Mar 2013 09:28:57 -0300 Subject: [media] s5p-tv: add dv_timings support for hdmiphy This just adds dv_timings support without modifying existing dv_preset support, although I had to refactor a little bit in order to share hdmiphy_find_conf() between the preset and timings code. Signed-off-by: Hans Verkuil Tested-by: Tomasz Stanislawski Acked-by: Tomasz Stanislawski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-tv/hdmiphy_drv.c | 60 ++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-tv/hdmiphy_drv.c b/drivers/media/platform/s5p-tv/hdmiphy_drv.c index 80717cec76ae..ef0d8122f3e9 100644 --- a/drivers/media/platform/s5p-tv/hdmiphy_drv.c +++ b/drivers/media/platform/s5p-tv/hdmiphy_drv.c @@ -197,14 +197,9 @@ static unsigned long hdmiphy_preset_to_pixclk(u32 preset) return 0; } -static const u8 *hdmiphy_find_conf(u32 preset, const struct hdmiphy_conf *conf) +static const u8 *hdmiphy_find_conf(unsigned long pixclk, + const struct hdmiphy_conf *conf) { - unsigned long pixclk; - - pixclk = hdmiphy_preset_to_pixclk(preset); - if (!pixclk) - return NULL; - for (; conf->pixclk; ++conf) if (conf->pixclk == pixclk) return conf->data; @@ -220,15 +215,49 @@ static int hdmiphy_s_power(struct v4l2_subdev *sd, int on) static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd, struct v4l2_dv_preset *preset) { - const u8 *data; + const u8 *data = NULL; u8 buffer[32]; int ret; struct hdmiphy_ctx *ctx = sd_to_ctx(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); + unsigned long pixclk; struct device *dev = &client->dev; dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset); - data = hdmiphy_find_conf(preset->preset, ctx->conf_tab); + + pixclk = hdmiphy_preset_to_pixclk(preset->preset); + data = hdmiphy_find_conf(pixclk, ctx->conf_tab); + if (!data) { + dev_err(dev, "format not supported\n"); + return -EINVAL; + } + + /* storing configuration to the device */ + memcpy(buffer, data, 32); + ret = i2c_master_send(client, buffer, 32); + if (ret != 32) { + dev_err(dev, "failed to configure HDMIPHY via I2C\n"); + return -EIO; + } + + return 0; +} + +static int hdmiphy_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + const u8 *data; + u8 buffer[32]; + int ret; + struct hdmiphy_ctx *ctx = sd_to_ctx(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct device *dev = &client->dev; + unsigned long pixclk = timings->bt.pixelclock; + + dev_info(dev, "s_dv_timings\n"); + if ((timings->bt.flags & V4L2_DV_FL_REDUCED_FPS) && pixclk == 74250000) + pixclk = 74176000; + data = hdmiphy_find_conf(pixclk, ctx->conf_tab); if (!data) { dev_err(dev, "format not supported\n"); return -EINVAL; @@ -245,6 +274,17 @@ static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd, return 0; } +static int hdmiphy_dv_timings_cap(struct v4l2_subdev *sd, + struct v4l2_dv_timings_cap *cap) +{ + cap->type = V4L2_DV_BT_656_1120; + /* The phy only determines the pixelclock, leave the other values + * at 0 to signify that we have no information for them. */ + cap->bt.min_pixelclock = 27000000; + cap->bt.max_pixelclock = 148500000; + return 0; +} + static int hdmiphy_s_stream(struct v4l2_subdev *sd, int enable) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -271,6 +311,8 @@ static const struct v4l2_subdev_core_ops hdmiphy_core_ops = { static const struct v4l2_subdev_video_ops hdmiphy_video_ops = { .s_dv_preset = hdmiphy_s_dv_preset, + .s_dv_timings = hdmiphy_s_dv_timings, + .dv_timings_cap = hdmiphy_dv_timings_cap, .s_stream = hdmiphy_s_stream, }; -- cgit v1.2.3 From 5efb54b2b7bf685f5d2efdf468418e26a74554f2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Mar 2013 09:29:33 -0300 Subject: [media] s5p-tv: add dv_timings support for hdmi This just adds dv_timings support without modifying existing dv_preset support. Signed-off-by: Hans Verkuil Tested-by: Tomasz Stanislawski Acked-by: Tomasz Stanislawski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-tv/hdmi_drv.c | 94 +++++++++++++++++++++++++++----- 1 file changed, 81 insertions(+), 13 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c index 8de1b3dce459..c78f54cd5df9 100644 --- a/drivers/media/platform/s5p-tv/hdmi_drv.c +++ b/drivers/media/platform/s5p-tv/hdmi_drv.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -93,6 +94,8 @@ struct hdmi_device { int cur_conf_dirty; /** current preset */ u32 cur_preset; + /** current timings */ + struct v4l2_dv_timings cur_timings; /** other resources */ struct hdmi_resources res; }; @@ -477,19 +480,21 @@ static const struct hdmi_timings hdmi_timings_1080p50 = { static const struct { u32 preset; - const struct hdmi_timings *timings; + bool reduced_fps; + const struct v4l2_dv_timings dv_timings; + const struct hdmi_timings *hdmi_timings; } hdmi_timings[] = { - { V4L2_DV_480P59_94, &hdmi_timings_480p }, - { V4L2_DV_576P50, &hdmi_timings_576p50 }, - { V4L2_DV_720P50, &hdmi_timings_720p50 }, - { V4L2_DV_720P59_94, &hdmi_timings_720p60 }, - { V4L2_DV_720P60, &hdmi_timings_720p60 }, - { V4L2_DV_1080P24, &hdmi_timings_1080p24 }, - { V4L2_DV_1080P30, &hdmi_timings_1080p60 }, - { V4L2_DV_1080P50, &hdmi_timings_1080p50 }, - { V4L2_DV_1080I50, &hdmi_timings_1080i50 }, - { V4L2_DV_1080I60, &hdmi_timings_1080i60 }, - { V4L2_DV_1080P60, &hdmi_timings_1080p60 }, + { V4L2_DV_480P59_94, false, V4L2_DV_BT_CEA_720X480P59_94, &hdmi_timings_480p }, + { V4L2_DV_576P50, false, V4L2_DV_BT_CEA_720X576P50, &hdmi_timings_576p50 }, + { V4L2_DV_720P50, false, V4L2_DV_BT_CEA_1280X720P50, &hdmi_timings_720p50 }, + { V4L2_DV_720P59_94, true, V4L2_DV_BT_CEA_1280X720P60, &hdmi_timings_720p60 }, + { V4L2_DV_720P60, false, V4L2_DV_BT_CEA_1280X720P60, &hdmi_timings_720p60 }, + { V4L2_DV_1080P24, false, V4L2_DV_BT_CEA_1920X1080P24, &hdmi_timings_1080p24 }, + { V4L2_DV_1080P30, false, V4L2_DV_BT_CEA_1920X1080P30, &hdmi_timings_1080p60 }, + { V4L2_DV_1080P50, false, V4L2_DV_BT_CEA_1920X1080P50, &hdmi_timings_1080p50 }, + { V4L2_DV_1080I50, false, V4L2_DV_BT_CEA_1920X1080I50, &hdmi_timings_1080i50 }, + { V4L2_DV_1080I60, false, V4L2_DV_BT_CEA_1920X1080I60, &hdmi_timings_1080i60 }, + { V4L2_DV_1080P60, false, V4L2_DV_BT_CEA_1920X1080P60, &hdmi_timings_1080p60 }, }; static const struct hdmi_timings *hdmi_preset2timings(u32 preset) @@ -498,7 +503,7 @@ static const struct hdmi_timings *hdmi_preset2timings(u32 preset) for (i = 0; i < ARRAY_SIZE(hdmi_timings); ++i) if (hdmi_timings[i].preset == preset) - return hdmi_timings[i].timings; + return hdmi_timings[i].hdmi_timings; return NULL; } @@ -647,6 +652,36 @@ static int hdmi_g_dv_preset(struct v4l2_subdev *sd, return 0; } +static int hdmi_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct hdmi_device *hdev = sd_to_hdmi_dev(sd); + struct device *dev = hdev->dev; + int i; + + for (i = 0; i < ARRAY_SIZE(hdmi_timings); i++) + if (v4l_match_dv_timings(&hdmi_timings[i].dv_timings, + timings, 0)) + break; + if (i == ARRAY_SIZE(hdmi_timings)) { + dev_err(dev, "timings not supported\n"); + return -EINVAL; + } + hdev->cur_conf = hdmi_timings[i].hdmi_timings; + hdev->cur_conf_dirty = 1; + hdev->cur_timings = *timings; + if (!hdmi_timings[i].reduced_fps) + hdev->cur_timings.bt.flags &= ~V4L2_DV_FL_CAN_REDUCE_FPS; + return 0; +} + +static int hdmi_g_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + *timings = sd_to_hdmi_dev(sd)->cur_timings; + return 0; +} + static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) { @@ -679,6 +714,35 @@ static int hdmi_enum_dv_presets(struct v4l2_subdev *sd, preset); } +static int hdmi_enum_dv_timings(struct v4l2_subdev *sd, + struct v4l2_enum_dv_timings *timings) +{ + if (timings->index >= ARRAY_SIZE(hdmi_timings)) + return -EINVAL; + timings->timings = hdmi_timings[timings->index].dv_timings; + if (!hdmi_timings[timings->index].reduced_fps) + timings->timings.bt.flags &= ~V4L2_DV_FL_CAN_REDUCE_FPS; + return 0; +} + +static int hdmi_dv_timings_cap(struct v4l2_subdev *sd, + struct v4l2_dv_timings_cap *cap) +{ + struct hdmi_device *hdev = sd_to_hdmi_dev(sd); + + /* Let the phy fill in the pixelclock range */ + v4l2_subdev_call(hdev->phy_sd, video, dv_timings_cap, cap); + cap->type = V4L2_DV_BT_656_1120; + cap->bt.min_width = 720; + cap->bt.max_width = 1920; + cap->bt.min_height = 480; + cap->bt.max_height = 1080; + cap->bt.standards = V4L2_DV_BT_STD_CEA861; + cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED | + V4L2_DV_BT_CAP_PROGRESSIVE; + return 0; +} + static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = { .s_power = hdmi_s_power, }; @@ -687,6 +751,10 @@ static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = { .s_dv_preset = hdmi_s_dv_preset, .g_dv_preset = hdmi_g_dv_preset, .enum_dv_presets = hdmi_enum_dv_presets, + .s_dv_timings = hdmi_s_dv_timings, + .g_dv_timings = hdmi_g_dv_timings, + .enum_dv_timings = hdmi_enum_dv_timings, + .dv_timings_cap = hdmi_dv_timings_cap, .g_mbus_fmt = hdmi_g_mbus_fmt, .s_stream = hdmi_s_stream, }; -- cgit v1.2.3 From 8e42bf033e1d2a4ece4050a9c3f6226e60a7bb2f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Mar 2013 09:30:48 -0300 Subject: [media] s5p-tv: add dv_timings support for mixer_video This just adds dv_timings support without modifying existing dv_preset support. Signed-off-by: Hans Verkuil Tested-by: Tomasz Stanislawski Acked-by: Tomasz Stanislawski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-tv/mixer_video.c | 80 +++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 82142a2d6d93..24fb38177c82 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c @@ -559,6 +559,79 @@ static int mxr_g_dv_preset(struct file *file, void *fh, return ret ? -EINVAL : 0; } +static int mxr_enum_dv_timings(struct file *file, void *fh, + struct v4l2_enum_dv_timings *timings) +{ + struct mxr_layer *layer = video_drvdata(file); + struct mxr_device *mdev = layer->mdev; + int ret; + + /* lock protects from changing sd_out */ + mutex_lock(&mdev->mutex); + ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_timings, timings); + mutex_unlock(&mdev->mutex); + + return ret ? -EINVAL : 0; +} + +static int mxr_s_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct mxr_layer *layer = video_drvdata(file); + struct mxr_device *mdev = layer->mdev; + int ret; + + /* lock protects from changing sd_out */ + mutex_lock(&mdev->mutex); + + /* timings change cannot be done while there is an entity + * dependant on output configuration + */ + if (mdev->n_output > 0) { + mutex_unlock(&mdev->mutex); + return -EBUSY; + } + + ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_timings, timings); + + mutex_unlock(&mdev->mutex); + + mxr_layer_update_output(layer); + + /* any failure should return EINVAL according to V4L2 doc */ + return ret ? -EINVAL : 0; +} + +static int mxr_g_dv_timings(struct file *file, void *fh, + struct v4l2_dv_timings *timings) +{ + struct mxr_layer *layer = video_drvdata(file); + struct mxr_device *mdev = layer->mdev; + int ret; + + /* lock protects from changing sd_out */ + mutex_lock(&mdev->mutex); + ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_timings, timings); + mutex_unlock(&mdev->mutex); + + return ret ? -EINVAL : 0; +} + +static int mxr_dv_timings_cap(struct file *file, void *fh, + struct v4l2_dv_timings_cap *cap) +{ + struct mxr_layer *layer = video_drvdata(file); + struct mxr_device *mdev = layer->mdev; + int ret; + + /* lock protects from changing sd_out */ + mutex_lock(&mdev->mutex); + ret = v4l2_subdev_call(to_outsd(mdev), video, dv_timings_cap, cap); + mutex_unlock(&mdev->mutex); + + return ret ? -EINVAL : 0; +} + static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm) { struct mxr_layer *layer = video_drvdata(file); @@ -618,6 +691,8 @@ static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a) a->capabilities = 0; if (sd->ops->video && sd->ops->video->s_dv_preset) a->capabilities |= V4L2_OUT_CAP_PRESETS; + if (sd->ops->video && sd->ops->video->s_dv_timings) + a->capabilities |= V4L2_OUT_CAP_DV_TIMINGS; if (sd->ops->video && sd->ops->video->s_std_output) a->capabilities |= V4L2_OUT_CAP_STD; a->type = V4L2_OUTPUT_TYPE_ANALOG; @@ -742,6 +817,11 @@ static const struct v4l2_ioctl_ops mxr_ioctl_ops = { .vidioc_enum_dv_presets = mxr_enum_dv_presets, .vidioc_s_dv_preset = mxr_s_dv_preset, .vidioc_g_dv_preset = mxr_g_dv_preset, + /* DV Timings functions */ + .vidioc_enum_dv_timings = mxr_enum_dv_timings, + .vidioc_s_dv_timings = mxr_s_dv_timings, + .vidioc_g_dv_timings = mxr_g_dv_timings, + .vidioc_dv_timings_cap = mxr_dv_timings_cap, /* analog TV standard functions */ .vidioc_s_std = mxr_s_std, .vidioc_g_std = mxr_g_std, -- cgit v1.2.3 From 3887056bc4a07b607be2e403b29e8006b465227b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 4 Mar 2013 09:32:00 -0300 Subject: [media] s5p-tv: remove dv_preset support from mixer_video The dv_preset API is deprecated and is replaced by the much improved dv_timings API. Remove the dv_preset support from this driver as this will allow us to remove the dv_preset API altogether (s5p-tv being the last user of this code). Signed-off-by: Hans Verkuil Tested-by: Tomasz Stanislawski Acked-by: Tomasz Stanislawski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-tv/mixer_video.c | 64 ----------------------------- 1 file changed, 64 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 24fb38177c82..9961e13f683d 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c @@ -501,64 +501,6 @@ fail: return -ERANGE; } -static int mxr_enum_dv_presets(struct file *file, void *fh, - struct v4l2_dv_enum_preset *preset) -{ - struct mxr_layer *layer = video_drvdata(file); - struct mxr_device *mdev = layer->mdev; - int ret; - - /* lock protects from changing sd_out */ - mutex_lock(&mdev->mutex); - ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_presets, preset); - mutex_unlock(&mdev->mutex); - - return ret ? -EINVAL : 0; -} - -static int mxr_s_dv_preset(struct file *file, void *fh, - struct v4l2_dv_preset *preset) -{ - struct mxr_layer *layer = video_drvdata(file); - struct mxr_device *mdev = layer->mdev; - int ret; - - /* lock protects from changing sd_out */ - mutex_lock(&mdev->mutex); - - /* preset change cannot be done while there is an entity - * dependant on output configuration - */ - if (mdev->n_output > 0) { - mutex_unlock(&mdev->mutex); - return -EBUSY; - } - - ret = v4l2_subdev_call(to_outsd(mdev), video, s_dv_preset, preset); - - mutex_unlock(&mdev->mutex); - - mxr_layer_update_output(layer); - - /* any failure should return EINVAL according to V4L2 doc */ - return ret ? -EINVAL : 0; -} - -static int mxr_g_dv_preset(struct file *file, void *fh, - struct v4l2_dv_preset *preset) -{ - struct mxr_layer *layer = video_drvdata(file); - struct mxr_device *mdev = layer->mdev; - int ret; - - /* lock protects from changing sd_out */ - mutex_lock(&mdev->mutex); - ret = v4l2_subdev_call(to_outsd(mdev), video, g_dv_preset, preset); - mutex_unlock(&mdev->mutex); - - return ret ? -EINVAL : 0; -} - static int mxr_enum_dv_timings(struct file *file, void *fh, struct v4l2_enum_dv_timings *timings) { @@ -689,8 +631,6 @@ static int mxr_enum_output(struct file *file, void *fh, struct v4l2_output *a) /* try to obtain supported tv norms */ v4l2_subdev_call(sd, video, g_tvnorms_output, &a->std); a->capabilities = 0; - if (sd->ops->video && sd->ops->video->s_dv_preset) - a->capabilities |= V4L2_OUT_CAP_PRESETS; if (sd->ops->video && sd->ops->video->s_dv_timings) a->capabilities |= V4L2_OUT_CAP_DV_TIMINGS; if (sd->ops->video && sd->ops->video->s_std_output) @@ -813,10 +753,6 @@ static const struct v4l2_ioctl_ops mxr_ioctl_ops = { /* Streaming control */ .vidioc_streamon = mxr_streamon, .vidioc_streamoff = mxr_streamoff, - /* Preset functions */ - .vidioc_enum_dv_presets = mxr_enum_dv_presets, - .vidioc_s_dv_preset = mxr_s_dv_preset, - .vidioc_g_dv_preset = mxr_g_dv_preset, /* DV Timings functions */ .vidioc_enum_dv_timings = mxr_enum_dv_timings, .vidioc_s_dv_timings = mxr_s_dv_timings, -- cgit v1.2.3 From 9b30af98b42ea5ff33768faaaf246a6c8efb6163 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 14:59:48 -0300 Subject: [media] s5p-tv: remove the dv_preset API from hdmi The dv_preset API is deprecated and is replaced by the much improved dv_timings API. Remove the dv_preset support from this driver as this will allow us to remove the dv_preset API altogether (s5p-tv being the last user of this code). Signed-off-by: Hans Verkuil Tested-by: Tomasz Stanislawski Acked-by: Tomasz Stanislawski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-tv/hdmi_drv.c | 95 ++++++++------------------------ 1 file changed, 22 insertions(+), 73 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c index c78f54cd5df9..4e86626dad4b 100644 --- a/drivers/media/platform/s5p-tv/hdmi_drv.c +++ b/drivers/media/platform/s5p-tv/hdmi_drv.c @@ -44,9 +44,6 @@ MODULE_AUTHOR("Tomasz Stanislawski, "); MODULE_DESCRIPTION("Samsung HDMI"); MODULE_LICENSE("GPL"); -/* default preset configured on probe */ -#define HDMI_DEFAULT_PRESET V4L2_DV_480P59_94 - struct hdmi_pulse { u32 beg; u32 end; @@ -92,8 +89,6 @@ struct hdmi_device { const struct hdmi_timings *cur_conf; /** flag indicating that timings are dirty */ int cur_conf_dirty; - /** current preset */ - u32 cur_preset; /** current timings */ struct v4l2_dv_timings cur_timings; /** other resources */ @@ -255,7 +250,6 @@ static int hdmi_conf_apply(struct hdmi_device *hdmi_dev) { struct device *dev = hdmi_dev->dev; const struct hdmi_timings *conf = hdmi_dev->cur_conf; - struct v4l2_dv_preset preset; int ret; dev_dbg(dev, "%s\n", __func__); @@ -270,11 +264,11 @@ static int hdmi_conf_apply(struct hdmi_device *hdmi_dev) hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, 0, HDMI_PHY_SW_RSTOUT); mdelay(10); - /* configure presets */ - preset.preset = hdmi_dev->cur_preset; - ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_preset, &preset); + /* configure timings */ + ret = v4l2_subdev_call(hdmi_dev->phy_sd, video, s_dv_timings, + &hdmi_dev->cur_timings); if (ret) { - dev_err(dev, "failed to set preset (%u)\n", preset.preset); + dev_err(dev, "failed to set timings\n"); return ret; } @@ -478,35 +472,26 @@ static const struct hdmi_timings hdmi_timings_1080p50 = { .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4}, }; +/* default hdmi_timings index of the timings configured on probe */ +#define HDMI_DEFAULT_TIMINGS_IDX (0) + static const struct { - u32 preset; bool reduced_fps; const struct v4l2_dv_timings dv_timings; const struct hdmi_timings *hdmi_timings; } hdmi_timings[] = { - { V4L2_DV_480P59_94, false, V4L2_DV_BT_CEA_720X480P59_94, &hdmi_timings_480p }, - { V4L2_DV_576P50, false, V4L2_DV_BT_CEA_720X576P50, &hdmi_timings_576p50 }, - { V4L2_DV_720P50, false, V4L2_DV_BT_CEA_1280X720P50, &hdmi_timings_720p50 }, - { V4L2_DV_720P59_94, true, V4L2_DV_BT_CEA_1280X720P60, &hdmi_timings_720p60 }, - { V4L2_DV_720P60, false, V4L2_DV_BT_CEA_1280X720P60, &hdmi_timings_720p60 }, - { V4L2_DV_1080P24, false, V4L2_DV_BT_CEA_1920X1080P24, &hdmi_timings_1080p24 }, - { V4L2_DV_1080P30, false, V4L2_DV_BT_CEA_1920X1080P30, &hdmi_timings_1080p60 }, - { V4L2_DV_1080P50, false, V4L2_DV_BT_CEA_1920X1080P50, &hdmi_timings_1080p50 }, - { V4L2_DV_1080I50, false, V4L2_DV_BT_CEA_1920X1080I50, &hdmi_timings_1080i50 }, - { V4L2_DV_1080I60, false, V4L2_DV_BT_CEA_1920X1080I60, &hdmi_timings_1080i60 }, - { V4L2_DV_1080P60, false, V4L2_DV_BT_CEA_1920X1080P60, &hdmi_timings_1080p60 }, + { false, V4L2_DV_BT_CEA_720X480P59_94, &hdmi_timings_480p }, + { false, V4L2_DV_BT_CEA_720X576P50, &hdmi_timings_576p50 }, + { false, V4L2_DV_BT_CEA_1280X720P50, &hdmi_timings_720p50 }, + { true, V4L2_DV_BT_CEA_1280X720P60, &hdmi_timings_720p60 }, + { false, V4L2_DV_BT_CEA_1920X1080P24, &hdmi_timings_1080p24 }, + { false, V4L2_DV_BT_CEA_1920X1080P30, &hdmi_timings_1080p60 }, + { false, V4L2_DV_BT_CEA_1920X1080P50, &hdmi_timings_1080p50 }, + { false, V4L2_DV_BT_CEA_1920X1080I50, &hdmi_timings_1080i50 }, + { false, V4L2_DV_BT_CEA_1920X1080I60, &hdmi_timings_1080i60 }, + { false, V4L2_DV_BT_CEA_1920X1080P60, &hdmi_timings_1080p60 }, }; -static const struct hdmi_timings *hdmi_preset2timings(u32 preset) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(hdmi_timings); ++i) - if (hdmi_timings[i].preset == preset) - return hdmi_timings[i].hdmi_timings; - return NULL; -} - static int hdmi_streamon(struct hdmi_device *hdev) { struct device *dev = hdev->dev; @@ -626,32 +611,6 @@ static int hdmi_s_power(struct v4l2_subdev *sd, int on) return IS_ERR_VALUE(ret) ? ret : 0; } -static int hdmi_s_dv_preset(struct v4l2_subdev *sd, - struct v4l2_dv_preset *preset) -{ - struct hdmi_device *hdev = sd_to_hdmi_dev(sd); - struct device *dev = hdev->dev; - const struct hdmi_timings *conf; - - conf = hdmi_preset2timings(preset->preset); - if (conf == NULL) { - dev_err(dev, "preset (%u) not supported\n", preset->preset); - return -EINVAL; - } - hdev->cur_conf = conf; - hdev->cur_conf_dirty = 1; - hdev->cur_preset = preset->preset; - return 0; -} - -static int hdmi_g_dv_preset(struct v4l2_subdev *sd, - struct v4l2_dv_preset *preset) -{ - memset(preset, 0, sizeof(*preset)); - preset->preset = sd_to_hdmi_dev(sd)->cur_preset; - return 0; -} - static int hdmi_s_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { @@ -705,15 +664,6 @@ static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd, return 0; } -static int hdmi_enum_dv_presets(struct v4l2_subdev *sd, - struct v4l2_dv_enum_preset *preset) -{ - if (preset->index >= ARRAY_SIZE(hdmi_timings)) - return -EINVAL; - return v4l_fill_dv_preset_info(hdmi_timings[preset->index].preset, - preset); -} - static int hdmi_enum_dv_timings(struct v4l2_subdev *sd, struct v4l2_enum_dv_timings *timings) { @@ -748,9 +698,6 @@ static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = { }; static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = { - .s_dv_preset = hdmi_s_dv_preset, - .g_dv_preset = hdmi_g_dv_preset, - .enum_dv_presets = hdmi_enum_dv_presets, .s_dv_timings = hdmi_s_dv_timings, .g_dv_timings = hdmi_g_dv_timings, .enum_dv_timings = hdmi_enum_dv_timings, @@ -1024,9 +971,11 @@ static int hdmi_probe(struct platform_device *pdev) sd->owner = THIS_MODULE; strlcpy(sd->name, "s5p-hdmi", sizeof(sd->name)); - hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET; - /* FIXME: missing fail preset is not supported */ - hdmi_dev->cur_conf = hdmi_preset2timings(hdmi_dev->cur_preset); + hdmi_dev->cur_timings = + hdmi_timings[HDMI_DEFAULT_TIMINGS_IDX].dv_timings; + /* FIXME: missing fail timings is not supported */ + hdmi_dev->cur_conf = + hdmi_timings[HDMI_DEFAULT_TIMINGS_IDX].hdmi_timings; hdmi_dev->cur_conf_dirty = 1; /* storing subdev for call that have only access to struct device */ -- cgit v1.2.3 From 34a518a0794135f8ac4031e2ebe1a26d29bd008c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 15:00:20 -0300 Subject: [media] s5p-tv: remove the dv_preset API from hdmiphy The dv_preset API is deprecated and is replaced by the much improved dv_timings API. Remove the dv_preset support from this driver as this will allow us to remove the dv_preset API altogether (s5p-tv being the last user of this code). Signed-off-by: Hans Verkuil Tested-by: Tomasz Stanislawski Acked-by: Tomasz Stanislawski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-tv/hdmiphy_drv.c | 53 ----------------------------- 1 file changed, 53 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-tv/hdmiphy_drv.c b/drivers/media/platform/s5p-tv/hdmiphy_drv.c index ef0d8122f3e9..e19a0af1ea4f 100644 --- a/drivers/media/platform/s5p-tv/hdmiphy_drv.c +++ b/drivers/media/platform/s5p-tv/hdmiphy_drv.c @@ -176,27 +176,6 @@ static inline struct hdmiphy_ctx *sd_to_ctx(struct v4l2_subdev *sd) return container_of(sd, struct hdmiphy_ctx, sd); } -static unsigned long hdmiphy_preset_to_pixclk(u32 preset) -{ - static const unsigned long pixclk[] = { - [V4L2_DV_480P59_94] = 27000000, - [V4L2_DV_576P50] = 27000000, - [V4L2_DV_720P59_94] = 74176000, - [V4L2_DV_720P50] = 74250000, - [V4L2_DV_720P60] = 74250000, - [V4L2_DV_1080P24] = 74250000, - [V4L2_DV_1080P30] = 74250000, - [V4L2_DV_1080I50] = 74250000, - [V4L2_DV_1080I60] = 74250000, - [V4L2_DV_1080P50] = 148500000, - [V4L2_DV_1080P60] = 148500000, - }; - if (preset < ARRAY_SIZE(pixclk)) - return pixclk[preset]; - else - return 0; -} - static const u8 *hdmiphy_find_conf(unsigned long pixclk, const struct hdmiphy_conf *conf) { @@ -212,37 +191,6 @@ static int hdmiphy_s_power(struct v4l2_subdev *sd, int on) return 0; } -static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd, - struct v4l2_dv_preset *preset) -{ - const u8 *data = NULL; - u8 buffer[32]; - int ret; - struct hdmiphy_ctx *ctx = sd_to_ctx(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - unsigned long pixclk; - struct device *dev = &client->dev; - - dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset); - - pixclk = hdmiphy_preset_to_pixclk(preset->preset); - data = hdmiphy_find_conf(pixclk, ctx->conf_tab); - if (!data) { - dev_err(dev, "format not supported\n"); - return -EINVAL; - } - - /* storing configuration to the device */ - memcpy(buffer, data, 32); - ret = i2c_master_send(client, buffer, 32); - if (ret != 32) { - dev_err(dev, "failed to configure HDMIPHY via I2C\n"); - return -EIO; - } - - return 0; -} - static int hdmiphy_s_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { @@ -310,7 +258,6 @@ static const struct v4l2_subdev_core_ops hdmiphy_core_ops = { }; static const struct v4l2_subdev_video_ops hdmiphy_video_ops = { - .s_dv_preset = hdmiphy_s_dv_preset, .s_dv_timings = hdmiphy_s_dv_timings, .dv_timings_cap = hdmiphy_dv_timings_cap, .s_stream = hdmiphy_s_stream, -- cgit v1.2.3 From 78c7bc4bd262ad41aae54eeeb80a25fa83c5417e Mon Sep 17 00:00:00 2001 From: Jose Alberto Reguero Date: Sun, 10 Feb 2013 15:43:03 -0300 Subject: [media] [PATH] enable dual tuner to Avermedia Twinstar in af9035 driver This patch enable dual tuner for Avermedia Twinstar. Signed-off-by: Jose Alberto Reguero Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index bc26b52e9887..b1f7059bf4a5 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -690,6 +690,7 @@ static int af9035_read_config(struct dvb_usb_device *d) case AF9033_TUNER_IT9135_60: case AF9033_TUNER_IT9135_61: case AF9033_TUNER_IT9135_62: + case AF9033_TUNER_MXL5007T: break; default: state->dual_mode = false; -- cgit v1.2.3 From efa914d7d05e69013054710e6aacaf225b8fc2a2 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 6 Mar 2013 05:04:26 -0300 Subject: [media] dvb-usb/dw2102: Remove duplicate inclusion of ts2020.h ts2020.h was included twice. Signed-off-by: Sachin Kamat Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dw2102.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index d5957b0299d3..6e237b6dd0a8 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -29,7 +29,6 @@ #include "stb6100.h" #include "stb6100_proc.h" #include "m88rs2000.h" -#include "ts2020.h" #ifndef USB_PID_DW2102 #define USB_PID_DW2102 0x2102 -- cgit v1.2.3 From 9719afae5e589b409e137c36f89073d134f0de33 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Wed, 6 Mar 2013 16:52:05 -0300 Subject: [media] rc-core: don't treat dev->rc_map.rc_type as a bitmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit store_protocols() treats dev->rc_map.rc_type as a bitmap which is wrong for two reasons. First of all, it is pretty bogus to change the protocol type of the keymap just because the hardware has been asked to decode a different protocol. Second, dev->rc_map.rc_type is an enum (i.e. a single protocol) as pointed out by James Hogan . Fix both issues by introducing a separate enabled_protocols member to struct rc_dev. Signed-off-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ir-kbd-i2c.c | 1 + drivers/media/rc/ir-jvc-decoder.c | 2 +- drivers/media/rc/ir-lirc-codec.c | 2 +- drivers/media/rc/ir-mce_kbd-decoder.c | 2 +- drivers/media/rc/ir-nec-decoder.c | 2 +- drivers/media/rc/ir-raw.c | 2 +- drivers/media/rc/ir-rc5-decoder.c | 6 +++--- drivers/media/rc/ir-rc5-sz-decoder.c | 2 +- drivers/media/rc/ir-rc6-decoder.c | 2 +- drivers/media/rc/ir-sanyo-decoder.c | 2 +- drivers/media/rc/ir-sony-decoder.c | 8 ++++---- drivers/media/rc/rc-core-priv.h | 1 - drivers/media/rc/rc-main.c | 32 ++++++++++---------------------- include/media/rc-core.h | 2 ++ 14 files changed, 28 insertions(+), 38 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 08ae067b2b6f..2586e46f14b5 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -423,6 +423,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) */ rc->map_name = ir->ir_codes; rc->allowed_protos = rc_type; + rc->enabled_protocols = rc_type; if (!rc->driver_name) rc->driver_name = MODULE_NAME; diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c index 69edffb9fe9a..3948138ca870 100644 --- a/drivers/media/rc/ir-jvc-decoder.c +++ b/drivers/media/rc/ir-jvc-decoder.c @@ -47,7 +47,7 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev) { struct jvc_dec *data = &dev->raw->jvc; - if (!(dev->raw->enabled_protocols & RC_BIT_JVC)) + if (!(dev->enabled_protocols & RC_BIT_JVC)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 9945e5e7f61a..ff4d93d1907f 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -35,7 +35,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) struct lirc_codec *lirc = &dev->raw->lirc; int sample; - if (!(dev->raw->enabled_protocols & RC_BIT_LIRC)) + if (!(dev->enabled_protocols & RC_BIT_LIRC)) return 0; if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf) diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 33fafa4cf7cb..9f3c9b59f30c 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -216,7 +216,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; unsigned long delay; - if (!(dev->raw->enabled_protocols & RC_BIT_MCE_KBD)) + if (!(dev->enabled_protocols & RC_BIT_MCE_KBD)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index a47ee3634969..9a9009411439 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -52,7 +52,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 address, not_address, command, not_command; bool send_32bits = false; - if (!(dev->raw->enabled_protocols & RC_BIT_NEC)) + if (!(dev->enabled_protocols & RC_BIT_NEC)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c index 17c94be9f24c..5c42750c7b71 100644 --- a/drivers/media/rc/ir-raw.c +++ b/drivers/media/rc/ir-raw.c @@ -256,7 +256,7 @@ int ir_raw_event_register(struct rc_dev *dev) return -ENOMEM; dev->raw->dev = dev; - dev->raw->enabled_protocols = ~0; + dev->enabled_protocols = ~0; rc = kfifo_alloc(&dev->raw->kfifo, sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE, GFP_KERNEL); diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index 5b4d1ddeac4e..4e53a319c5d8 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -52,7 +52,7 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 toggle; u32 scancode; - if (!(dev->raw->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X))) + if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X))) return 0; if (!is_timing_event(ev)) { @@ -128,7 +128,7 @@ again: if (data->wanted_bits == RC5X_NBITS) { /* RC5X */ u8 xdata, command, system; - if (!(dev->raw->enabled_protocols & RC_BIT_RC5X)) { + if (!(dev->enabled_protocols & RC_BIT_RC5X)) { data->state = STATE_INACTIVE; return 0; } @@ -145,7 +145,7 @@ again: } else { /* RC5 */ u8 command, system; - if (!(dev->raw->enabled_protocols & RC_BIT_RC5)) { + if (!(dev->enabled_protocols & RC_BIT_RC5)) { data->state = STATE_INACTIVE; return 0; } diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c index fd807a8308d8..865fe84fd854 100644 --- a/drivers/media/rc/ir-rc5-sz-decoder.c +++ b/drivers/media/rc/ir-rc5-sz-decoder.c @@ -48,7 +48,7 @@ static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 toggle, command, system; u32 scancode; - if (!(dev->raw->enabled_protocols & RC_BIT_RC5_SZ)) + if (!(dev->enabled_protocols & RC_BIT_RC5_SZ)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index e19072ffb36c..7cba7d33a3fa 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -89,7 +89,7 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 toggle; - if (!(dev->raw->enabled_protocols & + if (!(dev->enabled_protocols & (RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE))) return 0; diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c index 7e69a3b65370..0a06205b5677 100644 --- a/drivers/media/rc/ir-sanyo-decoder.c +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -58,7 +58,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 address, command, not_command; - if (!(dev->raw->enabled_protocols & RC_BIT_SANYO)) + if (!(dev->enabled_protocols & RC_BIT_SANYO)) return 0; if (!is_timing_event(ev)) { diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c index fb914342cf4d..29ab9c2db060 100644 --- a/drivers/media/rc/ir-sony-decoder.c +++ b/drivers/media/rc/ir-sony-decoder.c @@ -45,7 +45,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 device, subdevice, function; - if (!(dev->raw->enabled_protocols & + if (!(dev->enabled_protocols & (RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20))) return 0; @@ -124,7 +124,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) switch (data->count) { case 12: - if (!(dev->raw->enabled_protocols & RC_BIT_SONY12)) { + if (!(dev->enabled_protocols & RC_BIT_SONY12)) { data->state = STATE_INACTIVE; return 0; } @@ -133,7 +133,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) function = bitrev8((data->bits >> 4) & 0xFE); break; case 15: - if (!(dev->raw->enabled_protocols & RC_BIT_SONY15)) { + if (!(dev->enabled_protocols & RC_BIT_SONY15)) { data->state = STATE_INACTIVE; return 0; } @@ -142,7 +142,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) function = bitrev8((data->bits >> 7) & 0xFE); break; case 20: - if (!(dev->raw->enabled_protocols & RC_BIT_SONY20)) { + if (!(dev->enabled_protocols & RC_BIT_SONY20)) { data->state = STATE_INACTIVE; return 0; } diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 5d87287ed372..70a180bb0bd0 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -39,7 +39,6 @@ struct ir_raw_event_ctrl { ktime_t last_event; /* when last event occurred */ enum raw_event_type last_type; /* last event type */ struct rc_dev *dev; /* pointer to the parent rc_dev */ - u64 enabled_protocols; /* enabled raw protocol decoders */ /* raw decoder state follows */ struct ir_raw_event prev_ev; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index f3047920b8c0..1cf382a0b277 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -783,13 +783,12 @@ static ssize_t show_protocols(struct device *device, mutex_lock(&dev->lock); - if (dev->driver_type == RC_DRIVER_SCANCODE) { - enabled = dev->rc_map.rc_type; + enabled = dev->enabled_protocols; + if (dev->driver_type == RC_DRIVER_SCANCODE) allowed = dev->allowed_protos; - } else if (dev->raw) { - enabled = dev->raw->enabled_protocols; + else if (dev->raw) allowed = ir_raw_get_allowed_protocols(); - } else { + else { mutex_unlock(&dev->lock); return -ENODEV; } @@ -847,7 +846,6 @@ static ssize_t store_protocols(struct device *device, u64 type; u64 mask; int rc, i, count = 0; - unsigned long flags; ssize_t ret; /* Device is being removed */ @@ -856,15 +854,12 @@ static ssize_t store_protocols(struct device *device, mutex_lock(&dev->lock); - if (dev->driver_type == RC_DRIVER_SCANCODE) - type = dev->rc_map.rc_type; - else if (dev->raw) - type = dev->raw->enabled_protocols; - else { + if (dev->driver_type != RC_DRIVER_SCANCODE && !dev->raw) { IR_dprintk(1, "Protocol switching not supported\n"); ret = -EINVAL; goto out; } + type = dev->enabled_protocols; while ((tmp = strsep((char **) &data, " \n")) != NULL) { if (!*tmp) @@ -922,14 +917,7 @@ static ssize_t store_protocols(struct device *device, } } - if (dev->driver_type == RC_DRIVER_SCANCODE) { - spin_lock_irqsave(&dev->rc_map.lock, flags); - dev->rc_map.rc_type = type; - spin_unlock_irqrestore(&dev->rc_map.lock, flags); - } else { - dev->raw->enabled_protocols = type; - } - + dev->enabled_protocols = type; IR_dprintk(1, "Current protocol(s): 0x%llx\n", (long long)type); @@ -1068,9 +1056,8 @@ int rc_register_device(struct rc_dev *dev) /* * Take the lock here, as the device sysfs node will appear * when device_add() is called, which may trigger an ir-keytable udev - * rule, which will in turn call show_protocols and access either - * dev->rc_map.rc_type or dev->raw->enabled_protocols before it has - * been initialized. + * rule, which will in turn call show_protocols and access + * dev->enabled_protocols before it has been initialized. */ mutex_lock(&dev->lock); @@ -1132,6 +1119,7 @@ int rc_register_device(struct rc_dev *dev) rc = dev->change_protocol(dev, &rc_type); if (rc < 0) goto out_raw; + dev->enabled_protocols = rc_type; } mutex_unlock(&dev->lock); diff --git a/include/media/rc-core.h b/include/media/rc-core.h index f03445f3c767..06a75deff553 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -51,6 +51,7 @@ enum rc_driver_type { * @driver_type: specifies if protocol decoding is done in hardware or software * @idle: used to keep track of RX state * @allowed_protos: bitmask with the supported RC_BIT_* protocols + * @enabled_protocols: bitmask with the enabled RC_BIT_* protocols * @scanmask: some hardware decoders are not capable of providing the full * scancode to the application. As this is a hardware limit, we can't do * anything with it. Yet, as the same keycode table can be used with other @@ -99,6 +100,7 @@ struct rc_dev { enum rc_driver_type driver_type; bool idle; u64 allowed_protos; + u64 enabled_protocols; u32 scanmask; void *priv; spinlock_t keylock; -- cgit v1.2.3 From 28cafc38eca54851dd342b49bad9dd693890cb5c Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 21 Mar 2013 13:51:13 -0300 Subject: [media] bttv: audio_mux(): use a local variable "gpio_mute" instead of modifying the function parameter "mute" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function audio_mux() actually deals with two types of mute: gpio mute and subdevice muting. This patch claryfies the meaning of these values, but mainly prepares the code for the next patch. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 8610b6a8b8fb..a584d82ab909 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -992,7 +992,7 @@ static char *audio_modes[] = { static int audio_mux(struct bttv *btv, int input, int mute) { - int gpio_val, signal; + int gpio_val, signal, mute_gpio; struct v4l2_ctrl *ctrl; gpio_inout(bttv_tvcards[btv->c.type].gpiomask, @@ -1003,10 +1003,10 @@ audio_mux(struct bttv *btv, int input, int mute) btv->audio = input; /* automute */ - mute = mute || (btv->opt_automute && (!signal || !btv->users) + mute_gpio = mute || (btv->opt_automute && (!signal || !btv->users) && !btv->has_radio_tuner); - if (mute) + if (mute_gpio) gpio_val = bttv_tvcards[btv->c.type].gpiomute; else gpio_val = bttv_tvcards[btv->c.type].gpiomux[input]; @@ -1022,7 +1022,7 @@ audio_mux(struct bttv *btv, int input, int mute) } if (bttv_gpio) - bttv_gpio_tracking(btv, audio_modes[mute ? 4 : input]); + bttv_gpio_tracking(btv, audio_modes[mute_gpio ? 4 : input]); if (in_interrupt()) return 0; -- cgit v1.2.3 From 598728e9200a17970184b3d7d58a042accab7ecc Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 21 Mar 2013 13:51:14 -0300 Subject: [media] bttv: audio_mux(): do not change the value of the v4l2 mute control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are cases where we want to call audio_mux() without changing the value of the v4l2 mute control, for example - mute mute on last close - mute on device probing Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index a584d82ab909..a082ab4efff8 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -999,7 +999,6 @@ audio_mux(struct bttv *btv, int input, int mute) bttv_tvcards[btv->c.type].gpiomask); signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC; - btv->mute = mute; btv->audio = input; /* automute */ @@ -1031,7 +1030,7 @@ audio_mux(struct bttv *btv, int input, int mute) ctrl = v4l2_ctrl_find(btv->sd_msp34xx->ctrl_handler, V4L2_CID_AUDIO_MUTE); if (ctrl) - v4l2_ctrl_s_ctrl(ctrl, btv->mute); + v4l2_ctrl_s_ctrl(ctrl, mute); /* Note: the inputs tuner/radio/extern/intern are translated to msp routings. This assumes common behavior for all msp3400 @@ -1080,7 +1079,7 @@ audio_mux(struct bttv *btv, int input, int mute) ctrl = v4l2_ctrl_find(btv->sd_tvaudio->ctrl_handler, V4L2_CID_AUDIO_MUTE); if (ctrl) - v4l2_ctrl_s_ctrl(ctrl, btv->mute); + v4l2_ctrl_s_ctrl(ctrl, mute); v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing, input, 0, 0); } @@ -1088,7 +1087,7 @@ audio_mux(struct bttv *btv, int input, int mute) ctrl = v4l2_ctrl_find(btv->sd_tda7432->ctrl_handler, V4L2_CID_AUDIO_MUTE); if (ctrl) - v4l2_ctrl_s_ctrl(ctrl, btv->mute); + v4l2_ctrl_s_ctrl(ctrl, mute); } return 0; } @@ -1300,6 +1299,7 @@ static int bttv_s_ctrl(struct v4l2_ctrl *c) break; case V4L2_CID_AUDIO_MUTE: audio_mute(btv, c->val); + btv->mute = c->val; break; case V4L2_CID_AUDIO_VOLUME: btv->volume_gpio(btv, c->val); -- cgit v1.2.3 From 20167f17f19a5d842f74c3375468f68bf039eaa5 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 21 Mar 2013 13:51:15 -0300 Subject: [media] bttv: do not save the audio input in audio_mux() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can't and do not save the mute setting in function audio_mux(), so we should also not save the input in this function for consistency. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index a082ab4efff8..e01a8d8c9fd0 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -999,8 +999,6 @@ audio_mux(struct bttv *btv, int input, int mute) bttv_tvcards[btv->c.type].gpiomask); signal = btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC; - btv->audio = input; - /* automute */ mute_gpio = mute || (btv->opt_automute && (!signal || !btv->users) && !btv->has_radio_tuner); @@ -1197,8 +1195,9 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm) } else { video_mux(btv,input); } - audio_input(btv, (btv->tuner_type != TUNER_ABSENT && input == 0) ? - TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN); + btv->audio = (btv->tuner_type != TUNER_ABSENT && input == 0) ? + TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN; + audio_input(btv, btv->audio); set_tvnorm(btv, norm); } @@ -1707,7 +1706,8 @@ static void radio_enable(struct bttv *btv) if (!btv->has_radio_tuner) { btv->has_radio_tuner = 1; bttv_call_all(btv, tuner, s_radio); - audio_input(btv, TVAUDIO_INPUT_RADIO); + btv->audio = TVAUDIO_INPUT_RADIO; + audio_input(btv, btv->audio); } } -- cgit v1.2.3 From 2166f0a9710413ea60bd72a4983de11b764468e4 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 21 Mar 2013 13:51:16 -0300 Subject: [media] bttv: rename field 'audio' in struct 'bttv' to 'audio_input' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'audio_input' better describes the meaning of this field. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-cards.c | 2 +- drivers/media/pci/bt8xx/bttv-driver.c | 12 ++++++------ drivers/media/pci/bt8xx/bttvp.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index fa0faaa2a49a..b7dc921e1b91 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -3947,7 +3947,7 @@ static void avermedia_eeprom(struct bttv *btv) u32 bttv_tda9880_setnorm(struct bttv *btv, u32 gpiobits) { - if (btv->audio == TVAUDIO_INPUT_TUNER) { + if (btv->audio_input == TVAUDIO_INPUT_TUNER) { if (bttv_tvnorms[btv->tvnorm].v4l2_id & V4L2_STD_MN) gpiobits |= 0x10000; else diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index e01a8d8c9fd0..81ee70d93189 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1093,7 +1093,7 @@ audio_mux(struct bttv *btv, int input, int mute) static inline int audio_mute(struct bttv *btv, int mute) { - return audio_mux(btv, btv->audio, mute); + return audio_mux(btv, btv->audio_input, mute); } static inline int @@ -1195,9 +1195,9 @@ set_input(struct bttv *btv, unsigned int input, unsigned int norm) } else { video_mux(btv,input); } - btv->audio = (btv->tuner_type != TUNER_ABSENT && input == 0) ? - TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN; - audio_input(btv, btv->audio); + btv->audio_input = (btv->tuner_type != TUNER_ABSENT && input == 0) ? + TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN; + audio_input(btv, btv->audio_input); set_tvnorm(btv, norm); } @@ -1706,8 +1706,8 @@ static void radio_enable(struct bttv *btv) if (!btv->has_radio_tuner) { btv->has_radio_tuner = 1; bttv_call_all(btv, tuner, s_radio); - btv->audio = TVAUDIO_INPUT_RADIO; - audio_input(btv, btv->audio); + btv->audio_input = TVAUDIO_INPUT_RADIO; + audio_input(btv, btv->audio_input); } } diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index e7910e0ffa05..9c1cc2c50ee2 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -423,7 +423,7 @@ struct bttv { /* video state */ unsigned int input; - unsigned int audio; + unsigned int audio_input; unsigned int mute; unsigned long tv_freq; unsigned int tvnorm; -- cgit v1.2.3 From 5f45678173a79661409375ffa8b5c297cb932aad Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 21 Mar 2013 13:51:17 -0300 Subject: [media] bttv: separate GPIO part from function audio_mux() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the GPIO part of function audio_mux() to a separate function audio_mux_gpio(). This prepares the code for the next patch which will separate mute and input setting. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 81ee70d93189..f1cb0dbf34e3 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -989,11 +989,10 @@ static char *audio_modes[] = { "audio: intern", "audio: mute" }; -static int -audio_mux(struct bttv *btv, int input, int mute) +static void +audio_mux_gpio(struct bttv *btv, int input, int mute) { int gpio_val, signal, mute_gpio; - struct v4l2_ctrl *ctrl; gpio_inout(bttv_tvcards[btv->c.type].gpiomask, bttv_tvcards[btv->c.type].gpiomask); @@ -1020,8 +1019,14 @@ audio_mux(struct bttv *btv, int input, int mute) if (bttv_gpio) bttv_gpio_tracking(btv, audio_modes[mute_gpio ? 4 : input]); - if (in_interrupt()) - return 0; +} + +static int +audio_mux(struct bttv *btv, int input, int mute) +{ + struct v4l2_ctrl *ctrl; + + audio_mux_gpio(btv, input, mute); if (btv->sd_msp34xx) { u32 in; @@ -3846,7 +3851,8 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) bttv_irq_switch_video(btv); if ((astat & BT848_INT_HLOCK) && btv->opt_automute) - audio_mute(btv, btv->mute); /* trigger automute */ + /* trigger automute */ + audio_mux_gpio(btv, btv->audio_input, btv->mute); if (astat & (BT848_INT_SCERR|BT848_INT_OCERR)) { pr_info("%d: %s%s @ %08x,", -- cgit v1.2.3 From b1a301572a10d1daf69247c73fcd50f6e378654a Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 21 Mar 2013 13:51:18 -0300 Subject: [media] bttv: untangle audio input and mute setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split function audio_mux(): move the mute setting part to function audio_mute() and the input setting part to function audio_input(). Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 51 +++++++++++++++++------------------ 1 file changed, 24 insertions(+), 27 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index f1cb0dbf34e3..0df4a167585d 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1022,18 +1022,37 @@ audio_mux_gpio(struct bttv *btv, int input, int mute) } static int -audio_mux(struct bttv *btv, int input, int mute) +audio_mute(struct bttv *btv, int mute) { struct v4l2_ctrl *ctrl; - audio_mux_gpio(btv, input, mute); + audio_mux_gpio(btv, btv->audio_input, mute); if (btv->sd_msp34xx) { - u32 in; - ctrl = v4l2_ctrl_find(btv->sd_msp34xx->ctrl_handler, V4L2_CID_AUDIO_MUTE); if (ctrl) v4l2_ctrl_s_ctrl(ctrl, mute); + } + if (btv->sd_tvaudio) { + ctrl = v4l2_ctrl_find(btv->sd_tvaudio->ctrl_handler, V4L2_CID_AUDIO_MUTE); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, mute); + } + if (btv->sd_tda7432) { + ctrl = v4l2_ctrl_find(btv->sd_tda7432->ctrl_handler, V4L2_CID_AUDIO_MUTE); + if (ctrl) + v4l2_ctrl_s_ctrl(ctrl, mute); + } + return 0; +} + +static int +audio_input(struct bttv *btv, int input) +{ + audio_mux_gpio(btv, input, btv->mute); + + if (btv->sd_msp34xx) { + u32 in; /* Note: the inputs tuner/radio/extern/intern are translated to msp routings. This assumes common behavior for all msp3400 @@ -1079,34 +1098,12 @@ audio_mux(struct bttv *btv, int input, int mute) in, MSP_OUTPUT_DEFAULT, 0); } if (btv->sd_tvaudio) { - ctrl = v4l2_ctrl_find(btv->sd_tvaudio->ctrl_handler, V4L2_CID_AUDIO_MUTE); - - if (ctrl) - v4l2_ctrl_s_ctrl(ctrl, mute); v4l2_subdev_call(btv->sd_tvaudio, audio, s_routing, - input, 0, 0); - } - if (btv->sd_tda7432) { - ctrl = v4l2_ctrl_find(btv->sd_tda7432->ctrl_handler, V4L2_CID_AUDIO_MUTE); - - if (ctrl) - v4l2_ctrl_s_ctrl(ctrl, mute); + input, 0, 0); } return 0; } -static inline int -audio_mute(struct bttv *btv, int mute) -{ - return audio_mux(btv, btv->audio_input, mute); -} - -static inline int -audio_input(struct bttv *btv, int input) -{ - return audio_mux(btv, input, btv->mute); -} - static void bttv_crop_calc_limits(struct bttv_crop *c) { -- cgit v1.2.3 From da9f07f2d4dae676992b7f5d3e1377beea0d7644 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 21 Mar 2013 13:51:19 -0300 Subject: [media] bttv: do not unmute the device before the first open MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 0df4a167585d..55eab61bed63 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -4212,11 +4212,13 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) btv->std = V4L2_STD_PAL; init_irqreg(btv); v4l2_ctrl_handler_setup(hdl); - if (hdl->error) { result = hdl->error; goto fail2; } + /* mute device */ + audio_mute(btv, 1); + /* register video4linux + input */ if (!bttv_tvcards[btv->c.type].no_video) { v4l2_ctrl_add_handler(&btv->radio_ctrl_handler, hdl, -- cgit v1.2.3 From 0757f5c503a8b2eebc67c6bb8e3b88077d73049a Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 21 Mar 2013 13:51:20 -0300 Subject: [media] bttv: apply mute settings on open MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, this has been done implicitly for video device nodes by calling set_input() (which calls audio_input() and also modified the mute setting). Since input and mute setting are now untangled (as much as possible), we need to apply the mute setting with an explicit call to audio_mute(). Also apply the mute setting when the radio device node gets opened. Signed-off-by: Frank Schäfer Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 55eab61bed63..2fb2168f74e2 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -3065,7 +3065,7 @@ static int bttv_open(struct file *file) fh, &btv->lock); set_tvnorm(btv,btv->tvnorm); set_input(btv, btv->input, btv->tvnorm); - + audio_mute(btv, btv->mute); /* The V4L2 spec requires one global set of cropping parameters which only change on request. These are stored in btv->crop[1]. @@ -3230,6 +3230,7 @@ static int radio_open(struct file *file) v4l2_fh_init(&fh->fh, vdev); btv->radio_user++; + audio_mute(btv, btv->mute); v4l2_fh_add(&fh->fh); -- cgit v1.2.3 From b530a447bb588fdf43fdf4eb909e4ee1921d47ac Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 19 Mar 2013 04:09:26 -0300 Subject: [media] v4l2: add const to argument of write-only s_frequency ioctl This ioctl is defined as IOW, so pass the argument as const. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-core.c | 2 +- drivers/media/i2c/msp3400-driver.c | 2 +- drivers/media/i2c/tvaudio.c | 2 +- drivers/media/i2c/upd64031a.c | 2 +- drivers/media/i2c/wm8775.c | 2 +- drivers/media/pci/bt8xx/bttv-driver.c | 14 ++++---- drivers/media/pci/cx18/cx18-av-core.c | 2 +- drivers/media/pci/cx18/cx18-ioctl.c | 2 +- drivers/media/pci/cx18/cx18-ioctl.h | 2 +- drivers/media/pci/cx23885/cx23885-417.c | 2 +- drivers/media/pci/cx23885/cx23885-video.c | 8 ++--- drivers/media/pci/cx23885/cx23885.h | 2 +- drivers/media/pci/cx25821/cx25821-video.c | 4 +-- drivers/media/pci/cx25821/cx25821-video.h | 4 +-- drivers/media/pci/cx88/cx88-blackbird.c | 2 +- drivers/media/pci/cx88/cx88-video.c | 10 +++--- drivers/media/pci/cx88/cx88.h | 2 +- drivers/media/pci/ivtv/ivtv-ioctl.c | 2 +- drivers/media/pci/ivtv/ivtv-ioctl.h | 2 +- drivers/media/pci/saa7134/saa7134-video.c | 2 +- drivers/media/pci/saa7146/mxb.c | 4 +-- drivers/media/pci/saa7164/saa7164-encoder.c | 2 +- drivers/media/pci/saa7164/saa7164-vbi.c | 2 +- drivers/media/pci/ttpci/av7110_v4l.c | 2 +- drivers/media/radio/dsbr100.c | 2 +- drivers/media/radio/radio-cadet.c | 46 ++++++++++++------------ drivers/media/radio/radio-isa.c | 9 ++--- drivers/media/radio/radio-keene.c | 8 ++--- drivers/media/radio/radio-ma901.c | 2 +- drivers/media/radio/radio-miropcm20.c | 4 +-- drivers/media/radio/radio-mr800.c | 2 +- drivers/media/radio/radio-sf16fmi.c | 2 +- drivers/media/radio/radio-si4713.c | 2 +- drivers/media/radio/radio-tea5764.c | 2 +- drivers/media/radio/radio-tea5777.c | 2 +- drivers/media/radio/radio-timb.c | 2 +- drivers/media/radio/radio-wl1273.c | 2 +- drivers/media/radio/si470x/radio-si470x-common.c | 2 +- drivers/media/radio/si4713-i2c.c | 5 ++- drivers/media/radio/tef6862.c | 2 +- drivers/media/radio/wl128x/fmdrv_v4l2.c | 6 ++-- drivers/media/usb/au0828/au0828-video.c | 2 +- drivers/media/usb/cx231xx/cx231xx-video.c | 7 ++-- drivers/media/usb/cx231xx/cx231xx.h | 2 +- drivers/media/usb/em28xx/em28xx-video.c | 7 ++-- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 2 +- drivers/media/usb/tlg2300/pd-radio.c | 2 +- drivers/media/usb/tlg2300/pd-video.c | 5 +-- drivers/media/usb/tm6000/tm6000-video.c | 2 +- drivers/media/usb/usbvision/usbvision-video.c | 2 +- drivers/media/v4l2-core/tuner-core.c | 2 +- drivers/media/v4l2-core/v4l2-ioctl.c | 2 +- drivers/staging/media/go7007/go7007-v4l2.c | 2 +- include/media/v4l2-ioctl.h | 2 +- include/media/v4l2-subdev.h | 2 +- sound/i2c/other/tea575x-tuner.c | 4 +-- 56 files changed, 115 insertions(+), 110 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index f4149eb4d7b4..f4339ed8f2e5 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -1835,7 +1835,7 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd, return set_input(client, state->vid_input, input); } -static int cx25840_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) +static int cx25840_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index 766305f69a28..77053ba09627 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -445,7 +445,7 @@ static int msp_s_radio(struct v4l2_subdev *sd) return 0; } -static int msp_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) +static int msp_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index 4c91b355b55a..4b12c5188075 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -1817,7 +1817,7 @@ static int tvaudio_s_std(struct v4l2_subdev *sd, v4l2_std_id std) return 0; } -static int tvaudio_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) +static int tvaudio_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq) { struct CHIPSTATE *chip = to_state(sd); struct CHIPDESC *desc = chip->desc; diff --git a/drivers/media/i2c/upd64031a.c b/drivers/media/i2c/upd64031a.c index 1e7446542091..d15cfd944e57 100644 --- a/drivers/media/i2c/upd64031a.c +++ b/drivers/media/i2c/upd64031a.c @@ -111,7 +111,7 @@ static void upd64031a_write(struct v4l2_subdev *sd, u8 reg, u8 val) /* ------------------------------------------------------------------------ */ /* The input changed due to new input or channel changed */ -static int upd64031a_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) +static int upd64031a_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq) { struct upd64031a_state *state = to_state(sd); u8 reg = state->regs[R00]; diff --git a/drivers/media/i2c/wm8775.c b/drivers/media/i2c/wm8775.c index bee77ea9f49e..27c27b4ae238 100644 --- a/drivers/media/i2c/wm8775.c +++ b/drivers/media/i2c/wm8775.c @@ -174,7 +174,7 @@ static int wm8775_log_status(struct v4l2_subdev *sd) return 0; } -static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) +static int wm8775_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq) { wm8775_set_audio(sd, 0); return 0; diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 2fb2168f74e2..3156daf2c804 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1852,24 +1852,26 @@ static int bttv_g_frequency(struct file *file, void *priv, return 0; } -static void bttv_set_frequency(struct bttv *btv, struct v4l2_frequency *f) +static void bttv_set_frequency(struct bttv *btv, const struct v4l2_frequency *f) { + struct v4l2_frequency new_freq = *f; + bttv_call_all(btv, tuner, s_frequency, f); /* s_frequency may clamp the frequency, so get the actual frequency before assigning radio/tv_freq. */ - bttv_call_all(btv, tuner, g_frequency, f); - if (f->type == V4L2_TUNER_RADIO) { + bttv_call_all(btv, tuner, g_frequency, &new_freq); + if (new_freq.type == V4L2_TUNER_RADIO) { radio_enable(btv); - btv->radio_freq = f->frequency; + btv->radio_freq = new_freq.frequency; if (btv->has_matchbox) tea5757_set_freq(btv, btv->radio_freq); } else { - btv->tv_freq = f->frequency; + btv->tv_freq = new_freq.frequency; } } static int bttv_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c index f164b7f610a5..a2c51e0468a8 100644 --- a/drivers/media/pci/cx18/cx18-av-core.c +++ b/drivers/media/pci/cx18/cx18-av-core.c @@ -576,7 +576,7 @@ static void input_change(struct cx18 *cx) } static int cx18_av_s_frequency(struct v4l2_subdev *sd, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct cx18 *cx = v4l2_get_subdevdata(sd); input_change(cx); diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index cd8d2c2b1624..5cd22e7095e6 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -614,7 +614,7 @@ static int cx18_g_frequency(struct file *file, void *fh, return 0; } -int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +int cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; diff --git a/drivers/media/pci/cx18/cx18-ioctl.h b/drivers/media/pci/cx18/cx18-ioctl.h index 2f9dd591ee0f..aa9b44a611d3 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.h +++ b/drivers/media/pci/cx18/cx18-ioctl.h @@ -27,5 +27,5 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt); void cx18_set_funcs(struct video_device *vdev); int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std); -int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); +int cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); int cx18_s_input(struct file *file, void *fh, unsigned int inp); diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 5d5052d0253f..84a1b75d5444 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1311,7 +1311,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { return cx23885_set_frequency(file, priv, f); } diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 5991bc8dc158..5ba15b8dafe0 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1518,7 +1518,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, return 0; } -static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) +static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency *f) { struct v4l2_control ctrl; @@ -1550,7 +1550,7 @@ static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) } static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct v4l2_control ctrl; struct videobuf_dvb_frontend *vfe; @@ -1608,7 +1608,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, } int cx23885_set_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct cx23885_fh *fh = priv; struct cx23885_dev *dev = fh->dev; @@ -1628,7 +1628,7 @@ int cx23885_set_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { return cx23885_set_frequency(file, priv, f); } diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 59c322d870f2..5687d3f678db 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -587,7 +587,7 @@ extern void cx23885_video_wakeup(struct cx23885_dev *dev, int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i); int cx23885_set_input(struct file *file, void *priv, unsigned int i); int cx23885_get_input(struct file *file, void *priv, unsigned int *i); -int cx23885_set_frequency(struct file *file, void *priv, struct v4l2_frequency *f); +int cx23885_set_frequency(struct file *file, void *priv, const struct v4l2_frequency *f); int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl); int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl); int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm); diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index d4de021dc844..1219d60cdd79 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -1312,7 +1312,7 @@ int cx25821_vidioc_g_frequency(struct file *file, void *priv, return 0; } -int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f) +int cx25821_set_freq(struct cx25821_dev *dev, const struct v4l2_frequency *f) { mutex_lock(&dev->lock); dev->freq = f->frequency; @@ -1328,7 +1328,7 @@ int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f) } int cx25821_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct cx25821_fh *fh = priv; struct cx25821_dev *dev; diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index c265e35b37c3..969340c2dcfa 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -149,9 +149,9 @@ extern int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); extern int cx25821_vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f); -extern int cx25821_set_freq(struct cx25821_dev *dev, struct v4l2_frequency *f); +extern int cx25821_set_freq(struct cx25821_dev *dev, const struct v4l2_frequency *f); extern int cx25821_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f); + const struct v4l2_frequency *f); extern int cx25821_vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg); extern int cx25821_vidioc_s_register(struct file *file, void *fh, diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index a6ff8a6f4fc0..82aa11f526f0 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -815,7 +815,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) } static int vidioc_s_frequency (struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct cx8802_fh *fh = priv; struct cx8802_dev *dev = fh->dev; diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index bc78354262ac..4f10875295e8 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1321,8 +1321,10 @@ static int vidioc_g_frequency (struct file *file, void *priv, } int cx88_set_freq (struct cx88_core *core, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { + struct v4l2_frequency new_freq = *f; + if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; if (unlikely(f->tuner != 0)) @@ -1331,8 +1333,8 @@ int cx88_set_freq (struct cx88_core *core, mutex_lock(&core->lock); cx88_newstation(core); call_all(core, tuner, s_frequency, f); - call_all(core, tuner, g_frequency, f); - core->freq = f->frequency; + call_all(core, tuner, g_frequency, &new_freq); + core->freq = new_freq.frequency; /* When changing channels it is required to reset TVAUDIO */ msleep (10); @@ -1345,7 +1347,7 @@ int cx88_set_freq (struct cx88_core *core, EXPORT_SYMBOL(cx88_set_freq); static int vidioc_s_frequency (struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct cx8800_fh *fh = priv; struct cx88_core *core = fh->dev->core; diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index feff53c0a251..eca02c2435de 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -740,7 +740,7 @@ void cx8802_cancel_buffers(struct cx8802_dev *dev); /* ----------------------------------------------------------- */ /* cx88-video.c*/ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i); -int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f); +int cx88_set_freq(struct cx88_core *core, const struct v4l2_frequency *f); int cx88_video_mux(struct cx88_core *core, unsigned int input); void cx88_querycap(struct file *file, struct cx88_core *core, struct v4l2_capability *cap); diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 7a8b0d0b6127..e6258b68d22c 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -1078,7 +1078,7 @@ static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency * return 0; } -int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) { struct ivtv *itv = fh2id(fh)->itv; struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.h b/drivers/media/pci/ivtv/ivtv-ioctl.h index 7c553d16579b..34c6bc132ebd 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.h +++ b/drivers/media/pci/ivtv/ivtv-ioctl.h @@ -29,7 +29,7 @@ int ivtv_set_speed(struct ivtv *itv, int speed); void ivtv_set_funcs(struct video_device *vdev); void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std); void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std); -int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); +int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); int ivtv_s_input(struct file *file, void *fh, unsigned int inp); #endif diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 7c503fb68526..6c619d13f731 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -2057,7 +2057,7 @@ static int saa7134_g_frequency(struct file *file, void *priv, } static int saa7134_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index 91369daad722..27dc49b03d02 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -595,7 +595,7 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency return 0; } -static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *f) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct mxb *mxb = (struct mxb *)dev->ext_priv; @@ -612,8 +612,8 @@ static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency /* tune in desired frequency */ tuner_call(mxb, tuner, s_frequency, f); /* let the tuner subdev clamp the frequency to the tuner range */ - tuner_call(mxb, tuner, g_frequency, f); mxb->cur_freq = *f; + tuner_call(mxb, tuner, g_frequency, &mxb->cur_freq); if (mxb->cur_audinput == 0) mxb_update_audmode(mxb); diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index 9bb0903ee5f1..34f700da2e7a 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -337,7 +337,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct saa7164_encoder_fh *fh = file->private_data; struct saa7164_port *port = fh->port; diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index b4532299c0ed..5a8a6adb894b 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -309,7 +309,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct saa7164_vbi_fh *fh = file->private_data; struct saa7164_port *port = fh->port; diff --git a/drivers/media/pci/ttpci/av7110_v4l.c b/drivers/media/pci/ttpci/av7110_v4l.c index 730e906ea912..65adaa74c511 100644 --- a/drivers/media/pci/ttpci/av7110_v4l.c +++ b/drivers/media/pci/ttpci/av7110_v4l.c @@ -426,7 +426,7 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency return 0; } -static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) +static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *f) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index 63b112b555b2..e140a725820d 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -214,7 +214,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct dsbr100_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 643d80ac28fb..59be293cbf42 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -90,6 +90,26 @@ static u16 sigtable[2][4] = { { 2185, 4369, 13107, 65535 }, }; +static const struct v4l2_frequency_band bands[] = { + { + .index = 0, + .type = V4L2_TUNER_RADIO, + .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 8320, /* 520 kHz */ + .rangehigh = 26400, /* 1650 kHz */ + .modulation = V4L2_BAND_MODULATION_AM, + }, { + .index = 1, + .type = V4L2_TUNER_RADIO, + .capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | + V4L2_TUNER_CAP_RDS_BLOCK_IO | V4L2_TUNER_CAP_LOW | + V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 1400000, /* 87.5 MHz */ + .rangehigh = 1728000, /* 108.0 MHz */ + .modulation = V4L2_BAND_MODULATION_FM, + }, +}; + static int cadet_getstereo(struct cadet *dev) { @@ -196,6 +216,8 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq) int i, j, test; int curvol; + freq = clamp(freq, bands[dev->is_fm_band].rangelow, + bands[dev->is_fm_band].rangehigh); dev->curfreq = freq; /* * Formulate a fifo command @@ -337,26 +359,6 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static const struct v4l2_frequency_band bands[] = { - { - .index = 0, - .type = V4L2_TUNER_RADIO, - .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = 8320, /* 520 kHz */ - .rangehigh = 26400, /* 1650 kHz */ - .modulation = V4L2_BAND_MODULATION_AM, - }, { - .index = 1, - .type = V4L2_TUNER_RADIO, - .capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_RDS_BLOCK_IO | V4L2_TUNER_CAP_LOW | - V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = 1400000, /* 87.5 MHz */ - .rangehigh = 1728000, /* 108.0 MHz */ - .modulation = V4L2_BAND_MODULATION_FM, - }, -}; - static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { @@ -418,7 +420,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct cadet *dev = video_drvdata(file); @@ -426,8 +428,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, return -EINVAL; dev->is_fm_band = f->frequency >= (bands[0].rangehigh + bands[1].rangelow) / 2; - clamp(f->frequency, bands[dev->is_fm_band].rangelow, - bands[dev->is_fm_band].rangehigh); cadet_setfreq(dev, f->frequency); return 0; } diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c index fe0a4f85c422..0c1e27b13e69 100644 --- a/drivers/media/radio/radio-isa.c +++ b/drivers/media/radio/radio-isa.c @@ -102,17 +102,18 @@ static int radio_isa_s_tuner(struct file *file, void *priv, } static int radio_isa_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct radio_isa_card *isa = video_drvdata(file); + u32 freq = f->frequency; int res; if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) return -EINVAL; - f->frequency = clamp(f->frequency, FREQ_LOW, FREQ_HIGH); - res = isa->drv->ops->s_frequency(isa, f->frequency); + freq = clamp(freq, FREQ_LOW, FREQ_HIGH); + res = isa->drv->ops->s_frequency(isa, freq); if (res == 0) - isa->freq = f->frequency; + isa->freq = freq; return res; } diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c index 296941a9ae25..4c9ae767fb31 100644 --- a/drivers/media/radio/radio-keene.c +++ b/drivers/media/radio/radio-keene.c @@ -215,15 +215,15 @@ static int vidioc_s_modulator(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct keene_device *radio = video_drvdata(file); + unsigned freq = f->frequency; if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) return -EINVAL; - f->frequency = clamp(f->frequency, - FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL); - return keene_cmd_main(radio, f->frequency, true); + freq = clamp(freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL); + return keene_cmd_main(radio, freq, true); } static int vidioc_g_frequency(struct file *file, void *priv, diff --git a/drivers/media/radio/radio-ma901.c b/drivers/media/radio/radio-ma901.c index c61f590029ad..7f85c6f98009 100644 --- a/drivers/media/radio/radio-ma901.c +++ b/drivers/media/radio/radio-ma901.c @@ -257,7 +257,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, /* vidioc_s_frequency - set tuner radio frequency */ static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct ma901radio_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 3d0ff4404d12..2b8d31d8330b 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -131,14 +131,14 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct pcm20 *dev = video_drvdata(file); if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) return -EINVAL; - dev->freq = clamp(f->frequency, 87 * 16000U, 108 * 16000U); + dev->freq = clamp_t(u32, f->frequency, 87 * 16000U, 108 * 16000U); pcm20_setfreq(dev, dev->freq); return 0; } diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index 9c5a267b60b4..f9cdd8b96add 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -323,7 +323,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, /* vidioc_s_frequency - set tuner radio frequency */ static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct amradio_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 637a55564958..6142b5b3e81b 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -151,7 +151,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct fmi *fmi = video_drvdata(file); diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 3df4339460d2..2a2d21ed9133 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -215,7 +215,7 @@ static int radio_si4713_g_frequency(struct file *file, void *p, } static int radio_si4713_s_frequency(struct file *file, void *p, - struct v4l2_frequency *vf) + const struct v4l2_frequency *vf) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, s_frequency, vf); diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 1978516af67e..893842874d89 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -351,7 +351,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct tea5764_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/radio-tea5777.c b/drivers/media/radio/radio-tea5777.c index 4b5190d4fea5..fcd7c195e0c5 100644 --- a/drivers/media/radio/radio-tea5777.c +++ b/drivers/media/radio/radio-tea5777.c @@ -368,7 +368,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct radio_tea5777 *tea = video_drvdata(file); diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index b87effeb5dc6..1712c05c113d 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -91,7 +91,7 @@ static int timbradio_vidioc_s_audio(struct file *file, void *priv, } static int timbradio_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct timbradio *tr = video_drvdata(file); return v4l2_subdev_call(tr->sd_tuner, tuner, s_frequency, f); diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 02151e0e6e63..9a02fee904bf 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1640,7 +1640,7 @@ static int wl1273_fm_vidioc_g_frequency(struct file *file, void *priv, } static int wl1273_fm_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); struct wl1273_core *core = radio->core; diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 18989388ddc1..5708633a3d78 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -678,7 +678,7 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv, * si470x_vidioc_s_frequency - set tuner or modulator radio frequency */ static int si470x_vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct si470x_device *radio = video_drvdata(file); int retval; diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index bd61b3bd0ca3..e305c14272b5 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c @@ -1212,7 +1212,7 @@ exit: return rval; } -static int si4713_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f); +static int si4713_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *f); static int si4713_s_modulator(struct v4l2_subdev *sd, const struct v4l2_modulator *); /* * si4713_setup - Sets the device up with current configuration. @@ -1950,7 +1950,7 @@ unlock: } /* si4713_s_frequency - set tuner or modulator radio frequency */ -static int si4713_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) +static int si4713_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *f) { struct si4713_device *sdev = to_si4713_device(sd); int rval = 0; @@ -1970,7 +1970,6 @@ static int si4713_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) rval = 0; } sdev->frequency = frequency; - f->frequency = si4713_to_v4l2(frequency); unlock: mutex_unlock(&sdev->mutex); diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c index b18c2dc268ba..867395568f92 100644 --- a/drivers/media/radio/tef6862.c +++ b/drivers/media/radio/tef6862.c @@ -101,7 +101,7 @@ static int tef6862_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) return v->index ? -EINVAL : 0; } -static int tef6862_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) +static int tef6862_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *f) { struct tef6862_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index 0a8ee8fab924..0183956d9b02 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -388,7 +388,7 @@ static int fm_v4l2_vidioc_g_freq(struct file *file, void *priv, /* Set tuner or modulator radio frequency */ static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct fmdev *fmdev = video_drvdata(file); @@ -396,9 +396,7 @@ static int fm_v4l2_vidioc_s_freq(struct file *file, void *priv, * As V4L2_TUNER_CAP_LOW is set 1 user sends the frequency * in units of 62.5 Hz. */ - freq->frequency = (u32)(freq->frequency / 16); - - return fmc_set_freq(fmdev, freq->frequency); + return fmc_set_freq(fmdev, freq->frequency / 16); } /* Set hardware frequency seek. If current mode is NOT RX, set it RX. */ diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 8b9e8268e911..b1d6b034e1a1 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1545,7 +1545,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index ac6200870a62..96f65318d788 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1172,10 +1172,11 @@ int cx231xx_g_frequency(struct file *file, void *priv, } int cx231xx_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; + struct v4l2_frequency new_freq = *f; int rc; u32 if_frequency = 5400000; @@ -1194,8 +1195,8 @@ int cx231xx_s_frequency(struct file *file, void *priv, rc = cx231xx_tuner_pre_channel_change(dev); call_all(dev, tuner, s_frequency, f); - call_all(dev, tuner, g_frequency, f); - dev->ctl_freq = f->frequency; + call_all(dev, tuner, g_frequency, &new_freq); + dev->ctl_freq = new_freq.frequency; /* set post channel change settings in DIF first */ rc = cx231xx_tuner_post_channel_change(dev); diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index dff3f1d73f28..6f701e9bec44 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -940,7 +940,7 @@ int cx231xx_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t); int cx231xx_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f); int cx231xx_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f); + const struct v4l2_frequency *f); int cx231xx_enum_input(struct file *file, void *priv, struct v4l2_input *i); int cx231xx_g_input(struct file *file, void *priv, unsigned int *i); diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index d585c19a5d9c..af79089a0169 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1221,8 +1221,9 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { + struct v4l2_frequency new_freq = *f; struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; @@ -1230,8 +1231,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, return -EINVAL; v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f); - dev->ctl_freq = f->frequency; + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq); + dev->ctl_freq = new_freq.frequency; return 0; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 34c3b6e80e86..75657c6dc013 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -365,7 +365,7 @@ static int pvr2_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) vt->audmode); } -static int pvr2_s_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) +static int pvr2_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf) { struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 0f958f74dbc4..8b1daf1f1e99 100644 --- a/drivers/media/usb/tlg2300/pd-radio.c +++ b/drivers/media/usb/tlg2300/pd-radio.c @@ -252,7 +252,7 @@ error: } static int fm_set_freq(struct file *file, void *priv, - struct v4l2_frequency *argp) + const struct v4l2_frequency *argp) { struct poseidon *p = video_drvdata(file); diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index dab0ca32d396..8ef7c8c419f7 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -1079,10 +1079,11 @@ static int set_frequency(struct poseidon *pd, u32 *frequency) } static int vidioc_s_frequency(struct file *file, void *fh, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct front_face *front = fh; struct poseidon *pd = front->pd; + u32 frequency = freq->frequency; if (freq->tuner) return -EINVAL; @@ -1090,7 +1091,7 @@ static int vidioc_s_frequency(struct file *file, void *fh, pd->pm_suspend = pm_video_suspend; pd->pm_resume = pm_video_resume; #endif - return set_frequency(pd, &freq->frequency); + return set_frequency(pd, &frequency); } static int vidioc_reqbufs(struct file *file, void *fh, diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 1a6857929c15..49df7537fa63 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -1255,7 +1255,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct tm6000_fh *fh = priv; struct tm6000_core *dev = fh->dev; diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index cd1fe78a5532..b66844564144 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -657,7 +657,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) + const struct v4l2_frequency *freq) { struct usb_usbvision *usbvision = video_drvdata(file); diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index b5a8aac2e126..279f65efe9ba 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -1134,7 +1134,7 @@ static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std) return 0; } -static int tuner_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) +static int tuner_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *f) { struct tuner *t = to_tuner(sd); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index aa6e7c788db2..8ec8abe0ffe7 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1316,7 +1316,7 @@ static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { struct video_device *vfd = video_devdata(file); - struct v4l2_frequency *p = arg; + const struct v4l2_frequency *p = arg; enum v4l2_tuner_type type; type = (vfd->vfl_type == VFL_TYPE_RADIO) ? diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index cb9fe33050c7..1288f1cab129 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -1281,7 +1281,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct go7007 *go = ((struct go7007_file *) priv)->go; diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 4118ad1324c9..f06436dbaf75 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -223,7 +223,7 @@ struct v4l2_ioctl_ops { int (*vidioc_g_frequency) (struct file *file, void *fh, struct v4l2_frequency *a); int (*vidioc_s_frequency) (struct file *file, void *fh, - struct v4l2_frequency *a); + const struct v4l2_frequency *a); int (*vidioc_enum_freq_bands) (struct file *file, void *fh, struct v4l2_frequency_band *band); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index b137a5e1151a..1a82a50ea9c8 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -191,7 +191,7 @@ struct v4l2_subdev_core_ops { */ struct v4l2_subdev_tuner_ops { int (*s_radio)(struct v4l2_subdev *sd); - int (*s_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq); + int (*s_frequency)(struct v4l2_subdev *sd, const struct v4l2_frequency *freq); int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq); int (*g_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt); int (*s_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt); diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index 3c6c1e3226f3..738c5ad9c93f 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -336,7 +336,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct snd_tea575x *tea = video_drvdata(file); @@ -350,7 +350,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, else tea->band = BAND_FM; - tea->freq = clamp(f->frequency, bands[tea->band].rangelow, + tea->freq = clamp_t(u32, f->frequency, bands[tea->band].rangelow, bands[tea->band].rangehigh); snd_tea575x_set_freq(tea); return 0; -- cgit v1.2.3 From 2f73c7c582a685b3198b974cd6d964d0338f8ab5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2013 06:10:06 -0300 Subject: [media] v4l2: add const to argument of write-only s_tuner ioctl This ioctl is defined as IOW, so pass the argument as const. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Acked-by: Alexey Klimov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-core.c | 2 +- drivers/media/i2c/msp3400-driver.c | 2 +- drivers/media/i2c/saa6588.c | 2 +- drivers/media/i2c/saa717x.c | 2 +- drivers/media/i2c/tda9840.c | 2 +- drivers/media/i2c/tvaudio.c | 2 +- drivers/media/i2c/vp27smpx.c | 2 +- drivers/media/pci/bt8xx/bttv-driver.c | 11 +++++++---- drivers/media/pci/cx18/cx18-av-core.c | 2 +- drivers/media/pci/cx18/cx18-ioctl.c | 2 +- drivers/media/pci/cx23885/cx23885-417.c | 2 +- drivers/media/pci/cx23885/cx23885-video.c | 2 +- drivers/media/pci/cx25821/cx25821-video.c | 2 +- drivers/media/pci/cx25821/cx25821-video.h | 2 +- drivers/media/pci/cx88/cx88-blackbird.c | 2 +- drivers/media/pci/cx88/cx88-video.c | 9 ++------- drivers/media/pci/ivtv/ivtv-gpio.c | 2 +- drivers/media/pci/ivtv/ivtv-ioctl.c | 2 +- drivers/media/pci/saa7134/saa7134-video.c | 4 ++-- drivers/media/pci/saa7146/mxb.c | 2 +- drivers/media/pci/saa7164/saa7164-encoder.c | 2 +- drivers/media/pci/saa7164/saa7164-vbi.c | 2 +- drivers/media/pci/ttpci/av7110_v4l.c | 2 +- drivers/media/radio/dsbr100.c | 2 +- drivers/media/radio/radio-cadet.c | 2 +- drivers/media/radio/radio-isa.c | 2 +- drivers/media/radio/radio-ma901.c | 2 +- drivers/media/radio/radio-miropcm20.c | 8 +++++--- drivers/media/radio/radio-mr800.c | 2 +- drivers/media/radio/radio-sf16fmi.c | 2 +- drivers/media/radio/radio-tea5764.c | 2 +- drivers/media/radio/radio-tea5777.c | 7 +++---- drivers/media/radio/radio-timb.c | 2 +- drivers/media/radio/radio-wl1273.c | 2 +- drivers/media/radio/si470x/radio-si470x-common.c | 2 +- drivers/media/radio/tef6862.c | 2 +- drivers/media/radio/wl128x/fmdrv_v4l2.c | 2 +- drivers/media/usb/au0828/au0828-video.c | 4 +--- drivers/media/usb/cx231xx/cx231xx-video.c | 4 ++-- drivers/media/usb/cx231xx/cx231xx.h | 2 +- drivers/media/usb/em28xx/em28xx-video.c | 4 ++-- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 2 +- drivers/media/usb/tlg2300/pd-radio.c | 2 +- drivers/media/usb/tlg2300/pd-video.c | 2 +- drivers/media/usb/tm6000/tm6000-video.c | 8 ++------ drivers/media/usb/usbvision/usbvision-video.c | 2 +- drivers/media/v4l2-core/tuner-core.c | 2 +- drivers/staging/media/go7007/go7007-v4l2.c | 2 +- include/media/v4l2-ioctl.h | 2 +- include/media/v4l2-subdev.h | 2 +- sound/i2c/other/tea575x-tuner.c | 2 +- 51 files changed, 68 insertions(+), 75 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index f4339ed8f2e5..234b7c63d087 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -1881,7 +1881,7 @@ static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; } -static int cx25840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int cx25840_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index 77053ba09627..54a9dd394f45 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -535,7 +535,7 @@ static int msp_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; } -static int msp_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int msp_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct msp_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c index 0caac50d7cf4..b4e1ccbd87ec 100644 --- a/drivers/media/i2c/saa6588.c +++ b/drivers/media/i2c/saa6588.c @@ -435,7 +435,7 @@ static int saa6588_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; } -static int saa6588_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int saa6588_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct saa6588 *s = to_saa6588(sd); diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c index 1e84466515aa..5608b937f8b2 100644 --- a/drivers/media/i2c/saa717x.c +++ b/drivers/media/i2c/saa717x.c @@ -1113,7 +1113,7 @@ static int saa717x_s_stream(struct v4l2_subdev *sd, int enable) } /* change audio mode */ -static int saa717x_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int saa717x_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct saa717x_state *decoder = to_state(sd); int audio_mode; diff --git a/drivers/media/i2c/tda9840.c b/drivers/media/i2c/tda9840.c index 3d7ddd93282d..01441e35d88b 100644 --- a/drivers/media/i2c/tda9840.c +++ b/drivers/media/i2c/tda9840.c @@ -87,7 +87,7 @@ static int tda9840_status(struct v4l2_subdev *sd) return byte & 0x60; } -static int tda9840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t) +static int tda9840_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *t) { int stat = tda9840_status(sd); int byte; diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index 4b12c5188075..b72a59d3216a 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -1761,7 +1761,7 @@ static int tvaudio_s_routing(struct v4l2_subdev *sd, return 0; } -static int tvaudio_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int tvaudio_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct CHIPSTATE *chip = to_state(sd); struct CHIPDESC *desc = chip->desc; diff --git a/drivers/media/i2c/vp27smpx.c b/drivers/media/i2c/vp27smpx.c index 7cfbc9d94a48..e71f139695af 100644 --- a/drivers/media/i2c/vp27smpx.c +++ b/drivers/media/i2c/vp27smpx.c @@ -90,7 +90,7 @@ static int vp27smpx_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) return 0; } -static int vp27smpx_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int vp27smpx_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct vp27smpx_state *state = to_state(sd); diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 3156daf2c804..7aea24bf3a37 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1820,7 +1820,7 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i) } static int bttv_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; @@ -1830,8 +1830,11 @@ static int bttv_s_tuner(struct file *file, void *priv, bttv_call_all(btv, tuner, s_tuner, t); - if (btv->audio_mode_gpio) - btv->audio_mode_gpio(btv, t, 1); + if (btv->audio_mode_gpio) { + struct v4l2_tuner copy = *t; + + btv->audio_mode_gpio(btv, ©, 1); + } return 0; } @@ -3279,7 +3282,7 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) } static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c index a2c51e0468a8..c22242bc10df 100644 --- a/drivers/media/pci/cx18/cx18-av-core.c +++ b/drivers/media/pci/cx18/cx18-av-core.c @@ -809,7 +809,7 @@ static int cx18_av_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; } -static int cx18_av_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int cx18_av_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct cx18_av_state *state = to_cx18_av_state(sd); struct cx18 *cx = v4l2_get_subdevdata(sd); diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 5cd22e7095e6..173ccd204c1f 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -673,7 +673,7 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) return 0; } -static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +static int cx18_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 84a1b75d5444..812ec5ff5939 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1280,7 +1280,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct cx23885_fh *fh = file->private_data; struct cx23885_dev *dev = fh->dev; diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 5ba15b8dafe0..2bbda43eb00e 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1486,7 +1486,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 1219d60cdd79..75281c1530d8 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -1397,7 +1397,7 @@ int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return 0; } -int cx25821_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +int cx25821_vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; struct cx25821_fh *fh = priv; diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index 969340c2dcfa..f0e70ffbedd4 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -159,7 +159,7 @@ extern int cx25821_vidioc_s_register(struct file *file, void *fh, extern int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t); extern int cx25821_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t); + const struct v4l2_tuner *t); extern int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm); extern int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm); diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index 82aa11f526f0..486ca8d5f2a0 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -918,7 +918,7 @@ static int vidioc_g_tuner (struct file *file, void *priv, } static int vidioc_s_tuner (struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index 4f10875295e8..ede6f139b5cc 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1289,7 +1289,7 @@ static int vidioc_g_tuner (struct file *file, void *priv, } static int vidioc_s_tuner (struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; @@ -1409,20 +1409,15 @@ static int radio_g_tuner (struct file *file, void *priv, return 0; } -/* FIXME: Should add a standard for radio */ - static int radio_s_tuner (struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; if (0 != t->index) return -EINVAL; - if (t->audmode > V4L2_TUNER_MODE_STEREO) - t->audmode = V4L2_TUNER_MODE_STEREO; call_all(core, tuner, s_tuner, t); - return 0; } diff --git a/drivers/media/pci/ivtv/ivtv-gpio.c b/drivers/media/pci/ivtv/ivtv-gpio.c index 8f0d07789053..af52def700cc 100644 --- a/drivers/media/pci/ivtv/ivtv-gpio.c +++ b/drivers/media/pci/ivtv/ivtv-gpio.c @@ -192,7 +192,7 @@ static int subdev_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; } -static int subdev_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int subdev_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct ivtv *itv = sd_to_ivtv(sd); u16 mask, data; diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index e6258b68d22c..852f11e0d636 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -1196,7 +1196,7 @@ static int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std) return 0; } -static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +static int ivtv_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) { struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 6c619d13f731..1e23547531b9 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -2023,7 +2023,7 @@ static int saa7134_g_tuner(struct file *file, void *priv, } static int saa7134_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; @@ -2347,7 +2347,7 @@ static int radio_g_tuner(struct file *file, void *priv, return 0; } static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct saa7134_fh *fh = file->private_data; struct saa7134_dev *dev = fh->dev; diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index 27dc49b03d02..9dd044b563e7 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -560,7 +560,7 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) return call_all(dev, tuner, g_tuner, t); } -static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *t) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct mxb *mxb = (struct mxb *)dev->ext_priv; diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index 34f700da2e7a..e7fbd036ba44 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -318,7 +318,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { /* Update the A/V core */ return 0; diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index 5a8a6adb894b..bfc8cec110de 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -290,7 +290,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { /* Update the A/V core */ return 0; diff --git a/drivers/media/pci/ttpci/av7110_v4l.c b/drivers/media/pci/ttpci/av7110_v4l.c index 65adaa74c511..6c4076acb131 100644 --- a/drivers/media/pci/ttpci/av7110_v4l.c +++ b/drivers/media/pci/ttpci/av7110_v4l.c @@ -366,7 +366,7 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) return 0; } -static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) +static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *t) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index e140a725820d..142c2ee64d31 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -208,7 +208,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { return v->index ? -EINVAL : 0; } diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 59be293cbf42..545c04cf7226 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -390,7 +390,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { return v->index ? -EINVAL : 0; } diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c index 0c1e27b13e69..6ff350831d56 100644 --- a/drivers/media/radio/radio-isa.c +++ b/drivers/media/radio/radio-isa.c @@ -87,7 +87,7 @@ static int radio_isa_g_tuner(struct file *file, void *priv, } static int radio_isa_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct radio_isa_card *isa = video_drvdata(file); const struct radio_isa_ops *ops = isa->drv->ops; diff --git a/drivers/media/radio/radio-ma901.c b/drivers/media/radio/radio-ma901.c index 7f85c6f98009..18320c2c4607 100644 --- a/drivers/media/radio/radio-ma901.c +++ b/drivers/media/radio/radio-ma901.c @@ -239,7 +239,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, /* vidioc_s_tuner - set tuner attributes */ static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct ma901radio_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 2b8d31d8330b..a7e93d7477dd 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -103,16 +103,18 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct pcm20 *dev = video_drvdata(file); if (v->index) return -EINVAL; if (v->audmode > V4L2_TUNER_MODE_STEREO) - v->audmode = V4L2_TUNER_MODE_STEREO; + dev->audmode = V4L2_TUNER_MODE_STEREO; + else + dev->audmode = v->audmode; snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO, - v->audmode == V4L2_TUNER_MODE_MONO, -1); + dev->audmode == V4L2_TUNER_MODE_MONO, -1); return 0; } diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index f9cdd8b96add..2ce75d1564dc 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -305,7 +305,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, /* vidioc_s_tuner - set tuner attributes */ static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct amradio_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 6142b5b3e81b..adfcc61bdf0b 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -145,7 +145,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { return v->index ? -EINVAL : 0; } diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 893842874d89..38d563d62595 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -339,7 +339,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct tea5764_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/radio-tea5777.c b/drivers/media/radio/radio-tea5777.c index fcd7c195e0c5..e2455970725a 100644 --- a/drivers/media/radio/radio-tea5777.c +++ b/drivers/media/radio/radio-tea5777.c @@ -336,7 +336,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct radio_tea5777 *tea = video_drvdata(file); u32 orig_audmode = tea->audmode; @@ -344,10 +344,9 @@ static int vidioc_s_tuner(struct file *file, void *priv, if (v->index) return -EINVAL; - if (v->audmode > V4L2_TUNER_MODE_STEREO) - v->audmode = V4L2_TUNER_MODE_STEREO; - tea->audmode = v->audmode; + if (tea->audmode > V4L2_TUNER_MODE_STEREO) + tea->audmode = V4L2_TUNER_MODE_STEREO; if (tea->audmode != orig_audmode && tea->band == BAND_FM) return radio_tea5777_set_freq(tea); diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index 1712c05c113d..bb7b143b65d1 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -56,7 +56,7 @@ static int timbradio_vidioc_g_tuner(struct file *file, void *priv, } static int timbradio_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct timbradio *tr = video_drvdata(file); return v4l2_subdev_call(tr->sd_tuner, tuner, s_tuner, v); diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 9a02fee904bf..97c2c18803ef 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1559,7 +1559,7 @@ out: } static int wl1273_fm_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) + const struct v4l2_tuner *tuner) { struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); struct wl1273_core *core = radio->core; diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 5708633a3d78..5c57e5b0f949 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -636,7 +636,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, * si470x_vidioc_s_tuner - set tuner attributes */ static int si470x_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) + const struct v4l2_tuner *tuner) { struct si470x_device *radio = video_drvdata(file); diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c index 867395568f92..82c6c9475d7c 100644 --- a/drivers/media/radio/tef6862.c +++ b/drivers/media/radio/tef6862.c @@ -96,7 +96,7 @@ static int tef6862_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) return 0; } -static int tef6862_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *v) +static int tef6862_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *v) { return v->index ? -EINVAL : 0; } diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index 0183956d9b02..5dec323f4247 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -331,7 +331,7 @@ static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv, * Should we set other tuner attributes, too? */ static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) + const struct v4l2_tuner *tuner) { struct fmdev *fmdev = video_drvdata(file); u16 aud_mode; diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index b1d6b034e1a1..11316f2f2e42 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1508,7 +1508,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; @@ -1516,8 +1516,6 @@ static int vidioc_s_tuner(struct file *file, void *priv, if (t->index != 0) return -EINVAL; - t->type = V4L2_TUNER_ANALOG_TV; - if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl) dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1); diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 96f65318d788..53020a7e01fe 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1139,7 +1139,7 @@ int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return 0; } -int cx231xx_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +int cx231xx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; @@ -1808,7 +1808,7 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return 0; } -static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t) +static int radio_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { struct cx231xx *dev = ((struct cx231xx_fh *)priv)->dev; diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 6f701e9bec44..2f9faee539cb 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -936,7 +936,7 @@ void cx231xx_close_extension(struct cx231xx *dev); int cx231xx_querycap(struct file *file, void *priv, struct v4l2_capability *cap); int cx231xx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t); -int cx231xx_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t); +int cx231xx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t); int cx231xx_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f); int cx231xx_s_frequency(struct file *file, void *priv, diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index af79089a0169..3ef696d36c7e 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1195,7 +1195,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; @@ -1493,7 +1493,7 @@ static int radio_g_tuner(struct file *file, void *priv, } static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 75657c6dc013..0f729c92e3cf 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -352,7 +352,7 @@ static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) return pvr2_hdw_get_tuner_status(hdw, vt); } -static int pvr2_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) +static int pvr2_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 8b1daf1f1e99..ea6070ba835e 100644 --- a/drivers/media/usb/tlg2300/pd-radio.c +++ b/drivers/media/usb/tlg2300/pd-radio.c @@ -283,7 +283,7 @@ static int tlg_fm_s_ctrl(struct v4l2_ctrl *ctrl) return -EINVAL; } -static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) +static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { return vt->index > 0 ? -EINVAL : 0; } diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 8ef7c8c419f7..9595309caed4 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -1031,7 +1031,7 @@ static int pd_vidioc_s_tuner(struct poseidon *pd, int index) return ret; } -static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *a) +static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *a) { struct front_face *front = fh; struct poseidon *pd = front->pd; diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 49df7537fa63..b4618d7d9c4b 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -1215,7 +1215,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct tm6000_fh *fh = priv; struct tm6000_core *dev = fh->dev; @@ -1293,18 +1293,14 @@ static int radio_g_tuner(struct file *file, void *priv, } static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct tm6000_fh *fh = file->private_data; struct tm6000_core *dev = fh->dev; if (0 != t->index) return -EINVAL; - if (t->audmode > V4L2_TUNER_MODE_STEREO) - t->audmode = V4L2_TUNER_MODE_STEREO; - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); - return 0; } diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index b66844564144..874cfec0b8db 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -628,7 +628,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *vt) + const struct v4l2_tuner *vt) { struct usb_usbvision *usbvision = video_drvdata(file); diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index 279f65efe9ba..f775768d088d 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -1233,7 +1233,7 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) * Note: vt->type should be initialized before calling it. * This is done by either video_ioctl2 or by the bridge driver. */ -static int tuner_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int tuner_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct tuner *t = to_tuner(sd); diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 1288f1cab129..4e477f3b78f3 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -1242,7 +1242,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct go7007 *go = ((struct go7007_file *) priv)->go; diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index f06436dbaf75..0da8682a0481 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -219,7 +219,7 @@ struct v4l2_ioctl_ops { int (*vidioc_g_tuner) (struct file *file, void *fh, struct v4l2_tuner *a); int (*vidioc_s_tuner) (struct file *file, void *fh, - struct v4l2_tuner *a); + const struct v4l2_tuner *a); int (*vidioc_g_frequency) (struct file *file, void *fh, struct v4l2_frequency *a); int (*vidioc_s_frequency) (struct file *file, void *fh, diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 1a82a50ea9c8..79784fc8f9e9 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -194,7 +194,7 @@ struct v4l2_subdev_tuner_ops { int (*s_frequency)(struct v4l2_subdev *sd, const struct v4l2_frequency *freq); int (*g_frequency)(struct v4l2_subdev *sd, struct v4l2_frequency *freq); int (*g_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt); - int (*s_tuner)(struct v4l2_subdev *sd, struct v4l2_tuner *vt); + int (*s_tuner)(struct v4l2_subdev *sd, const struct v4l2_tuner *vt); int (*g_modulator)(struct v4l2_subdev *sd, struct v4l2_modulator *vm); int (*s_modulator)(struct v4l2_subdev *sd, const struct v4l2_modulator *vm); int (*s_type_addr)(struct v4l2_subdev *sd, struct tuner_setup *type); diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index 738c5ad9c93f..8a36a1d9803f 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -306,7 +306,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, } static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *v) + const struct v4l2_tuner *v) { struct snd_tea575x *tea = video_drvdata(file); u32 orig_val = tea->val; -- cgit v1.2.3 From 314527acbbb3f33f72c2ef19d8cfabcada9912a5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2013 06:10:40 -0300 Subject: [media] v4l2: pass std by value to the write-only s_std ioctl This ioctl is defined as IOW, so pass the argument by value instead of by reference. I could have chosen to add const instead, but this is 1) easier to handle in drivers and 2) consistent with the s_std subdev operation. Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Acked-by: Jonathan Corbet Acked-by: Guennadi Liakhovetski Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_video.c | 4 ++-- drivers/media/parport/pms.c | 4 ++-- drivers/media/pci/bt8xx/bttv-driver.c | 6 +++--- drivers/media/pci/cx18/cx18-driver.c | 2 +- drivers/media/pci/cx18/cx18-ioctl.c | 10 +++++----- drivers/media/pci/cx18/cx18-ioctl.h | 2 +- drivers/media/pci/cx23885/cx23885-417.c | 6 +++--- drivers/media/pci/cx23885/cx23885-video.c | 4 ++-- drivers/media/pci/cx25821/cx25821-video.c | 6 +++--- drivers/media/pci/cx25821/cx25821-video.h | 2 +- drivers/media/pci/cx88/cx88-blackbird.c | 4 ++-- drivers/media/pci/cx88/cx88-video.c | 4 ++-- drivers/media/pci/ivtv/ivtv-driver.c | 4 ++-- drivers/media/pci/ivtv/ivtv-firmware.c | 4 ++-- drivers/media/pci/ivtv/ivtv-ioctl.c | 18 +++++++++--------- drivers/media/pci/ivtv/ivtv-ioctl.h | 4 ++-- drivers/media/pci/saa7134/saa7134-empress.c | 2 +- drivers/media/pci/saa7134/saa7134-video.c | 14 +++++++------- drivers/media/pci/saa7134/saa7134.h | 2 +- drivers/media/pci/saa7164/saa7164-encoder.c | 8 ++++---- drivers/media/pci/saa7164/saa7164-vbi.c | 8 ++++---- drivers/media/pci/sta2x11/sta2x11_vip.c | 18 +++++++++--------- drivers/media/pci/zoran/zoran_driver.c | 4 ++-- drivers/media/platform/blackfin/bfin_capture.c | 6 +++--- drivers/media/platform/davinci/vpbe.c | 8 ++++---- drivers/media/platform/davinci/vpbe_display.c | 2 +- drivers/media/platform/davinci/vpfe_capture.c | 12 ++++++------ drivers/media/platform/davinci/vpif_capture.c | 6 +++--- drivers/media/platform/davinci/vpif_display.c | 10 +++++----- drivers/media/platform/fsl-viu.c | 6 +++--- drivers/media/platform/marvell-ccic/mcam-core.c | 2 +- drivers/media/platform/s5p-tv/mixer_video.c | 4 ++-- drivers/media/platform/sh_vou.c | 12 ++++++------ drivers/media/platform/soc_camera/soc_camera.c | 4 ++-- drivers/media/platform/timblogiw.c | 6 +++--- drivers/media/platform/via-camera.c | 2 +- drivers/media/platform/vino.c | 10 +++++----- drivers/media/usb/au0828/au0828-video.c | 4 ++-- drivers/media/usb/cx231xx/cx231xx-417.c | 4 ++-- drivers/media/usb/cx231xx/cx231xx-video.c | 6 +++--- drivers/media/usb/em28xx/em28xx-video.c | 8 ++++---- drivers/media/usb/hdpvr/hdpvr-video.c | 4 ++-- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 4 ++-- drivers/media/usb/s2255/s2255drv.c | 8 ++++---- drivers/media/usb/stk1160/stk1160-v4l.c | 4 ++-- drivers/media/usb/tlg2300/pd-video.c | 8 ++++---- drivers/media/usb/tm6000/tm6000-video.c | 6 +++--- drivers/media/usb/usbvision/usbvision-video.c | 4 ++-- drivers/media/v4l2-core/v4l2-ioctl.c | 6 +++--- drivers/staging/media/davinci_vpfe/vpfe_video.c | 6 +++--- drivers/staging/media/dt3155v4l/dt3155v4l.c | 4 ++-- drivers/staging/media/go7007/go7007-v4l2.c | 16 ++++++++-------- drivers/staging/media/solo6x10/v4l2-enc.c | 2 +- drivers/staging/media/solo6x10/v4l2.c | 2 +- include/media/davinci/vpbe.h | 2 +- include/media/v4l2-ioctl.h | 2 +- 56 files changed, 165 insertions(+), 165 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index 4143d61f79b1..fe907f2e8f59 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -832,7 +832,7 @@ static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) } */ -static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; struct saa7146_vv *vv = dev->vv_data; @@ -856,7 +856,7 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) } for (i = 0; i < dev->ext_vv_data->num_stds; i++) - if (*id & dev->ext_vv_data->stds[i].id) + if (id & dev->ext_vv_data->stds[i].id) break; if (i != dev->ext_vv_data->num_stds) { vv->standard = &dev->ext_vv_data->stds[i]; diff --git a/drivers/media/parport/pms.c b/drivers/media/parport/pms.c index 77f9c92186f4..66c957a02ba7 100644 --- a/drivers/media/parport/pms.c +++ b/drivers/media/parport/pms.c @@ -735,12 +735,12 @@ static int pms_g_std(struct file *file, void *fh, v4l2_std_id *std) return 0; } -static int pms_s_std(struct file *file, void *fh, v4l2_std_id *std) +static int pms_s_std(struct file *file, void *fh, v4l2_std_id std) { struct pms *dev = video_drvdata(file); int ret = 0; - dev->std = *std; + dev->std = std; if (dev->std & V4L2_STD_NTSC) { pms_framerate(dev, 30); pms_secamcross(dev, 0); diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 7aea24bf3a37..4b9a256f506e 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1713,7 +1713,7 @@ static void radio_enable(struct bttv *btv) } } -static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int bttv_s_std(struct file *file, void *priv, v4l2_std_id id) { struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; @@ -1721,14 +1721,14 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id) int err = 0; for (i = 0; i < BTTV_TVNORMS; i++) - if (*id & bttv_tvnorms[i].v4l2_id) + if (id & bttv_tvnorms[i].v4l2_id) break; if (i == BTTV_TVNORMS) { err = -EINVAL; goto err; } - btv->std = *id; + btv->std = id; set_tvnorm(btv, i); err: diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 613e5ae7d5ca..67b61cf3e03a 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -1243,7 +1243,7 @@ int cx18_init_on_first_open(struct cx18 *cx) in one place. */ cx->std++; /* Force full standard initialization */ std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std; - cx18_s_std(NULL, &fh, &std); + cx18_s_std(NULL, &fh, std); cx18_s_frequency(NULL, &fh, &vf); return 0; } diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 173ccd204c1f..254c50fabd73 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -637,15 +637,15 @@ static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std) return 0; } -int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) +int cx18_s_std(struct file *file, void *fh, v4l2_std_id std) { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; - if ((*std & V4L2_STD_ALL) == 0) + if ((std & V4L2_STD_ALL) == 0) return -EINVAL; - if (*std == cx->std) + if (std == cx->std) return 0; if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) || @@ -656,8 +656,8 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) return -EBUSY; } - cx->std = *std; - cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; + cx->std = std; + cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; cx->is_50hz = !cx->is_60hz; cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz); cx->cxhdl.width = 720; diff --git a/drivers/media/pci/cx18/cx18-ioctl.h b/drivers/media/pci/cx18/cx18-ioctl.h index aa9b44a611d3..43433969d633 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.h +++ b/drivers/media/pci/cx18/cx18-ioctl.h @@ -26,6 +26,6 @@ u16 cx18_service2vbi(int type); void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt); void cx18_set_funcs(struct video_device *vdev); -int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std); +int cx18_s_std(struct file *file, void *fh, v4l2_std_id std); int cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); int cx18_s_input(struct file *file, void *fh, unsigned int inp); diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 812ec5ff5939..6dea11a7a858 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1222,14 +1222,14 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct cx23885_fh *fh = file->private_data; struct cx23885_dev *dev = fh->dev; unsigned int i; for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++) - if (*id & cx23885_tvnorms[i].id) + if (id & cx23885_tvnorms[i].id) break; if (i == ARRAY_SIZE(cx23885_tvnorms)) return -EINVAL; @@ -1237,7 +1237,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) /* Have the drier core notify the subdevices */ mutex_lock(&dev->lock); - cx23885_set_tvnorm(dev, *id); + cx23885_set_tvnorm(dev, id); mutex_unlock(&dev->lock); return 0; diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 2bbda43eb00e..ed08c89adde0 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1259,13 +1259,13 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) { struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; dprintk(1, "%s()\n", __func__); mutex_lock(&dev->lock); - cx23885_set_tvnorm(dev, *tvnorms); + cx23885_set_tvnorm(dev, tvnorms); mutex_unlock(&dev->lock); return 0; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 75281c1530d8..93c7d576199b 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -1203,7 +1203,7 @@ int cx25821_vidioc_s_priority(struct file *file, void *f, } #ifdef TUNER_FLAG -int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms) +int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) { struct cx25821_fh *fh = priv; struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; @@ -1218,11 +1218,11 @@ int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id * tvnorms) return err; } - if (dev->tvnorm == *tvnorms) + if (dev->tvnorm == tvnorms) return 0; mutex_lock(&dev->lock); - cx25821_set_tvnorm(dev, *tvnorms); + cx25821_set_tvnorm(dev, tvnorms); mutex_unlock(&dev->lock); medusa_set_videostandard(dev); diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index f0e70ffbedd4..239f63c12f33 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -135,7 +135,7 @@ extern int cx25821_vidioc_querybuf(struct file *file, void *priv, extern int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p); extern int cx25821_vidioc_s_std(struct file *file, void *priv, - v4l2_std_id *tvnorms); + v4l2_std_id tvnorms); extern int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i); extern int cx25821_vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i); diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index 486ca8d5f2a0..150bb76e7839 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -939,12 +939,12 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm) return 0; } -static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; mutex_lock(&core->lock); - cx88_set_tvnorm(core,*id); + cx88_set_tvnorm(core, id); mutex_unlock(&core->lock); return 0; } diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index ede6f139b5cc..ead5be58303d 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1193,12 +1193,12 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm) return 0; } -static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) { struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; mutex_lock(&core->lock); - cx88_set_tvnorm(core,*tvnorms); + cx88_set_tvnorm(core, tvnorms); mutex_unlock(&core->lock); return 0; diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index 2928e7287da8..07b8460953b6 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -1387,7 +1387,7 @@ int ivtv_init_on_first_open(struct ivtv *itv) if (!itv->has_cx23415) write_reg_sync(0x03, IVTV_REG_DMACONTROL); - ivtv_s_std_enc(itv, &itv->tuner_std); + ivtv_s_std_enc(itv, itv->tuner_std); /* Default interrupts enabled. For the PVR350 this includes the decoder VSYNC interrupt, which is always on. It is not only used @@ -1397,7 +1397,7 @@ int ivtv_init_on_first_open(struct ivtv *itv) if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC); ivtv_set_osd_alpha(itv); - ivtv_s_std_dec(itv, &itv->tuner_std); + ivtv_s_std_dec(itv, itv->tuner_std); } else { ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT); } diff --git a/drivers/media/pci/ivtv/ivtv-firmware.c b/drivers/media/pci/ivtv/ivtv-firmware.c index 68387d4369d6..ed73edd2bcd3 100644 --- a/drivers/media/pci/ivtv/ivtv-firmware.c +++ b/drivers/media/pci/ivtv/ivtv-firmware.c @@ -302,7 +302,7 @@ static int ivtv_firmware_restart(struct ivtv *itv) /* Restore encoder video standard */ std = itv->std; itv->std = 0; - ivtv_s_std_enc(itv, &std); + ivtv_s_std_enc(itv, std); if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { ivtv_init_mpeg_decoder(itv); @@ -310,7 +310,7 @@ static int ivtv_firmware_restart(struct ivtv *itv) /* Restore decoder video standard */ std = itv->std_out; itv->std_out = 0; - ivtv_s_std_dec(itv, &std); + ivtv_s_std_dec(itv, std); /* Restore framebuffer if active */ if (itv->ivtvfb_restore) diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 852f11e0d636..080f179070a6 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -1103,10 +1103,10 @@ static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std) return 0; } -void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std) +void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id std) { - itv->std = *std; - itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; + itv->std = std; + itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; itv->is_50hz = !itv->is_60hz; cx2341x_handler_set_50hz(&itv->cxhdl, itv->is_50hz); itv->cxhdl.width = 720; @@ -1122,15 +1122,15 @@ void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std) ivtv_call_all(itv, core, s_std, itv->std); } -void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std) +void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id std) { struct yuv_playback_info *yi = &itv->yuv_info; DEFINE_WAIT(wait); int f; /* set display standard */ - itv->std_out = *std; - itv->is_out_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; + itv->std_out = std; + itv->is_out_60hz = (std & V4L2_STD_525_60) ? 1 : 0; itv->is_out_50hz = !itv->is_out_60hz; ivtv_call_all(itv, video, s_std_output, itv->std_out); @@ -1168,14 +1168,14 @@ void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std) } } -static int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std) +static int ivtv_s_std(struct file *file, void *fh, v4l2_std_id std) { struct ivtv *itv = fh2id(fh)->itv; - if ((*std & V4L2_STD_ALL) == 0) + if ((std & V4L2_STD_ALL) == 0) return -EINVAL; - if (*std == itv->std) + if (std == itv->std) return 0; if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) || diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.h b/drivers/media/pci/ivtv/ivtv-ioctl.h index 34c6bc132ebd..75c397756116 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.h +++ b/drivers/media/pci/ivtv/ivtv-ioctl.h @@ -27,8 +27,8 @@ u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt); void ivtv_set_osd_alpha(struct ivtv *itv); int ivtv_set_speed(struct ivtv *itv, int speed); void ivtv_set_funcs(struct video_device *vdev); -void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id *std); -void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std); +void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id std); +void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id std); int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); int ivtv_s_input(struct file *file, void *fh, unsigned int inp); diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index 4df79c656909..66a70814004c 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -428,7 +428,7 @@ static int empress_g_chip_ident(struct file *file, void *fh, return -EINVAL; } -static int empress_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int empress_s_std(struct file *file, void *priv, v4l2_std_id id) { struct saa7134_dev *dev = file->private_data; diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 1e23547531b9..a6c69a4c7fbd 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1828,7 +1828,7 @@ static int saa7134_querycap(struct file *file, void *priv, return 0; } -int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id) +int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id id) { unsigned long flags; unsigned int i; @@ -1849,17 +1849,17 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_ } for (i = 0; i < TVNORMS; i++) - if (*id == tvnorms[i].id) + if (id == tvnorms[i].id) break; if (i == TVNORMS) for (i = 0; i < TVNORMS; i++) - if (*id & tvnorms[i].id) + if (id & tvnorms[i].id) break; if (i == TVNORMS) return -EINVAL; - if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) { + if ((id & V4L2_STD_SECAM) && (secam[0] != '-')) { if (secam[0] == 'L' || secam[0] == 'l') { if (secam[1] == 'C' || secam[1] == 'c') fixup = V4L2_STD_SECAM_LC; @@ -1879,7 +1879,7 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_ return -EINVAL; } - *id = tvnorms[i].id; + id = tvnorms[i].id; mutex_lock(&dev->lock); if (fh && res_check(fh, RESOURCE_OVERLAY)) { @@ -1901,7 +1901,7 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_ } EXPORT_SYMBOL_GPL(saa7134_s_std_internal); -static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id) { struct saa7134_fh *fh = priv; @@ -2396,7 +2396,7 @@ static int radio_s_input(struct file *filp, void *priv, unsigned int i) return 0; } -static int radio_s_std(struct file *file, void *fh, v4l2_std_id *norm) +static int radio_s_std(struct file *file, void *fh, v4l2_std_id norm) { return 0; } diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index 71eefef5e324..62169dd74c6a 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -766,7 +766,7 @@ extern struct video_device saa7134_radio_template; int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c); int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c); int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c); -int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id); +int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id id); int saa7134_videoport_init(struct saa7134_dev *dev); void saa7134_set_tvnorm_hw(struct saa7134_dev *dev); diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index e7fbd036ba44..538de52b9cfd 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -211,17 +211,17 @@ static int saa7164_encoder_initialize(struct saa7164_port *port) } /* -- V4L2 --------------------------------------------------------- */ -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct saa7164_encoder_fh *fh = file->private_data; struct saa7164_port *port = fh->port; struct saa7164_dev *dev = port->dev; unsigned int i; - dprintk(DBGLVL_ENC, "%s(id=0x%x)\n", __func__, (u32)*id); + dprintk(DBGLVL_ENC, "%s(id=0x%x)\n", __func__, (u32)id); for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) { - if (*id & saa7164_tvnorms[i].id) + if (id & saa7164_tvnorms[i].id) break; } if (i == ARRAY_SIZE(saa7164_tvnorms)) @@ -234,7 +234,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) */ saa7164_api_set_audio_std(port); - dprintk(DBGLVL_ENC, "%s(id=0x%x) OK\n", __func__, (u32)*id); + dprintk(DBGLVL_ENC, "%s(id=0x%x) OK\n", __func__, (u32)id); return 0; } diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index bfc8cec110de..da224eb39b95 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -183,17 +183,17 @@ static int saa7164_vbi_initialize(struct saa7164_port *port) } /* -- V4L2 --------------------------------------------------------- */ -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct saa7164_vbi_fh *fh = file->private_data; struct saa7164_port *port = fh->port; struct saa7164_dev *dev = port->dev; unsigned int i; - dprintk(DBGLVL_VBI, "%s(id=0x%x)\n", __func__, (u32)*id); + dprintk(DBGLVL_VBI, "%s(id=0x%x)\n", __func__, (u32)id); for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) { - if (*id & saa7164_tvnorms[i].id) + if (id & saa7164_tvnorms[i].id) break; } if (i == ARRAY_SIZE(saa7164_tvnorms)) @@ -206,7 +206,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) */ saa7164_api_set_audio_std(port); - dprintk(DBGLVL_VBI, "%s(id=0x%x) OK\n", __func__, (u32)*id); + dprintk(DBGLVL_VBI, "%s(id=0x%x) OK\n", __func__, (u32)id); return 0; } diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 4b703fe8c953..7005695aa4bd 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -439,22 +439,22 @@ static int vidioc_querycap(struct file *file, void *priv, * * other, returned from video DAC. */ -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) { struct sta2x11_vip *vip = video_drvdata(file); v4l2_std_id oldstd = vip->std, newstd; int status; - if (V4L2_STD_ALL == *std) { - v4l2_subdev_call(vip->decoder, core, s_std, *std); + if (V4L2_STD_ALL == std) { + v4l2_subdev_call(vip->decoder, core, s_std, std); ssleep(2); v4l2_subdev_call(vip->decoder, video, querystd, &newstd); v4l2_subdev_call(vip->decoder, video, g_input_status, &status); if (status & V4L2_IN_ST_NO_SIGNAL) return -EIO; - *std = vip->std = newstd; - if (oldstd != *std) { - if (V4L2_STD_525_60 & (*std)) + std = vip->std = newstd; + if (oldstd != std) { + if (V4L2_STD_525_60 & std) vip->format = formats_60[0]; else vip->format = formats_50[0]; @@ -462,14 +462,14 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std) return 0; } - if (oldstd != *std) { - if (V4L2_STD_525_60 & (*std)) + if (oldstd != std) { + if (V4L2_STD_525_60 & std) vip->format = formats_60[0]; else vip->format = formats_50[0]; } - return v4l2_subdev_call(vip->decoder, core, s_std, *std); + return v4l2_subdev_call(vip->decoder, core, s_std, std); } /** diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index 2e8f518f298f..1168a84a737d 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -2435,14 +2435,14 @@ static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std) return 0; } -static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id *std) +static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id std) { struct zoran_fh *fh = __fh; struct zoran *zr = fh->zr; int res = 0; mutex_lock(&zr->resource_lock); - res = zoran_set_norm(zr, *std); + res = zoran_set_norm(zr, std); if (res) goto sstd_unlock_and_return; diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 476cfc88d144..96f6a4922d0c 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -633,7 +633,7 @@ static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std) return 0; } -static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std) +static int bcap_s_std(struct file *file, void *priv, v4l2_std_id std) { struct bcap_device *bcap_dev = video_drvdata(file); int ret; @@ -641,11 +641,11 @@ static int bcap_s_std(struct file *file, void *priv, v4l2_std_id *std) if (vb2_is_busy(&bcap_dev->buffer_queue)) return -EBUSY; - ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, *std); + ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, std); if (ret < 0) return ret; - bcap_dev->std = *std; + bcap_dev->std = std; return 0; } diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 2a49f00c4543..33b9660b7f77 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -431,7 +431,7 @@ static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev, * Sets the standard if supported by the current encoder. Return the status. * 0 - success & -EINVAL on error */ -static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) +static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id std_id) { struct vpbe_config *cfg = vpbe_dev->cfg; int out_index = vpbe_dev->current_out_index; @@ -442,14 +442,14 @@ static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id) V4L2_OUT_CAP_STD)) return -EINVAL; - ret = vpbe_get_std_info(vpbe_dev, *std_id); + ret = vpbe_get_std_info(vpbe_dev, std_id); if (ret) return ret; mutex_lock(&vpbe_dev->lock); ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, - s_std_output, *std_id); + s_std_output, std_id); /* set the lcd controller output for the given mode */ if (!ret) { struct osd_state *osd_device = vpbe_dev->osd_device; @@ -513,7 +513,7 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev, */ if (preset_mode->timings_type & VPBE_ENC_STD) return vpbe_s_std(vpbe_dev, - &preset_mode->std_id); + preset_mode->std_id); if (preset_mode->timings_type & VPBE_ENC_DV_TIMINGS) { dv_timings = diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 30976dc9f346..bcf0ada3481d 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -983,7 +983,7 @@ static int vpbe_display_try_fmt(struct file *file, void *priv, * 0 - success & -EINVAL on error */ static int vpbe_display_s_std(struct file *file, void *priv, - v4l2_std_id *std_id) + v4l2_std_id std_id) { struct vpbe_fh *fh = priv; struct vpbe_layer *layer = fh->layer; diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 3d1af6704822..20db8a077990 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -376,7 +376,7 @@ static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev) * values in ccdc */ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, - const v4l2_std_id *std_id) + v4l2_std_id std_id) { struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev; struct v4l2_mbus_framefmt mbus_fmt; @@ -384,7 +384,7 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, int i, ret = 0; for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { - if (vpfe_standards[i].std_id & *std_id) { + if (vpfe_standards[i].std_id & std_id) { vpfe_dev->std_info.active_pixels = vpfe_standards[i].width; vpfe_dev->std_info.active_lines = @@ -461,7 +461,7 @@ static int vpfe_initialize_device(struct vpfe_device *vpfe_dev) /* Configure the default format information */ ret = vpfe_config_image_format(vpfe_dev, - &vpfe_standards[vpfe_dev->std_index].std_id); + vpfe_standards[vpfe_dev->std_index].std_id); if (ret) return ret; @@ -1168,7 +1168,7 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index) /* set the default image parameters in the device */ ret = vpfe_config_image_format(vpfe_dev, - &vpfe_standards[vpfe_dev->std_index].std_id); + vpfe_standards[vpfe_dev->std_index].std_id); unlock_out: mutex_unlock(&vpfe_dev->lock); return ret; @@ -1193,7 +1193,7 @@ static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) return ret; } -static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id) { struct vpfe_device *vpfe_dev = video_drvdata(file); struct vpfe_subdev_info *sdinfo; @@ -1215,7 +1215,7 @@ static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) } ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, s_std, *std_id); + core, s_std, std_id); if (ret < 0) { v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); goto unlock_out; diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index d869c8e868ee..00b7f9c5ac04 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1395,7 +1395,7 @@ static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) * @priv: file handle * @std_id: ptr to std id */ -static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id) { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; @@ -1424,7 +1424,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) fh->initialized = 1; /* Call encoder subdevice function to set the standard */ - ch->video.stdid = *std_id; + ch->video.stdid = std_id; memset(&ch->video.dv_timings, 0, sizeof(ch->video.dv_timings)); /* Get the information about the standard */ @@ -1437,7 +1437,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) vpif_config_format(ch); /* set standard in the sub device */ - ret = v4l2_subdev_call(ch->sd, core, s_std, *std_id); + ret = v4l2_subdev_call(ch->sd, core, s_std, std_id); if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) { vpif_dbg(1, debug, "Failed to set standard for sub devices\n"); return ret; diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 3bb187c9402b..f1dff9ec1ea2 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1059,14 +1059,14 @@ static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) return vb2_qbuf(&common->buffer_queue, buf); } -static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id) { struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; int ret = 0; - if (!(*std_id & VPIF_V4L2_STD)) + if (!(std_id & VPIF_V4L2_STD)) return -EINVAL; if (common->started) { @@ -1075,7 +1075,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) } /* Call encoder subdevice function to set the standard */ - ch->video.stdid = *std_id; + ch->video.stdid = std_id; memset(&ch->video.dv_timings, 0, sizeof(ch->video.dv_timings)); /* Get the information about the standard */ if (vpif_update_resolution(ch)) @@ -1093,14 +1093,14 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) vpif_config_format(ch); ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video, - s_std_output, *std_id); + s_std_output, std_id); if (ret < 0) { vpif_err("Failed to set output standard\n"); return ret; } ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core, - s_std, *std_id); + s_std, std_id); if (ret < 0) vpif_err("Failed to set standard for sub devices\n"); return ret; diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index 5f7db3f1f6f5..3a6a0dcdc3e4 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -957,12 +957,12 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std_id) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct viu_fh *fh = priv; - fh->dev->std = *id; - decoder_call(fh->dev, core, s_std, *id); + fh->dev->std = id; + decoder_call(fh->dev, core, s_std, id); return 0; } diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 92a33f081852..76a862318a7e 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1357,7 +1357,7 @@ static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i) } /* from vivi.c */ -static int mcam_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id *a) +static int mcam_vidioc_s_std(struct file *filp, void *priv, v4l2_std_id a) { return 0; } diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 9961e13f683d..ef0efdf422fe 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c @@ -574,7 +574,7 @@ static int mxr_dv_timings_cap(struct file *file, void *fh, return ret ? -EINVAL : 0; } -static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm) +static int mxr_s_std(struct file *file, void *fh, v4l2_std_id norm) { struct mxr_layer *layer = video_drvdata(file); struct mxr_device *mdev = layer->mdev; @@ -591,7 +591,7 @@ static int mxr_s_std(struct file *file, void *fh, v4l2_std_id *norm) return -EBUSY; } - ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, *norm); + ret = v4l2_subdev_call(to_outsd(mdev), video, s_std_output, norm); mutex_unlock(&mdev->mutex); diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index d853162586fa..8e3b95a6c29e 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -881,29 +881,29 @@ static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt) } } -static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id std_id) { struct sh_vou_device *vou_dev = video_drvdata(file); int ret; - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, *std_id); + dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, std_id); - if (*std_id & ~vou_dev->vdev->tvnorms) + if (std_id & ~vou_dev->vdev->tvnorms) return -EINVAL; ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, - s_std_output, *std_id); + s_std_output, std_id); /* Shall we continue, if the subdev doesn't support .s_std_output()? */ if (ret < 0 && ret != -ENOIOCTLCMD) return ret; - if (*std_id & V4L2_STD_525_60) + if (std_id & V4L2_STD_525_60) sh_vou_reg_ab_set(vou_dev, VOUCR, sh_vou_ntsc_mode(vou_dev->pdata->bus_fmt) << 29, 7 << 29); else sh_vou_reg_ab_set(vou_dev, VOUCR, 5 << 29, 7 << 29); - vou_dev->std = *std_id; + vou_dev->std = std_id; return 0; } diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 8ec98051ea73..3592968026cd 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -256,12 +256,12 @@ static int soc_camera_s_input(struct file *file, void *priv, unsigned int i) return 0; } -static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a) +static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id a) { struct soc_camera_device *icd = file->private_data; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - return v4l2_subdev_call(sd, core, s_std, *a); + return v4l2_subdev_call(sd, core, s_std, a); } static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a) diff --git a/drivers/media/platform/timblogiw.c b/drivers/media/platform/timblogiw.c index 2d91eeb1d2ae..a2f7bdd5104f 100644 --- a/drivers/media/platform/timblogiw.c +++ b/drivers/media/platform/timblogiw.c @@ -336,7 +336,7 @@ static int timblogiw_g_std(struct file *file, void *priv, v4l2_std_id *std) return 0; } -static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id *std) +static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id std) { struct video_device *vdev = video_devdata(file); struct timblogiw *lw = video_get_drvdata(vdev); @@ -348,10 +348,10 @@ static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id *std) mutex_lock(&lw->lock); if (TIMBLOGIW_HAS_DECODER(lw)) - err = v4l2_subdev_call(lw->sd_enc, core, s_std, *std); + err = v4l2_subdev_call(lw->sd_enc, core, s_std, std); if (!err) - fh->cur_norm = timblogiw_get_norm(*std); + fh->cur_norm = timblogiw_get_norm(std); mutex_unlock(&lw->lock); diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index b051c4a28554..a794cd6c4441 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -847,7 +847,7 @@ static int viacam_s_input(struct file *filp, void *priv, unsigned int i) return 0; } -static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id *std) +static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id std) { return 0; } diff --git a/drivers/media/platform/vino.c b/drivers/media/platform/vino.c index eb5d6f955709..c6af974c5b45 100644 --- a/drivers/media/platform/vino.c +++ b/drivers/media/platform/vino.c @@ -3042,7 +3042,7 @@ static int vino_g_std(struct file *file, void *__fh, } static int vino_s_std(struct file *file, void *__fh, - v4l2_std_id *std) + v4l2_std_id std) { struct vino_channel_settings *vcs = video_drvdata(file); unsigned long flags; @@ -3056,7 +3056,7 @@ static int vino_s_std(struct file *file, void *__fh, } /* check if the standard is valid for the current input */ - if ((*std) & vino_inputs[vcs->input].std) { + if (std & vino_inputs[vcs->input].std) { dprintk("standard accepted\n"); /* change the video norm for SAA7191 @@ -3065,13 +3065,13 @@ static int vino_s_std(struct file *file, void *__fh, if (vcs->input == VINO_INPUT_D1) goto out; - if ((*std) & V4L2_STD_PAL) { + if (std & V4L2_STD_PAL) { ret = vino_set_data_norm(vcs, VINO_DATA_NORM_PAL, &flags); - } else if ((*std) & V4L2_STD_NTSC) { + } else if (std & V4L2_STD_NTSC) { ret = vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC, &flags); - } else if ((*std) & V4L2_STD_SECAM) { + } else if (std & V4L2_STD_SECAM) { ret = vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM, &flags); } else { diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 11316f2f2e42..e9dd01c4b6ed 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1320,7 +1320,7 @@ out: return rc; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; @@ -1332,7 +1332,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm) have to make the au0828 bridge adjust the size of its capture buffer, which is currently hardcoded at 720x480 */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, *norm); + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, norm); dev->std_set_in_tuner_core = 1; if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl) diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 49c842aa1f70..f548db8043d4 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1492,14 +1492,14 @@ static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct cx231xx_fh *fh = file->private_data; struct cx231xx *dev = fh->dev; unsigned int i; for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++) - if (*id & cx231xx_tvnorms[i].id) + if (id & cx231xx_tvnorms[i].id) break; if (i == ARRAY_SIZE(cx231xx_tvnorms)) return -EINVAL; diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 53020a7e01fe..4cff2f4075e1 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -987,7 +987,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; @@ -998,13 +998,13 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) if (rc < 0) return rc; - if (dev->norm == *norm) + if (dev->norm == norm) return 0; if (videobuf_queue_is_busy(&fh->vb_vidq)) return -EBUSY; - dev->norm = *norm; + dev->norm = norm; /* Adjusts width/height, if needed */ dev->width = 720; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 3ef696d36c7e..96d84c22ef00 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -996,23 +996,23 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; struct v4l2_format f; - if (*norm == dev->norm) + if (norm == dev->norm) return 0; if (dev->streaming_users > 0) return -EBUSY; - dev->norm = *norm; + dev->norm = norm; /* Adjusts width/height, if needed */ f.fmt.pix.width = 720; - f.fmt.pix.height = (*norm & V4L2_STD_525_60) ? 480 : 576; + f.fmt.pix.height = (norm & V4L2_STD_525_60) ? 480 : 576; vidioc_try_fmt_vid_cap(file, priv, &f); /* set new image size */ diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 6a15405360dc..2983bf0d5f0f 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -582,13 +582,13 @@ static int vidioc_querycap(struct file *file, void *priv, } static int vidioc_s_std(struct file *file, void *private_data, - v4l2_std_id *std) + v4l2_std_id std) { struct hdpvr_fh *fh = file->private_data; struct hdpvr_device *dev = fh->dev; u8 std_type = 1; - if (*std & (V4L2_STD_NTSC | V4L2_STD_PAL_60)) + if (std & (V4L2_STD_NTSC | V4L2_STD_PAL_60)) std_type = 0; return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type); diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 0f729c92e3cf..a7774e3836d4 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -196,13 +196,13 @@ static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std) return ret; } -static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id *std) +static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id std) { struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; return pvr2_ctrl_set_value( - pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), *std); + pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), std); } static int pvr2_querystd(struct file *file, void *priv, v4l2_std_id *std) diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 2bd86132d3e3..ab97e7d0b4f2 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -1294,7 +1294,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i) { struct s2255_fh *fh = priv; struct s2255_mode mode; @@ -1314,7 +1314,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) goto out_s_std; } mode = fh->channel->mode; - if (*i & V4L2_STD_525_60) { + if (i & V4L2_STD_525_60) { dprintk(4, "%s 60 Hz\n", __func__); /* if changing format, reset frame decimation/intervals */ if (mode.format != FORMAT_NTSC) { @@ -1324,7 +1324,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) channel->width = LINE_SZ_4CIFS_NTSC; channel->height = NUM_LINES_4CIFS_NTSC * 2; } - } else if (*i & V4L2_STD_625_50) { + } else if (i & V4L2_STD_625_50) { dprintk(4, "%s 50 Hz\n", __func__); if (mode.format != FORMAT_PAL) { mode.restart = 1; @@ -1337,7 +1337,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) ret = -EINVAL; goto out_s_std; } - fh->channel->std = *i; + fh->channel->std = i; if (mode.restart) s2255_set_mode(fh->channel, &mode); out_s_std: diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 5307a63e378f..f6a6cdc8b288 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -375,7 +375,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { struct stk1160 *dev = video_drvdata(file); struct vb2_queue *q = &dev->vb_vidq; @@ -388,7 +388,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) return -ENODEV; /* We need to set this now, before we call stk1160_set_std */ - dev->norm = *norm; + dev->norm = norm; /* This is taken from saa7115 video decoder */ if (dev->norm & V4L2_STD_525_60) { diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 9595309caed4..8df668d06552 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -801,7 +801,7 @@ static int vidioc_g_fmt_vbi(struct file *file, void *fh, return 0; } -static int set_std(struct poseidon *pd, v4l2_std_id *norm) +static int set_std(struct poseidon *pd, v4l2_std_id norm) { struct video_data *video = &pd->video_data; struct vbi_data *vbi = &pd->vbi_data; @@ -811,7 +811,7 @@ static int set_std(struct poseidon *pd, v4l2_std_id *norm) int height; for (i = 0; i < POSEIDON_TVNORMS; i++) { - if (*norm & poseidon_tvnorms[i].v4l2_id) { + if (norm & poseidon_tvnorms[i].v4l2_id) { param = poseidon_tvnorms[i].tlg_tvnorm; log("name : %s", poseidon_tvnorms[i].name); goto found; @@ -846,7 +846,7 @@ out: return ret; } -static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *norm) +static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id norm) { struct front_face *front = fh; @@ -1270,7 +1270,7 @@ static int restore_v4l2_context(struct poseidon *pd, pd_video_checkmode(pd); - set_std(pd, &context->tvnormid); + set_std(pd, context->tvnormid); vidioc_s_input(NULL, front, context->sig_index); pd_vidioc_s_tuner(pd, context->audio_idx); pd_vidioc_s_fmt(pd, &context->pix); diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index b4618d7d9c4b..a78de1d1bc9e 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -1056,13 +1056,13 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { int rc = 0; struct tm6000_fh *fh = priv; struct tm6000_core *dev = fh->dev; - dev->norm = *norm; + dev->norm = norm; rc = tm6000_init_analog_mode(dev); fh->width = dev->width; @@ -1134,7 +1134,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) dev->input = i; - rc = vidioc_s_std(file, priv, &dev->vfd->current_norm); + rc = vidioc_s_std(file, priv, dev->vfd->current_norm); return rc; } diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index 874cfec0b8db..041f19e1b05b 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -595,11 +595,11 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int input) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct usb_usbvision *usbvision = video_drvdata(file); - usbvision->tvnorm_id = *id; + usbvision->tvnorm_id = id; call_all(usbvision, core, s_std, usbvision->tvnorm_id); /* propagate the change to the decoder */ diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 8ec8abe0ffe7..d80d8afba3fb 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1383,15 +1383,15 @@ static int v4l_s_std(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { struct video_device *vfd = video_devdata(file); - v4l2_std_id *id = arg, norm; + v4l2_std_id id = *(v4l2_std_id *)arg, norm; int ret; - norm = (*id) & vfd->tvnorms; + norm = id & vfd->tvnorms; if (vfd->tvnorms && !norm) /* Check if std is supported */ return -EINVAL; /* Calls the specific handler */ - ret = ops->vidioc_s_std(file, fh, &norm); + ret = ops->vidioc_s_std(file, fh, norm); /* Updates standard information */ if (ret >= 0) diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c index 19dc5b062d07..3670a7b0724e 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c @@ -924,7 +924,7 @@ static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) * * Return 0 on success, error code otherwise */ -static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) +static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id) { struct vpfe_video_device *video = video_drvdata(file); struct vpfe_device *vpfe_dev = video->vpfe_dev; @@ -945,13 +945,13 @@ static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id *std_id) goto unlock_out; } ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, - core, s_std, *std_id); + core, s_std, std_id); if (ret < 0) { v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); video->stdid = V4L2_STD_UNKNOWN; goto unlock_out; } - video->stdid = *std_id; + video->stdid = std_id; unlock_out: mutex_unlock(&video->lock); return ret; diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c index e33b7f55d84e..073b3b35f8f4 100644 --- a/drivers/staging/media/dt3155v4l/dt3155v4l.c +++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c @@ -612,9 +612,9 @@ dt3155_ioc_g_std(struct file *filp, void *p, v4l2_std_id *norm) } static int -dt3155_ioc_s_std(struct file *filp, void *p, v4l2_std_id *norm) +dt3155_ioc_s_std(struct file *filp, void *p, v4l2_std_id norm) { - if (*norm & DT3155_CURRENT_NORM) + if (norm & DT3155_CURRENT_NORM) return 0; return -EINVAL; } diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 4e477f3b78f3..29fe94da5f71 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -1117,40 +1117,40 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std) return 0; } -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) { struct go7007 *go = ((struct go7007_file *) priv)->go; if (go->streaming) return -EBUSY; - if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) && *std != 0) + if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) && std != 0) return -EINVAL; - if (*std == 0) + if (std == 0) return -EINVAL; if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && go->input == go->board_info->num_inputs - 1) { if (!go->i2c_adapter_online) return -EIO; - if (call_all(&go->v4l2_dev, core, s_std, *std) < 0) + if (call_all(&go->v4l2_dev, core, s_std, std) < 0) return -EINVAL; } - if (*std & V4L2_STD_NTSC) { + if (std & V4L2_STD_NTSC) { go->standard = GO7007_STD_NTSC; go->sensor_framerate = 30000; - } else if (*std & V4L2_STD_PAL) { + } else if (std & V4L2_STD_PAL) { go->standard = GO7007_STD_PAL; go->sensor_framerate = 25025; - } else if (*std & V4L2_STD_SECAM) { + } else if (std & V4L2_STD_SECAM) { go->standard = GO7007_STD_PAL; go->sensor_framerate = 25025; } else return -EINVAL; - call_all(&go->v4l2_dev, core, s_std, *std); + call_all(&go->v4l2_dev, core, s_std, std); set_capture_size(go, NULL, 0); return 0; diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index 4977e869d5b7..310b126e1288 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -1326,7 +1326,7 @@ static int solo_enc_streamoff(struct file *file, void *priv, return videobuf_streamoff(&fh->vidq); } -static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id *i) +static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id i) { return 0; } diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index ca774cc57539..87f3c0452ca4 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c @@ -773,7 +773,7 @@ static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return videobuf_streamoff(&fh->vidq); } -static int solo_s_std(struct file *file, void *priv, v4l2_std_id *i) +static int solo_s_std(struct file *file, void *priv, v4l2_std_id i) { return 0; } diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h index a7ca4884c46c..57585c7004a4 100644 --- a/include/media/davinci/vpbe.h +++ b/include/media/davinci/vpbe.h @@ -132,7 +132,7 @@ struct vpbe_device_ops { struct v4l2_enum_dv_timings *timings_info); /* Set std at the output */ - int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); + int (*s_std)(struct vpbe_device *vpbe_dev, v4l2_std_id std_id); /* Get the current std at the output */ int (*g_std)(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id); diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 0da8682a0481..ee7b7c67c87a 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -132,7 +132,7 @@ struct v4l2_ioctl_ops { ENUMSTD is handled by videodev.c */ int (*vidioc_g_std) (struct file *file, void *fh, v4l2_std_id *norm); - int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id *norm); + int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id norm); int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a); /* Input handling */ -- cgit v1.2.3 From 27d5a87cf4b44cbcbd0f4706a433e4a68d496236 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 18 Mar 2013 11:02:22 -0300 Subject: [media] v4l2-ioctl: add precision when printing names Never print more than the size of the buffer containing the name. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 60 ++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 26 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index d80d8afba3fb..29c751d86061 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -167,9 +167,11 @@ static void v4l_print_querycap(const void *arg, bool write_only) { const struct v4l2_capability *p = arg; - pr_cont("driver=%s, card=%s, bus=%s, version=0x%08x, " + pr_cont("driver=%.*s, card=%.*s, bus=%.*s, version=0x%08x, " "capabilities=0x%08x, device_caps=0x%08x\n", - p->driver, p->card, p->bus_info, + (int)sizeof(p->driver), p->driver, + (int)sizeof(p->card), p->card, + (int)sizeof(p->bus_info), p->bus_info, p->version, p->capabilities, p->device_caps); } @@ -177,20 +179,21 @@ static void v4l_print_enuminput(const void *arg, bool write_only) { const struct v4l2_input *p = arg; - pr_cont("index=%u, name=%s, type=%u, audioset=0x%x, tuner=%u, " + pr_cont("index=%u, name=%.*s, type=%u, audioset=0x%x, tuner=%u, " "std=0x%08Lx, status=0x%x, capabilities=0x%x\n", - p->index, p->name, p->type, p->audioset, p->tuner, - (unsigned long long)p->std, p->status, p->capabilities); + p->index, (int)sizeof(p->name), p->name, p->type, p->audioset, + p->tuner, (unsigned long long)p->std, p->status, + p->capabilities); } static void v4l_print_enumoutput(const void *arg, bool write_only) { const struct v4l2_output *p = arg; - pr_cont("index=%u, name=%s, type=%u, audioset=0x%x, " + pr_cont("index=%u, name=%.*s, type=%u, audioset=0x%x, " "modulator=%u, std=0x%08Lx, capabilities=0x%x\n", - p->index, p->name, p->type, p->audioset, p->modulator, - (unsigned long long)p->std, p->capabilities); + p->index, (int)sizeof(p->name), p->name, p->type, p->audioset, + p->modulator, (unsigned long long)p->std, p->capabilities); } static void v4l_print_audio(const void *arg, bool write_only) @@ -200,8 +203,9 @@ static void v4l_print_audio(const void *arg, bool write_only) if (write_only) pr_cont("index=%u, mode=0x%x\n", p->index, p->mode); else - pr_cont("index=%u, name=%s, capability=0x%x, mode=0x%x\n", - p->index, p->name, p->capability, p->mode); + pr_cont("index=%u, name=%.*s, capability=0x%x, mode=0x%x\n", + p->index, (int)sizeof(p->name), p->name, + p->capability, p->mode); } static void v4l_print_audioout(const void *arg, bool write_only) @@ -211,21 +215,22 @@ static void v4l_print_audioout(const void *arg, bool write_only) if (write_only) pr_cont("index=%u\n", p->index); else - pr_cont("index=%u, name=%s, capability=0x%x, mode=0x%x\n", - p->index, p->name, p->capability, p->mode); + pr_cont("index=%u, name=%.*s, capability=0x%x, mode=0x%x\n", + p->index, (int)sizeof(p->name), p->name, + p->capability, p->mode); } static void v4l_print_fmtdesc(const void *arg, bool write_only) { const struct v4l2_fmtdesc *p = arg; - pr_cont("index=%u, type=%s, flags=0x%x, pixelformat=%c%c%c%c, description='%s'\n", + pr_cont("index=%u, type=%s, flags=0x%x, pixelformat=%c%c%c%c, description='%.*s'\n", p->index, prt_names(p->type, v4l2_type_names), p->flags, (p->pixelformat & 0xff), (p->pixelformat >> 8) & 0xff, (p->pixelformat >> 16) & 0xff, (p->pixelformat >> 24) & 0xff, - p->description); + (int)sizeof(p->description), p->description); } static void v4l_print_format(const void *arg, bool write_only) @@ -348,9 +353,9 @@ static void v4l_print_modulator(const void *arg, bool write_only) if (write_only) pr_cont("index=%u, txsubchans=0x%x", p->index, p->txsubchans); else - pr_cont("index=%u, name=%s, capability=0x%x, " + pr_cont("index=%u, name=%.*s, capability=0x%x, " "rangelow=%u, rangehigh=%u, txsubchans=0x%x\n", - p->index, p->name, p->capability, + p->index, (int)sizeof(p->name), p->name, p->capability, p->rangelow, p->rangehigh, p->txsubchans); } @@ -361,10 +366,10 @@ static void v4l_print_tuner(const void *arg, bool write_only) if (write_only) pr_cont("index=%u, audmode=%u\n", p->index, p->audmode); else - pr_cont("index=%u, name=%s, type=%u, capability=0x%x, " + pr_cont("index=%u, name=%.*s, type=%u, capability=0x%x, " "rangelow=%u, rangehigh=%u, signal=%u, afc=%d, " "rxsubchans=0x%x, audmode=%u\n", - p->index, p->name, p->type, + p->index, (int)sizeof(p->name), p->name, p->type, p->capability, p->rangelow, p->rangehigh, p->signal, p->afc, p->rxsubchans, p->audmode); @@ -382,9 +387,9 @@ static void v4l_print_standard(const void *arg, bool write_only) { const struct v4l2_standard *p = arg; - pr_cont("index=%u, id=0x%Lx, name=%s, fps=%u/%u, " + pr_cont("index=%u, id=0x%Lx, name=%.*s, fps=%u/%u, " "framelines=%u\n", p->index, - (unsigned long long)p->id, p->name, + (unsigned long long)p->id, (int)sizeof(p->name), p->name, p->frameperiod.numerator, p->frameperiod.denominator, p->framelines); @@ -504,9 +509,9 @@ static void v4l_print_queryctrl(const void *arg, bool write_only) { const struct v4l2_queryctrl *p = arg; - pr_cont("id=0x%x, type=%d, name=%s, min/max=%d/%d, " + pr_cont("id=0x%x, type=%d, name=%.*s, min/max=%d/%d, " "step=%d, default=%d, flags=0x%08x\n", - p->id, p->type, p->name, + p->id, p->type, (int)sizeof(p->name), p->name, p->minimum, p->maximum, p->step, p->default_value, p->flags); } @@ -623,7 +628,8 @@ static void v4l_print_dbg_chip_ident(const void *arg, bool write_only) pr_cont("type=%u, ", p->match.type); if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) - pr_cont("name=%s, ", p->match.name); + pr_cont("name=%.*s, ", + (int)sizeof(p->match.name), p->match.name); else pr_cont("addr=%u, ", p->match.addr); pr_cont("chip_ident=%u, revision=0x%x\n", @@ -636,7 +642,8 @@ static void v4l_print_dbg_register(const void *arg, bool write_only) pr_cont("type=%u, ", p->match.type); if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) - pr_cont("name=%s, ", p->match.name); + pr_cont("name=%.*s, ", + (int)sizeof(p->match.name), p->match.name); else pr_cont("addr=%u, ", p->match.addr); pr_cont("reg=0x%llx, val=0x%llx\n", @@ -647,8 +654,9 @@ static void v4l_print_dv_enum_presets(const void *arg, bool write_only) { const struct v4l2_dv_enum_preset *p = arg; - pr_cont("index=%u, preset=%u, name=%s, width=%u, height=%u\n", - p->index, p->preset, p->name, p->width, p->height); + pr_cont("index=%u, preset=%u, name=%.*s, width=%u, height=%u\n", + p->index, p->preset, + (int)sizeof(p->name), p->name, p->width, p->height); } static void v4l_print_dv_preset(const void *arg, bool write_only) -- cgit v1.2.3 From b5656e8b7363c4e248e6372dc34828d3dfb17832 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 24 Mar 2013 08:24:19 -0300 Subject: [media] ivtv: prepare ivtv for adding const to s_register The ivtv_itvc function receives a pointer to v4l2_dbg_register. When we add const to that pointer in the s_register case we will run into a problem here since this common function would discard const in that case. So change this function so it receives the address and a pointer to a value. In addition we now set the size field in the g_register function which is where it belongs. This will simplify the next patch where const will be added to s_register. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ivtv/ivtv-ioctl.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 080f179070a6..861e4629c7fc 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -711,28 +711,26 @@ static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_i } #ifdef CONFIG_VIDEO_ADV_DEBUG -static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg) +static int ivtv_itvc(struct ivtv *itv, bool get, u64 reg, u64 *val) { - struct v4l2_dbg_register *regs = arg; volatile u8 __iomem *reg_start; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (regs->reg >= IVTV_REG_OFFSET && regs->reg < IVTV_REG_OFFSET + IVTV_REG_SIZE) + if (reg >= IVTV_REG_OFFSET && reg < IVTV_REG_OFFSET + IVTV_REG_SIZE) reg_start = itv->reg_mem - IVTV_REG_OFFSET; - else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET && - regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE) + else if (itv->has_cx23415 && reg >= IVTV_DECODER_OFFSET && + reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE) reg_start = itv->dec_mem - IVTV_DECODER_OFFSET; - else if (regs->reg < IVTV_ENCODER_SIZE) + else if (reg < IVTV_ENCODER_SIZE) reg_start = itv->enc_mem; else return -EINVAL; - regs->size = 4; - if (cmd == VIDIOC_DBG_G_REGISTER) - regs->val = readl(regs->reg + reg_start); + if (get) + *val = readl(reg + reg_start); else - writel(regs->val, regs->reg + reg_start); + writel(*val, reg + reg_start); return 0; } @@ -740,8 +738,10 @@ static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register { struct ivtv *itv = fh2id(fh)->itv; - if (v4l2_chip_match_host(®->match)) - return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg); + if (v4l2_chip_match_host(®->match)) { + reg->size = 4; + return ivtv_itvc(itv, true, reg->reg, ®->val); + } /* TODO: subdev errors should not be ignored, this should become a subdev helper function. */ ivtv_call_all(itv, core, g_register, reg); @@ -753,7 +753,7 @@ static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register struct ivtv *itv = fh2id(fh)->itv; if (v4l2_chip_match_host(®->match)) - return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg); + return ivtv_itvc(itv, false, reg->reg, ®->val); /* TODO: subdev errors should not be ignored, this should become a subdev helper function. */ ivtv_call_all(itv, core, s_register, reg); -- cgit v1.2.3 From 977ba3b1b73f24fae2d0c8bd59d7a4696f1e0ccc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 24 Mar 2013 08:28:46 -0300 Subject: [media] v4l2: add const to argument of write-only s_register ioctl This ioctl is defined as IOW, so pass the argument as const. Signed-off-by: Hans Verkuil Acked-by: Guennadi Liakhovetski Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/au8522_decoder.c | 2 +- drivers/media/i2c/ad9389b.c | 2 +- drivers/media/i2c/adv7183.c | 2 +- drivers/media/i2c/adv7604.c | 2 +- drivers/media/i2c/ak881x.c | 2 +- drivers/media/i2c/cs5345.c | 2 +- drivers/media/i2c/cx25840/cx25840-core.c | 2 +- drivers/media/i2c/m52790.c | 2 +- drivers/media/i2c/mt9m032.c | 2 +- drivers/media/i2c/mt9v011.c | 2 +- drivers/media/i2c/ov7670.c | 2 +- drivers/media/i2c/saa7115.c | 2 +- drivers/media/i2c/saa7127.c | 2 +- drivers/media/i2c/saa717x.c | 2 +- drivers/media/i2c/soc_camera/mt9m001.c | 2 +- drivers/media/i2c/soc_camera/mt9m111.c | 2 +- drivers/media/i2c/soc_camera/mt9t031.c | 2 +- drivers/media/i2c/soc_camera/mt9t112.c | 2 +- drivers/media/i2c/soc_camera/mt9v022.c | 2 +- drivers/media/i2c/soc_camera/ov2640.c | 2 +- drivers/media/i2c/soc_camera/ov5642.c | 2 +- drivers/media/i2c/soc_camera/ov6650.c | 2 +- drivers/media/i2c/soc_camera/ov772x.c | 2 +- drivers/media/i2c/soc_camera/ov9640.c | 2 +- drivers/media/i2c/soc_camera/ov9740.c | 2 +- drivers/media/i2c/soc_camera/rj54n1cb0c.c | 2 +- drivers/media/i2c/soc_camera/tw9910.c | 2 +- drivers/media/i2c/ths7303.c | 2 +- drivers/media/i2c/tvp5150.c | 2 +- drivers/media/i2c/tvp7002.c | 2 +- drivers/media/i2c/upd64031a.c | 2 +- drivers/media/i2c/upd64083.c | 2 +- drivers/media/i2c/vs6624.c | 2 +- drivers/media/pci/bt8xx/bttv-driver.c | 5 ++-- drivers/media/pci/cx18/cx18-av-core.c | 2 +- drivers/media/pci/cx18/cx18-ioctl.c | 36 ++++++++++--------------- drivers/media/pci/cx23885/cx23885-ioctl.c | 9 +++---- drivers/media/pci/cx23885/cx23885-ioctl.h | 2 +- drivers/media/pci/cx23885/cx23888-ir.c | 2 +- drivers/media/pci/cx25821/cx25821-video.c | 2 +- drivers/media/pci/cx25821/cx25821-video.h | 2 +- drivers/media/pci/cx88/cx88-video.c | 2 +- drivers/media/pci/ivtv/ivtv-ioctl.c | 9 ++++--- drivers/media/pci/saa7134/saa7134-video.c | 2 +- drivers/media/pci/saa7146/mxb.c | 3 +-- drivers/media/pci/saa7164/saa7164-encoder.c | 2 +- drivers/media/platform/blackfin/bfin_capture.c | 2 +- drivers/media/platform/davinci/vpbe_display.c | 2 +- drivers/media/platform/davinci/vpif_capture.c | 3 ++- drivers/media/platform/davinci/vpif_display.c | 3 ++- drivers/media/platform/marvell-ccic/mcam-core.c | 2 +- drivers/media/platform/sh_vou.c | 2 +- drivers/media/platform/soc_camera/soc_camera.c | 2 +- drivers/media/usb/au0828/au0828-video.c | 2 +- drivers/media/usb/cx231xx/cx231xx-video.c | 2 +- drivers/media/usb/cx231xx/cx231xx.h | 2 +- drivers/media/usb/em28xx/em28xx-video.c | 2 +- drivers/media/usb/gspca/gspca.c | 2 +- drivers/media/usb/gspca/gspca.h | 8 +++--- drivers/media/usb/gspca/pac7302.c | 2 +- drivers/media/usb/gspca/sn9c20x.c | 2 +- drivers/media/usb/pvrusb2/pvrusb2-hdw.c | 2 +- drivers/media/usb/pvrusb2/pvrusb2-hdw.h | 2 +- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 2 +- drivers/media/usb/stk1160/stk1160-v4l.c | 2 +- drivers/media/usb/usbvision/usbvision-video.c | 2 +- drivers/media/v4l2-core/v4l2-ioctl.c | 2 +- include/media/v4l2-ioctl.h | 2 +- include/media/v4l2-subdev.h | 2 +- 69 files changed, 96 insertions(+), 102 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c index 5243ba6295cc..526902b45f9c 100644 --- a/drivers/media/dvb-frontends/au8522_decoder.c +++ b/drivers/media/dvb-frontends/au8522_decoder.c @@ -583,7 +583,7 @@ static int au8522_g_register(struct v4l2_subdev *sd, } static int au8522_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct au8522_state *state = to_state(sd); diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c index c2886b6a727d..58344b6c3a55 100644 --- a/drivers/media/i2c/ad9389b.c +++ b/drivers/media/i2c/ad9389b.c @@ -354,7 +354,7 @@ static int ad9389b_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int ad9389b_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int ad9389b_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c index 6fed5b74e743..56a1fa4af0fe 100644 --- a/drivers/media/i2c/adv7183.c +++ b/drivers/media/i2c/adv7183.c @@ -507,7 +507,7 @@ static int adv7183_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int adv7183_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int adv7183_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index f47555b1000a..31a63c9324fe 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -699,7 +699,7 @@ static int adv7604_g_register(struct v4l2_subdev *sd, } static int adv7604_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c index ba674656b10d..fd47465e4f6a 100644 --- a/drivers/media/i2c/ak881x.c +++ b/drivers/media/i2c/ak881x.c @@ -101,7 +101,7 @@ static int ak881x_g_register(struct v4l2_subdev *sd, } static int ak881x_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/cs5345.c b/drivers/media/i2c/cs5345.c index c8581e26fa9c..1d2f7c8512b5 100644 --- a/drivers/media/i2c/cs5345.c +++ b/drivers/media/i2c/cs5345.c @@ -110,7 +110,7 @@ static int cs5345_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r return 0; } -static int cs5345_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int cs5345_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 234b7c63d087..12fb9b2eb887 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -1671,7 +1671,7 @@ static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int cx25840_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int cx25840_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/m52790.c b/drivers/media/i2c/m52790.c index 0991576f4c82..39f50fd2b8d2 100644 --- a/drivers/media/i2c/m52790.c +++ b/drivers/media/i2c/m52790.c @@ -96,7 +96,7 @@ static int m52790_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r return 0; } -static int m52790_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int m52790_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct m52790_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c index f80c1d7ec884..2526b66b91fd 100644 --- a/drivers/media/i2c/mt9m032.c +++ b/drivers/media/i2c/mt9m032.c @@ -548,7 +548,7 @@ static int mt9m032_g_register(struct v4l2_subdev *sd, } static int mt9m032_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct mt9m032 *sensor = to_mt9m032(sd); struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index 73b7688cbebd..3f415fd12de3 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -421,7 +421,7 @@ static int mt9v011_g_register(struct v4l2_subdev *sd, } static int mt9v011_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 05ed5b8e7f88..617ad3fff4aa 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -1487,7 +1487,7 @@ static int ov7670_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r return ret; } -static int ov7670_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int ov7670_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index 6b6788cd08f6..5d9d0330b3df 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -1428,7 +1428,7 @@ static int saa711x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int saa711x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int saa711x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c index b745f68fbc92..8a47ac10927f 100644 --- a/drivers/media/i2c/saa7127.c +++ b/drivers/media/i2c/saa7127.c @@ -672,7 +672,7 @@ static int saa7127_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int saa7127_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int saa7127_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c index 5608b937f8b2..cf3a0aa7e45e 100644 --- a/drivers/media/i2c/saa717x.c +++ b/drivers/media/i2c/saa717x.c @@ -988,7 +988,7 @@ static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int saa717x_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); u16 addr = reg->reg & 0xffff; diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c index bcdc86175549..dd9089805757 100644 --- a/drivers/media/i2c/soc_camera/mt9m001.c +++ b/drivers/media/i2c/soc_camera/mt9m001.c @@ -360,7 +360,7 @@ static int mt9m001_g_register(struct v4l2_subdev *sd, } static int mt9m001_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index 2902ba633da6..8bd4e0d2ea03 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/soc_camera/mt9m111.c @@ -641,7 +641,7 @@ static int mt9m111_g_register(struct v4l2_subdev *sd, } static int mt9m111_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c index d80d044ebf15..26a15b87a9a2 100644 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ b/drivers/media/i2c/soc_camera/mt9t031.c @@ -430,7 +430,7 @@ static int mt9t031_g_register(struct v4l2_subdev *sd, } static int mt9t031_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 188e29b03273..a7256b732804 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -766,7 +766,7 @@ static int mt9t112_g_register(struct v4l2_subdev *sd, } static int mt9t112_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); int ret; diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index 53eaf899d3b6..a295e598486f 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -497,7 +497,7 @@ static int mt9v022_g_register(struct v4l2_subdev *sd, } static int mt9v022_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 0f520f693b6e..e3168424f9ba 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -756,7 +756,7 @@ static int ov2640_g_register(struct v4l2_subdev *sd, } static int ov2640_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c index 9d53309619d2..9aa56de69eed 100644 --- a/drivers/media/i2c/soc_camera/ov5642.c +++ b/drivers/media/i2c/soc_camera/ov5642.c @@ -708,7 +708,7 @@ static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register return ret; } -static int ov5642_set_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int ov5642_set_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c index dbe4f564e6b2..991202d4bbae 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/soc_camera/ov6650.c @@ -421,7 +421,7 @@ static int ov6650_get_register(struct v4l2_subdev *sd, } static int ov6650_set_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index fbeb5b2f3ae5..713d62e349f6 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -652,7 +652,7 @@ static int ov772x_g_register(struct v4l2_subdev *sd, } static int ov772x_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c index 05993041be31..20ca62d371c1 100644 --- a/drivers/media/i2c/soc_camera/ov9640.c +++ b/drivers/media/i2c/soc_camera/ov9640.c @@ -322,7 +322,7 @@ static int ov9640_get_register(struct v4l2_subdev *sd, } static int ov9640_set_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index 2f236da80165..012bd6271124 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c @@ -835,7 +835,7 @@ static int ov9740_get_register(struct v4l2_subdev *sd, } static int ov9740_set_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c index 5c92679bfefb..1f9ec3b06b4e 100644 --- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c +++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c @@ -1161,7 +1161,7 @@ static int rj54n1_g_register(struct v4l2_subdev *sd, } static int rj54n1_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c index 7d2074601881..bad90b16a6dd 100644 --- a/drivers/media/i2c/soc_camera/tw9910.c +++ b/drivers/media/i2c/soc_camera/tw9910.c @@ -554,7 +554,7 @@ static int tw9910_g_register(struct v4l2_subdev *sd, } static int tw9910_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index 3ca60c7cd95f..c4339556a2ea 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c @@ -245,7 +245,7 @@ static int ths7303_g_register(struct v4l2_subdev *sd, } static int ths7303_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 5967e1a0c809..485159a3c0b7 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -1067,7 +1067,7 @@ static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int tvp5150_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 7406de9b45db..027809cca5f5 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -768,7 +768,7 @@ static int tvp7002_g_register(struct v4l2_subdev *sd, * -EPERM if call not allowed. */ static int tvp7002_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/upd64031a.c b/drivers/media/i2c/upd64031a.c index d15cfd944e57..f0a09214c519 100644 --- a/drivers/media/i2c/upd64031a.c +++ b/drivers/media/i2c/upd64031a.c @@ -175,7 +175,7 @@ static int upd64031a_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register return 0; } -static int upd64031a_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int upd64031a_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/upd64083.c b/drivers/media/i2c/upd64083.c index 75d6acc62018..343e0215f74c 100644 --- a/drivers/media/i2c/upd64083.c +++ b/drivers/media/i2c/upd64083.c @@ -133,7 +133,7 @@ static int upd64083_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register return 0; } -static int upd64083_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int upd64083_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index 9ac1b8c3a837..f366fad6269e 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c @@ -748,7 +748,7 @@ static int vs6624_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r return 0; } -static int vs6624_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int vs6624_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 4b9a256f506e..e33a2d2f81a8 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1945,7 +1945,7 @@ static int bttv_g_register(struct file *file, void *f, } static int bttv_s_register(struct file *file, void *f, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct bttv_fh *fh = f; struct bttv *btv = fh->btv; @@ -1961,8 +1961,7 @@ static int bttv_s_register(struct file *file, void *f, } /* bt848 has a 12-bit register space */ - reg->reg &= 0xfff; - btwrite(reg->val, reg->reg); + btwrite(reg->val, reg->reg & 0xfff); return 0; } diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c index c22242bc10df..38b1d64ffc27 100644 --- a/drivers/media/pci/cx18/cx18-av-core.c +++ b/drivers/media/pci/cx18/cx18-av-core.c @@ -1266,7 +1266,7 @@ static int cx18_av_g_register(struct v4l2_subdev *sd, } static int cx18_av_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx18 *cx = v4l2_get_subdevdata(sd); diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 254c50fabd73..7dbd5a9451ed 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -415,42 +415,34 @@ static int cx18_g_chip_ident(struct file *file, void *fh, } #ifdef CONFIG_VIDEO_ADV_DEBUG -static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) -{ - struct v4l2_dbg_register *regs = arg; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE) - return -EINVAL; - - regs->size = 4; - if (cmd == VIDIOC_DBG_S_REGISTER) - cx18_write_enc(cx, regs->val, regs->reg); - else - regs->val = cx18_read_enc(cx, regs->reg); - return 0; -} - static int cx18_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { struct cx18 *cx = fh2id(fh)->cx; - if (v4l2_chip_match_host(®->match)) - return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg); + if (v4l2_chip_match_host(®->match)) { + if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE) + return -EINVAL; + reg->size = 4; + reg->val = cx18_read_enc(cx, reg->reg); + return 0; + } /* FIXME - errors shouldn't be ignored */ cx18_call_all(cx, core, g_register, reg); return 0; } static int cx18_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx18 *cx = fh2id(fh)->cx; - if (v4l2_chip_match_host(®->match)) - return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg); + if (v4l2_chip_match_host(®->match)) { + if (reg->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE) + return -EINVAL; + cx18_write_enc(cx, reg->val, reg->reg); + return 0; + } /* FIXME - errors shouldn't be ignored */ cx18_call_all(cx, core, s_register, reg); return 0; diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c index ea9a614f3bbf..acdb6d58db58 100644 --- a/drivers/media/pci/cx23885/cx23885-ioctl.c +++ b/drivers/media/pci/cx23885/cx23885-ioctl.c @@ -158,18 +158,17 @@ int cx23885_g_register(struct file *file, void *fh, } static int cx23885_s_host_register(struct cx23885_dev *dev, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { if ((reg->reg & 0x3) != 0 || reg->reg >= pci_resource_len(dev->pci, 0)) return -EINVAL; - reg->size = 4; cx_write(reg->reg, reg->val); return 0; } static int cx23417_s_register(struct cx23885_dev *dev, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { if (dev->v4l_device == NULL) return -EINVAL; @@ -179,13 +178,11 @@ static int cx23417_s_register(struct cx23885_dev *dev, if (mc417_register_write(dev, (u16) reg->reg, (u32) reg->val)) return -EINVAL; /* V4L2 spec, but -EREMOTEIO really */ - - reg->size = 4; return 0; } int cx23885_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.h b/drivers/media/pci/cx23885/cx23885-ioctl.h index 315be0ca5a04..a6080964a9ee 100644 --- a/drivers/media/pci/cx23885/cx23885-ioctl.h +++ b/drivers/media/pci/cx23885/cx23885-ioctl.h @@ -33,7 +33,7 @@ int cx23885_g_register(struct file *file, void *fh, int cx23885_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg); + const struct v4l2_dbg_register *reg); #endif #endif diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index d51eed051d59..fa672fe41079 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -1124,7 +1124,7 @@ static int cx23888_ir_g_register(struct v4l2_subdev *sd, } static int cx23888_ir_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx23888_ir_state *state = to_state(sd); u32 addr = CX23888_IR_REG_BASE + (u32) reg->reg; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 93c7d576199b..1465591d000c 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -1364,7 +1364,7 @@ int cx25821_vidioc_g_register(struct file *file, void *fh, } int cx25821_vidioc_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev; diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index 239f63c12f33..11ba5eb93677 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -155,7 +155,7 @@ extern int cx25821_vidioc_s_frequency(struct file *file, void *priv, extern int cx25821_vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg); extern int cx25821_vidioc_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg); + const struct v4l2_dbg_register *reg); extern int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t); extern int cx25821_vidioc_s_tuner(struct file *file, void *priv, diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index ead5be58303d..e3f6181d1044 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1380,7 +1380,7 @@ static int vidioc_g_register (struct file *file, void *fh, } static int vidioc_s_register (struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 861e4629c7fc..50379b26768b 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -748,12 +748,15 @@ static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register return 0; } -static int ivtv_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) +static int ivtv_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) { struct ivtv *itv = fh2id(fh)->itv; - if (v4l2_chip_match_host(®->match)) - return ivtv_itvc(itv, false, reg->reg, ®->val); + if (v4l2_chip_match_host(®->match)) { + u64 val = reg->val; + + return ivtv_itvc(itv, false, reg->reg, &val); + } /* TODO: subdev errors should not be ignored, this should become a subdev helper function. */ ivtv_call_all(itv, core, s_register, reg); diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index a6c69a4c7fbd..1363e97ccda4 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -2300,7 +2300,7 @@ static int vidioc_g_register (struct file *file, void *priv, } static int vidioc_s_register (struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index 9dd044b563e7..71e8bead321b 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -680,7 +680,7 @@ static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_regist return 0; } -static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) +static int vidioc_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) { struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; @@ -688,7 +688,6 @@ static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_regist return -EPERM; if (v4l2_chip_match_host(®->match)) { saa7146_write(dev, reg->reg, reg->val); - reg->size = 4; return 0; } return call_all(dev, core, s_register, reg); diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index 538de52b9cfd..0b74fb2300dd 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -1313,7 +1313,7 @@ static int saa7164_g_register(struct file *file, void *fh, } static int saa7164_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port; struct saa7164_dev *dev = port->dev; diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 96f6a4922d0c..0e55b087076f 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -890,7 +890,7 @@ static int bcap_dbg_g_register(struct file *file, void *priv, } static int bcap_dbg_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct bcap_device *bcap_dev = video_drvdata(file); diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index bcf0ada3481d..1802f11e939f 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -1597,7 +1597,7 @@ static int vpbe_display_g_register(struct file *file, void *priv, } static int vpbe_display_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { return 0; } diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 00b7f9c5ac04..5f98df1fc8a0 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1924,7 +1924,8 @@ static int vpif_dbg_g_register(struct file *file, void *priv, * Returns zero or -EINVAL if write operations fails. */ static int vpif_dbg_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg){ + const struct v4l2_dbg_register *reg) +{ struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index f1dff9ec1ea2..1b3fb5ca2ad4 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1568,7 +1568,8 @@ static int vpif_dbg_g_register(struct file *file, void *priv, * Returns zero or -EINVAL if write operations fails. */ static int vpif_dbg_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg){ + const struct v4l2_dbg_register *reg) +{ struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 76a862318a7e..64ab91edfb81 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1445,7 +1445,7 @@ static int mcam_vidioc_g_register(struct file *file, void *priv, } static int mcam_vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct mcam_camera *cam = priv; diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 8e3b95a6c29e..7d0235069c87 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -1266,7 +1266,7 @@ static int sh_vou_g_register(struct file *file, void *fh, } static int sh_vou_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct sh_vou_device *vou_dev = video_drvdata(file); diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 3592968026cd..bf55abfb7cbc 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1042,7 +1042,7 @@ static int soc_camera_g_register(struct file *file, void *fh, } static int soc_camera_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct soc_camera_device *icd = file->private_data; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index e9dd01c4b6ed..79f1d510cc2e 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1754,7 +1754,7 @@ static int vidioc_g_register(struct file *file, void *priv, } static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 4cff2f4075e1..cd221474e1b9 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1404,7 +1404,7 @@ int cx231xx_g_register(struct file *file, void *priv, } int cx231xx_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index 2f9faee539cb..5ad9fd61d3c8 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -949,7 +949,7 @@ int cx231xx_g_chip_ident(struct file *file, void *fh, struct v4l2_dbg_chip_ident int cx231xx_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg); int cx231xx_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg); + const struct v4l2_dbg_register *reg); /* Provided by cx231xx-cards.c */ extern void cx231xx_pre_card_setup(struct cx231xx *dev); diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 96d84c22ef00..d09b5c03c723 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1323,7 +1323,7 @@ static int vidioc_g_register(struct file *file, void *priv, } static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 924e032461d0..5995ec4de6bc 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1039,7 +1039,7 @@ static int vidioc_g_register(struct file *file, void *priv, } static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct gspca_dev *gspca_dev = video_drvdata(file); diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h index c3af3212d51e..ef8efeb80070 100644 --- a/drivers/media/usb/gspca/gspca.h +++ b/drivers/media/usb/gspca/gspca.h @@ -74,8 +74,10 @@ typedef int (*cam_get_jpg_op) (struct gspca_dev *, struct v4l2_jpegcompression *); typedef int (*cam_set_jpg_op) (struct gspca_dev *, const struct v4l2_jpegcompression *); -typedef int (*cam_reg_op) (struct gspca_dev *, +typedef int (*cam_get_reg_op) (struct gspca_dev *, struct v4l2_dbg_register *); +typedef int (*cam_set_reg_op) (struct gspca_dev *, + const struct v4l2_dbg_register *); typedef int (*cam_ident_op) (struct gspca_dev *, struct v4l2_dbg_chip_ident *); typedef void (*cam_streamparm_op) (struct gspca_dev *, @@ -108,8 +110,8 @@ struct sd_desc { cam_streamparm_op get_streamparm; cam_streamparm_op set_streamparm; #ifdef CONFIG_VIDEO_ADV_DEBUG - cam_reg_op set_register; - cam_reg_op get_register; + cam_set_reg_op set_register; + cam_get_reg_op get_register; #endif cam_ident_op get_chip_ident; #if IS_ENABLED(CONFIG_INPUT) diff --git a/drivers/media/usb/gspca/pac7302.c b/drivers/media/usb/gspca/pac7302.c index 682ef3340911..6008c8d546a3 100644 --- a/drivers/media/usb/gspca/pac7302.c +++ b/drivers/media/usb/gspca/pac7302.c @@ -840,7 +840,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, #ifdef CONFIG_VIDEO_ADV_DEBUG static int sd_dbg_s_register(struct gspca_dev *gspca_dev, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { u8 index; u8 value; diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c index 4ec544f4a845..ead9a1f58513 100644 --- a/drivers/media/usb/gspca/sn9c20x.c +++ b/drivers/media/usb/gspca/sn9c20x.c @@ -1598,7 +1598,7 @@ static int sd_dbg_g_register(struct gspca_dev *gspca_dev, } static int sd_dbg_s_register(struct gspca_dev *gspca_dev, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct sd *sd = (struct sd *) gspca_dev; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index 299751a8b06b..e11267f35d87 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -5165,7 +5165,7 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw) int pvr2_hdw_register_access(struct pvr2_hdw *hdw, - struct v4l2_dbg_match *match, u64 reg_id, + const struct v4l2_dbg_match *match, u64 reg_id, int setFl, u64 *val_ptr) { #ifdef CONFIG_VIDEO_ADV_DEBUG diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h index 8060fc666eeb..91bae930cd79 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h @@ -240,7 +240,7 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *, setFl - true to set the register, false to read it val_ptr - storage location for source / result. */ int pvr2_hdw_register_access(struct pvr2_hdw *, - struct v4l2_dbg_match *match, u64 reg_id, + const struct v4l2_dbg_match *match, u64 reg_id, int setFl, u64 *val_ptr); /* The following entry points are all lower level things you normally don't diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index a7774e3836d4..a8a65fa57930 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -815,7 +815,7 @@ static int pvr2_g_register(struct file *file, void *priv, struct v4l2_dbg_regist return ret; } -static int pvr2_s_register(struct file *file, void *priv, struct v4l2_dbg_register *req) +static int pvr2_s_register(struct file *file, void *priv, const struct v4l2_dbg_register *req) { struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index f6a6cdc8b288..c4c723b92f6e 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -500,7 +500,7 @@ static int vidioc_g_register(struct file *file, void *priv, } static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct stk1160 *dev = video_drvdata(file); diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index 041f19e1b05b..d34c2afe2c24 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -483,7 +483,7 @@ static int vidioc_g_register(struct file *file, void *priv, } static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct usb_usbvision *usbvision = video_drvdata(file); int err_code; diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 29c751d86061..936ca25bd5be 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1813,7 +1813,7 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { #ifdef CONFIG_VIDEO_ADV_DEBUG - struct v4l2_dbg_register *p = arg; + const struct v4l2_dbg_register *p = arg; if (!capable(CAP_SYS_ADMIN)) return -EPERM; diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index ee7b7c67c87a..a4175cda4fc1 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -242,7 +242,7 @@ struct v4l2_ioctl_ops { int (*vidioc_g_register) (struct file *file, void *fh, struct v4l2_dbg_register *reg); int (*vidioc_s_register) (struct file *file, void *fh, - struct v4l2_dbg_register *reg); + const struct v4l2_dbg_register *reg); #endif int (*vidioc_g_chip_ident) (struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 79784fc8f9e9..8158a0810fdc 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -165,7 +165,7 @@ struct v4l2_subdev_core_ops { long (*ioctl)(struct v4l2_subdev *sd, unsigned int cmd, void *arg); #ifdef CONFIG_VIDEO_ADV_DEBUG int (*g_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg); - int (*s_register)(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg); + int (*s_register)(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg); #endif int (*s_power)(struct v4l2_subdev *sd, int on); int (*interrupt_service_routine)(struct v4l2_subdev *sd, -- cgit v1.2.3 From 505d04bdc43a6a6c828835e90ab5fcb380d631d5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 14 Mar 2013 07:40:45 -0300 Subject: [media] v4l2-ioctl: simplify debug code The core debug code can now be simplified since all the write-only ioctls are now const and will not modify the data they pass to the drivers. So instead of logging write-only ioctls before the driver is called this can now be done afterwards, which is cleaner when it comes to error reporting as well. This also fixes a logic error in the debugging code where there was one 'else' too many. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 936ca25bd5be..168b51e193cd 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2155,11 +2155,6 @@ static long __video_do_ioctl(struct file *file, } write_only = _IOC_DIR(cmd) == _IOC_WRITE; - if (write_only && debug > V4L2_DEBUG_IOCTL) { - v4l_printk_ioctl(video_device_node_name(vfd), cmd); - pr_cont(": "); - info->debug(arg, write_only); - } if (info->flags & INFO_FL_STD) { typedef int (*vidioc_op)(struct file *file, void *fh, void *p); const void *p = vfd->ioctl_ops; @@ -2178,16 +2173,10 @@ static long __video_do_ioctl(struct file *file, done: if (debug) { - if (write_only && debug > V4L2_DEBUG_IOCTL) { - if (ret < 0) - printk(KERN_DEBUG "%s: error %ld\n", - video_device_node_name(vfd), ret); - return ret; - } v4l_printk_ioctl(video_device_node_name(vfd), cmd); if (ret < 0) - pr_cont(": error %ld\n", ret); - else if (debug == V4L2_DEBUG_IOCTL) + pr_cont(": error %ld", ret); + if (debug == V4L2_DEBUG_IOCTL) pr_cont("\n"); else if (_IOC_DIR(cmd) == _IOC_NONE) info->debug(arg, write_only); -- cgit v1.2.3 From 6cd247ef22e493e1884e576c066661538b031981 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sat, 9 Mar 2013 05:55:11 -0300 Subject: [media] v4l2-ctrls: eliminate lockdep false alarms for struct v4l2_ctrl_handler.lock When calling v4l2_ctrl_add_handler(), lockdep would detect a potential recursive locking problem on a situation that is by design intended and not a recursive lock. This happened because all struct v4l2_ctrl_handler.lock mutexes were created as members of the same lock class in v4l2_ctrl_handler_init(), and v4l2_ctrl_add_handler() takes the hdl->lock on two different v4l2_ctrl_handler instances. This change breaks the large lockdep lock class for struct v4l2_ctrl_handler.lock and breaks it into v4l2_ctrl_handler instantiation specific lock classes with meaningful class names. This will validly eliminate lockdep alarms for v4l2_ctrl_handler locking validation, as long as the relationships between drivers adding v4l2 controls to their own handler from other v4l2 drivers' control handlers remains straightforward. struct v4l2_ctrl_handler.lock lock classes are created with names such that the output of cat /proc/lockdep indicates where in the v4l2 driver code v4l2_ctrl_handle_init() is being called on instantiations: ffffffffa045f490 FD: 10 BD: 8 +.+...: cx2341x:1534:(hdl)->lock ffffffffa0497d20 FD: 12 BD: 2 +.+.+.: saa7115:1581:(hdl)->lock ffffffffa04ac660 FD: 14 BD: 2 +.+.+.: msp3400_driver:756:(hdl)->lock ffffffffa0484b90 FD: 12 BD: 1 +.+.+.: ivtv_gpio:366:(&itv->hdl_gpio)->lock ffffffffa04eb530 FD: 11 BD: 2 +.+.+.: cx25840_core:1982:(&state->hdl)->lock ffffffffa04fbc80 FD: 11 BD: 3 +.+.+.: wm8775:246:(&state->hdl)->lock Some lock chains, that were previously causing the recursion alarms, are now visible in the output of cat /proc/lockdep_chains: irq_context: 0 [ffffffffa0497d20] saa7115:1581:(hdl)->lock [ffffffffa045f490] cx2341x:1534:(hdl)->lock irq_context: 0 [ffffffffa04ac660] msp3400_driver:756:(hdl)->lock [ffffffffa045f490] cx2341x:1534:(hdl)->lock irq_context: 0 [ffffffffa0484b90] ivtv_gpio:366:(&itv->hdl_gpio)->lock [ffffffffa045f490] cx2341x:1534:(hdl)->lock irq_context: 0 [ffffffffa04eb530] cx25840_core:1982:(&state->hdl)->lock [ffffffffa045f490] cx2341x:1534:(hdl)->lock irq_context: 0 [ffffffffa04fbc80] wm8775:246:(&state->hdl)->lock [ffffffffa045f490] cx2341x:1534:(hdl)->lock Signed-off-by: Andy Walls [hans.verkuil@cisco.com: keep mutex_init in v4l2_ctrl_handler_init_class] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 8 +++++--- include/media/v4l2-ctrls.h | 29 ++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 6b28b5800500..b36d1ec13ee6 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1362,11 +1362,13 @@ static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err) } /* Initialize the handler */ -int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl, - unsigned nr_of_controls_hint) +int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl, + unsigned nr_of_controls_hint, + struct lock_class_key *key, const char *name) { hdl->lock = &hdl->_lock; mutex_init(hdl->lock); + lockdep_set_class_and_name(hdl->lock, key, name); INIT_LIST_HEAD(&hdl->ctrls); INIT_LIST_HEAD(&hdl->ctrl_refs); hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8; @@ -1375,7 +1377,7 @@ int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl, hdl->error = hdl->buckets ? 0 : -ENOMEM; return hdl->error; } -EXPORT_SYMBOL(v4l2_ctrl_handler_init); +EXPORT_SYMBOL(v4l2_ctrl_handler_init_class); /* Free all controls and control refs */ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index f00d42bc01a6..7343a27fe819 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -259,7 +259,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags); -/** v4l2_ctrl_handler_init() - Initialize the control handler. +/** v4l2_ctrl_handler_init_class() - Initialize the control handler. * @hdl: The control handler. * @nr_of_controls_hint: A hint of how many controls this handler is * expected to refer to. This is the total number, so including @@ -268,12 +268,35 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, * are allocated) or the control lookup becomes slower (not enough * buckets are allocated, so there are more slow list lookups). * It will always work, though. + * @key: Used by the lock validator if CONFIG_LOCKDEP is set. + * @name: Used by the lock validator if CONFIG_LOCKDEP is set. * * Returns an error if the buckets could not be allocated. This error will * also be stored in @hdl->error. + * + * Never use this call directly, always use the v4l2_ctrl_handler_init + * macro that hides the @key and @name arguments. */ -int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl, - unsigned nr_of_controls_hint); +int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl, + unsigned nr_of_controls_hint, + struct lock_class_key *key, const char *name); + +#ifdef CONFIG_LOCKDEP +#define v4l2_ctrl_handler_init(hdl, nr_of_controls_hint) \ +( \ + ({ \ + static struct lock_class_key _key; \ + v4l2_ctrl_handler_init_class(hdl, nr_of_controls_hint, \ + &_key, \ + KBUILD_BASENAME ":" \ + __stringify(__LINE__) ":" \ + "(" #hdl ")->_lock"); \ + }) \ +) +#else +#define v4l2_ctrl_handler_init(hdl, nr_of_controls_hint) \ + v4l2_ctrl_handler_init_class(hdl, nr_of_controls_hint, NULL, NULL) +#endif /** v4l2_ctrl_handler_free() - Free all controls owned by the handler and free * the control list. -- cgit v1.2.3 From 73f35418a1e921443b5c9f4c58ae70df8b9d1bb6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 10 Mar 2013 13:12:25 -0300 Subject: [media] v4l2-ioctl: check if an ioctl is valid Just checking if the op exists isn't correct, you should check if the ioctl is valid (which implies that the op exists as well). One exception is g_std: if current_norm is non-zero, then the g_std op may be absent. This sort of weird behavior is one of the reasons why I am trying to get rid of current_norm. This patch fixes the case where the g/s_std op is set, but these ioctls are disabled. This can happen in drivers supporting multiple models, some that have TV input (and support the STD API) and some that have a sensor (and do not support the STD API). In the latter case qv4l2 would still show the Standards combobox. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 168b51e193cd..72c22fde2b69 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -35,6 +35,8 @@ memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \ 0, sizeof(*(p)) - offsetof(typeof(*(p)), field) - sizeof((p)->field)) +#define is_valid_ioctl(vfd, cmd) test_bit(_IOC_NR(cmd), (vfd)->valid_ioctls) + struct std_descr { v4l2_std_id std; const char *descr; @@ -1005,6 +1007,7 @@ static int v4l_s_priority(const struct v4l2_ioctl_ops *ops, static int v4l_enuminput(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vfd = video_devdata(file); struct v4l2_input *p = arg; /* @@ -1013,11 +1016,11 @@ static int v4l_enuminput(const struct v4l2_ioctl_ops *ops, * driver. If the driver doesn't support these * for a specific input, it must override these flags. */ - if (ops->vidioc_s_std) + if (is_valid_ioctl(vfd, VIDIOC_S_STD)) p->capabilities |= V4L2_IN_CAP_STD; - if (ops->vidioc_s_dv_preset) + if (is_valid_ioctl(vfd, VIDIOC_S_DV_PRESET)) p->capabilities |= V4L2_IN_CAP_PRESETS; - if (ops->vidioc_s_dv_timings) + if (is_valid_ioctl(vfd, VIDIOC_S_DV_TIMINGS)) p->capabilities |= V4L2_IN_CAP_DV_TIMINGS; return ops->vidioc_enum_input(file, fh, p); @@ -1026,6 +1029,7 @@ static int v4l_enuminput(const struct v4l2_ioctl_ops *ops, static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vfd = video_devdata(file); struct v4l2_output *p = arg; /* @@ -1034,11 +1038,11 @@ static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops, * driver. If the driver doesn't support these * for a specific output, it must override these flags. */ - if (ops->vidioc_s_std) + if (is_valid_ioctl(vfd, VIDIOC_S_STD)) p->capabilities |= V4L2_OUT_CAP_STD; - if (ops->vidioc_s_dv_preset) + if (is_valid_ioctl(vfd, VIDIOC_S_DV_PRESET)) p->capabilities |= V4L2_OUT_CAP_PRESETS; - if (ops->vidioc_s_dv_timings) + if (is_valid_ioctl(vfd, VIDIOC_S_DV_TIMINGS)) p->capabilities |= V4L2_OUT_CAP_DV_TIMINGS; return ops->vidioc_enum_output(file, fh, p); @@ -1521,7 +1525,7 @@ static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return -EINVAL; p->parm.capture.readbuffers = 2; - if (ops->vidioc_g_std) + if (is_valid_ioctl(vfd, VIDIOC_G_STD) && ops->vidioc_g_std) ret = ops->vidioc_g_std(file, fh, &std); if (ret == 0) v4l2_video_std_frame_period(std, @@ -1881,7 +1885,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops, return -EINVAL; if (ops->vidioc_enum_freq_bands) return ops->vidioc_enum_freq_bands(file, fh, p); - if (ops->vidioc_g_tuner) { + if (is_valid_ioctl(vfd, VIDIOC_G_TUNER)) { struct v4l2_tuner t = { .index = p->tuner, .type = type, @@ -1899,7 +1903,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops, V4L2_BAND_MODULATION_FM : V4L2_BAND_MODULATION_VSB; return 0; } - if (ops->vidioc_g_modulator) { + if (is_valid_ioctl(vfd, VIDIOC_G_MODULATOR)) { struct v4l2_modulator m = { .index = p->tuner, }; -- cgit v1.2.3 From 9ca5470cc1433200698a43de2d6e683815e536e6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 17 Mar 2013 10:34:04 -0300 Subject: [media] v4l2-ctrls: add V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER control Control whether video sequence headers should be repeated. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 6 ++++++ drivers/media/v4l2-core/v4l2-ctrls.c | 2 ++ include/uapi/linux/v4l2-controls.h | 1 + 3 files changed, 9 insertions(+) (limited to 'drivers/media') diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 9e8f85498678..b4952e23201b 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -2299,6 +2299,12 @@ Possible values are: + + V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER  + boolean + Repeat the video sequence headers. Repeating these +headers makes random access to the video stream easier. Applicable to the MPEG1, 2 and 4 encoder. + V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER  boolean diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index b36d1ec13ee6..f662df3bfe2d 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -695,6 +695,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS"; case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count"; case V4L2_CID_MPEG_VIDEO_VBV_DELAY: return "Initial Delay for VBV Control"; + case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: return "Repeat Sequence Header"; /* CAMERA controls */ /* Keep the order of the 'case's the same as in videodev2.h! */ @@ -844,6 +845,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: + case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: case V4L2_CID_WIDE_DYNAMIC_RANGE: case V4L2_CID_IMAGE_STABILIZATION: *type = V4L2_CTRL_TYPE_BOOLEAN; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 7eab0b91827b..844dc0205037 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -360,6 +360,7 @@ enum v4l2_mpeg_video_multi_slice_mode { #define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223) #define V4L2_CID_MPEG_VIDEO_DEC_FRAME (V4L2_CID_MPEG_BASE+224) #define V4L2_CID_MPEG_VIDEO_VBV_DELAY (V4L2_CID_MPEG_BASE+225) +#define V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER (V4L2_CID_MPEG_BASE+226) #define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP (V4L2_CID_MPEG_BASE+300) #define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP (V4L2_CID_MPEG_BASE+301) -- cgit v1.2.3 From a0fc58868bbf34d0935947cdf1bc8c0ea32c68c4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 8 Mar 2013 11:22:03 -0300 Subject: [media] saa7115: add config flag to change the IDQ polarity Needed by the go7007 driver: it assumes a different polarity of the IDQ signal, so we need to be able to tell the saa7115 about this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/saa7115.c | 6 ++++++ include/media/saa7115.h | 31 +++++++++++++++++++++---------- 2 files changed, 27 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index 5d9d0330b3df..c3e7e12e006a 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -1259,6 +1259,12 @@ static int saa711x_s_routing(struct v4l2_subdev *sd, (saa711x_read(sd, R_83_X_PORT_I_O_ENA_AND_OUT_CLK) & 0xfe) | (state->output & 0x01)); } + if (state->ident > V4L2_IDENT_SAA7111A) { + if (config & SAA7115_IDQ_IS_DEFAULT) + saa711x_write(sd, R_85_I_PORT_SIGNAL_POLAR, 0x20); + else + saa711x_write(sd, R_85_I_PORT_SIGNAL_POLAR, 0x21); + } return 0; } diff --git a/include/media/saa7115.h b/include/media/saa7115.h index bab212719591..8b2ecc69a702 100644 --- a/include/media/saa7115.h +++ b/include/media/saa7115.h @@ -21,6 +21,8 @@ #ifndef _SAA7115_H_ #define _SAA7115_H_ +/* s_routing inputs, outputs, and config */ + /* SAA7111/3/4/5 HW inputs */ #define SAA7115_COMPOSITE0 0 #define SAA7115_COMPOSITE1 1 @@ -33,24 +35,33 @@ #define SAA7115_SVIDEO2 8 #define SAA7115_SVIDEO3 9 -/* SAA7115 v4l2_crystal_freq frequency values */ -#define SAA7115_FREQ_32_11_MHZ 32110000 /* 32.11 MHz crystal, SAA7114/5 only */ -#define SAA7115_FREQ_24_576_MHZ 24576000 /* 24.576 MHz crystal */ - -/* SAA7115 v4l2_crystal_freq audio clock control flags */ -#define SAA7115_FREQ_FL_UCGC (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */ -#define SAA7115_FREQ_FL_CGCDIV (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */ -#define SAA7115_FREQ_FL_APLL (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */ - +/* outputs */ #define SAA7115_IPORT_ON 1 #define SAA7115_IPORT_OFF 0 -/* SAA7111 specific output flags */ +/* SAA7111 specific outputs. */ #define SAA7111_VBI_BYPASS 2 #define SAA7111_FMT_YUV422 0x00 #define SAA7111_FMT_RGB 0x40 #define SAA7111_FMT_CCIR 0x80 #define SAA7111_FMT_YUV411 0xc0 +/* config flags */ +/* Register 0x85 should set bit 0 to 0 (it's 1 by default). This bit + * controls the IDQ signal polarity which is set to 'inverted' if the bit + * it 1 and to 'default' if it is 0. */ +#define SAA7115_IDQ_IS_DEFAULT (1 << 0) + +/* s_crystal_freq values and flags */ + +/* SAA7115 v4l2_crystal_freq frequency values */ +#define SAA7115_FREQ_32_11_MHZ 32110000 /* 32.11 MHz crystal, SAA7114/5 only */ +#define SAA7115_FREQ_24_576_MHZ 24576000 /* 24.576 MHz crystal */ + +/* SAA7115 v4l2_crystal_freq audio clock control flags */ +#define SAA7115_FREQ_FL_UCGC (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */ +#define SAA7115_FREQ_FL_CGCDIV (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */ +#define SAA7115_FREQ_FL_APLL (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */ + #endif -- cgit v1.2.3 From c875dee536ee2a95a353f5ef991717383baf8d60 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 10 Mar 2013 09:59:37 -0300 Subject: [media] saa7115: improve querystd handling for the saa7115 The saa7115 has better PAL/NTSC detection, so it can detect PAL even though the chip is currently set up for NTSC. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/saa7115.c | 56 ++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index c3e7e12e006a..cdff1f6e8546 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -1360,6 +1360,34 @@ static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) */ reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC); + + if (state->ident == V4L2_IDENT_SAA7115) { + reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC); + + v4l2_dbg(1, debug, sd, "Status byte 1 (0x1e)=0x%02x\n", reg1e); + + switch (reg1e & 0x03) { + case 1: + *std &= V4L2_STD_NTSC; + break; + case 2: + /* + * V4L2_STD_PAL just cover the european PAL standards. + * This is wrong, as the device could also be using an + * other PAL standard. + */ + *std &= V4L2_STD_PAL | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | + V4L2_STD_PAL_M | V4L2_STD_PAL_60; + break; + case 3: + *std &= V4L2_STD_SECAM; + break; + default: + /* Can't detect anything */ + break; + } + } + v4l2_dbg(1, debug, sd, "Status byte 2 (0x1f)=0x%02x\n", reg1f); /* horizontal/vertical not locked */ @@ -1371,34 +1399,6 @@ static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) else *std &= V4L2_STD_625_50; - if (state->ident != V4L2_IDENT_SAA7115) - goto ret; - - reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC); - - switch (reg1e & 0x03) { - case 1: - *std &= V4L2_STD_NTSC; - break; - case 2: - /* - * V4L2_STD_PAL just cover the european PAL standards. - * This is wrong, as the device could also be using an - * other PAL standard. - */ - *std &= V4L2_STD_PAL | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | - V4L2_STD_PAL_M | V4L2_STD_PAL_60; - break; - case 3: - *std &= V4L2_STD_SECAM; - break; - default: - /* Can't detect anything */ - break; - } - - v4l2_dbg(1, debug, sd, "Status byte 1 (0x1e)=0x%02x\n", reg1e); - ret: v4l2_dbg(1, debug, sd, "detected std mask = %08Lx\n", *std); -- cgit v1.2.3 From 1589037f8716a605a36ee6dda6f7cdd4d043522b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 03:47:25 -0300 Subject: [media] saa7115: add support for double-rate ASCLK Some devices expect a double rate ASCLK. Add a flag to let the driver know through the s_crystal_freq call. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/saa7115.c | 16 +++++++++++----- include/media/saa7115.h | 7 ++++--- 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index cdff1f6e8546..52c717d977c9 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -83,9 +83,10 @@ struct saa711x_state { u32 ident; u32 audclk_freq; u32 crystal_freq; - u8 ucgc; + bool ucgc; u8 cgcdiv; - u8 apll; + bool apll; + bool double_asclk; }; static inline struct saa711x_state *to_state(struct v4l2_subdev *sd) @@ -732,8 +733,12 @@ static int saa711x_s_clock_freq(struct v4l2_subdev *sd, u32 freq) if (state->apll) acc |= 0x08; + if (state->double_asclk) { + acpf <<= 1; + acni <<= 1; + } saa711x_write(sd, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03); - saa711x_write(sd, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10); + saa711x_write(sd, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10 << state->double_asclk); saa711x_write(sd, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc); saa711x_write(sd, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff); @@ -1302,9 +1307,10 @@ static int saa711x_s_crystal_freq(struct v4l2_subdev *sd, u32 freq, u32 flags) if (freq != SAA7115_FREQ_32_11_MHZ && freq != SAA7115_FREQ_24_576_MHZ) return -EINVAL; state->crystal_freq = freq; + state->double_asclk = flags & SAA7115_FREQ_FL_DOUBLE_ASCLK; state->cgcdiv = (flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4; - state->ucgc = (flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0; - state->apll = (flags & SAA7115_FREQ_FL_APLL) ? 1 : 0; + state->ucgc = flags & SAA7115_FREQ_FL_UCGC; + state->apll = flags & SAA7115_FREQ_FL_APLL; saa711x_s_clock_freq(sd, state->audclk_freq); return 0; } diff --git a/include/media/saa7115.h b/include/media/saa7115.h index 8b2ecc69a702..407918625c80 100644 --- a/include/media/saa7115.h +++ b/include/media/saa7115.h @@ -59,9 +59,10 @@ #define SAA7115_FREQ_24_576_MHZ 24576000 /* 24.576 MHz crystal */ /* SAA7115 v4l2_crystal_freq audio clock control flags */ -#define SAA7115_FREQ_FL_UCGC (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */ -#define SAA7115_FREQ_FL_CGCDIV (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */ -#define SAA7115_FREQ_FL_APLL (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */ +#define SAA7115_FREQ_FL_UCGC (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */ +#define SAA7115_FREQ_FL_CGCDIV (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */ +#define SAA7115_FREQ_FL_APLL (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */ +#define SAA7115_FREQ_FL_DOUBLE_ASCLK (1 << 3) /* SA 39, LRDIV, SAA7114/5 only */ #endif -- cgit v1.2.3 From e4d2a6162d2a0a27be16b75da36f6bba64af63bc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 13:14:32 -0300 Subject: [media] tuner: add Sony BTF tuners This adds support for three Sony BTF tuners: TUNER_SONY_BTF_PG472Z: PAL+SECAM TUNER_SONY_BTF_PK467Z: NTSC-M-JP TUNER_SONY_BTF_PB463Z: NTSC-M These come from the go7007 staging driver where they were implemented in the wis-sony-tuner i2c driver. Adding support for these tuners to tuner-types.c is the first step towards removing the wis-sony-tuner driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.tuner | 3 ++ drivers/media/tuners/tuner-types.c | 69 ++++++++++++++++++++++++++++++ drivers/staging/media/go7007/go7007-usb.c | 1 + drivers/staging/media/go7007/go7007-v4l2.c | 1 + drivers/staging/media/go7007/wis-i2c.h | 6 --- include/media/tuner.h | 4 ++ 6 files changed, 78 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index c83f6e418879..5b83a3ff15c2 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner @@ -86,3 +86,6 @@ tuner=85 - Philips FQ1236 MK5 tuner=86 - Tena TNF5337 MFD tuner=87 - Xceive 4000 tuner tuner=88 - Xceive 5000C tuner +tuner=89 - Sony PAL+SECAM (BTF-PG472Z) +tuner=90 - Sony NTSC-M-JP (BTF-PK467Z) +tuner=91 - Sony NTSC-M (BTF-PB463Z) diff --git a/drivers/media/tuners/tuner-types.c b/drivers/media/tuners/tuner-types.c index 2da4440c16ee..98bc15a388be 100644 --- a/drivers/media/tuners/tuner-types.c +++ b/drivers/media/tuners/tuner-types.c @@ -1381,6 +1381,58 @@ static struct tuner_params tuner_philips_fq1236_mk5_params[] = { }, }; +/* --------- Sony BTF-PG472Z PAL/SECAM ------- */ + +static struct tuner_range tuner_sony_btf_pg472z_ranges[] = { + { 16 * 144.25 /*MHz*/, 0xc6, 0x01, }, + { 16 * 427.25 /*MHz*/, 0xc6, 0x02, }, + { 16 * 999.99 , 0xc6, 0x04, }, +}; + +static struct tuner_params tuner_sony_btf_pg472z_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_sony_btf_pg472z_ranges, + .count = ARRAY_SIZE(tuner_sony_btf_pg472z_ranges), + .has_tda9887 = 1, + .port1_active = 1, + .port2_invert_for_secam_lc = 1, + }, +}; + +/* 90-99 */ +/* --------- Sony BTF-PG467Z NTSC-M-JP ------- */ + +static struct tuner_range tuner_sony_btf_pg467z_ranges[] = { + { 16 * 220.25 /*MHz*/, 0xc6, 0x01, }, + { 16 * 467.25 /*MHz*/, 0xc6, 0x02, }, + { 16 * 999.99 , 0xc6, 0x04, }, +}; + +static struct tuner_params tuner_sony_btf_pg467z_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_sony_btf_pg467z_ranges, + .count = ARRAY_SIZE(tuner_sony_btf_pg467z_ranges), + }, +}; + +/* --------- Sony BTF-PG463Z NTSC-M ------- */ + +static struct tuner_range tuner_sony_btf_pg463z_ranges[] = { + { 16 * 130.25 /*MHz*/, 0xc6, 0x01, }, + { 16 * 364.25 /*MHz*/, 0xc6, 0x02, }, + { 16 * 999.99 , 0xc6, 0x04, }, +}; + +static struct tuner_params tuner_sony_btf_pg463z_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_sony_btf_pg463z_ranges, + .count = ARRAY_SIZE(tuner_sony_btf_pg463z_ranges), + }, +}; + /* --------------------------------------------------------------------- */ struct tunertype tuners[] = { @@ -1872,6 +1924,23 @@ struct tunertype tuners[] = { .name = "Xceive 5000C tuner", /* see xc5000.c for details */ }, + [TUNER_SONY_BTF_PG472Z] = { + .name = "Sony BTF-PG472Z PAL/SECAM", + .params = tuner_sony_btf_pg472z_params, + .count = ARRAY_SIZE(tuner_sony_btf_pg472z_params), + }, + + /* 90-99 */ + [TUNER_SONY_BTF_PK467Z] = { + .name = "Sony BTF-PK467Z NTSC-M-JP", + .params = tuner_sony_btf_pg467z_params, + .count = ARRAY_SIZE(tuner_sony_btf_pg467z_params), + }, + [TUNER_SONY_BTF_PB463Z] = { + .name = "Sony BTF-PB463Z NTSC-M", + .params = tuner_sony_btf_pg463z_params, + .count = ARRAY_SIZE(tuner_sony_btf_pg463z_params), + }, }; EXPORT_SYMBOL(tuners); diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 914b247e9652..3333a8f3b654 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "go7007-priv.h" #include "wis-i2c.h" diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 29fe94da5f71..4ad383ad8758 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -1238,6 +1238,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, if (!go->i2c_adapter_online) return -EIO; + strlcpy(t->name, "Tuner", sizeof(t->name)); return call_all(&go->v4l2_dev, tuner, g_tuner, t); } diff --git a/drivers/staging/media/go7007/wis-i2c.h b/drivers/staging/media/go7007/wis-i2c.h index 6d09c06c8560..97763db80bac 100644 --- a/drivers/staging/media/go7007/wis-i2c.h +++ b/drivers/staging/media/go7007/wis-i2c.h @@ -34,9 +34,3 @@ struct video_decoder_resolution { #define DECODER_SET_RESOLUTION _IOW('d', 200, struct video_decoder_resolution) #define DECODER_SET_CHANNEL _IOW('d', 201, int) - -/* Sony tuner types */ - -#define TUNER_SONY_BTF_PG472Z 200 -#define TUNER_SONY_BTF_PK467Z 201 -#define TUNER_SONY_BTF_PB463Z 202 diff --git a/include/media/tuner.h b/include/media/tuner.h index 926aff9bdf65..24eaafe461bd 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -138,6 +138,10 @@ #define TUNER_XC4000 87 /* Xceive Silicon Tuner */ #define TUNER_XC5000C 88 /* Xceive Silicon Tuner */ +#define TUNER_SONY_BTF_PG472Z 89 /* PAL+SECAM */ +#define TUNER_SONY_BTF_PK467Z 90 /* NTSC_JP */ +#define TUNER_SONY_BTF_PB463Z 91 /* NTSC */ + /* tv card specific */ #define TDA9887_PRESENT (1<<0) #define TDA9887_PORT1_INACTIVE (1<<1) -- cgit v1.2.3 From c7c54a988d21626874e9f1b8dc6bb0547bcddf9c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 22 Mar 2013 11:13:58 -0300 Subject: [media] sony-btf-mpx: the MPX driver for the sony BTF PAL/SECAM tuner The Sony BTF PG472Z has an internal MPX to deal with mono/stereo/bilingual audio. This is split off from the wis-sony-tuner driver that is part of the go7007 driver as it should be a separate i2c sub-device driver. The wis-sony-tuner is really three i2c devices: a standard tuner, a tda9887 compatible demodulator and this mpx. After this patch the wis-sony-tuner can be replaced by this driver and the standard tuner driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 11 +- drivers/media/i2c/Makefile | 1 + drivers/media/i2c/sony-btf-mpx.c | 399 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 410 insertions(+), 1 deletion(-) create mode 100644 drivers/media/i2c/sony-btf-mpx.c (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index ec07ceb41c9c..785e2132a573 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -133,7 +133,7 @@ config VIDEO_WM8739 module will be called wm8739. config VIDEO_VP27SMPX - tristate "Panasonic VP27s internal MPX" + tristate "Panasonic VP27's internal MPX" depends on VIDEO_V4L2 && I2C ---help--- Support for the internal MPX of the Panasonic VP27s tuner. @@ -141,6 +141,15 @@ config VIDEO_VP27SMPX To compile this driver as a module, choose M here: the module will be called vp27smpx. +config VIDEO_SONY_BTF_MPX + tristate "Sony BTF's internal MPX" + depends on VIDEO_V4L2 && I2C + help + Support for the internal MPX of the Sony BTF-PG472Z tuner. + + To compile this driver as a module, choose M here: the + module will be called sony-btf-mpx. + comment "RDS decoders" config VIDEO_SAA6588 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index cfefd30cc1bc..4c570757089e 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o obj-$(CONFIG_VIDEO_WM8775) += wm8775.o obj-$(CONFIG_VIDEO_WM8739) += wm8739.o obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o +obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o diff --git a/drivers/media/i2c/sony-btf-mpx.c b/drivers/media/i2c/sony-btf-mpx.c new file mode 100644 index 000000000000..bc73e8ff0471 --- /dev/null +++ b/drivers/media/i2c/sony-btf-mpx.c @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2005-2006 Micronas USA Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("sony-btf-mpx driver"); +MODULE_LICENSE("GPL v2"); + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level 0=off(default) 1=on\n"); + +/* #define MPX_DEBUG */ + +/* + * Note: + * + * AS(IF/MPX) pin: LOW HIGH/OPEN + * IF/MPX address: 0x42/0x40 0x43/0x44 + */ + + +static int force_mpx_mode = -1; +module_param(force_mpx_mode, int, 0644); + +struct sony_btf_mpx { + struct v4l2_subdev sd; + int mpxmode; + u32 audmode; +}; + +static inline struct sony_btf_mpx *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct sony_btf_mpx, sd); +} + +static int mpx_write(struct i2c_client *client, int dev, int addr, int val) +{ + u8 buffer[5]; + struct i2c_msg msg; + + buffer[0] = dev; + buffer[1] = addr >> 8; + buffer[2] = addr & 0xff; + buffer[3] = val >> 8; + buffer[4] = val & 0xff; + msg.addr = client->addr; + msg.flags = 0; + msg.len = 5; + msg.buf = buffer; + i2c_transfer(client->adapter, &msg, 1); + return 0; +} + +/* + * MPX register values for the BTF-PG472Z: + * + * FM_ NICAM_ SCART_ + * MODUS SOURCE ACB PRESCAL PRESCAL PRESCAL SYSTEM VOLUME + * 10/0030 12/0008 12/0013 12/000E 12/0010 12/0000 10/0020 12/0000 + * --------------------------------------------------------------- + * Auto 1003 0020 0100 2603 5000 XXXX 0001 7500 + * + * B/G + * Mono 1003 0020 0100 2603 5000 XXXX 0003 7500 + * A2 1003 0020 0100 2601 5000 XXXX 0003 7500 + * NICAM 1003 0120 0100 2603 5000 XXXX 0008 7500 + * + * I + * Mono 1003 0020 0100 2603 7900 XXXX 000A 7500 + * NICAM 1003 0120 0100 2603 7900 XXXX 000A 7500 + * + * D/K + * Mono 1003 0020 0100 2603 5000 XXXX 0004 7500 + * A2-1 1003 0020 0100 2601 5000 XXXX 0004 7500 + * A2-2 1003 0020 0100 2601 5000 XXXX 0005 7500 + * A2-3 1003 0020 0100 2601 5000 XXXX 0007 7500 + * NICAM 1003 0120 0100 2603 5000 XXXX 000B 7500 + * + * L/L' + * Mono 0003 0200 0100 7C03 5000 2200 0009 7500 + * NICAM 0003 0120 0100 7C03 5000 XXXX 0009 7500 + * + * M + * Mono 1003 0200 0100 2B03 5000 2B00 0002 7500 + * + * For Asia, replace the 0x26XX in FM_PRESCALE with 0x14XX. + * + * Bilingual selection in A2/NICAM: + * + * High byte of SOURCE Left chan Right chan + * 0x01 MAIN SUB + * 0x03 MAIN MAIN + * 0x04 SUB SUB + * + * Force mono in NICAM by setting the high byte of SOURCE to 0x02 (L/L') or + * 0x00 (all other bands). Force mono in A2 with FMONO_A2: + * + * FMONO_A2 + * 10/0022 + * -------- + * Forced mono ON 07F0 + * Forced mono OFF 0190 + */ + +static const struct { + enum { AUD_MONO, AUD_A2, AUD_NICAM, AUD_NICAM_L } audio_mode; + u16 modus; + u16 source; + u16 acb; + u16 fm_prescale; + u16 nicam_prescale; + u16 scart_prescale; + u16 system; + u16 volume; +} mpx_audio_modes[] = { + /* Auto */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, + 0x5000, 0x0000, 0x0001, 0x7500 }, + /* B/G Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, + 0x5000, 0x0000, 0x0003, 0x7500 }, + /* B/G A2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, + 0x5000, 0x0000, 0x0003, 0x7500 }, + /* B/G NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, + 0x5000, 0x0000, 0x0008, 0x7500 }, + /* I Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, + 0x7900, 0x0000, 0x000A, 0x7500 }, + /* I NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, + 0x7900, 0x0000, 0x000A, 0x7500 }, + /* D/K Mono */ { AUD_MONO, 0x1003, 0x0020, 0x0100, 0x2603, + 0x5000, 0x0000, 0x0004, 0x7500 }, + /* D/K A2-1 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, + 0x5000, 0x0000, 0x0004, 0x7500 }, + /* D/K A2-2 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, + 0x5000, 0x0000, 0x0005, 0x7500 }, + /* D/K A2-3 */ { AUD_A2, 0x1003, 0x0020, 0x0100, 0x2601, + 0x5000, 0x0000, 0x0007, 0x7500 }, + /* D/K NICAM */ { AUD_NICAM, 0x1003, 0x0120, 0x0100, 0x2603, + 0x5000, 0x0000, 0x000B, 0x7500 }, + /* L/L' Mono */ { AUD_MONO, 0x0003, 0x0200, 0x0100, 0x7C03, + 0x5000, 0x2200, 0x0009, 0x7500 }, + /* L/L' NICAM */{ AUD_NICAM_L, 0x0003, 0x0120, 0x0100, 0x7C03, + 0x5000, 0x0000, 0x0009, 0x7500 }, +}; + +#define MPX_NUM_MODES ARRAY_SIZE(mpx_audio_modes) + +static int mpx_setup(struct sony_btf_mpx *t) +{ + struct i2c_client *client = v4l2_get_subdevdata(&t->sd); + u16 source = 0; + u8 buffer[3]; + struct i2c_msg msg; + int mode = t->mpxmode; + + /* reset MPX */ + buffer[0] = 0x00; + buffer[1] = 0x80; + buffer[2] = 0x00; + msg.addr = client->addr; + msg.flags = 0; + msg.len = 3; + msg.buf = buffer; + i2c_transfer(client->adapter, &msg, 1); + buffer[1] = 0x00; + i2c_transfer(client->adapter, &msg, 1); + + if (t->audmode != V4L2_TUNER_MODE_MONO) + mode++; + + if (mpx_audio_modes[mode].audio_mode != AUD_MONO) { + switch (t->audmode) { + case V4L2_TUNER_MODE_MONO: + switch (mpx_audio_modes[mode].audio_mode) { + case AUD_A2: + source = mpx_audio_modes[mode].source; + break; + case AUD_NICAM: + source = 0x0000; + break; + case AUD_NICAM_L: + source = 0x0200; + break; + default: + break; + } + break; + case V4L2_TUNER_MODE_STEREO: + source = mpx_audio_modes[mode].source; + break; + case V4L2_TUNER_MODE_LANG1: + source = 0x0300; + break; + case V4L2_TUNER_MODE_LANG2: + source = 0x0400; + break; + } + source |= mpx_audio_modes[mode].source & 0x00ff; + } else + source = mpx_audio_modes[mode].source; + + mpx_write(client, 0x10, 0x0030, mpx_audio_modes[mode].modus); + mpx_write(client, 0x12, 0x0008, source); + mpx_write(client, 0x12, 0x0013, mpx_audio_modes[mode].acb); + mpx_write(client, 0x12, 0x000e, + mpx_audio_modes[mode].fm_prescale); + mpx_write(client, 0x12, 0x0010, + mpx_audio_modes[mode].nicam_prescale); + mpx_write(client, 0x12, 0x000d, + mpx_audio_modes[mode].scart_prescale); + mpx_write(client, 0x10, 0x0020, mpx_audio_modes[mode].system); + mpx_write(client, 0x12, 0x0000, mpx_audio_modes[mode].volume); + if (mpx_audio_modes[mode].audio_mode == AUD_A2) + mpx_write(client, 0x10, 0x0022, + t->audmode == V4L2_TUNER_MODE_MONO ? 0x07f0 : 0x0190); + +#ifdef MPX_DEBUG + { + u8 buf1[3], buf2[2]; + struct i2c_msg msgs[2]; + + v4l2_info(client, + "MPX registers: %04x %04x %04x %04x %04x %04x %04x %04x\n", + mpx_audio_modes[mode].modus, + source, + mpx_audio_modes[mode].acb, + mpx_audio_modes[mode].fm_prescale, + mpx_audio_modes[mode].nicam_prescale, + mpx_audio_modes[mode].scart_prescale, + mpx_audio_modes[mode].system, + mpx_audio_modes[mode].volume); + buf1[0] = 0x11; + buf1[1] = 0x00; + buf1[2] = 0x7e; + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = 3; + msgs[0].buf = buf1; + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = 2; + msgs[1].buf = buf2; + i2c_transfer(client->adapter, msgs, 2); + v4l2_info(client, "MPX system: %02x%02x\n", + buf2[0], buf2[1]); + buf1[0] = 0x11; + buf1[1] = 0x02; + buf1[2] = 0x00; + i2c_transfer(client->adapter, msgs, 2); + v4l2_info(client, "MPX status: %02x%02x\n", + buf2[0], buf2[1]); + } +#endif + return 0; +} + + +static int sony_btf_mpx_s_std(struct v4l2_subdev *sd, v4l2_std_id std) +{ + struct sony_btf_mpx *t = to_state(sd); + int default_mpx_mode = 0; + + if (std & V4L2_STD_PAL_BG) + default_mpx_mode = 1; + else if (std & V4L2_STD_PAL_I) + default_mpx_mode = 4; + else if (std & V4L2_STD_PAL_DK) + default_mpx_mode = 6; + else if (std & V4L2_STD_SECAM_L) + default_mpx_mode = 11; + + if (default_mpx_mode != t->mpxmode) { + t->mpxmode = default_mpx_mode; + mpx_setup(t); + } + return 0; +} + +static int sony_btf_mpx_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +{ + struct sony_btf_mpx *t = to_state(sd); + + vt->capability = V4L2_TUNER_CAP_NORM | + V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2; + vt->rxsubchans = V4L2_TUNER_SUB_MONO | + V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; + vt->audmode = t->audmode; + return 0; +} + +static int sony_btf_mpx_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +{ + struct sony_btf_mpx *t = to_state(sd); + + if (vt->type != V4L2_TUNER_ANALOG_TV) + return -EINVAL; + + if (vt->audmode != t->audmode) { + t->audmode = vt->audmode; + mpx_setup(t); + } + return 0; +} + +/* --------------------------------------------------------------------------*/ + +static const struct v4l2_subdev_core_ops sony_btf_mpx_core_ops = { + .s_std = sony_btf_mpx_s_std, +}; + +static const struct v4l2_subdev_tuner_ops sony_btf_mpx_tuner_ops = { + .s_tuner = sony_btf_mpx_s_tuner, + .g_tuner = sony_btf_mpx_g_tuner, +}; + +static const struct v4l2_subdev_ops sony_btf_mpx_ops = { + .core = &sony_btf_mpx_core_ops, + .tuner = &sony_btf_mpx_tuner_ops, +}; + +/* --------------------------------------------------------------------------*/ + +static int sony_btf_mpx_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct sony_btf_mpx *t; + struct v4l2_subdev *sd; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) + return -ENODEV; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + t = kzalloc(sizeof(struct sony_btf_mpx), GFP_KERNEL); + if (t == NULL) + return -ENOMEM; + + sd = &t->sd; + v4l2_i2c_subdev_init(sd, client, &sony_btf_mpx_ops); + + /* Initialize sony_btf_mpx */ + t->mpxmode = 0; + t->audmode = V4L2_TUNER_MODE_STEREO; + + return 0; +} + +static int sony_btf_mpx_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(to_state(sd)); + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct i2c_device_id sony_btf_mpx_id[] = { + { "sony-btf-mpx", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sony_btf_mpx_id); + +static struct i2c_driver sony_btf_mpx_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "sony-btf-mpx", + }, + .probe = sony_btf_mpx_probe, + .remove = sony_btf_mpx_remove, + .id_table = sony_btf_mpx_id, +}; +module_i2c_driver(sony_btf_mpx_driver); -- cgit v1.2.3 From ec367c3cd18697991923685eb0e833f4424d37fb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 07:09:18 -0300 Subject: [media] ov7640: add new ov7640 driver This based on the wis-ov7640.c driver that's part of the go7007 driver. It has been converted to a v4l subdev driver by Pete Eberlein, and I made additional cleanups. Based on work by: Pete Eberlein Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 11 +++++ drivers/media/i2c/Makefile | 3 +- drivers/media/i2c/ov7640.c | 106 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 drivers/media/i2c/ov7640.c (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 785e2132a573..790788597bad 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -395,6 +395,17 @@ config VIDEO_APTINA_PLL config VIDEO_SMIAPP_PLL tristate +config VIDEO_OV7640 + tristate "OmniVision OV7640 sensor support" + depends on I2C && VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV7640 camera. + + To compile this driver as a module, choose M here: the + module will be called ov7640. + config VIDEO_OV7670 tristate "OmniVision OV7670 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 4c570757089e..adf950406a94 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -47,7 +47,8 @@ obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o -obj-$(CONFIG_VIDEO_OV7670) += ov7670.o +obj-$(CONFIG_VIDEO_OV7640) += ov7640.o +obj-$(CONFIG_VIDEO_OV7670) += ov7670.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o diff --git a/drivers/media/i2c/ov7640.c b/drivers/media/i2c/ov7640.c new file mode 100644 index 000000000000..b0cc927e8b19 --- /dev/null +++ b/drivers/media/i2c/ov7640.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2005-2006 Micronas USA Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("OmniVision ov7640 sensor driver"); +MODULE_LICENSE("GPL v2"); + +static const u8 initial_registers[] = { + 0x12, 0x80, + 0x12, 0x54, + 0x14, 0x24, + 0x15, 0x01, + 0x28, 0x20, + 0x75, 0x82, + 0xFF, 0xFF, /* Terminator (reg 0xFF is unused) */ +}; + +static int write_regs(struct i2c_client *client, const u8 *regs) +{ + int i; + + for (i = 0; regs[i] != 0xFF; i += 2) + if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) + return -1; + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct v4l2_subdev_ops ov7640_ops; + +static int ov7640_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = client->adapter; + struct v4l2_subdev *sd; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + if (sd == NULL) + return -ENOMEM; + v4l2_i2c_subdev_init(sd, client, &ov7640_ops); + + client->flags = I2C_CLIENT_SCCB; + + v4l_info(client, "chip found @ 0x%02x (%s)\n", + client->addr << 1, client->adapter->name); + + if (write_regs(client, initial_registers) < 0) { + v4l_err(client, "error initializing OV7640\n"); + kfree(sd); + return -ENODEV; + } + + return 0; +} + + +static int ov7640_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(sd); + return 0; +} + +static const struct i2c_device_id ov7640_id[] = { + { "ov7640", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ov7640_id); + +static struct i2c_driver ov7640_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "ov7640", + }, + .probe = ov7640_probe, + .remove = ov7640_remove, + .id_table = ov7640_id, +}; +module_i2c_driver(ov7640_driver); -- cgit v1.2.3 From 73d9f979335e9ae40f3901d38af739bc36d008c4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 07:20:12 -0300 Subject: [media] uda1342: add new uda1342 audio codec driver This based on the wis-uda1342.c driver that's part of the go7007 driver. It has been converted to a v4l subdev driver by Pete Eberlein, and I made additional cleanups. Based on work by: Pete Eberlein Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 9 ++++ drivers/media/i2c/Makefile | 1 + drivers/media/i2c/uda1342.c | 113 ++++++++++++++++++++++++++++++++++++++++++++ include/media/uda1342.h | 29 ++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 drivers/media/i2c/uda1342.c create mode 100644 include/media/uda1342.h (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 790788597bad..5df353f7c552 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -112,6 +112,15 @@ config VIDEO_TLV320AIC23B To compile this driver as a module, choose M here: the module will be called tlv320aic23b. +config VIDEO_UDA1342 + tristate "Philips UDA1342 audio codec" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Philips UDA1342 audio codec. + + To compile this driver as a module, choose M here: the + module will be called uda1342. + config VIDEO_WM8775 tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index adf950406a94..b1775b3fad04 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_VIDEO_CS5345) += cs5345.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o obj-$(CONFIG_VIDEO_M52790) += m52790.o obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o +obj-$(CONFIG_VIDEO_UDA1342) += uda1342.o obj-$(CONFIG_VIDEO_WM8775) += wm8775.o obj-$(CONFIG_VIDEO_WM8739) += wm8739.o obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o diff --git a/drivers/media/i2c/uda1342.c b/drivers/media/i2c/uda1342.c new file mode 100644 index 000000000000..3af408556d27 --- /dev/null +++ b/drivers/media/i2c/uda1342.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2005-2006 Micronas USA Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +static int write_reg(struct i2c_client *client, int reg, int value) +{ + /* UDA1342 wants MSB first, but SMBus sends LSB first */ + i2c_smbus_write_word_data(client, reg, swab16(value)); + return 0; +} + +static int uda1342_s_routing(struct v4l2_subdev *sd, + u32 input, u32 output, u32 config) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + switch (input) { + case UDA1342_IN1: + write_reg(client, 0x00, 0x1241); /* select input 1 */ + break; + case UDA1342_IN2: + write_reg(client, 0x00, 0x1441); /* select input 2 */ + break; + default: + v4l2_err(sd, "input %d not supported\n", input); + break; + } + return 0; +} + +static const struct v4l2_subdev_audio_ops uda1342_audio_ops = { + .s_routing = uda1342_s_routing, +}; + +static const struct v4l2_subdev_ops uda1342_ops = { + .audio = &uda1342_audio_ops, +}; + +static int uda1342_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = client->adapter; + struct v4l2_subdev *sd; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) + return -ENODEV; + + dev_dbg(&client->dev, "initializing UDA1342 at address %d on %s\n", + client->addr, adapter->name); + + sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + if (sd == NULL) + return -ENOMEM; + + v4l2_i2c_subdev_init(sd, client, &uda1342_ops); + + write_reg(client, 0x00, 0x8000); /* reset registers */ + write_reg(client, 0x00, 0x1241); /* select input 1 */ + + v4l_info(client, "chip found @ 0x%02x (%s)\n", + client->addr << 1, client->adapter->name); + + return 0; +} + +static int uda1342_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + kfree(sd); + return 0; +} + +static const struct i2c_device_id uda1342_id[] = { + { "uda1342", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, uda1342_id); + +static struct i2c_driver uda1342_driver = { + .driver = { + .name = "uda1342", + }, + .probe = uda1342_probe, + .remove = uda1342_remove, + .id_table = uda1342_id, +}; + +module_i2c_driver(uda1342_driver); + +MODULE_LICENSE("GPL v2"); diff --git a/include/media/uda1342.h b/include/media/uda1342.h new file mode 100644 index 000000000000..cd156403a368 --- /dev/null +++ b/include/media/uda1342.h @@ -0,0 +1,29 @@ +/* + * uda1342.h - definition for uda1342 inputs + * + * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +#ifndef _UDA1342_H_ +#define _UDA1342_H_ + +/* The UDA1342 has 2 inputs */ + +#define UDA1342_IN1 1 +#define UDA1342_IN2 2 + +#endif -- cgit v1.2.3 From 0890ec19c65def8c8e445931b026e0fa8d809a34 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 18 Mar 2013 04:10:56 -0300 Subject: [media] tw9903: add new tw9903 video decoder This based on the wis-tw9903.c driver that's part of the go7007 driver. It has been converted to a v4l subdev driver by Pete Eberlein, and I made additional cleanups. Based on work by: Pete Eberlein Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 10 ++ drivers/media/i2c/Makefile | 1 + drivers/media/i2c/tw9903.c | 272 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 283 insertions(+) create mode 100644 drivers/media/i2c/tw9903.c (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 5df353f7c552..eb1831c66864 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -301,6 +301,16 @@ config VIDEO_TVP7002 To compile this driver as a module, choose M here: the module will be called tvp7002. +config VIDEO_TW9903 + tristate "Techwell TW9903 video decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Techwell 9903 multi-standard video decoder + with high quality down scaler. + + To compile this driver as a module, choose M here: the + module will be called tw9903. + config VIDEO_VPX3220 tristate "vpx3220a, vpx3216b & vpx3214c video decoders" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index b1775b3fad04..af8fb29ab327 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_VIDEO_THS7303) += ths7303.o obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o +obj-$(CONFIG_VIDEO_TW9903) += tw9903.o obj-$(CONFIG_VIDEO_CS5345) += cs5345.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o obj-$(CONFIG_VIDEO_M52790) += m52790.o diff --git a/drivers/media/i2c/tw9903.c b/drivers/media/i2c/tw9903.c new file mode 100644 index 000000000000..f0d0ef5da30c --- /dev/null +++ b/drivers/media/i2c/tw9903.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2005-2006 Micronas USA Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("TW9903 I2C subdev driver"); +MODULE_LICENSE("GPL v2"); + +/* + * This driver is based on the wis-tw9903.c source that was in + * drivers/staging/media/go7007. That source had commented out code for + * saturation and scaling (neither seemed to work). If anyone ever gets + * hardware to test this driver, then that code might be useful to look at. + * You need to get the kernel sources of, say, kernel 3.8 where that + * wis-tw9903 driver is still present. + */ + +struct tw9903 { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + v4l2_std_id norm; +}; + +static inline struct tw9903 *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct tw9903, sd); +} + +static const u8 initial_registers[] = { + 0x02, 0x44, /* input 1, composite */ + 0x03, 0x92, /* correct digital format */ + 0x04, 0x00, + 0x05, 0x80, /* or 0x00 for PAL */ + 0x06, 0x40, /* second internal current reference */ + 0x07, 0x02, /* window */ + 0x08, 0x14, /* window */ + 0x09, 0xf0, /* window */ + 0x0a, 0x81, /* window */ + 0x0b, 0xd0, /* window */ + 0x0c, 0x8c, + 0x0d, 0x00, /* scaling */ + 0x0e, 0x11, /* scaling */ + 0x0f, 0x00, /* scaling */ + 0x10, 0x00, /* brightness */ + 0x11, 0x60, /* contrast */ + 0x12, 0x01, /* sharpness */ + 0x13, 0x7f, /* U gain */ + 0x14, 0x5a, /* V gain */ + 0x15, 0x00, /* hue */ + 0x16, 0xc3, /* sharpness */ + 0x18, 0x00, + 0x19, 0x58, /* vbi */ + 0x1a, 0x80, + 0x1c, 0x0f, /* video norm */ + 0x1d, 0x7f, /* video norm */ + 0x20, 0xa0, /* clamping gain (working 0x50) */ + 0x21, 0x22, + 0x22, 0xf0, + 0x23, 0xfe, + 0x24, 0x3c, + 0x25, 0x38, + 0x26, 0x44, + 0x27, 0x20, + 0x28, 0x00, + 0x29, 0x15, + 0x2a, 0xa0, + 0x2b, 0x44, + 0x2c, 0x37, + 0x2d, 0x00, + 0x2e, 0xa5, /* burst PLL control (working: a9) */ + 0x2f, 0xe0, /* 0xea is blue test frame -- 0xe0 for normal */ + 0x31, 0x00, + 0x33, 0x22, + 0x34, 0x11, + 0x35, 0x35, + 0x3b, 0x05, + 0x06, 0xc0, /* reset device */ + 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */ +}; + +static int write_reg(struct v4l2_subdev *sd, u8 reg, u8 value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_write_byte_data(client, reg, value); +} + +static int write_regs(struct v4l2_subdev *sd, const u8 *regs) +{ + int i; + + for (i = 0; regs[i] != 0x00; i += 2) + if (write_reg(sd, regs[i], regs[i + 1]) < 0) + return -1; + return 0; +} + +static int tw9903_s_video_routing(struct v4l2_subdev *sd, u32 input, + u32 output, u32 config) +{ + write_reg(sd, 0x02, 0x40 | (input << 1)); + return 0; +} + +static int tw9903_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) +{ + struct tw9903 *dec = to_state(sd); + bool is_60hz = norm & V4L2_STD_525_60; + u8 regs[] = { + 0x05, is_60hz ? 0x80 : 0x00, + 0x07, is_60hz ? 0x02 : 0x12, + 0x08, is_60hz ? 0x14 : 0x18, + 0x09, is_60hz ? 0xf0 : 0x20, + 0, 0, + }; + + write_regs(sd, regs); + dec->norm = norm; + return 0; +} + + +static int tw9903_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct tw9903 *dec = container_of(ctrl->handler, struct tw9903, hdl); + struct v4l2_subdev *sd = &dec->sd; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + write_reg(sd, 0x10, ctrl->val); + break; + case V4L2_CID_CONTRAST: + write_reg(sd, 0x11, ctrl->val); + break; + case V4L2_CID_HUE: + write_reg(sd, 0x15, ctrl->val); + break; + default: + return -EINVAL; + } + return 0; +} + +static int tw9903_log_status(struct v4l2_subdev *sd) +{ + struct tw9903 *dec = to_state(sd); + bool is_60hz = dec->norm & V4L2_STD_525_60; + + v4l2_info(sd, "Standard: %d Hz\n", is_60hz ? 60 : 50); + v4l2_ctrl_subdev_log_status(sd); + return 0; +} + +/* --------------------------------------------------------------------------*/ + +static const struct v4l2_ctrl_ops tw9903_ctrl_ops = { + .s_ctrl = tw9903_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops tw9903_core_ops = { + .log_status = tw9903_log_status, + .s_std = tw9903_s_std, +}; + +static const struct v4l2_subdev_video_ops tw9903_video_ops = { + .s_routing = tw9903_s_video_routing, +}; + +static const struct v4l2_subdev_ops tw9903_ops = { + .core = &tw9903_core_ops, + .video = &tw9903_video_ops, +}; + +/* --------------------------------------------------------------------------*/ + +static int tw9903_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tw9903 *dec; + struct v4l2_subdev *sd; + struct v4l2_ctrl_handler *hdl; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + v4l_info(client, "chip found @ 0x%02x (%s)\n", + client->addr << 1, client->adapter->name); + + dec = kzalloc(sizeof(struct tw9903), GFP_KERNEL); + if (dec == NULL) + return -ENOMEM; + sd = &dec->sd; + v4l2_i2c_subdev_init(sd, client, &tw9903_ops); + hdl = &dec->hdl; + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &tw9903_ctrl_ops, + V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); + v4l2_ctrl_new_std(hdl, &tw9903_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 0x60); + v4l2_ctrl_new_std(hdl, &tw9903_ctrl_ops, + V4L2_CID_HUE, -128, 127, 1, 0); + sd->ctrl_handler = hdl; + if (hdl->error) { + int err = hdl->error; + + v4l2_ctrl_handler_free(hdl); + kfree(dec); + return err; + } + + /* Initialize tw9903 */ + dec->norm = V4L2_STD_NTSC; + + if (write_regs(sd, initial_registers) < 0) { + v4l2_err(client, "error initializing TW9903\n"); + kfree(dec); + return -EINVAL; + } + + return 0; +} + +static int tw9903_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&to_state(sd)->hdl); + kfree(to_state(sd)); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct i2c_device_id tw9903_id[] = { + { "tw9903", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tw9903_id); + +static struct i2c_driver tw9903_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "tw9903", + }, + .probe = tw9903_probe, + .remove = tw9903_remove, + .id_table = tw9903_id, +}; +module_i2c_driver(tw9903_driver); -- cgit v1.2.3 From 12be52a9e0b3e6f0402d721e8dada40a705cb78a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 08:06:07 -0300 Subject: [media] tw2804: add support for the Techwell tw2804 This is based on the wis-tw2804.c driver that's part of the go7007 driver. It has been converted to a v4l subdev driver by Volokh Konstantin, and I made additional cleanups. Based on work by: Volokh Konstantin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 11 +- drivers/media/i2c/Makefile | 1 + drivers/media/i2c/tw2804.c | 467 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 478 insertions(+), 1 deletion(-) create mode 100644 drivers/media/i2c/tw2804.c (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index eb1831c66864..07d9c11e91aa 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -301,11 +301,20 @@ config VIDEO_TVP7002 To compile this driver as a module, choose M here: the module will be called tvp7002. +config VIDEO_TW2804 + tristate "Techwell TW2804 multiple video decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Techwell tw2804 multiple video decoder. + + To compile this driver as a module, choose M here: the + module will be called tw2804. + config VIDEO_TW9903 tristate "Techwell TW9903 video decoder" depends on VIDEO_V4L2 && I2C ---help--- - Support for the Techwell 9903 multi-standard video decoder + Support for the Techwell tw9903 multi-standard video decoder with high quality down scaler. To compile this driver as a module, choose M here: the diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index af8fb29ab327..399050a99b19 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_VIDEO_THS7303) += ths7303.o obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o +obj-$(CONFIG_VIDEO_TW2804) += tw2804.o obj-$(CONFIG_VIDEO_TW9903) += tw9903.o obj-$(CONFIG_VIDEO_CS5345) += cs5345.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o diff --git a/drivers/media/i2c/tw2804.c b/drivers/media/i2c/tw2804.c new file mode 100644 index 000000000000..4bb5ba671c0d --- /dev/null +++ b/drivers/media/i2c/tw2804.c @@ -0,0 +1,467 @@ +/* + * Copyright (C) 2005-2006 Micronas USA Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TW2804_REG_AUTOGAIN 0x02 +#define TW2804_REG_HUE 0x0f +#define TW2804_REG_SATURATION 0x10 +#define TW2804_REG_CONTRAST 0x11 +#define TW2804_REG_BRIGHTNESS 0x12 +#define TW2804_REG_COLOR_KILLER 0x14 +#define TW2804_REG_GAIN 0x3c +#define TW2804_REG_CHROMA_GAIN 0x3d +#define TW2804_REG_BLUE_BALANCE 0x3e +#define TW2804_REG_RED_BALANCE 0x3f + +struct tw2804 { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + u8 channel:2; + u8 input:1; + int norm; +}; + +static const u8 global_registers[] = { + 0x39, 0x00, + 0x3a, 0xff, + 0x3b, 0x84, + 0x3c, 0x80, + 0x3d, 0x80, + 0x3e, 0x82, + 0x3f, 0x82, + 0xff, 0xff, /* Terminator (reg 0xff does not exist) */ +}; + +static const u8 channel_registers[] = { + 0x01, 0xc4, + 0x02, 0xa5, + 0x03, 0x20, + 0x04, 0xd0, + 0x05, 0x20, + 0x06, 0xd0, + 0x07, 0x88, + 0x08, 0x20, + 0x09, 0x07, + 0x0a, 0xf0, + 0x0b, 0x07, + 0x0c, 0xf0, + 0x0d, 0x40, + 0x0e, 0xd2, + 0x0f, 0x80, + 0x10, 0x80, + 0x11, 0x80, + 0x12, 0x80, + 0x13, 0x1f, + 0x14, 0x00, + 0x15, 0x00, + 0x16, 0x00, + 0x17, 0x00, + 0x18, 0xff, + 0x19, 0xff, + 0x1a, 0xff, + 0x1b, 0xff, + 0x1c, 0xff, + 0x1d, 0xff, + 0x1e, 0xff, + 0x1f, 0xff, + 0x20, 0x07, + 0x21, 0x07, + 0x22, 0x00, + 0x23, 0x91, + 0x24, 0x51, + 0x25, 0x03, + 0x26, 0x00, + 0x27, 0x00, + 0x28, 0x00, + 0x29, 0x00, + 0x2a, 0x00, + 0x2b, 0x00, + 0x2c, 0x00, + 0x2d, 0x00, + 0x2e, 0x00, + 0x2f, 0x00, + 0x30, 0x00, + 0x31, 0x00, + 0x32, 0x00, + 0x33, 0x00, + 0x34, 0x00, + 0x35, 0x00, + 0x36, 0x00, + 0x37, 0x00, + 0xff, 0xff, /* Terminator (reg 0xff does not exist) */ +}; + +static int write_reg(struct i2c_client *client, u8 reg, u8 value, u8 channel) +{ + return i2c_smbus_write_byte_data(client, reg | (channel << 6), value); +} + +static int write_regs(struct i2c_client *client, const u8 *regs, u8 channel) +{ + int ret; + int i; + + for (i = 0; regs[i] != 0xff; i += 2) { + ret = i2c_smbus_write_byte_data(client, + regs[i] | (channel << 6), regs[i + 1]); + if (ret < 0) + return ret; + } + return 0; +} + +static int read_reg(struct i2c_client *client, u8 reg, u8 channel) +{ + return i2c_smbus_read_byte_data(client, (reg) | (channel << 6)); +} + +static inline struct tw2804 *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct tw2804, sd); +} + +static inline struct tw2804 *to_state_from_ctrl(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct tw2804, hdl); +} + +static int tw2804_log_status(struct v4l2_subdev *sd) +{ + struct tw2804 *state = to_state(sd); + + v4l2_info(sd, "Standard: %s\n", + state->norm & V4L2_STD_525_60 ? "60 Hz" : "50 Hz"); + v4l2_info(sd, "Channel: %d\n", state->channel); + v4l2_info(sd, "Input: %d\n", state->input); + return v4l2_ctrl_subdev_log_status(sd); +} + +/* + * These volatile controls are needed because all four channels share + * these controls. So a change made to them through one channel would + * require another channel to be updated. + * + * Normally this would have been done in a different way, but since the one + * board that uses this driver sees this single chip as if it was on four + * different i2c adapters (each adapter belonging to a separate instance of + * the same USB driver) there is no reliable method that I have found to let + * the instances know about each other. + * + * So implementing these global registers as volatile is the best we can do. + */ +static int tw2804_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct tw2804 *state = to_state_from_ctrl(ctrl); + struct i2c_client *client = v4l2_get_subdevdata(&state->sd); + + switch (ctrl->id) { + case V4L2_CID_GAIN: + ctrl->val = read_reg(client, TW2804_REG_GAIN, 0); + return 0; + + case V4L2_CID_CHROMA_GAIN: + ctrl->val = read_reg(client, TW2804_REG_CHROMA_GAIN, 0); + return 0; + + case V4L2_CID_BLUE_BALANCE: + ctrl->val = read_reg(client, TW2804_REG_BLUE_BALANCE, 0); + return 0; + + case V4L2_CID_RED_BALANCE: + ctrl->val = read_reg(client, TW2804_REG_RED_BALANCE, 0); + return 0; + } + return 0; +} + +static int tw2804_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct tw2804 *state = to_state_from_ctrl(ctrl); + struct i2c_client *client = v4l2_get_subdevdata(&state->sd); + int addr; + int reg; + + switch (ctrl->id) { + case V4L2_CID_AUTOGAIN: + addr = TW2804_REG_AUTOGAIN; + reg = read_reg(client, addr, state->channel); + if (reg < 0) + return reg; + if (ctrl->val == 0) + reg &= ~(1 << 7); + else + reg |= 1 << 7; + return write_reg(client, addr, reg, state->channel); + + case V4L2_CID_COLOR_KILLER: + addr = TW2804_REG_COLOR_KILLER; + reg = read_reg(client, addr, state->channel); + if (reg < 0) + return reg; + reg = (reg & ~(0x03)) | (ctrl->val == 0 ? 0x02 : 0x03); + return write_reg(client, addr, reg, state->channel); + + case V4L2_CID_GAIN: + return write_reg(client, TW2804_REG_GAIN, ctrl->val, 0); + + case V4L2_CID_CHROMA_GAIN: + return write_reg(client, TW2804_REG_CHROMA_GAIN, ctrl->val, 0); + + case V4L2_CID_BLUE_BALANCE: + return write_reg(client, TW2804_REG_BLUE_BALANCE, ctrl->val, 0); + + case V4L2_CID_RED_BALANCE: + return write_reg(client, TW2804_REG_RED_BALANCE, ctrl->val, 0); + + case V4L2_CID_BRIGHTNESS: + return write_reg(client, TW2804_REG_BRIGHTNESS, + ctrl->val, state->channel); + + case V4L2_CID_CONTRAST: + return write_reg(client, TW2804_REG_CONTRAST, + ctrl->val, state->channel); + + case V4L2_CID_SATURATION: + return write_reg(client, TW2804_REG_SATURATION, + ctrl->val, state->channel); + + case V4L2_CID_HUE: + return write_reg(client, TW2804_REG_HUE, + ctrl->val, state->channel); + + default: + break; + } + return -EINVAL; +} + +static int tw2804_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) +{ + struct tw2804 *dec = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + bool is_60hz = norm & V4L2_STD_525_60; + u8 regs[] = { + 0x01, is_60hz ? 0xc4 : 0x84, + 0x09, is_60hz ? 0x07 : 0x04, + 0x0a, is_60hz ? 0xf0 : 0x20, + 0x0b, is_60hz ? 0x07 : 0x04, + 0x0c, is_60hz ? 0xf0 : 0x20, + 0x0d, is_60hz ? 0x40 : 0x4a, + 0x16, is_60hz ? 0x00 : 0x40, + 0x17, is_60hz ? 0x00 : 0x40, + 0x20, is_60hz ? 0x07 : 0x0f, + 0x21, is_60hz ? 0x07 : 0x0f, + 0xff, 0xff, + }; + + write_regs(client, regs, dec->channel); + dec->norm = norm; + return 0; +} + +static int tw2804_s_video_routing(struct v4l2_subdev *sd, u32 input, u32 output, + u32 config) +{ + struct tw2804 *dec = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int reg; + + if (config && config - 1 != dec->channel) { + if (config > 4) { + dev_err(&client->dev, + "channel %d is not between 1 and 4!\n", config); + return -EINVAL; + } + dec->channel = config - 1; + dev_dbg(&client->dev, "initializing TW2804 channel %d\n", + dec->channel); + if (dec->channel == 0 && + write_regs(client, global_registers, 0) < 0) { + dev_err(&client->dev, + "error initializing TW2804 global registers\n"); + return -EIO; + } + if (write_regs(client, channel_registers, dec->channel) < 0) { + dev_err(&client->dev, + "error initializing TW2804 channel %d\n", + dec->channel); + return -EIO; + } + } + + if (input > 1) + return -EINVAL; + + if (input == dec->input) + return 0; + + reg = read_reg(client, 0x22, dec->channel); + + if (reg >= 0) { + if (input == 0) + reg &= ~(1 << 2); + else + reg |= 1 << 2; + reg = write_reg(client, 0x22, reg, dec->channel); + } + + if (reg >= 0) + dec->input = input; + else + return reg; + return 0; +} + +static int tw2804_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct tw2804 *dec = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + u32 reg = read_reg(client, 0x78, 0); + + if (enable == 1) + write_reg(client, 0x78, reg & ~(1 << dec->channel), 0); + else + write_reg(client, 0x78, reg | (1 << dec->channel), 0); + + return 0; +} + +static const struct v4l2_ctrl_ops tw2804_ctrl_ops = { + .g_volatile_ctrl = tw2804_g_volatile_ctrl, + .s_ctrl = tw2804_s_ctrl, +}; + +static const struct v4l2_subdev_video_ops tw2804_video_ops = { + .s_routing = tw2804_s_video_routing, + .s_stream = tw2804_s_stream, +}; + +static const struct v4l2_subdev_core_ops tw2804_core_ops = { + .log_status = tw2804_log_status, + .s_std = tw2804_s_std, +}; + +static const struct v4l2_subdev_ops tw2804_ops = { + .core = &tw2804_core_ops, + .video = &tw2804_video_ops, +}; + +static int tw2804_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = client->adapter; + struct tw2804 *state; + struct v4l2_subdev *sd; + struct v4l2_ctrl *ctrl; + int err; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + state = kzalloc(sizeof(struct tw2804), GFP_KERNEL); + + if (state == NULL) + return -ENOMEM; + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &tw2804_ops); + state->channel = -1; + state->norm = V4L2_STD_NTSC; + + v4l2_ctrl_handler_init(&state->hdl, 10); + v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 128); + v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 128); + v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops, + V4L2_CID_HUE, 0, 255, 1, 128); + v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops, + V4L2_CID_COLOR_KILLER, 0, 1, 1, 0); + v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 0); + ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops, + V4L2_CID_GAIN, 0, 255, 1, 128); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops, + V4L2_CID_CHROMA_GAIN, 0, 255, 1, 128); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 0, 255, 1, 122); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + ctrl = v4l2_ctrl_new_std(&state->hdl, &tw2804_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 255, 1, 122); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + sd->ctrl_handler = &state->hdl; + err = state->hdl.error; + if (err) { + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return err; + } + + v4l_info(client, "chip found @ 0x%02x (%s)\n", + client->addr << 1, client->adapter->name); + + return 0; +} + +static int tw2804_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct tw2804 *state = to_state(sd); + + v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return 0; +} + +static const struct i2c_device_id tw2804_id[] = { + { "tw2804", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tw2804_id); + +static struct i2c_driver tw2804_driver = { + .driver = { + .name = "tw2804", + }, + .probe = tw2804_probe, + .remove = tw2804_remove, + .id_table = tw2804_id, +}; + +module_i2c_driver(tw2804_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TW2804/TW2802 V4L2 i2c driver"); +MODULE_AUTHOR("Micronas USA Inc"); -- cgit v1.2.3 From 523a4f7fbcf856fb1c2a4850f44edea6738ee37b Mon Sep 17 00:00:00 2001 From: Volokh Konstantin Date: Wed, 22 Aug 2012 07:45:15 -0300 Subject: [media] tw2804: modify ADC power control Switch off all ADC (max 4) with first init, we control it when starting/stopping streaming. Signed-off-by: Volokh Konstantin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw2804.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tw2804.c b/drivers/media/i2c/tw2804.c index 4bb5ba671c0d..441b7661d491 100644 --- a/drivers/media/i2c/tw2804.c +++ b/drivers/media/i2c/tw2804.c @@ -53,6 +53,7 @@ static const u8 global_registers[] = { 0x3d, 0x80, 0x3e, 0x82, 0x3f, 0x82, + 0x78, 0x0f, 0xff, 0xff, /* Terminator (reg 0xff does not exist) */ }; -- cgit v1.2.3 From a000e9a02b5885b1b69f691c80e346d102f94a88 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 17 Mar 2013 09:26:40 -0300 Subject: [media] tw9906: add Techwell tw9906 video decoder Taken from the 0.9.8-5 version of the out-of-tree wis-go7007 driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 10 ++ drivers/media/i2c/Makefile | 1 + drivers/media/i2c/tw9906.c | 241 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 252 insertions(+) create mode 100644 drivers/media/i2c/tw9906.c (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 07d9c11e91aa..9e7ce8bff4e9 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -320,6 +320,16 @@ config VIDEO_TW9903 To compile this driver as a module, choose M here: the module will be called tw9903. +config VIDEO_TW9906 + tristate "Techwell TW9906 video decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Techwell tw9906 enhanced multi-standard comb filter + video decoder with YCbCr input support. + + To compile this driver as a module, choose M here: the + module will be called tw9906. + config VIDEO_VPX3220 tristate "vpx3220a, vpx3216b & vpx3214c video decoders" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 399050a99b19..720f42d9d9f4 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o obj-$(CONFIG_VIDEO_TW2804) += tw2804.o obj-$(CONFIG_VIDEO_TW9903) += tw9903.o +obj-$(CONFIG_VIDEO_TW9906) += tw9906.o obj-$(CONFIG_VIDEO_CS5345) += cs5345.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o obj-$(CONFIG_VIDEO_M52790) += m52790.o diff --git a/drivers/media/i2c/tw9906.c b/drivers/media/i2c/tw9906.c new file mode 100644 index 000000000000..2263a914cd08 --- /dev/null +++ b/drivers/media/i2c/tw9906.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2005-2006 Micronas USA Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("TW9906 I2C subdev driver"); +MODULE_LICENSE("GPL v2"); + +struct tw9906 { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + v4l2_std_id norm; +}; + +static inline struct tw9906 *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct tw9906, sd); +} + +static const u8 initial_registers[] = { + 0x02, 0x40, /* input 0, composite */ + 0x03, 0xa2, /* correct digital format */ + 0x05, 0x81, /* or 0x01 for PAL */ + 0x07, 0x02, /* window */ + 0x08, 0x14, /* window */ + 0x09, 0xf0, /* window */ + 0x0a, 0x10, /* window */ + 0x0b, 0xd0, /* window */ + 0x0d, 0x00, /* scaling */ + 0x0e, 0x11, /* scaling */ + 0x0f, 0x00, /* scaling */ + 0x10, 0x00, /* brightness */ + 0x11, 0x60, /* contrast */ + 0x12, 0x11, /* sharpness */ + 0x13, 0x7e, /* U gain */ + 0x14, 0x7e, /* V gain */ + 0x15, 0x00, /* hue */ + 0x19, 0x57, /* vbi */ + 0x1a, 0x0f, + 0x1b, 0x40, + 0x29, 0x03, + 0x55, 0x00, + 0x6b, 0x26, + 0x6c, 0x36, + 0x6d, 0xf0, + 0x6e, 0x41, + 0x6f, 0x13, + 0xad, 0x70, + 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */ +}; + +static int write_reg(struct v4l2_subdev *sd, u8 reg, u8 value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return i2c_smbus_write_byte_data(client, reg, value); +} + +static int write_regs(struct v4l2_subdev *sd, const u8 *regs) +{ + int i; + + for (i = 0; regs[i] != 0x00; i += 2) + if (write_reg(sd, regs[i], regs[i + 1]) < 0) + return -1; + return 0; +} + +static int tw9906_s_video_routing(struct v4l2_subdev *sd, u32 input, + u32 output, u32 config) +{ + write_reg(sd, 0x02, 0x40 | (input << 1)); + return 0; +} + +static int tw9906_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) +{ + struct tw9906 *dec = to_state(sd); + bool is_60hz = norm & V4L2_STD_525_60; + u8 regs[] = { + 0x05, is_60hz ? 0x81 : 0x01, + 0x07, is_60hz ? 0x02 : 0x12, + 0x08, is_60hz ? 0x14 : 0x18, + 0x09, is_60hz ? 0xf0 : 0x20, + 0, 0, + }; + + write_regs(sd, regs); + dec->norm = norm; + return 0; +} + +static int tw9906_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct tw9906 *dec = container_of(ctrl->handler, struct tw9906, hdl); + struct v4l2_subdev *sd = &dec->sd; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + write_reg(sd, 0x10, ctrl->val); + break; + case V4L2_CID_CONTRAST: + write_reg(sd, 0x11, ctrl->val); + break; + case V4L2_CID_HUE: + write_reg(sd, 0x15, ctrl->val); + break; + default: + return -EINVAL; + } + return 0; +} + +static int tw9906_log_status(struct v4l2_subdev *sd) +{ + struct tw9906 *dec = to_state(sd); + bool is_60hz = dec->norm & V4L2_STD_525_60; + + v4l2_info(sd, "Standard: %d Hz\n", is_60hz ? 60 : 50); + v4l2_ctrl_subdev_log_status(sd); + return 0; +} + +/* --------------------------------------------------------------------------*/ + +static const struct v4l2_ctrl_ops tw9906_ctrl_ops = { + .s_ctrl = tw9906_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops tw9906_core_ops = { + .log_status = tw9906_log_status, + .s_std = tw9906_s_std, +}; + +static const struct v4l2_subdev_video_ops tw9906_video_ops = { + .s_routing = tw9906_s_video_routing, +}; + +static const struct v4l2_subdev_ops tw9906_ops = { + .core = &tw9906_core_ops, + .video = &tw9906_video_ops, +}; + +static int tw9906_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tw9906 *dec; + struct v4l2_subdev *sd; + struct v4l2_ctrl_handler *hdl; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + v4l_info(client, "chip found @ 0x%02x (%s)\n", + client->addr << 1, client->adapter->name); + + dec = kzalloc(sizeof(struct tw9906), GFP_KERNEL); + if (dec == NULL) + return -ENOMEM; + sd = &dec->sd; + v4l2_i2c_subdev_init(sd, client, &tw9906_ops); + hdl = &dec->hdl; + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &tw9906_ctrl_ops, + V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); + v4l2_ctrl_new_std(hdl, &tw9906_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 0x60); + v4l2_ctrl_new_std(hdl, &tw9906_ctrl_ops, + V4L2_CID_HUE, -128, 127, 1, 0); + sd->ctrl_handler = hdl; + if (hdl->error) { + int err = hdl->error; + + v4l2_ctrl_handler_free(hdl); + kfree(dec); + return err; + } + + /* Initialize tw9906 */ + dec->norm = V4L2_STD_NTSC; + + if (write_regs(sd, initial_registers) < 0) { + v4l2_err(client, "error initializing TW9906\n"); + kfree(dec); + return -EINVAL; + } + + return 0; +} + +static int tw9906_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(&to_state(sd)->hdl); + kfree(to_state(sd)); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct i2c_device_id tw9906_id[] = { + { "tw9906", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tw9906_id); + +static struct i2c_driver tw9906_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "tw9906", + }, + .probe = tw9906_probe, + .remove = tw9906_remove, + .id_table = tw9906_id, +}; +module_i2c_driver(tw9906_driver); -- cgit v1.2.3 From 2d80647b6ebd2db6ef1df5e4e3319afd8867580c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 15:18:04 -0300 Subject: [media] v4l2-common: remove obsolete v4l_fill_dv_preset_info It's no longer used, so it can now be removed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-common.c | 47 ----------------------------------- include/media/v4l2-common.h | 1 - 2 files changed, 48 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index aa044f491666..b81f274e60b0 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -550,53 +550,6 @@ void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, } EXPORT_SYMBOL_GPL(v4l_bound_align_image); -/** - * v4l_fill_dv_preset_info - fill description of a digital video preset - * @preset - preset value - * @info - pointer to struct v4l2_dv_enum_preset - * - * drivers can use this helper function to fill description of dv preset - * in info. - */ -int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info) -{ - static const struct v4l2_dv_preset_info { - u16 width; - u16 height; - const char *name; - } dv_presets[] = { - { 0, 0, "Invalid" }, /* V4L2_DV_INVALID */ - { 720, 480, "480p@59.94" }, /* V4L2_DV_480P59_94 */ - { 720, 576, "576p@50" }, /* V4L2_DV_576P50 */ - { 1280, 720, "720p@24" }, /* V4L2_DV_720P24 */ - { 1280, 720, "720p@25" }, /* V4L2_DV_720P25 */ - { 1280, 720, "720p@30" }, /* V4L2_DV_720P30 */ - { 1280, 720, "720p@50" }, /* V4L2_DV_720P50 */ - { 1280, 720, "720p@59.94" }, /* V4L2_DV_720P59_94 */ - { 1280, 720, "720p@60" }, /* V4L2_DV_720P60 */ - { 1920, 1080, "1080i@29.97" }, /* V4L2_DV_1080I29_97 */ - { 1920, 1080, "1080i@30" }, /* V4L2_DV_1080I30 */ - { 1920, 1080, "1080i@25" }, /* V4L2_DV_1080I25 */ - { 1920, 1080, "1080i@50" }, /* V4L2_DV_1080I50 */ - { 1920, 1080, "1080i@60" }, /* V4L2_DV_1080I60 */ - { 1920, 1080, "1080p@24" }, /* V4L2_DV_1080P24 */ - { 1920, 1080, "1080p@25" }, /* V4L2_DV_1080P25 */ - { 1920, 1080, "1080p@30" }, /* V4L2_DV_1080P30 */ - { 1920, 1080, "1080p@50" }, /* V4L2_DV_1080P50 */ - { 1920, 1080, "1080p@60" }, /* V4L2_DV_1080P60 */ - }; - - if (info == NULL || preset >= ARRAY_SIZE(dv_presets)) - return -EINVAL; - - info->preset = preset; - info->width = dv_presets[preset].width; - info->height = dv_presets[preset].height; - strlcpy(info->name, dv_presets[preset].name, sizeof(info->name)); - return 0; -} -EXPORT_SYMBOL_GPL(v4l_fill_dv_preset_info); - /** * v4l_match_dv_timings - check if two timings match * @t1 - compare this v4l2_dv_timings struct... diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index ec7c9c00b256..1d93c48cb371 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -201,7 +201,6 @@ void v4l_bound_align_image(unsigned int *w, unsigned int wmin, unsigned int *h, unsigned int hmin, unsigned int hmax, unsigned int halign, unsigned int salign); -int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info); struct v4l2_discrete_probe { const struct v4l2_frmsize_discrete *sizes; -- cgit v1.2.3 From 02fa628217e995bd7b1fe8c1b7cc7a510f6b8349 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 15:21:06 -0300 Subject: [media] v4l2 core: remove the obsolete dv_preset support These ioctls are no longer used by any drivers, so remove them. [mchehab@redhat.com: Fix merge conflict] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 ---- drivers/media/v4l2-core/v4l2-dev.c | 4 ---- drivers/media/v4l2-core/v4l2-ioctl.c | 32 ++------------------------- include/media/v4l2-ioctl.h | 9 -------- 4 files changed, 2 insertions(+), 47 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 7157af301b14..f1295519f285 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -1076,10 +1076,6 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_DBG_G_REGISTER: case VIDIOC_DBG_G_CHIP_IDENT: case VIDIOC_S_HW_FREQ_SEEK: - case VIDIOC_ENUM_DV_PRESETS: - case VIDIOC_S_DV_PRESET: - case VIDIOC_G_DV_PRESET: - case VIDIOC_QUERY_DV_PRESET: case VIDIOC_S_DV_TIMINGS: case VIDIOC_G_DV_TIMINGS: case VIDIOC_DQEVENT: diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index de1e9ab7db99..1fbd95755e75 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -685,7 +685,6 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDIO, vidioc_enumaudio); SET_VALID_IOCTL(ops, VIDIOC_G_AUDIO, vidioc_g_audio); SET_VALID_IOCTL(ops, VIDIOC_S_AUDIO, vidioc_s_audio); - SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_PRESET, vidioc_query_dv_preset); SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings); } if (is_tx) { @@ -708,9 +707,6 @@ static void determine_valid_ioctls(struct video_device *vdev) (ops->vidioc_g_std || vdev->current_norm))) set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls); SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm); - SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_PRESETS, vidioc_enum_dv_presets); - SET_VALID_IOCTL(ops, VIDIOC_S_DV_PRESET, vidioc_s_dv_preset); - SET_VALID_IOCTL(ops, VIDIOC_G_DV_PRESET, vidioc_g_dv_preset); SET_VALID_IOCTL(ops, VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings); SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 72c22fde2b69..83aa39dfe07c 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -652,22 +652,6 @@ static void v4l_print_dbg_register(const void *arg, bool write_only) p->reg, p->val); } -static void v4l_print_dv_enum_presets(const void *arg, bool write_only) -{ - const struct v4l2_dv_enum_preset *p = arg; - - pr_cont("index=%u, preset=%u, name=%.*s, width=%u, height=%u\n", - p->index, p->preset, - (int)sizeof(p->name), p->name, p->width, p->height); -} - -static void v4l_print_dv_preset(const void *arg, bool write_only) -{ - const struct v4l2_dv_preset *p = arg; - - pr_cont("preset=%u\n", p->preset); -} - static void v4l_print_dv_timings(const void *arg, bool write_only) { const struct v4l2_dv_timings *p = arg; @@ -1011,17 +995,13 @@ static int v4l_enuminput(const struct v4l2_ioctl_ops *ops, struct v4l2_input *p = arg; /* - * We set the flags for CAP_PRESETS, CAP_DV_TIMINGS & + * We set the flags for CAP_DV_TIMINGS & * CAP_STD here based on ioctl handler provided by the * driver. If the driver doesn't support these * for a specific input, it must override these flags. */ if (is_valid_ioctl(vfd, VIDIOC_S_STD)) p->capabilities |= V4L2_IN_CAP_STD; - if (is_valid_ioctl(vfd, VIDIOC_S_DV_PRESET)) - p->capabilities |= V4L2_IN_CAP_PRESETS; - if (is_valid_ioctl(vfd, VIDIOC_S_DV_TIMINGS)) - p->capabilities |= V4L2_IN_CAP_DV_TIMINGS; return ops->vidioc_enum_input(file, fh, p); } @@ -1033,17 +1013,13 @@ static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops, struct v4l2_output *p = arg; /* - * We set the flags for CAP_PRESETS, CAP_DV_TIMINGS & + * We set the flags for CAP_DV_TIMINGS & * CAP_STD here based on ioctl handler provided by the * driver. If the driver doesn't support these * for a specific output, it must override these flags. */ if (is_valid_ioctl(vfd, VIDIOC_S_STD)) p->capabilities |= V4L2_OUT_CAP_STD; - if (is_valid_ioctl(vfd, VIDIOC_S_DV_PRESET)) - p->capabilities |= V4L2_OUT_CAP_PRESETS; - if (is_valid_ioctl(vfd, VIDIOC_S_DV_TIMINGS)) - p->capabilities |= V4L2_OUT_CAP_DV_TIMINGS; return ops->vidioc_enum_output(file, fh, p); } @@ -2040,10 +2016,6 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_FNC(VIDIOC_DBG_G_REGISTER, v4l_dbg_g_register, v4l_print_dbg_register, 0), IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_IDENT, v4l_dbg_g_chip_ident, v4l_print_dbg_chip_ident, 0), IOCTL_INFO_FNC(VIDIOC_S_HW_FREQ_SEEK, v4l_s_hw_freq_seek, v4l_print_hw_freq_seek, INFO_FL_PRIO), - IOCTL_INFO_STD(VIDIOC_ENUM_DV_PRESETS, vidioc_enum_dv_presets, v4l_print_dv_enum_presets, 0), - IOCTL_INFO_STD(VIDIOC_S_DV_PRESET, vidioc_s_dv_preset, v4l_print_dv_preset, INFO_FL_PRIO), - IOCTL_INFO_STD(VIDIOC_G_DV_PRESET, vidioc_g_dv_preset, v4l_print_dv_preset, 0), - IOCTL_INFO_STD(VIDIOC_QUERY_DV_PRESET, vidioc_query_dv_preset, v4l_print_dv_preset, 0), IOCTL_INFO_STD(VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings, v4l_print_dv_timings, INFO_FL_PRIO), IOCTL_INFO_STD(VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings, v4l_print_dv_timings, 0), IOCTL_INFO_FNC(VIDIOC_DQEVENT, v4l_dqevent, v4l_print_event, 0), diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index a4175cda4fc1..e10c2432f902 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -254,15 +254,6 @@ struct v4l2_ioctl_ops { struct v4l2_frmivalenum *fival); /* DV Timings IOCTLs */ - int (*vidioc_enum_dv_presets) (struct file *file, void *fh, - struct v4l2_dv_enum_preset *preset); - - int (*vidioc_s_dv_preset) (struct file *file, void *fh, - struct v4l2_dv_preset *preset); - int (*vidioc_g_dv_preset) (struct file *file, void *fh, - struct v4l2_dv_preset *preset); - int (*vidioc_query_dv_preset) (struct file *file, void *fh, - struct v4l2_dv_preset *qpreset); int (*vidioc_s_dv_timings) (struct file *file, void *fh, struct v4l2_dv_timings *timings); int (*vidioc_g_dv_timings) (struct file *file, void *fh, -- cgit v1.2.3 From b781e6be79a394cd6980e9cd8fd5c25822d152b6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 24 Mar 2013 13:51:21 -0300 Subject: [media] sony-btf-mpx: v4l2_tuner struct is now constant A patchset applied earlier changed v4l2_tuner struct parameter at vidioc_s_tuner to const. Do this change at sony_btf_mpx_s_tuner(), in order to remove this warning: drivers/media/i2c/sony-btf-mpx.c:335:2: warning: initialization from incompatible pointer type [enabled by default] drivers/media/i2c/sony-btf-mpx.c:335:2: warning: (near initialization for 'sony_btf_mpx_tuner_ops.s_tuner') [enabled by default] Cc: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/sony-btf-mpx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/sony-btf-mpx.c b/drivers/media/i2c/sony-btf-mpx.c index bc73e8ff0471..38cbea98764c 100644 --- a/drivers/media/i2c/sony-btf-mpx.c +++ b/drivers/media/i2c/sony-btf-mpx.c @@ -311,7 +311,7 @@ static int sony_btf_mpx_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; } -static int sony_btf_mpx_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) +static int sony_btf_mpx_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) { struct sony_btf_mpx *t = to_state(sd); -- cgit v1.2.3 From af2d68d1be24972a79b1616cf7d4d29137841f87 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 12 Mar 2013 03:56:55 -0300 Subject: [media] vivi: add v4l2_ctrl_modify_range test case Update the brighness range depending on the selected input. Useful for testing control range events. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c index c46d2e8677a5..85bc314382d3 100644 --- a/drivers/media/platform/vivi.c +++ b/drivers/media/platform/vivi.c @@ -1093,6 +1093,15 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) return 0; dev->input = i; + /* + * Modify the brightness range depending on the input. + * This makes it easy to use vivi to test if applications can + * handle control range modifications and is also how this is + * typically used in practice as different inputs may be hooked + * up to different receivers with different control ranges. + */ + v4l2_ctrl_modify_range(dev->brightness, + 128 * i, 255 + 128 * i, 1, 127 + 128 * i); precalculate_bars(dev); precalculate_line(dev); return 0; -- cgit v1.2.3 From d230d5ad0bca1c2d90b387549d4eebafabd60569 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 24 Mar 2013 14:58:03 -0300 Subject: [media] em28xx-i2c: do not break strings across lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 45 ++++++++++++++++------------------- 1 file changed, 20 insertions(+), 25 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 9e2fa41044b3..db40835888d1 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -68,8 +68,8 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) /* trigger write */ ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len); if (ret != 2 + len) { - em28xx_warn("failed to trigger write to i2c address 0x%x " - "(error=%i)\n", addr, ret); + em28xx_warn("failed to trigger write to i2c address 0x%x (error=%i)\n", + addr, ret); return (ret < 0) ? ret : -EIO; } /* wait for completion */ @@ -81,8 +81,8 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) } else if (ret == 0x94 + len - 1) { return -ENODEV; } else if (ret < 0) { - em28xx_warn("failed to get i2c transfer status from " - "bridge register (error=%i)\n", ret); + em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", + ret); return ret; } msleep(5); @@ -110,8 +110,8 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) buf2[0] = addr; ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2); if (ret != 2) { - em28xx_warn("failed to trigger read from i2c address 0x%x " - "(error=%i)\n", addr, ret); + em28xx_warn("failed to trigger read from i2c address 0x%x (error=%i)\n", + addr, ret); return (ret < 0) ? ret : -EIO; } @@ -124,8 +124,8 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) } else if (ret == 0x94 + len - 1) { return -ENODEV; } else if (ret < 0) { - em28xx_warn("failed to get i2c transfer status from " - "bridge register (error=%i)\n", ret); + em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", + ret); return ret; } msleep(5); @@ -136,9 +136,8 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) /* get the received message */ ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len); if (ret != len) { - em28xx_warn("reading from i2c device at 0x%x failed: " - "couldn't get the received message from the bridge " - "(error=%i)\n", addr, ret); + em28xx_warn("reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n", + addr, ret); return (ret < 0) ? ret : -EIO; } for (i = 0; i < len; i++) @@ -179,12 +178,11 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); if (ret != len) { if (ret < 0) { - em28xx_warn("writing to i2c device at 0x%x failed " - "(error=%i)\n", addr, ret); + em28xx_warn("writing to i2c device at 0x%x failed (error=%i)\n", + addr, ret); return ret; } else { - em28xx_warn("%i bytes write to i2c device at 0x%x " - "requested, but %i bytes written\n", + em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", len, addr, ret); return -EIO; } @@ -199,8 +197,8 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, } else if (ret == 0x10) { return -ENODEV; } else if (ret < 0) { - em28xx_warn("failed to read i2c transfer status from " - "bridge (error=%i)\n", ret); + em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n", + ret); return ret; } msleep(5); @@ -243,8 +241,8 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) /* Check success of the i2c operation */ ret = dev->em28xx_read_reg(dev, 0x05); if (ret < 0) { - em28xx_warn("failed to read i2c transfer status from " - "bridge (error=%i)\n", ret); + em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n", + ret); return ret; } if (ret > 0) { @@ -494,12 +492,10 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, dev->hash = em28xx_hash_mem(data, len, 32); mc_start = (data[1] << 8) + 4; /* usually 0x0004 */ - em28xx_info("EEPROM ID = %02x %02x %02x %02x, " - "EEPROM hash = 0x%08lx\n", + em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", data[0], data[1], data[2], data[3], dev->hash); em28xx_info("EEPROM info:\n"); - em28xx_info("\tmicrocode start address = 0x%04x, " - "boot configuration = 0x%02x\n", + em28xx_info("\tmicrocode start address = 0x%04x, boot configuration = 0x%02x\n", mc_start, data[2]); /* boot configuration (address 0x0002): * [0] microcode download speed: 1 = 400 kHz; 0 = 100 kHz @@ -552,8 +548,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, data[0] == 0x1a && data[1] == 0xeb && data[2] == 0x67 && data[3] == 0x95) { dev->hash = em28xx_hash_mem(data, len, 32); - em28xx_info("EEPROM ID = %02x %02x %02x %02x, " - "EEPROM hash = 0x%08lx\n", + em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", data[0], data[1], data[2], data[3], dev->hash); em28xx_info("EEPROM info:\n"); } else { -- cgit v1.2.3 From fa74aca3a3decbd8e8ff2f25ef86edcc61222455 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Sun, 24 Mar 2013 17:09:59 -0300 Subject: [media] em28xx-i2c: fix coding style of multi line comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-i2c.c | 52 +++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 18 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index db40835888d1..704f283d34ab 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -171,8 +171,10 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, if (len < 1 || len > 64) return -EOPNOTSUPP; - /* NOTE: limited by the USB ctrl message constraints - * Zero length reads always succeed, even if no device is connected */ + /* + * NOTE: limited by the USB ctrl message constraints + * Zero length reads always succeed, even if no device is connected + */ /* Write to i2c device */ ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); @@ -202,9 +204,11 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, return ret; } msleep(5); - /* NOTE: do we really have to wait for success ? - Never seen anything else than 0x00 or 0x10 - (even with high payload) ... */ + /* + * NOTE: do we really have to wait for success ? + * Never seen anything else than 0x00 or 0x10 + * (even with high payload) ... + */ } em28xx_warn("write to i2c device at 0x%x timed out\n", addr); return -EIO; @@ -220,8 +224,10 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) if (len < 1 || len > 64) return -EOPNOTSUPP; - /* NOTE: limited by the USB ctrl message constraints - * Zero length reads always succeed, even if no device is connected */ + /* + * NOTE: limited by the USB ctrl message constraints + * Zero length reads always succeed, even if no device is connected + */ /* Read data from i2c device */ ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); @@ -230,7 +236,8 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) addr, ret); return ret; } - /* NOTE: some devices with two i2c busses have the bad habit to return 0 + /* + * NOTE: some devices with two i2c busses have the bad habit to return 0 * bytes if we are on bus B AND there was no write attempt to the * specified slave address before AND no device is present at the * requested slave address. @@ -366,9 +373,10 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, return num; } -/* based on linux/sunrpc/svcauth.h and linux/hash.h +/* + * based on linux/sunrpc/svcauth.h and linux/hash.h * The original hash function returns a different value, if arch is x86_64 - * or i386. + * or i386. */ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) { @@ -391,8 +399,10 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) return (hash >> (32 - bits)) & 0xffffffffUL; } -/* Helper function to read data blocks from i2c clients with 8 or 16 bit - * address width, 8 bit register width and auto incrementation been activated */ +/* + * Helper function to read data blocks from i2c clients with 8 or 16 bit + * address width, 8 bit register width and auto incrementation been activated + */ static int em28xx_i2c_read_block(struct em28xx *dev, unsigned bus, u16 addr, bool addr_w16, u16 len, u8 *data) { @@ -434,9 +444,11 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, u8 **eedata, u16 *eedata_len) { const u16 len = 256; - /* FIXME common length/size for bytes to read, to display, hash + /* + * FIXME common length/size for bytes to read, to display, hash * calculation and returned device dataset. Simplifies the code a lot, - * but we might have to deal with multiple sizes in the future ! */ + * but we might have to deal with multiple sizes in the future ! + */ int i, err; struct em28xx_eeprom *dev_config; u8 buf, *data; @@ -497,7 +509,8 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, em28xx_info("EEPROM info:\n"); em28xx_info("\tmicrocode start address = 0x%04x, boot configuration = 0x%02x\n", mc_start, data[2]); - /* boot configuration (address 0x0002): + /* + * boot configuration (address 0x0002): * [0] microcode download speed: 1 = 400 kHz; 0 = 100 kHz * [1] always selects 12 kb RAM * [2] USB device speed: 1 = force Full Speed; 0 = auto detect @@ -506,8 +519,10 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, * characterization */ - /* Read hardware config dataset offset from address - * (microcode start + 46) */ + /* + * Read hardware config dataset offset from address + * (microcode start + 46) + */ err = em28xx_i2c_read_block(dev, bus, mc_start + 46, 1, 2, data); if (err != 2) { @@ -520,7 +535,8 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, hwconf_offset = mc_start + data[0] + (data[1] << 8); /* Read hardware config dataset */ - /* NOTE: the microcode copy can be multiple pages long, but + /* + * NOTE: the microcode copy can be multiple pages long, but * we assume the hardware config dataset is the same as in * the old eeprom and not longer than 256 bytes. * tveeprom is currently also limited to 256 bytes. -- cgit v1.2.3 From b12f7dd51abf419b9279f3ff2fdc3c06fe50c10f Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 25 Mar 2013 01:22:18 -0300 Subject: [media] tw9906: Remove unneeded version.h header include version.h header inclusion is not necessary as detected by versioncheck. Signed-off-by: Sachin Kamat Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw9906.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tw9906.c b/drivers/media/i2c/tw9906.c index 2263a914cd08..d94325b68b81 100644 --- a/drivers/media/i2c/tw9906.c +++ b/drivers/media/i2c/tw9906.c @@ -17,7 +17,6 @@ #include #include -#include #include #include #include -- cgit v1.2.3 From d4a2cea4f2fd9c935f30666e4acdb1065ff60544 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Mar 2013 06:23:23 -0300 Subject: [media] tw9603/6.c: use two separate const tables for the 50/60hz setup Using two separate tables to setup the registers for 50 or 60 hz is better than the non-const table that is filled in at runtime. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw9903.c | 19 +++++++++++++------ drivers/media/i2c/tw9906.c | 19 +++++++++++++------ 2 files changed, 26 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tw9903.c b/drivers/media/i2c/tw9903.c index f0d0ef5da30c..87880b19d8c3 100644 --- a/drivers/media/i2c/tw9903.c +++ b/drivers/media/i2c/tw9903.c @@ -127,15 +127,22 @@ static int tw9903_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) { struct tw9903 *dec = to_state(sd); bool is_60hz = norm & V4L2_STD_525_60; - u8 regs[] = { - 0x05, is_60hz ? 0x80 : 0x00, - 0x07, is_60hz ? 0x02 : 0x12, - 0x08, is_60hz ? 0x14 : 0x18, - 0x09, is_60hz ? 0xf0 : 0x20, + static const u8 config_60hz[] = { + 0x05, 0x80, + 0x07, 0x02, + 0x08, 0x14, + 0x09, 0xf0, + 0, 0, + }; + static const u8 config_50hz[] = { + 0x05, 0x00, + 0x07, 0x12, + 0x08, 0x18, + 0x09, 0x20, 0, 0, }; - write_regs(sd, regs); + write_regs(sd, is_60hz ? config_60hz : config_50hz); dec->norm = norm; return 0; } diff --git a/drivers/media/i2c/tw9906.c b/drivers/media/i2c/tw9906.c index d94325b68b81..accd79e5a7fd 100644 --- a/drivers/media/i2c/tw9906.c +++ b/drivers/media/i2c/tw9906.c @@ -98,15 +98,22 @@ static int tw9906_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) { struct tw9906 *dec = to_state(sd); bool is_60hz = norm & V4L2_STD_525_60; - u8 regs[] = { - 0x05, is_60hz ? 0x81 : 0x01, - 0x07, is_60hz ? 0x02 : 0x12, - 0x08, is_60hz ? 0x14 : 0x18, - 0x09, is_60hz ? 0xf0 : 0x20, + static const u8 config_60hz[] = { + 0x05, 0x81, + 0x07, 0x02, + 0x08, 0x14, + 0x09, 0xf0, + 0, 0, + }; + static const u8 config_50hz[] = { + 0x05, 0x01, + 0x07, 0x12, + 0x08, 0x18, + 0x09, 0x20, 0, 0, }; - write_regs(sd, regs); + write_regs(sd, is_60hz ? config_60hz : config_50hz); dec->norm = norm; return 0; } -- cgit v1.2.3 From 8dbee53b2a8dcc23e8d52d85d7e0b4fe268c55e7 Mon Sep 17 00:00:00 2001 From: Volokh Konstantin Date: Sat, 23 Mar 2013 19:28:28 -0300 Subject: [media] tw2804: Revert ADC Control commit 523a4f7fbcf856fb1c2a4850f44edea6738ee37b Case: In AdLink MPG24 there is bt878 exists (it captures one frame of all video inputs), Video Signal for it one transmits through tw2804 chip, so we can't control ADC (shut on/off) on tw2804, as some another can use bttv capture way. Signed-off-by: Volokh Konstantin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw2804.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tw2804.c b/drivers/media/i2c/tw2804.c index 441b7661d491..c5dc2c3bf2d7 100644 --- a/drivers/media/i2c/tw2804.c +++ b/drivers/media/i2c/tw2804.c @@ -53,7 +53,7 @@ static const u8 global_registers[] = { 0x3d, 0x80, 0x3e, 0x82, 0x3f, 0x82, - 0x78, 0x0f, + 0x78, 0x00, 0xff, 0xff, /* Terminator (reg 0xff does not exist) */ }; @@ -337,20 +337,6 @@ static int tw2804_s_video_routing(struct v4l2_subdev *sd, u32 input, u32 output, return 0; } -static int tw2804_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct tw2804 *dec = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u32 reg = read_reg(client, 0x78, 0); - - if (enable == 1) - write_reg(client, 0x78, reg & ~(1 << dec->channel), 0); - else - write_reg(client, 0x78, reg | (1 << dec->channel), 0); - - return 0; -} - static const struct v4l2_ctrl_ops tw2804_ctrl_ops = { .g_volatile_ctrl = tw2804_g_volatile_ctrl, .s_ctrl = tw2804_s_ctrl, @@ -358,7 +344,6 @@ static const struct v4l2_ctrl_ops tw2804_ctrl_ops = { static const struct v4l2_subdev_video_ops tw2804_video_ops = { .s_routing = tw2804_s_video_routing, - .s_stream = tw2804_s_stream, }; static const struct v4l2_subdev_core_ops tw2804_core_ops = { -- cgit v1.2.3 From 9b6f5dc07ae008c58ea27e91a7b1dfbbd0f6972a Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Mon, 12 Nov 2012 04:01:29 -0300 Subject: [media] videobuf2-core: print current state of buffer in vb2_buffer_done In vb2_buffer_done, it would be better the print the value of 'state' (current state of buffer) than to print 'vb->state' which is always VB2_BUF_STATE_ACTIVE. Signed-off-by: Tushar Behera Acked-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 70827feb87b4..02bb5e721657 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -855,7 +855,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) return; dprintk(4, "Done processing on buffer %d, state: %d\n", - vb->v4l2_buf.index, vb->state); + vb->v4l2_buf.index, state); /* sync buffers */ for (plane = 0; plane < vb->num_planes; ++plane) -- cgit v1.2.3 From 9d5f4839cc098f15a48f7063d39805ddfe84565c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 6 Mar 2013 04:34:26 -0300 Subject: [media] v4l2-common: remove obsolete check for ' at the end of a driver name During the transition to sub-devices several years ago non-subdev drivers had a ' at the end of their driver name to tell them apart from already converted drivers. This check was a left-over from that time and can be removed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-common.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index b81f274e60b0..a9e7703560ad 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -251,9 +251,6 @@ int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match if (c->driver == NULL || c->driver->driver.name == NULL) return 0; len = strlen(c->driver->driver.name); - /* legacy drivers have a ' suffix, don't try to match that */ - if (len && c->driver->driver.name[len - 1] == '\'') - len--; return len && !strncmp(c->driver->driver.name, match->name, len); case V4L2_CHIP_MATCH_I2C_ADDR: return c->addr == match->addr; -- cgit v1.2.3 From 79b0c6400517456935f84f8d46c8bb0cf73f1813 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 18 Mar 2013 12:16:34 -0300 Subject: [media] v4l2: add new VIDIOC_DBG_G_CHIP_NAME ioctl Simplify the debugging ioctls by creating the VIDIOC_DBG_G_CHIP_NAME ioctl. This will eventually replace VIDIOC_DBG_G_CHIP_IDENT. Chip matching is done by the name or index of subdevices or an index to a bridge chip. Most of this can all be done automatically, so most drivers just need to provide get/set register ops. In particular, it is now possible to get/set subdev registers without requiring assistance of the bridge driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-common.c | 5 +- drivers/media/v4l2-core/v4l2-dev.c | 5 +- drivers/media/v4l2-core/v4l2-ioctl.c | 115 ++++++++++++++++++++++++++++++++-- include/media/v4l2-ioctl.h | 3 + include/uapi/linux/videodev2.h | 34 +++++++--- 5 files changed, 146 insertions(+), 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index a9e7703560ad..f8fac9cefc3c 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -230,7 +230,7 @@ EXPORT_SYMBOL(v4l2_ctrl_next); int v4l2_chip_match_host(const struct v4l2_dbg_match *match) { switch (match->type) { - case V4L2_CHIP_MATCH_HOST: + case V4L2_CHIP_MATCH_BRIDGE: return match->addr == 0; default: return 0; @@ -254,6 +254,9 @@ int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match return len && !strncmp(c->driver->driver.name, match->name, len); case V4L2_CHIP_MATCH_I2C_ADDR: return c->addr == match->addr; + case V4L2_CHIP_MATCH_SUBDEV_IDX: + case V4L2_CHIP_MATCH_SUBDEV_NAME: + return 1; default: return 0; } diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 1fbd95755e75..670b9ca8ecbe 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -591,9 +591,10 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency); SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency); SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status); + set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_NAME), valid_ioctls); #ifdef CONFIG_VIDEO_ADV_DEBUG - SET_VALID_IOCTL(ops, VIDIOC_DBG_G_REGISTER, vidioc_g_register); - SET_VALID_IOCTL(ops, VIDIOC_DBG_S_REGISTER, vidioc_s_register); + set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls); #endif SET_VALID_IOCTL(ops, VIDIOC_DBG_G_CHIP_IDENT, vidioc_g_chip_ident); /* yes, really vidioc_subscribe_event */ diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 83aa39dfe07c..336ed2dd607c 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -629,7 +629,8 @@ static void v4l_print_dbg_chip_ident(const void *arg, bool write_only) const struct v4l2_dbg_chip_ident *p = arg; pr_cont("type=%u, ", p->match.type); - if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) pr_cont("name=%.*s, ", (int)sizeof(p->match.name), p->match.name); else @@ -638,12 +639,27 @@ static void v4l_print_dbg_chip_ident(const void *arg, bool write_only) p->ident, p->revision); } +static void v4l_print_dbg_chip_name(const void *arg, bool write_only) +{ + const struct v4l2_dbg_chip_name *p = arg; + + pr_cont("type=%u, ", p->match.type); + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) + pr_cont("name=%.*s, ", + (int)sizeof(p->match.name), p->match.name); + else + pr_cont("addr=%u, ", p->match.addr); + pr_cont("name=%.*s\n", (int)sizeof(p->name), p->name); +} + static void v4l_print_dbg_register(const void *arg, bool write_only) { const struct v4l2_dbg_register *p = arg; pr_cont("type=%u, ", p->match.type); - if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) pr_cont("name=%.*s, ", (int)sizeof(p->match.name), p->match.name); else @@ -1775,15 +1791,38 @@ static int v4l_log_status(const struct v4l2_ioctl_ops *ops, return ret; } +static bool v4l_dbg_found_match(const struct v4l2_dbg_match *match, + struct v4l2_subdev *sd, int idx) +{ + if (match->type == V4L2_CHIP_MATCH_SUBDEV_IDX) + return match->addr == idx; + return !strcmp(match->name, sd->name); +} + static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { #ifdef CONFIG_VIDEO_ADV_DEBUG struct v4l2_dbg_register *p = arg; + struct video_device *vfd = video_devdata(file); + struct v4l2_subdev *sd; + int idx = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - return ops->vidioc_g_register(file, fh, p); + if (p->match.type == V4L2_CHIP_MATCH_SUBDEV_IDX || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) { + if (vfd->v4l2_dev == NULL) + return -EINVAL; + v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { + if (v4l_dbg_found_match(&p->match, sd, idx++)) + return v4l2_subdev_call(sd, core, g_register, p); + } + return -EINVAL; + } + if (ops->vidioc_g_register) + return ops->vidioc_g_register(file, fh, p); + return -EINVAL; #else return -ENOTTY; #endif @@ -1794,10 +1833,25 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops, { #ifdef CONFIG_VIDEO_ADV_DEBUG const struct v4l2_dbg_register *p = arg; + struct video_device *vfd = video_devdata(file); + struct v4l2_subdev *sd; + int idx = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - return ops->vidioc_s_register(file, fh, p); + if (p->match.type == V4L2_CHIP_MATCH_SUBDEV_IDX || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) { + if (vfd->v4l2_dev == NULL) + return -EINVAL; + v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { + if (v4l_dbg_found_match(&p->match, sd, idx++)) + return v4l2_subdev_call(sd, core, s_register, p); + } + return -EINVAL; + } + if (ops->vidioc_s_register) + return ops->vidioc_s_register(file, fh, p); + return -EINVAL; #else return -ENOTTY; #endif @@ -1810,9 +1864,61 @@ static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops, p->ident = V4L2_IDENT_NONE; p->revision = 0; + if (p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME || + p->match.type == V4L2_CHIP_MATCH_SUBDEV_IDX) + return -EINVAL; return ops->vidioc_g_chip_ident(file, fh, p); } +static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, + struct file *file, void *fh, void *arg) +{ + struct video_device *vfd = video_devdata(file); + struct v4l2_dbg_chip_name *p = arg; + struct v4l2_subdev *sd; + int idx = 0; + + switch (p->match.type) { + case V4L2_CHIP_MATCH_BRIDGE: +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (ops->vidioc_s_register) + p->flags |= V4L2_CHIP_FL_WRITABLE; + if (ops->vidioc_g_register) + p->flags |= V4L2_CHIP_FL_READABLE; +#endif + if (ops->vidioc_g_chip_name) + return ops->vidioc_g_chip_name(file, fh, arg); + if (p->match.addr) + return -EINVAL; + if (vfd->v4l2_dev) + strlcpy(p->name, vfd->v4l2_dev->name, sizeof(p->name)); + else if (vfd->parent) + strlcpy(p->name, vfd->parent->driver->name, sizeof(p->name)); + else + strlcpy(p->name, "bridge", sizeof(p->name)); + return 0; + + case V4L2_CHIP_MATCH_SUBDEV_IDX: + case V4L2_CHIP_MATCH_SUBDEV_NAME: + if (vfd->v4l2_dev == NULL) + break; + v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { + if (v4l_dbg_found_match(&p->match, sd, idx++)) { +#ifdef CONFIG_VIDEO_ADV_DEBUG + if (sd->ops->core && sd->ops->core->s_register) + p->flags |= V4L2_CHIP_FL_WRITABLE; + if (sd->ops->core && sd->ops->core->g_register) + p->flags |= V4L2_CHIP_FL_READABLE; +#endif + strlcpy(p->name, sd->name, sizeof(p->name)); + return 0; + } + } + break; + } + return -EINVAL; +} + static int v4l_dqevent(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -2027,6 +2133,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_STD(VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings, v4l_print_dv_timings, 0), IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, type)), IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0), + IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_NAME, v4l_dbg_g_chip_name, v4l_print_dbg_chip_name, INFO_FL_CLEAR(v4l2_dbg_chip_name, match)), }; #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index e10c2432f902..75a7dfc07dec 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -247,6 +247,9 @@ struct v4l2_ioctl_ops { int (*vidioc_g_chip_ident) (struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip); + int (*vidioc_g_chip_name) (struct file *file, void *fh, + struct v4l2_dbg_chip_name *chip); + int (*vidioc_enum_framesizes) (struct file *file, void *fh, struct v4l2_frmsizeenum *fsize); diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 9d57dba27412..e9c49c5e6416 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1807,10 +1807,13 @@ struct v4l2_event_subscription { /* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */ -#define V4L2_CHIP_MATCH_HOST 0 /* Match against chip ID on host (0 for the host) */ -#define V4L2_CHIP_MATCH_I2C_DRIVER 1 /* Match against I2C driver name */ -#define V4L2_CHIP_MATCH_I2C_ADDR 2 /* Match against I2C 7-bit address */ -#define V4L2_CHIP_MATCH_AC97 3 /* Match against anciliary AC97 chip */ +#define V4L2_CHIP_MATCH_BRIDGE 0 /* Match against chip ID on the bridge (0 for the bridge) */ +#define V4L2_CHIP_MATCH_HOST V4L2_CHIP_MATCH_BRIDGE +#define V4L2_CHIP_MATCH_I2C_DRIVER 1 /* Match against I2C driver name */ +#define V4L2_CHIP_MATCH_I2C_ADDR 2 /* Match against I2C 7-bit address */ +#define V4L2_CHIP_MATCH_AC97 3 /* Match against anciliary AC97 chip */ +#define V4L2_CHIP_MATCH_SUBDEV_NAME 4 /* Match against subdev name */ +#define V4L2_CHIP_MATCH_SUBDEV_IDX 5 /* Match against subdev index */ struct v4l2_dbg_match { __u32 type; /* Match type */ @@ -1834,6 +1837,17 @@ struct v4l2_dbg_chip_ident { __u32 revision; /* chip revision, chip specific */ } __attribute__ ((packed)); +#define V4L2_CHIP_FL_READABLE (1 << 0) +#define V4L2_CHIP_FL_WRITABLE (1 << 1) + +/* VIDIOC_DBG_G_CHIP_NAME */ +struct v4l2_dbg_chip_name { + struct v4l2_dbg_match match; + char name[32]; + __u32 flags; + __u32 reserved[8]; +} __attribute__ ((packed)); + /** * struct v4l2_create_buffers - VIDIOC_CREATE_BUFS argument * @index: on return, index of the first created buffer @@ -1911,15 +1925,12 @@ struct v4l2_create_buffers { #define VIDIOC_G_EXT_CTRLS _IOWR('V', 71, struct v4l2_ext_controls) #define VIDIOC_S_EXT_CTRLS _IOWR('V', 72, struct v4l2_ext_controls) #define VIDIOC_TRY_EXT_CTRLS _IOWR('V', 73, struct v4l2_ext_controls) -#if 1 #define VIDIOC_ENUM_FRAMESIZES _IOWR('V', 74, struct v4l2_frmsizeenum) #define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct v4l2_frmivalenum) #define VIDIOC_G_ENC_INDEX _IOR('V', 76, struct v4l2_enc_idx) #define VIDIOC_ENCODER_CMD _IOWR('V', 77, struct v4l2_encoder_cmd) #define VIDIOC_TRY_ENCODER_CMD _IOWR('V', 78, struct v4l2_encoder_cmd) -#endif -#if 1 /* Experimental, meant for debugging, testing and internal use. Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined. You must be root to use these ioctls. Never use these in applications! */ @@ -1927,9 +1938,10 @@ struct v4l2_create_buffers { #define VIDIOC_DBG_G_REGISTER _IOWR('V', 80, struct v4l2_dbg_register) /* Experimental, meant for debugging, testing and internal use. - Never use this ioctl in applications! */ + Never use this ioctl in applications! + Note: this ioctl is deprecated in favor of VIDIOC_DBG_G_CHIP_NAME and + will go away in the future. */ #define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_dbg_chip_ident) -#endif #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) @@ -1963,6 +1975,10 @@ struct v4l2_create_buffers { versions. */ #define VIDIOC_ENUM_FREQ_BANDS _IOWR('V', 101, struct v4l2_frequency_band) +/* Experimental, meant for debugging, testing and internal use. + Never use these in applications! */ +#define VIDIOC_DBG_G_CHIP_NAME _IOWR('V', 102, struct v4l2_dbg_chip_name) + /* Reminder: when adding new ioctls please add support for them to drivers/media/video/v4l2-compat-ioctl32.c as well! */ -- cgit v1.2.3 From c7622fc9483f57f0dd77ad50e104b7e53d6b365d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 18 Mar 2013 12:20:36 -0300 Subject: [media] stk1160: remove V4L2_CHIP_MATCH_AC97 placeholder It was just a placeholder and we want to get rid of the AC97 matching define. Also replace MATCH_HOST with MATCH_BRIDGE since we are here anyway. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stk1160/stk1160-v4l.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index c4c723b92f6e..a59153d2f8bf 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -458,7 +458,7 @@ static int vidioc_g_chip_ident(struct file *file, void *priv, struct v4l2_dbg_chip_ident *chip) { switch (chip->match.type) { - case V4L2_CHIP_MATCH_HOST: + case V4L2_CHIP_MATCH_BRIDGE: chip->ident = V4L2_IDENT_NONE; chip->revision = 0; return 0; @@ -476,9 +476,6 @@ static int vidioc_g_register(struct file *file, void *priv, u8 val; switch (reg->match.type) { - case V4L2_CHIP_MATCH_AC97: - /* TODO: Support me please :-( */ - return -EINVAL; case V4L2_CHIP_MATCH_I2C_DRIVER: v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); return 0; @@ -505,8 +502,6 @@ static int vidioc_s_register(struct file *file, void *priv, struct stk1160 *dev = video_drvdata(file); switch (reg->match.type) { - case V4L2_CHIP_MATCH_AC97: - return -EINVAL; case V4L2_CHIP_MATCH_I2C_DRIVER: v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); return 0; -- cgit v1.2.3 From 3b2d17b4ba77dce3a83c9e71dc8f086d7e743ec9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 18 Mar 2013 12:21:53 -0300 Subject: [media] em28xx: add support for g_chip_name Add support for vidioc_g_chip_name, allowing AC97 to be implemented as a second chip on the bridge with the name "ac97". v4l2-dbg can just match the name with that string in order to detect a ac97-compliant set of registers. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 41 +++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index d09b5c03c723..b1817231f50c 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1245,9 +1245,9 @@ static int vidioc_g_chip_ident(struct file *file, void *priv, chip->ident = V4L2_IDENT_NONE; chip->revision = 0; - if (chip->match.type == V4L2_CHIP_MATCH_HOST) { - if (v4l2_chip_match_host(&chip->match)) - chip->ident = V4L2_IDENT_NONE; + if (chip->match.type == V4L2_CHIP_MATCH_BRIDGE) { + if (chip->match.addr > 1) + return -EINVAL; return 0; } if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER && @@ -1259,6 +1259,21 @@ static int vidioc_g_chip_ident(struct file *file, void *priv, return 0; } +static int vidioc_g_chip_name(struct file *file, void *priv, + struct v4l2_dbg_chip_name *chip) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + + if (chip->match.addr > 1) + return -EINVAL; + if (chip->match.addr == 1) + strlcpy(chip->name, "ac97", sizeof(chip->name)); + else + strlcpy(chip->name, dev->v4l2_dev.name, sizeof(chip->name)); + return 0; +} + #ifdef CONFIG_VIDEO_ADV_DEBUG static int em28xx_reg_len(int reg) { @@ -1280,6 +1295,12 @@ static int vidioc_g_register(struct file *file, void *priv, int ret; switch (reg->match.type) { + case V4L2_CHIP_MATCH_BRIDGE: + if (reg->match.addr > 1) + return -EINVAL; + if (!reg->match.addr) + break; + /* fall-through */ case V4L2_CHIP_MATCH_AC97: ret = em28xx_read_ac97(dev, reg->reg); if (ret < 0) @@ -1296,8 +1317,7 @@ static int vidioc_g_register(struct file *file, void *priv, v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg); return 0; default: - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; + return -EINVAL; } /* Match host */ @@ -1330,6 +1350,12 @@ static int vidioc_s_register(struct file *file, void *priv, __le16 buf; switch (reg->match.type) { + case V4L2_CHIP_MATCH_BRIDGE: + if (reg->match.addr > 1) + return -EINVAL; + if (!reg->match.addr) + break; + /* fall-through */ case V4L2_CHIP_MATCH_AC97: return em28xx_write_ac97(dev, reg->reg, reg->val); case V4L2_CHIP_MATCH_I2C_DRIVER: @@ -1340,8 +1366,7 @@ static int vidioc_s_register(struct file *file, void *priv, v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg); return 0; default: - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; + return -EINVAL; } /* Match host */ @@ -1699,6 +1724,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_g_chip_ident = vidioc_g_chip_ident, + .vidioc_g_chip_name = vidioc_g_chip_name, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, @@ -1729,6 +1755,7 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_g_chip_ident = vidioc_g_chip_ident, + .vidioc_g_chip_name = vidioc_g_chip_name, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, -- cgit v1.2.3 From 5a4bdb4b34b90655891f627679bbba0ed9791c2e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 08:04:29 -0300 Subject: [media] au8522_decoder: convert to the control framework Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/au8522_decoder.c | 130 +++++++++------------------ drivers/media/dvb-frontends/au8522_priv.h | 6 +- 2 files changed, 46 insertions(+), 90 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c index 526902b45f9c..ad46a8f86af0 100644 --- a/drivers/media/dvb-frontends/au8522_decoder.c +++ b/drivers/media/dvb-frontends/au8522_decoder.c @@ -229,15 +229,11 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode) /* Provide reasonable defaults for picture tuning values */ au8522_writereg(state, AU8522_TVDEC_SHARPNESSREG009H, 0x07); au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, 0xed); - state->brightness = 0xed - 128; au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, 0x79); - state->contrast = 0x79; au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, 0x80); au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, 0x80); - state->saturation = 0x80; au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, 0x00); au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, 0x00); - state->hue = 0x00; /* Other decoder registers */ au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00); @@ -489,75 +485,32 @@ static void set_audio_input(struct au8522_state *state, int aud_input) /* ----------------------------------------------------------------------- */ -static int au8522_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) +static int au8522_s_ctrl(struct v4l2_ctrl *ctrl) { - struct au8522_state *state = to_state(sd); + struct au8522_state *state = + container_of(ctrl->handler, struct au8522_state, hdl); switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - state->brightness = ctrl->value; au8522_writereg(state, AU8522_TVDEC_BRIGHTNESS_REG00AH, - ctrl->value - 128); + ctrl->val - 128); break; case V4L2_CID_CONTRAST: - state->contrast = ctrl->value; au8522_writereg(state, AU8522_TVDEC_CONTRAST_REG00BH, - ctrl->value); + ctrl->val); break; case V4L2_CID_SATURATION: - state->saturation = ctrl->value; au8522_writereg(state, AU8522_TVDEC_SATURATION_CB_REG00CH, - ctrl->value); + ctrl->val); au8522_writereg(state, AU8522_TVDEC_SATURATION_CR_REG00DH, - ctrl->value); + ctrl->val); break; case V4L2_CID_HUE: - state->hue = ctrl->value; au8522_writereg(state, AU8522_TVDEC_HUE_H_REG00EH, - ctrl->value >> 8); + ctrl->val >> 8); au8522_writereg(state, AU8522_TVDEC_HUE_L_REG00FH, - ctrl->value & 0xFF); - break; - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_MUTE: - /* Not yet implemented */ - default: - return -EINVAL; - } - - return 0; -} - -static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct au8522_state *state = to_state(sd); - - /* Note that we are using values cached in the state structure instead - of reading the registers due to issues with i2c reads not working - properly/consistently yet on the HVR-950q */ - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = state->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = state->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = state->saturation; - break; - case V4L2_CID_HUE: - ctrl->value = state->hue; + ctrl->val & 0xFF); break; - case V4L2_CID_AUDIO_VOLUME: - case V4L2_CID_AUDIO_BASS: - case V4L2_CID_AUDIO_TREBLE: - case V4L2_CID_AUDIO_BALANCE: - case V4L2_CID_AUDIO_MUTE: - /* Not yet supported */ default: return -EINVAL; } @@ -616,26 +569,6 @@ static int au8522_s_stream(struct v4l2_subdev *sd, int enable) return 0; } -static int au8522_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - switch (qc->id) { - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, - AU8522_TVDEC_CONTRAST_REG00BH_CVBS); - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 109); - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, -32768, 32768, 1, 0); - default: - break; - } - - qc->type = 0; - return -EINVAL; -} - static int au8522_reset(struct v4l2_subdev *sd, u32 val) { struct au8522_state *state = to_state(sd); @@ -712,20 +645,18 @@ static int au8522_g_chip_ident(struct v4l2_subdev *sd, return v4l2_chip_ident_i2c_client(client, chip, state->id, state->rev); } -static int au8522_log_status(struct v4l2_subdev *sd) -{ - /* FIXME: Add some status info here */ - return 0; -} - /* ----------------------------------------------------------------------- */ static const struct v4l2_subdev_core_ops au8522_core_ops = { - .log_status = au8522_log_status, + .log_status = v4l2_ctrl_subdev_log_status, + .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, + .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, + .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, + .g_ctrl = v4l2_subdev_g_ctrl, + .s_ctrl = v4l2_subdev_s_ctrl, + .queryctrl = v4l2_subdev_queryctrl, + .querymenu = v4l2_subdev_querymenu, .g_chip_ident = au8522_g_chip_ident, - .g_ctrl = au8522_g_ctrl, - .s_ctrl = au8522_s_ctrl, - .queryctrl = au8522_queryctrl, .reset = au8522_reset, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = au8522_g_register, @@ -753,12 +684,17 @@ static const struct v4l2_subdev_ops au8522_ops = { .video = &au8522_video_ops, }; +static const struct v4l2_ctrl_ops au8522_ctrl_ops = { + .s_ctrl = au8522_s_ctrl, +}; + /* ----------------------------------------------------------------------- */ static int au8522_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct au8522_state *state; + struct v4l2_ctrl_handler *hdl; struct v4l2_subdev *sd; int instance; struct au8522_config *demod_config; @@ -799,6 +735,27 @@ static int au8522_probe(struct i2c_client *client, sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &au8522_ops); + hdl = &state->hdl; + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 109); + v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, + AU8522_TVDEC_CONTRAST_REG00BH_CVBS); + v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 128); + v4l2_ctrl_new_std(hdl, &au8522_ctrl_ops, + V4L2_CID_HUE, -32768, 32767, 1, 0); + sd->ctrl_handler = hdl; + if (hdl->error) { + int err = hdl->error; + + v4l2_ctrl_handler_free(hdl); + kfree(demod_config); + kfree(state); + return err; + } + state->c = client; state->vid_input = AU8522_COMPOSITE_CH1; state->aud_input = AU8522_AUDIO_NONE; @@ -815,6 +772,7 @@ static int au8522_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(sd->ctrl_handler); au8522_release_state(to_state(sd)); return 0; } diff --git a/drivers/media/dvb-frontends/au8522_priv.h b/drivers/media/dvb-frontends/au8522_priv.h index 0529699a27bd..aa0f16d6b610 100644 --- a/drivers/media/dvb-frontends/au8522_priv.h +++ b/drivers/media/dvb-frontends/au8522_priv.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include "dvb_frontend.h" #include "au8522.h" @@ -65,10 +66,7 @@ struct au8522_state { int aud_input; u32 id; u32 rev; - u8 brightness; - u8 contrast; - u8 saturation; - s16 hue; + struct v4l2_ctrl_handler hdl; }; /* These are routines shared by both the VSB/QAM demodulator and the analog -- cgit v1.2.3 From 59e0548453bc24077e32748857e754d4bda2ab73 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 08:11:04 -0300 Subject: [media] au0828: fix querycap Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 79f1d510cc2e..ba90ffb3d921 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1241,20 +1241,25 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct au0828_fh *fh = priv; + struct video_device *vdev = video_devdata(file); + struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; strlcpy(cap->driver, "au0828", sizeof(cap->driver)); strlcpy(cap->card, dev->board.name, sizeof(cap->card)); - strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); + usb_make_path(dev->usbdev, cap->bus_info, sizeof(cap->bus_info)); - /*set the device capabilities */ - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_AUDIO | + /* set the device capabilities */ + cap->device_caps = V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_TUNER; + if (vdev->vfl_type == VFL_TYPE_GRABBER) + cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; + else + cap->device_caps |= V4L2_CAP_VBI_CAPTURE; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS | + V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE; return 0; } -- cgit v1.2.3 From e1cf6587d5ba2085d7e5eae064b1adde5d07f801 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 22 Mar 2013 13:32:20 -0300 Subject: [media] au0828: frequency handling fixes - define an initial frequency - return an error if g_frequency is called for an invalid tuner index - get the clamped frequency value after setting it: i.e. the tuner driver may clamp the given frequency to a valid frequency range and ctrl_freq should get that actual clamped frequency. - remove obsolete tuner type checks (done by the core). Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index ba90ffb3d921..8562cca80b36 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1542,7 +1542,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; - freq->type = V4L2_TUNER_ANALOG_TV; + if (freq->tuner != 0) + return -EINVAL; freq->frequency = dev->ctrl_freq; return 0; } @@ -1552,13 +1553,10 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; + struct v4l2_frequency new_freq = *freq; if (freq->tuner != 0) return -EINVAL; - if (freq->type != V4L2_TUNER_ANALOG_TV) - return -EINVAL; - - dev->ctrl_freq = freq->frequency; if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl) dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1); @@ -1573,6 +1571,9 @@ static int vidioc_s_frequency(struct file *file, void *priv, } v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq); + /* Get the actual set (and possibly clamped) frequency */ + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq); + dev->ctrl_freq = new_freq.frequency; if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl) dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0); @@ -1976,6 +1977,7 @@ int au0828_analog_register(struct au0828_dev *dev, dev->frame_size = dev->field_size << 1; dev->bytesperline = dev->width << 1; dev->ctrl_ainput = 0; + dev->ctrl_freq = 960; /* allocate and fill v4l2 video struct */ dev->vdev = video_device_alloc(); -- cgit v1.2.3 From 38823b29e70ab6d6b7092ce2fcafe299d0c5dd74 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 08:28:27 -0300 Subject: [media] au0828: fix intendation coding style issue No code change, just fixing a wrong indentation. Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 8562cca80b36..d0a438a4b9e5 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1562,12 +1562,12 @@ static int vidioc_s_frequency(struct file *file, void *priv, dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1); if (dev->std_set_in_tuner_core == 0) { - /* If we've never sent the standard in tuner core, do so now. We - don't do this at device probe because we don't want to incur - the cost of a firmware load */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, - dev->vdev->tvnorms); - dev->std_set_in_tuner_core = 1; + /* If we've never sent the standard in tuner core, do so now. + We don't do this at device probe because we don't want to + incur the cost of a firmware load */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, + dev->vdev->tvnorms); + dev->std_set_in_tuner_core = 1; } v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq); -- cgit v1.2.3 From a2cf96f929d54cb2c8041358053656bf76be2c34 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 08:41:24 -0300 Subject: [media] au0828: fix audio input handling - V4L2_CAP_AUDIO was set, but enumaudio was not implemented. - audioset was never filled by enum_input - ctrl_ainput was never updated when switching the video input - g_audio was broken due to faulty logic: g_audio should set the index, it doesn't receive it from the user. Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 35 ++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index d0a438a4b9e5..28071ff756e2 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1373,10 +1373,13 @@ static int vidioc_enum_input(struct file *file, void *priv, input->index = tmp; strcpy(input->name, inames[AUVI_INPUT(tmp).type]); if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) || - (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE)) + (AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE)) { input->type |= V4L2_INPUT_TYPE_TUNER; - else + input->audioset = 1; + } else { input->type |= V4L2_INPUT_TYPE_CAMERA; + input->audioset = 2; + } input->std = dev->vdev->tvnorms; @@ -1408,12 +1411,15 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index) switch (AUVI_INPUT(index).type) { case AU0828_VMUX_SVIDEO: dev->input_type = AU0828_VMUX_SVIDEO; + dev->ctrl_ainput = 1; break; case AU0828_VMUX_COMPOSITE: dev->input_type = AU0828_VMUX_COMPOSITE; + dev->ctrl_ainput = 1; break; case AU0828_VMUX_TELEVISION: dev->input_type = AU0828_VMUX_TELEVISION; + dev->ctrl_ainput = 0; break; default: dprintk(1, "VIDIOC_S_INPUT unknown input type set [%d]\n", @@ -1450,23 +1456,32 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index) return 0; } +static int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *a) +{ + if (a->index > 1) + return -EINVAL; + + if (a->index == 0) + strcpy(a->name, "Television"); + else + strcpy(a->name, "Line in"); + + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; - unsigned int index = a->index; - if (a->index > 1) - return -EINVAL; - - index = dev->ctrl_ainput; - if (index == 0) + a->index = dev->ctrl_ainput; + if (a->index == 0) strcpy(a->name, "Television"); else strcpy(a->name, "Line in"); a->capability = V4L2_AUDCAP_STEREO; - a->index = index; return 0; } @@ -1474,6 +1489,7 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio { struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; + if (a->index != dev->ctrl_ainput) return -EINVAL; return 0; @@ -1877,6 +1893,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, .vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, + .vidioc_enumaudio = vidioc_enumaudio, .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, .vidioc_cropcap = vidioc_cropcap, -- cgit v1.2.3 From e8c26f45b1f7e57ecf297903158823ecaa32c513 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 08:55:41 -0300 Subject: [media] au0828: convert to the control framework Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 15 +++++++++++-- drivers/media/usb/au0828/au0828-video.c | 39 ++------------------------------- drivers/media/usb/au0828/au0828.h | 2 ++ 3 files changed, 17 insertions(+), 39 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 1e6f40ef1c6b..ffd3bcba9c10 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -143,6 +143,7 @@ static void au0828_usb_disconnect(struct usb_interface *interface) au0828_i2c_unregister(dev); #ifdef CONFIG_VIDEO_AU0828_V4L2 + v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl); v4l2_device_unregister(&dev->v4l2_dev); #endif @@ -205,12 +206,22 @@ static int au0828_usb_probe(struct usb_interface *interface, /* Create the v4l2_device */ retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); if (retval) { - printk(KERN_ERR "%s() v4l2_device_register failed\n", + pr_err("%s() v4l2_device_register failed\n", __func__); mutex_unlock(&dev->lock); kfree(dev); - return -EIO; + return retval; } + /* This control handler will inherit the controls from au8522 */ + retval = v4l2_ctrl_handler_init(&dev->v4l2_ctrl_hdl, 4); + if (retval) { + pr_err("%s() v4l2_ctrl_handler_init failed\n", + __func__); + mutex_unlock(&dev->lock); + kfree(dev); + return retval; + } + dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl; #endif /* Power Up the bridge */ diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 28071ff756e2..afb600f9daa6 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1226,18 +1226,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd, } -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc); - if (qc->type) - return 0; - else - return -EINVAL; -} - static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -1495,26 +1483,6 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio return 0; } -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - - v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl); - return 0; - -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl); - return 0; -} - static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct au0828_fh *fh = priv; @@ -1905,9 +1873,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_g_tuner = vidioc_g_tuner, @@ -2013,13 +1978,13 @@ int au0828_analog_register(struct au0828_dev *dev, /* Fill the video capture device struct */ *dev->vdev = au0828_video_template; - dev->vdev->parent = &dev->usbdev->dev; + dev->vdev->v4l2_dev = &dev->v4l2_dev; dev->vdev->lock = &dev->lock; strcpy(dev->vdev->name, "au0828a video"); /* Setup the VBI device */ *dev->vbi_dev = au0828_video_template; - dev->vbi_dev->parent = &dev->usbdev->dev; + dev->vbi_dev->v4l2_dev = &dev->v4l2_dev; dev->vbi_dev->lock = &dev->lock; strcpy(dev->vbi_dev->name, "au0828a vbi"); diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index e579ff69ca4a..803af10f5130 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -28,6 +28,7 @@ #include #include #include +#include /* DVB */ #include "demux.h" @@ -202,6 +203,7 @@ struct au0828_dev { #ifdef CONFIG_VIDEO_AU0828_V4L2 /* Analog */ struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler v4l2_ctrl_hdl; #endif int users; unsigned int resources; /* resources in use */ -- cgit v1.2.3 From 83b0942232ba264d2ffe1b13f9ae62cafbd02399 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 09:14:00 -0300 Subject: [media] au0828: add prio, control event and log_status support Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 42 ++++++++++++++++++++++++++------- drivers/media/usb/au0828/au0828.h | 4 ++++ 2 files changed, 37 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index afb600f9daa6..97397a660af7 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include "au0828.h" @@ -988,6 +989,7 @@ static int au0828_v4l2_open(struct file *filp) fh->type = type; fh->dev = dev; + v4l2_fh_init(&fh->fh, vdev); filp->private_data = fh; if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { @@ -1031,6 +1033,7 @@ static int au0828_v4l2_open(struct file *filp) V4L2_FIELD_SEQ_TB, sizeof(struct au0828_buffer), fh, &dev->lock); + v4l2_fh_add(&fh->fh); return ret; } @@ -1040,6 +1043,8 @@ static int au0828_v4l2_close(struct file *filp) struct au0828_fh *fh = filp->private_data; struct au0828_dev *dev = fh->dev; + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); if (res_check(fh, AU0828_RESOURCE_VIDEO)) { /* Cancel timeout thread in case they didn't call streamoff */ dev->vid_timeout_running = 0; @@ -1061,6 +1066,7 @@ static int au0828_v4l2_close(struct file *filp) if (dev->users == 1) { if (dev->dev_state & DEV_DISCONNECTED) { au0828_analog_unregister(dev); + kfree(fh); kfree(dev); return 0; } @@ -1128,23 +1134,27 @@ static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait) { struct au0828_fh *fh = filp->private_data; struct au0828_dev *dev = fh->dev; - int rc; + unsigned long req_events = poll_requested_events(wait); + unsigned int res; - rc = check_dev(dev); - if (rc < 0) - return rc; + if (check_dev(dev) < 0) + return POLLERR; + + res = v4l2_ctrl_poll(filp, wait); + if (!(req_events & (POLLIN | POLLRDNORM))) + return res; if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { if (!res_get(fh, AU0828_RESOURCE_VIDEO)) return POLLERR; - return videobuf_poll_stream(filp, &fh->vb_vidq, wait); - } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + return res | videobuf_poll_stream(filp, &fh->vb_vidq, wait); + } + if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) { if (!res_get(fh, AU0828_RESOURCE_VBI)) return POLLERR; - return videobuf_poll_stream(filp, &fh->vb_vbiq, wait); - } else { - return POLLERR; + return res | videobuf_poll_stream(filp, &fh->vb_vbiq, wait); } + return POLLERR; } static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) @@ -1761,6 +1771,15 @@ static int vidioc_s_register(struct file *file, void *priv, } #endif +static int vidioc_log_status(struct file *file, void *fh) +{ + struct video_device *vdev = video_devdata(file); + + v4l2_ctrl_log_status(file, fh); + v4l2_device_call_all(vdev->v4l2_dev, 0, core, log_status); + return 0; +} + static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *rb) { @@ -1884,6 +1903,9 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_s_register = vidioc_s_register, #endif .vidioc_g_chip_ident = vidioc_g_chip_ident, + .vidioc_log_status = vidioc_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static const struct video_device au0828_video_template = { @@ -1980,12 +2002,14 @@ int au0828_analog_register(struct au0828_dev *dev, *dev->vdev = au0828_video_template; dev->vdev->v4l2_dev = &dev->v4l2_dev; dev->vdev->lock = &dev->lock; + set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev->flags); strcpy(dev->vdev->name, "au0828a video"); /* Setup the VBI device */ *dev->vbi_dev = au0828_video_template; dev->vbi_dev->v4l2_dev = &dev->v4l2_dev; dev->vbi_dev->lock = &dev->lock; + set_bit(V4L2_FL_USE_FH_PRIO, &dev->vbi_dev->flags); strcpy(dev->vbi_dev->name, "au0828a vbi"); /* Register the v4l2 device */ diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index 803af10f5130..ad400482b2f3 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -29,6 +29,7 @@ #include #include #include +#include /* DVB */ #include "demux.h" @@ -119,6 +120,9 @@ enum au0828_dev_state { }; struct au0828_fh { + /* must be the first field of this struct! */ + struct v4l2_fh fh; + struct au0828_dev *dev; unsigned int resources; -- cgit v1.2.3 From 8d86e4e814c72cb1b1145c2e645727b46eee3b45 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 17:48:34 -0300 Subject: [media] au0828: add try_fmt_vbi support, zero vbi.reserved, pix.priv Also get rid of unnecessary format type check. Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 97397a660af7..5cec18bb7966 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1182,9 +1182,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd, int width = format->fmt.pix.width; int height = format->fmt.pix.height; - if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - /* If they are demanding a format other than the one we support, bail out (tvtime asks for UYVY and then retries with YUYV) */ if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY) @@ -1203,6 +1200,7 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd, format->fmt.pix.sizeimage = width * height * 2; format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; format->fmt.pix.field = V4L2_FIELD_INTERLACED; + format->fmt.pix.priv = 0; if (cmd == VIDIOC_TRY_FMT) return 0; @@ -1289,6 +1287,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.sizeimage = dev->frame_size; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* NTSC/PAL */ f->fmt.pix.field = V4L2_FIELD_INTERLACED; + f->fmt.pix.priv = 0; return 0; } @@ -1596,6 +1595,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, format->fmt.vbi.count[1] = dev->vbi_height; format->fmt.vbi.start[0] = 21; format->fmt.vbi.start[1] = 284; + memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved)); return 0; } @@ -1879,6 +1879,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, + .vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, .vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, .vidioc_enumaudio = vidioc_enumaudio, .vidioc_g_audio = vidioc_g_audio, -- cgit v1.2.3 From 33b6b89bd32ff54ac17fa07408e9743b20542542 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 09:22:37 -0300 Subject: [media] au0828: replace deprecated current_norm by g_std Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 13 ++++++++++++- drivers/media/usb/au0828/au0828.h | 1 + 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 5cec18bb7966..691df9157e51 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1339,10 +1339,20 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl) dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0); + dev->std = norm; return 0; } +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + *norm = dev->std; + return 0; +} + static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *input) { @@ -1890,6 +1900,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, @@ -1914,7 +1925,6 @@ static const struct video_device au0828_video_template = { .release = video_device_release, .ioctl_ops = &video_ioctl_ops, .tvnorms = V4L2_STD_NTSC_M, - .current_norm = V4L2_STD_NTSC_M, }; /**************************************************************************/ @@ -1983,6 +1993,7 @@ int au0828_analog_register(struct au0828_dev *dev, dev->bytesperline = dev->width << 1; dev->ctrl_ainput = 0; dev->ctrl_freq = 960; + dev->std = V4L2_STD_NTSC_M; /* allocate and fill v4l2 video struct */ dev->vdev = video_device_alloc(); diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index ad400482b2f3..ef1f57f22be7 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -222,6 +222,7 @@ struct au0828_dev { int vbi_width; int vbi_height; u32 vbi_read; + v4l2_std_id std; u32 field_size; u32 frame_size; u32 bytesperline; -- cgit v1.2.3 From dc6d2a2f66a156ea90924abde553560481b6b57b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 09:24:08 -0300 Subject: [media] au8522_decoder: remove obsolete control ops Now that au0828 has been converted to the control framework these compatilibity ops are no longer needed. Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/au8522_decoder.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c index ad46a8f86af0..2099f21e374d 100644 --- a/drivers/media/dvb-frontends/au8522_decoder.c +++ b/drivers/media/dvb-frontends/au8522_decoder.c @@ -649,13 +649,6 @@ static int au8522_g_chip_ident(struct v4l2_subdev *sd, static const struct v4l2_subdev_core_ops au8522_core_ops = { .log_status = v4l2_ctrl_subdev_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, .g_chip_ident = au8522_g_chip_ident, .reset = au8522_reset, #ifdef CONFIG_VIDEO_ADV_DEBUG -- cgit v1.2.3 From 823beb7e22d04ed545e7adfcd5ec8db934218872 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 10:16:45 -0300 Subject: [media] au0828: fix disconnect sequence The driver crashed when the device was disconnected while an application still had a device node open. Fixed by using the release() callback of struct v4l2_device. Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 48 +++++++++++++++++++++------------ drivers/media/usb/au0828/au0828-video.c | 9 +------ 2 files changed, 32 insertions(+), 25 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index ffd3bcba9c10..bd9d19a73efd 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -125,36 +125,48 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value, return status; } -static void au0828_usb_disconnect(struct usb_interface *interface) +static void au0828_usb_release(struct au0828_dev *dev) { - struct au0828_dev *dev = usb_get_intfdata(interface); - - dprintk(1, "%s()\n", __func__); - - /* Digital TV */ - au0828_dvb_unregister(dev); - -#ifdef CONFIG_VIDEO_AU0828_V4L2 - if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) - au0828_analog_unregister(dev); -#endif - /* I2C */ au0828_i2c_unregister(dev); + kfree(dev); +} + #ifdef CONFIG_VIDEO_AU0828_V4L2 +static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev) +{ + struct au0828_dev *dev = + container_of(v4l2_dev, struct au0828_dev, v4l2_dev); + v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl); v4l2_device_unregister(&dev->v4l2_dev); + au0828_usb_release(dev); +} #endif - usb_set_intfdata(interface, NULL); +static void au0828_usb_disconnect(struct usb_interface *interface) +{ + struct au0828_dev *dev = usb_get_intfdata(interface); + + dprintk(1, "%s()\n", __func__); + + /* Digital TV */ + au0828_dvb_unregister(dev); + usb_set_intfdata(interface, NULL); mutex_lock(&dev->mutex); dev->usbdev = NULL; mutex_unlock(&dev->mutex); - - kfree(dev); - +#ifdef CONFIG_VIDEO_AU0828_V4L2 + if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) { + au0828_analog_unregister(dev); + v4l2_device_disconnect(&dev->v4l2_dev); + v4l2_device_put(&dev->v4l2_dev); + return; + } +#endif + au0828_usb_release(dev); } static int au0828_usb_probe(struct usb_interface *interface, @@ -203,6 +215,8 @@ static int au0828_usb_probe(struct usb_interface *interface, dev->boardnr = id->driver_info; #ifdef CONFIG_VIDEO_AU0828_V4L2 + dev->v4l2_dev.release = au0828_usb_v4l2_release; + /* Create the v4l2_device */ retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev); if (retval) { diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 691df9157e51..3b525cb0078f 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1063,14 +1063,7 @@ static int au0828_v4l2_close(struct file *filp) res_free(fh, AU0828_RESOURCE_VBI); } - if (dev->users == 1) { - if (dev->dev_state & DEV_DISCONNECTED) { - au0828_analog_unregister(dev); - kfree(fh); - kfree(dev); - return 0; - } - + if (dev->users == 1 && video_is_registered(video_devdata(filp))) { au0828_analog_stream_disable(dev); au0828_uninit_isoc(dev); -- cgit v1.2.3 From fa09cb9a992be135fa6f3ac8a0841c478f29d844 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 16:10:33 -0300 Subject: [media] au0828: simplify i2c_gate_ctrl Turn it into a simple function. Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 3b525cb0078f..2f24e54cb837 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -59,6 +59,12 @@ do {\ } \ } while (0) +static inline void i2c_gate_ctrl(struct au0828_dev *dev, int val) +{ + if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl) + dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, val); +} + static inline void print_err_status(struct au0828_dev *dev, int packet, int status) { @@ -1320,8 +1326,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; - if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl) - dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1); + i2c_gate_ctrl(dev, 1); /* FIXME: when we support something other than NTSC, we are going to have to make the au0828 bridge adjust the size of its capture @@ -1330,8 +1335,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, norm); dev->std_set_in_tuner_core = 1; - if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl) - dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0); + i2c_gate_ctrl(dev, 0); dev->std = norm; return 0; @@ -1517,13 +1521,11 @@ static int vidioc_s_tuner(struct file *file, void *priv, if (t->index != 0) return -EINVAL; - if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl) - dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1); + i2c_gate_ctrl(dev, 1); v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); - if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl) - dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0); + i2c_gate_ctrl(dev, 0); dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal, t->afc); @@ -1554,8 +1556,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, if (freq->tuner != 0) return -EINVAL; - if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl) - dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1); + i2c_gate_ctrl(dev, 1); if (dev->std_set_in_tuner_core == 0) { /* If we've never sent the standard in tuner core, do so now. @@ -1571,8 +1572,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq); dev->ctrl_freq = new_freq.frequency; - if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl) - dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0); + i2c_gate_ctrl(dev, 0); au0828_analog_stream_reset(dev); -- cgit v1.2.3 From de8d2bbf0a6bebce51a2ab08adbb0dd897825777 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 16:12:17 -0300 Subject: [media] au0828: don't change global state information on open() Just opening a device shouldn't have any side-effects. Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 2f24e54cb837..6f2a6264d173 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1005,11 +1005,6 @@ static int au0828_v4l2_open(struct file *filp) printk(KERN_INFO "Au0828 can't set alternate to 5!\n"); return -EBUSY; } - dev->width = NTSC_STD_W; - dev->height = NTSC_STD_H; - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->width * dev->height; - dev->bytesperline = dev->width * 2; au0828_analog_stream_enable(dev); au0828_analog_stream_reset(dev); @@ -1031,8 +1026,6 @@ static int au0828_v4l2_open(struct file *filp) &dev->lock); /* VBI Setup */ - dev->vbi_width = 720; - dev->vbi_height = 1; videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops, NULL, &dev->slock, V4L2_BUF_TYPE_VBI_CAPTURE, @@ -1984,6 +1977,8 @@ int au0828_analog_register(struct au0828_dev *dev, dev->field_size = dev->width * dev->height; dev->frame_size = dev->field_size << 1; dev->bytesperline = dev->width << 1; + dev->vbi_width = 720; + dev->vbi_height = 1; dev->ctrl_ainput = 0; dev->ctrl_freq = 960; dev->std = V4L2_STD_NTSC_M; -- cgit v1.2.3 From 56230d1e292acad1367ae15f7a7dce70ee30f483 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 16:18:31 -0300 Subject: [media] au0828: fix initial video routing After loading the module the initial video routing is not setup. Explicitly call s_input to get this right. Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 6f2a6264d173..a90a0b9771b3 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1391,20 +1391,10 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) return 0; } -static int vidioc_s_input(struct file *file, void *priv, unsigned int index) +static void au0828_s_input(struct au0828_dev *dev, int index) { - struct au0828_fh *fh = priv; - struct au0828_dev *dev = fh->dev; int i; - dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__, - index); - if (index >= AU0828_MAX_INPUT) - return -EINVAL; - if (AUVI_INPUT(index).type == 0) - return -EINVAL; - dev->ctrl_input = index; - switch (AUVI_INPUT(index).type) { case AU0828_VMUX_SVIDEO: dev->input_type = AU0828_VMUX_SVIDEO; @@ -1419,7 +1409,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index) dev->ctrl_ainput = 0; break; default: - dprintk(1, "VIDIOC_S_INPUT unknown input type set [%d]\n", + dprintk(1, "unknown input type set [%d]\n", AUVI_INPUT(index).type); break; } @@ -1450,6 +1440,21 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int index) v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing, AUVI_INPUT(index).amux, 0, 0); +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int index) +{ + struct au0828_fh *fh = priv; + struct au0828_dev *dev = fh->dev; + + dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__, + index); + if (index >= AU0828_MAX_INPUT) + return -EINVAL; + if (AUVI_INPUT(index).type == 0) + return -EINVAL; + dev->ctrl_input = index; + au0828_s_input(dev, index); return 0; } @@ -1982,6 +1987,7 @@ int au0828_analog_register(struct au0828_dev *dev, dev->ctrl_ainput = 0; dev->ctrl_freq = 960; dev->std = V4L2_STD_NTSC_M; + au0828_s_input(dev, 0); /* allocate and fill v4l2 video struct */ dev->vdev = video_device_alloc(); -- cgit v1.2.3 From ea86968fb91471493ccac7d8f2a65bc65db6803b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 16:22:13 -0300 Subject: [media] au0828: improve firmware loading & locking - open/close/read and poll need to take the core lock as well. - when the tuner goes to sleep we should set std_set_in_tuner_core to 0 since the tuner loses the firmware at that time. - initialize the tuner if std_set_in_tuner_core == 0 whenever: 1) g/s_tuner, s_std or s_frequency is called 2) read or poll is called 3) streamon is called Signed-off-by: Hans Verkuil Reviewed-by: Devin Heitmueller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 66 ++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 14 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index a90a0b9771b3..75ac9947cdac 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -998,11 +998,17 @@ static int au0828_v4l2_open(struct file *filp) v4l2_fh_init(&fh->fh, vdev); filp->private_data = fh; - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { + if (mutex_lock_interruptible(&dev->lock)) { + kfree(fh); + return -ERESTARTSYS; + } + if (dev->users == 0) { /* set au0828 interface0 to AS5 here again */ ret = usb_set_interface(dev->usbdev, 0, 5); if (ret < 0) { + mutex_unlock(&dev->lock); printk(KERN_INFO "Au0828 can't set alternate to 5!\n"); + kfree(fh); return -EBUSY; } @@ -1017,6 +1023,7 @@ static int au0828_v4l2_open(struct file *filp) } dev->users++; + mutex_unlock(&dev->lock); videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops, NULL, &dev->slock, @@ -1044,6 +1051,7 @@ static int au0828_v4l2_close(struct file *filp) v4l2_fh_del(&fh->fh); v4l2_fh_exit(&fh->fh); + mutex_lock(&dev->lock); if (res_check(fh, AU0828_RESOURCE_VIDEO)) { /* Cancel timeout thread in case they didn't call streamoff */ dev->vid_timeout_running = 0; @@ -1069,6 +1077,7 @@ static int au0828_v4l2_close(struct file *filp) /* Save some power by putting tuner to sleep */ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0); + dev->std_set_in_tuner_core = 0; /* When close the device, set the usb intf0 into alt0 to free USB bandwidth */ @@ -1076,6 +1085,7 @@ static int au0828_v4l2_close(struct file *filp) if (ret < 0) printk(KERN_INFO "Au0828 can't set alternate to 0!\n"); } + mutex_unlock(&dev->lock); videobuf_mmap_free(&fh->vb_vidq); videobuf_mmap_free(&fh->vb_vbiq); @@ -1085,6 +1095,26 @@ static int au0828_v4l2_close(struct file *filp) return 0; } +/* Must be called with dev->lock held */ +static void au0828_init_tuner(struct au0828_dev *dev) +{ + struct v4l2_frequency f = { + .frequency = dev->ctrl_freq, + .type = V4L2_TUNER_ANALOG_TV, + }; + + if (dev->std_set_in_tuner_core) + return; + dev->std_set_in_tuner_core = 1; + i2c_gate_ctrl(dev, 1); + /* If we've never sent the standard in tuner core, do so now. + We don't do this at device probe because we don't want to + incur the cost of a firmware load */ + v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->std); + v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); + i2c_gate_ctrl(dev, 0); +} + static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { @@ -1096,6 +1126,11 @@ static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf, if (rc < 0) return rc; + if (mutex_lock_interruptible(&dev->lock)) + return -ERESTARTSYS; + au0828_init_tuner(dev); + mutex_unlock(&dev->lock); + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { if (res_locked(dev, AU0828_RESOURCE_VIDEO)) return -EBUSY; @@ -1136,6 +1171,11 @@ static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait) if (!(req_events & (POLLIN | POLLRDNORM))) return res; + if (mutex_lock_interruptible(&dev->lock)) + return -ERESTARTSYS; + au0828_init_tuner(dev); + mutex_unlock(&dev->lock); + if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { if (!res_get(fh, AU0828_RESOURCE_VIDEO)) return POLLERR; @@ -1319,6 +1359,10 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) struct au0828_fh *fh = priv; struct au0828_dev *dev = fh->dev; + dev->std = norm; + + au0828_init_tuner(dev); + i2c_gate_ctrl(dev, 1); /* FIXME: when we support something other than NTSC, we are going to @@ -1326,10 +1370,8 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) buffer, which is currently hardcoded at 720x480 */ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, norm); - dev->std_set_in_tuner_core = 1; i2c_gate_ctrl(dev, 0); - dev->std = norm; return 0; } @@ -1506,7 +1548,11 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) return -EINVAL; strcpy(t->name, "Auvitek tuner"); + + au0828_init_tuner(dev); + i2c_gate_ctrl(dev, 1); v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t); + i2c_gate_ctrl(dev, 0); return 0; } @@ -1519,10 +1565,9 @@ static int vidioc_s_tuner(struct file *file, void *priv, if (t->index != 0) return -EINVAL; + au0828_init_tuner(dev); i2c_gate_ctrl(dev, 1); - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t); - i2c_gate_ctrl(dev, 0); dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal, @@ -1554,17 +1599,9 @@ static int vidioc_s_frequency(struct file *file, void *priv, if (freq->tuner != 0) return -EINVAL; + au0828_init_tuner(dev); i2c_gate_ctrl(dev, 1); - if (dev->std_set_in_tuner_core == 0) { - /* If we've never sent the standard in tuner core, do so now. - We don't do this at device probe because we don't want to - incur the cost of a firmware load */ - v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, - dev->vdev->tvnorms); - dev->std_set_in_tuner_core = 1; - } - v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq); /* Get the actual set (and possibly clamped) frequency */ v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq); @@ -1663,6 +1700,7 @@ static int vidioc_streamon(struct file *file, void *priv, if (unlikely(!res_get(fh, get_ressource(fh)))) return -EBUSY; + au0828_init_tuner(dev); if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { au0828_analog_stream_enable(dev); v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1); -- cgit v1.2.3 From 106cf649d06c55b881cf4eadf2ca1a28a04d93aa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Mar 2013 08:14:13 -0300 Subject: [media] tuner-core: don't set has_signal/get_afc if not supported If the tuner frontend does not support get_rf_strength, then don't set the has_signal callback. Ditto for get_afc. Both callbacks overwrite the signal and afc fields of struct v4l2_tuner but that should only happen if the tuner can actually detect this. If it can't, then it should leave those fields alone so other subdevices can try and detect the signal/afc. This fixes the bug where the au8522 detected a signal and then tuner-core overwrote it with 0 since the xc5000 tuner does not support get_rf_strength. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/tuner-core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index f775768d088d..dd8a803fb111 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -253,7 +253,7 @@ static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg) static void tuner_status(struct dvb_frontend *fe); -static struct analog_demod_ops tuner_analog_ops = { +static const struct analog_demod_ops tuner_analog_ops = { .set_params = fe_set_params, .standby = fe_standby, .has_signal = fe_has_signal, @@ -453,6 +453,11 @@ static void set_type(struct i2c_client *c, unsigned int type, memcpy(analog_ops, &tuner_analog_ops, sizeof(struct analog_demod_ops)); + if (fe_tuner_ops->get_rf_strength == NULL) + analog_ops->has_signal = NULL; + if (fe_tuner_ops->get_afc == NULL) + analog_ops->get_afc = NULL; + } else { t->name = analog_ops->info.name; } -- cgit v1.2.3 From 383730c36419b85233fe2b5081253a2181160d17 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 25 Mar 2013 09:55:57 -0300 Subject: [media] tuner-core: return afc instead of zero While the driver gets AFC from the tuner, it doesn't return it back via V4L2 API due to a mistake at the return. fix it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/tuner-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index dd8a803fb111..5e18f4401801 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -235,7 +235,7 @@ static int fe_get_afc(struct dvb_frontend *fe) if (fe->ops.tuner_ops.get_afc) fe->ops.tuner_ops.get_afc(fe, &afc); - return 0; + return afc; } static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg) -- cgit v1.2.3 From 6f8ca0b541c8bb542edb02dad68bd723625132e7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 25 Mar 2013 09:55:58 -0300 Subject: [media] tuner-core: Remove the now uneeded checks at fe_has_signal/get_afc Now that those functions are only used when the corresponding function calls are defined, we don't need to check if those function calls are present at the structure before using it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/tuner-core.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index 5e18f4401801..f1e8b402b7ca 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -222,8 +222,7 @@ static int fe_has_signal(struct dvb_frontend *fe) { u16 strength = 0; - if (fe->ops.tuner_ops.get_rf_strength) - fe->ops.tuner_ops.get_rf_strength(fe, &strength); + fe->ops.tuner_ops.get_rf_strength(fe, &strength); return strength; } @@ -232,8 +231,7 @@ static int fe_get_afc(struct dvb_frontend *fe) { s32 afc = 0; - if (fe->ops.tuner_ops.get_afc) - fe->ops.tuner_ops.get_afc(fe, &afc); + fe->ops.tuner_ops.get_afc(fe, &afc); return afc; } @@ -256,8 +254,6 @@ static void tuner_status(struct dvb_frontend *fe); static const struct analog_demod_ops tuner_analog_ops = { .set_params = fe_set_params, .standby = fe_standby, - .has_signal = fe_has_signal, - .get_afc = fe_get_afc, .set_config = fe_set_config, .tuner_status = tuner_status }; @@ -453,10 +449,10 @@ static void set_type(struct i2c_client *c, unsigned int type, memcpy(analog_ops, &tuner_analog_ops, sizeof(struct analog_demod_ops)); - if (fe_tuner_ops->get_rf_strength == NULL) - analog_ops->has_signal = NULL; - if (fe_tuner_ops->get_afc == NULL) - analog_ops->get_afc = NULL; + if (fe_tuner_ops->get_rf_strength) + analog_ops->has_signal = fe_has_signal; + if (fe_tuner_ops->get_afc) + analog_ops->get_afc = fe_get_afc; } else { t->name = analog_ops->info.name; -- cgit v1.2.3 From 004e45d736bfe62159bd4dc1549eff414bd27496 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 25 Mar 2013 09:55:59 -0300 Subject: [media] tuner-core: handle errors when getting signal strength/afc If those callbacks fail, it should return zero, and not a random value. The previous code assumed that all drivers would only change signal strength if it succeeds, but this may not be true. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/tuner-core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index f1e8b402b7ca..cf9a9af90322 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -220,18 +220,20 @@ static void fe_standby(struct dvb_frontend *fe) static int fe_has_signal(struct dvb_frontend *fe) { - u16 strength = 0; + u16 strength; - fe->ops.tuner_ops.get_rf_strength(fe, &strength); + if (fe->ops.tuner_ops.get_rf_strength(fe, &strength) < 0) + return 0; return strength; } static int fe_get_afc(struct dvb_frontend *fe) { - s32 afc = 0; + s32 afc; - fe->ops.tuner_ops.get_afc(fe, &afc); + if (fe->ops.tuner_ops.get_afc(fe, &afc) < 0) + return 0; return afc; } -- cgit v1.2.3 From 0170a39b69ae65fffb40bd162730e3de2b87c835 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 26 Mar 2013 01:32:19 -0300 Subject: [media] af9035: fix missing unlock on error in af9035_ctrl_msg() Add the missing unlock before return from function af9035_ctrl_msg() in the error handling case. Signed-off-by: Wei Yongjun Acked-by: Antti Palosaari Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index b1f7059bf4a5..b638fc1cd574 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -57,7 +57,7 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) dev_err(&d->udev->dev, "%s: too much data wlen=%d rlen=%d\n", __func__, req->wlen, req->rlen); ret = -EINVAL; - goto err; + goto exit; } state->buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1; @@ -81,7 +81,7 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) ret = dvb_usbv2_generic_rw_locked(d, state->buf, wlen, state->buf, rlen); if (ret) - goto err; + goto exit; /* no ack for those packets */ if (req->cmd == CMD_FW_DL) @@ -95,28 +95,29 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) "(%04x != %04x)\n", KBUILD_MODNAME, req->cmd, tmp_checksum, checksum); ret = -EIO; - goto err; + goto exit; } /* check status */ if (state->buf[2]) { /* fw returns status 1 when IR code was not received */ - if (req->cmd == CMD_IR_GET || state->buf[2] == 1) - return 1; + if (req->cmd == CMD_IR_GET || state->buf[2] == 1) { + ret = 1; + goto exit; + } dev_dbg(&d->udev->dev, "%s: command=%02x failed fw error=%d\n", __func__, req->cmd, state->buf[2]); ret = -EIO; - goto err; + goto exit; } /* read request, copy returned data to return buf */ if (req->rlen) memcpy(req->rbuf, &state->buf[ACK_HDR_LEN], req->rlen); exit: -err: mutex_unlock(&d->usb_mutex); - if (ret) + if (ret < 0) dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); return ret; } -- cgit v1.2.3 From 80f23305ba43f9eda9596092735bffc283b9ae8d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 26 Mar 2013 07:17:42 -0300 Subject: [media] Fix undefined reference to `au8522_attach' au8522_attach is dependent on CONFIG_DVB_AU8522_DTV, not CONFIG_DVB_AU8522. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/au8522.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/au8522.h b/drivers/media/dvb-frontends/au8522.h index f2111e0fefda..83fe9a615619 100644 --- a/drivers/media/dvb-frontends/au8522.h +++ b/drivers/media/dvb-frontends/au8522.h @@ -61,7 +61,7 @@ struct au8522_config { enum au8522_if_freq qam_if; }; -#if IS_ENABLED(CONFIG_DVB_AU8522) +#if IS_ENABLED(CONFIG_DVB_AU8522_DTV) extern struct dvb_frontend *au8522_attach(const struct au8522_config *config, struct i2c_adapter *i2c); #else -- cgit v1.2.3 From a3ea4bf98bc8499e64b619808fcca09ca3eb4e2f Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Tue, 26 Mar 2013 13:38:36 -0300 Subject: [media] em28xx: add support for em25xx i2c bus B read/write/check device operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The webcam "SpeedLink VAD Laplace" (em2765 + ov2640) uses a special algorithm for i2c communication with the sensor, which is connected to a second i2c bus. We don't know yet how to find out which devices support/use it. It's very likely used by all em25xx and em276x+ bridges. Tests with other em28xx chips (em2820, em2882/em2883) show, that this algorithm always succeeds there although no slave device is connected. The algorithm likely also works for real i2c client devices (OV2640 uses SCCB), because the Windows driver seems to use it for probing Samsung and Kodak sensors. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 8 +- drivers/media/usb/em28xx/em28xx-i2c.c | 236 ++++++++++++++++++++++++++------ drivers/media/usb/em28xx/em28xx.h | 10 +- 3 files changed, 212 insertions(+), 42 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index cb7cdd322702..033b6cb5fbe8 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3139,15 +3139,19 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, rt_mutex_init(&dev->i2c_bus_lock); /* register i2c bus 0 */ - retval = em28xx_i2c_register(dev, 0); + if (dev->board.is_em2800) + retval = em28xx_i2c_register(dev, 0, EM28XX_I2C_ALGO_EM2800); + else + retval = em28xx_i2c_register(dev, 0, EM28XX_I2C_ALGO_EM28XX); if (retval < 0) { em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n", __func__, retval); goto unregister_dev; } + /* register i2c bus 1 */ if (dev->def_i2c_bus) { - retval = em28xx_i2c_register(dev, 1); + retval = em28xx_i2c_register(dev, 1, EM28XX_I2C_ALGO_EM28XX); if (retval < 0) { em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n", __func__, retval); diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 704f283d34ab..4851cc2e4a4d 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -5,6 +5,7 @@ Markus Rechberger Mauro Carvalho Chehab Sascha Sommer + Copyright (C) 2013 Frank Schäfer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -278,6 +279,183 @@ static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr) return (ret < 0) ? ret : -EIO; } +/* + * em25xx_bus_B_send_bytes + * write bytes to the i2c device + */ +static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, + u16 len) +{ + int ret; + + if (len < 1 || len > 64) + return -EOPNOTSUPP; + /* + * NOTE: limited by the USB ctrl message constraints + * Zero length reads always succeed, even if no device is connected + */ + + /* Set register and write value */ + ret = dev->em28xx_write_regs_req(dev, 0x06, addr, buf, len); + if (ret != len) { + if (ret < 0) { + em28xx_warn("writing to i2c device at 0x%x failed (error=%i)\n", + addr, ret); + return ret; + } else { + em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", + len, addr, ret); + return -EIO; + } + } + /* Check success */ + ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000); + /* + * NOTE: the only error we've seen so far is + * 0x01 when the slave device is not present + */ + if (!ret) + return len; + else if (ret > 0) + return -ENODEV; + + return ret; + /* + * NOTE: With chip types (other chip IDs) which actually don't support + * this operation, it seems to succeed ALWAYS ! (even if there is no + * slave device or even no second i2c bus provided) + */ +} + +/* + * em25xx_bus_B_recv_bytes + * read bytes from the i2c device + */ +static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, + u16 len) +{ + int ret; + + if (len < 1 || len > 64) + return -EOPNOTSUPP; + /* + * NOTE: limited by the USB ctrl message constraints + * Zero length reads always succeed, even if no device is connected + */ + + /* Read value */ + ret = dev->em28xx_read_reg_req_len(dev, 0x06, addr, buf, len); + if (ret < 0) { + em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n", + addr, ret); + return ret; + } + /* + * NOTE: some devices with two i2c busses have the bad habit to return 0 + * bytes if we are on bus B AND there was no write attempt to the + * specified slave address before AND no device is present at the + * requested slave address. + * Anyway, the next check will fail with -ENODEV in this case, so avoid + * spamming the system log on device probing and do nothing here. + */ + + /* Check success */ + ret = dev->em28xx_read_reg_req(dev, 0x08, 0x0000); + /* + * NOTE: the only error we've seen so far is + * 0x01 when the slave device is not present + */ + if (!ret) + return len; + else if (ret > 0) + return -ENODEV; + + return ret; + /* + * NOTE: With chip types (other chip IDs) which actually don't support + * this operation, it seems to succeed ALWAYS ! (even if there is no + * slave device or even no second i2c bus provided) + */ +} + +/* + * em25xx_bus_B_check_for_device() + * check if there is a i2c device at the supplied address + */ +static int em25xx_bus_B_check_for_device(struct em28xx *dev, u16 addr) +{ + u8 buf; + int ret; + + ret = em25xx_bus_B_recv_bytes(dev, addr, &buf, 1); + if (ret < 0) + return ret; + + return 0; + /* + * NOTE: With chips which do not support this operation, + * it seems to succeed ALWAYS ! (even if no device connected) + */ +} + +static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr) +{ + struct em28xx *dev = i2c_bus->dev; + int rc = -EOPNOTSUPP; + + if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) + rc = em28xx_i2c_check_for_device(dev, addr); + else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800) + rc = em2800_i2c_check_for_device(dev, addr); + else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B) + rc = em25xx_bus_B_check_for_device(dev, addr); + if (rc == -ENODEV) { + if (i2c_debug) + printk(" no device\n"); + } + return rc; +} + +static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus, + struct i2c_msg msg) +{ + struct em28xx *dev = i2c_bus->dev; + u16 addr = msg.addr << 1; + int byte, rc = -EOPNOTSUPP; + + if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) + rc = em28xx_i2c_recv_bytes(dev, addr, msg.buf, msg.len); + else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800) + rc = em2800_i2c_recv_bytes(dev, addr, msg.buf, msg.len); + else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B) + rc = em25xx_bus_B_recv_bytes(dev, addr, msg.buf, msg.len); + if (i2c_debug) { + for (byte = 0; byte < msg.len; byte++) + printk(" %02x", msg.buf[byte]); + } + return rc; +} + +static inline int i2c_send_bytes(struct em28xx_i2c_bus *i2c_bus, + struct i2c_msg msg, int stop) +{ + struct em28xx *dev = i2c_bus->dev; + u16 addr = msg.addr << 1; + int byte, rc = -EOPNOTSUPP; + + if (i2c_debug) { + for (byte = 0; byte < msg.len; byte++) + printk(" %02x", msg.buf[byte]); + } + if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) + rc = em28xx_i2c_send_bytes(dev, addr, msg.buf, msg.len, stop); + else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800) + rc = em2800_i2c_send_bytes(dev, addr, msg.buf, msg.len); + else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B) + rc = em25xx_bus_B_send_bytes(dev, addr, msg.buf, msg.len); + return rc; +} + /* * em28xx_i2c_xfer() * the main i2c transfer function @@ -288,7 +466,7 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data; struct em28xx *dev = i2c_bus->dev; unsigned bus = i2c_bus->bus; - int addr, rc, i, byte; + int addr, rc, i; u8 reg; rc = rt_mutex_trylock(&dev->i2c_bus_lock); @@ -296,7 +474,8 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, return rc; /* Switch I2C bus if needed */ - if (bus != dev->cur_i2c_bus) { + if (bus != dev->cur_i2c_bus && + i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) { if (bus == 1) reg = EM2874_I2C_SECONDARY_BUS_SELECT; else @@ -319,45 +498,17 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); if (!msgs[i].len) { /* no len: check only for device presence */ - if (dev->board.is_em2800) - rc = em2800_i2c_check_for_device(dev, addr); - else - rc = em28xx_i2c_check_for_device(dev, addr); + rc = i2c_check_for_device(i2c_bus, addr); if (rc == -ENODEV) { - if (i2c_debug) - printk(" no device\n"); rt_mutex_unlock(&dev->i2c_bus_lock); return rc; } } else if (msgs[i].flags & I2C_M_RD) { /* read bytes */ - if (dev->board.is_em2800) - rc = em2800_i2c_recv_bytes(dev, addr, - msgs[i].buf, - msgs[i].len); - else - rc = em28xx_i2c_recv_bytes(dev, addr, - msgs[i].buf, - msgs[i].len); - if (i2c_debug) { - for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); - } + rc = i2c_recv_bytes(i2c_bus, msgs[i]); } else { /* write bytes */ - if (i2c_debug) { - for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); - } - if (dev->board.is_em2800) - rc = em2800_i2c_send_bytes(dev, addr, - msgs[i].buf, - msgs[i].len); - else - rc = em28xx_i2c_send_bytes(dev, addr, - msgs[i].buf, - msgs[i].len, - i == num - 1); + rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1); } if (rc < 0) { if (i2c_debug) @@ -633,12 +784,17 @@ error: static u32 functionality(struct i2c_adapter *i2c_adap) { struct em28xx_i2c_bus *i2c_bus = i2c_adap->algo_data; - struct em28xx *dev = i2c_bus->dev; - u32 func_flags = I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; - if (dev->board.is_em2800) - func_flags &= ~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA; - return func_flags; + if ((i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX) || + (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)) { + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + } else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800) { + return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL) & + ~I2C_FUNC_SMBUS_WRITE_BLOCK_DATA; + } + + WARN(1, "Unknown i2c bus algorithm.\n"); + return 0; } static struct i2c_algorithm em28xx_algo = { @@ -712,7 +868,8 @@ void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus) * em28xx_i2c_register() * register i2c bus */ -int em28xx_i2c_register(struct em28xx *dev, unsigned bus) +int em28xx_i2c_register(struct em28xx *dev, unsigned bus, + enum em28xx_i2c_algo_type algo_type) { int retval; @@ -727,6 +884,7 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus) strcpy(dev->i2c_adap[bus].name, dev->name); dev->i2c_bus[bus].bus = bus; + dev->i2c_bus[bus].algo_type = algo_type; dev->i2c_bus[bus].dev = dev; dev->i2c_adap[bus].algo_data = &dev->i2c_bus[bus]; i2c_set_adapdata(&dev->i2c_adap[bus], &dev->v4l2_dev); diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 4c667fd1661d..aeee896f8149 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -461,10 +461,17 @@ struct em28xx_fh { enum v4l2_buf_type type; }; +enum em28xx_i2c_algo_type { + EM28XX_I2C_ALGO_EM28XX = 0, + EM28XX_I2C_ALGO_EM2800, + EM28XX_I2C_ALGO_EM25XX_BUS_B, +}; + struct em28xx_i2c_bus { struct em28xx *dev; unsigned bus; + enum em28xx_i2c_algo_type algo_type; }; @@ -651,7 +658,8 @@ struct em28xx_ops { /* Provided by em28xx-i2c.c */ void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus); -int em28xx_i2c_register(struct em28xx *dev, unsigned bus); +int em28xx_i2c_register(struct em28xx *dev, unsigned bus, + enum em28xx_i2c_algo_type algo_type); int em28xx_i2c_unregister(struct em28xx *dev, unsigned bus); /* Provided by em28xx-core.c */ -- cgit v1.2.3 From 736a320bd285b4b90cdc49d1506461518979f240 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Tue, 26 Mar 2013 13:38:37 -0300 Subject: [media] em28xx: add chip id of the em2765 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This chip can be found in the SpeedLink VAD Laplace webcam (1ae7:9003 and 1ae7:9004). Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 13 ++++++++++++- drivers/media/usb/em28xx/em28xx-reg.h | 1 + drivers/media/usb/em28xx/em28xx.h | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 033b6cb5fbe8..54e0362d8e3d 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3041,6 +3041,12 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, case CHIP_ID_EM2750: chip_name = "em2750"; break; + case CHIP_ID_EM2765: + chip_name = "em2765"; + dev->wait_after_write = 0; + dev->is_em25xx = 1; + dev->eeprom_addrwidth_16bit = 1; + break; case CHIP_ID_EM2820: chip_name = "em2710/2820"; break; @@ -3151,7 +3157,12 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, /* register i2c bus 1 */ if (dev->def_i2c_bus) { - retval = em28xx_i2c_register(dev, 1, EM28XX_I2C_ALGO_EM28XX); + if (dev->is_em25xx) + retval = em28xx_i2c_register(dev, 1, + EM28XX_I2C_ALGO_EM25XX_BUS_B); + else + retval = em28xx_i2c_register(dev, 1, + EM28XX_I2C_ALGO_EM28XX); if (retval < 0) { em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n", __func__, retval); diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index 8fd3c7f80201..1b0ecd6acfe2 100644 --- a/drivers/media/usb/em28xx/em28xx-reg.h +++ b/drivers/media/usb/em28xx/em28xx-reg.h @@ -219,6 +219,7 @@ enum em28xx_chip_id { CHIP_ID_EM2860 = 34, CHIP_ID_EM2870 = 35, CHIP_ID_EM2883 = 36, + CHIP_ID_EM2765 = 54, CHIP_ID_EM2874 = 65, CHIP_ID_EM2884 = 68, CHIP_ID_EM28174 = 113, diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index aeee896f8149..7be008f2d8a1 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -482,6 +482,7 @@ struct em28xx { int model; /* index in the device_data struct */ int devno; /* marks the number of this device */ enum em28xx_chip_id chip_id; + unsigned int is_em25xx:1; /* em25xx/em276x/7x/8x family bridge */ unsigned char disconnected:1; /* device has been diconnected */ -- cgit v1.2.3 From e507e0e513c41ccfc68d6f619faa212f97c88ddb Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Tue, 26 Mar 2013 13:38:38 -0300 Subject: [media] em28xx: add support for em25xx/em276x/em277x/em278x frame data processing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The em25xx/em276x/em277x/em278x frame data format is different to the one used by the em2710/em2750/em28xx chips. With the recent cleanups and reorganization of the frame data processing code it can be easily extended to support these devices. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 74 ++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index b1817231f50c..ef1959bbd23f 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -76,6 +76,16 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); MODULE_VERSION(EM28XX_VERSION); + +#define EM25XX_FRMDATAHDR_BYTE1 0x02 +#define EM25XX_FRMDATAHDR_BYTE2_STILL_IMAGE 0x20 +#define EM25XX_FRMDATAHDR_BYTE2_FRAME_END 0x02 +#define EM25XX_FRMDATAHDR_BYTE2_FRAME_ID 0x01 +#define EM25XX_FRMDATAHDR_BYTE2_MASK (EM25XX_FRMDATAHDR_BYTE2_STILL_IMAGE | \ + EM25XX_FRMDATAHDR_BYTE2_FRAME_END | \ + EM25XX_FRMDATAHDR_BYTE2_FRAME_ID) + + static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U }; static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U }; static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U }; @@ -408,6 +418,62 @@ static inline void process_frame_data_em28xx(struct em28xx *dev, em28xx_copy_video(dev, buf, data_pkt, data_len); } +/* + * Process data packet according to the em25xx/em276x/7x/8x frame data format + */ +static inline void process_frame_data_em25xx(struct em28xx *dev, + unsigned char *data_pkt, + unsigned int data_len) +{ + struct em28xx_buffer *buf = dev->usb_ctl.vid_buf; + struct em28xx_dmaqueue *dmaq = &dev->vidq; + bool frame_end = 0; + + /* Check for header */ + /* NOTE: at least with bulk transfers, only the first packet + * has a header and has always set the FRAME_END bit */ + if (data_len >= 2) { /* em25xx header is only 2 bytes long */ + if ((data_pkt[0] == EM25XX_FRMDATAHDR_BYTE1) && + ((data_pkt[1] & ~EM25XX_FRMDATAHDR_BYTE2_MASK) == 0x00)) { + dev->top_field = !(data_pkt[1] & + EM25XX_FRMDATAHDR_BYTE2_FRAME_ID); + frame_end = data_pkt[1] & + EM25XX_FRMDATAHDR_BYTE2_FRAME_END; + data_pkt += 2; + data_len -= 2; + } + + /* Finish field and prepare next (BULK only) */ + if (dev->analog_xfer_bulk && frame_end) { + buf = finish_field_prepare_next(dev, buf, dmaq); + dev->usb_ctl.vid_buf = buf; + } + /* NOTE: in ISOC mode when a new frame starts and buf==NULL, + * we COULD already prepare a buffer here to avoid skipping the + * first frame. + */ + } + + /* Copy data */ + if (buf != NULL && data_len > 0) + em28xx_copy_video(dev, buf, data_pkt, data_len); + + /* Finish frame (ISOC only) => avoids lag of 1 frame */ + if (!dev->analog_xfer_bulk && frame_end) { + buf = finish_field_prepare_next(dev, buf, dmaq); + dev->usb_ctl.vid_buf = buf; + } + + /* NOTE: Tested with USB bulk transfers only ! + * The wording in the datasheet suggests that isoc might work different. + * The current code assumes that with isoc transfers each packet has a + * header like with the other em28xx devices. + */ + /* NOTE: Support for interlaced mode is pure theory. It has not been + * tested and it is unknown if these devices actually support it. */ + /* NOTE: No VBI support yet (these chips likely do not support VBI). */ +} + /* Processes and copies the URB data content (video and VBI data) */ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb) { @@ -460,7 +526,13 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb) continue; } - process_frame_data_em28xx(dev, usb_data_pkt, usb_data_len); + if (dev->is_em25xx) + process_frame_data_em25xx(dev, + usb_data_pkt, usb_data_len); + else + process_frame_data_em28xx(dev, + usb_data_pkt, usb_data_len); + } return 1; } -- cgit v1.2.3 From c8c39796c484fc6f4e45d8d71f3cf55e9ab27e6c Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Tue, 26 Mar 2013 13:38:39 -0300 Subject: [media] em28xx: make em28xx_set_outfmt() working with EM25xx family bridges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Streaming doesn't work with the EM2765 if bit 5 of the output format register 0x27 is set. It's actually not clear if really has to be set for the other chips, but for now let's keep it to avoid regressions and add a comment to the code. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-core.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index b2dcb3d1342d..575a46a18e1f 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -697,12 +697,23 @@ int em28xx_vbi_supported(struct em28xx *dev) int em28xx_set_outfmt(struct em28xx *dev) { int ret; - u8 vinctrl; - - ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT, - dev->format->reg | 0x20, 0xff); + u8 fmt, vinctrl; + + fmt = dev->format->reg; + if (!dev->is_em25xx) + fmt |= 0x20; + /* + * NOTE: it's not clear if this is really needed ! + * The datasheets say bit 5 is a reserved bit and devices seem to work + * fine without it. But the Windows driver sets it for em2710/50+em28xx + * devices and we've always been setting it, too. + * + * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set, + * it's likely used for an additional (compressed ?) format there. + */ + ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt); if (ret < 0) - return ret; + return ret; ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode); if (ret < 0) -- cgit v1.2.3 From 1e2e9086c7a668489383a6cb7e7a8d7ac86bca36 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Tue, 26 Mar 2013 13:38:40 -0300 Subject: [media] em28xx: write output frame resolution to regs 0x34+0x35 for em25xx family bridges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Windows driver writes the output resolution to registers 0x34 (width / 16) and 0x35 (height / 16) always. We don't know yet what these registers are used for. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-core.c | 7 +++++++ drivers/media/usb/em28xx/em28xx-reg.h | 9 ++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 575a46a18e1f..a802128ce9c5 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -767,6 +767,13 @@ static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart, em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1); em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1); em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1); + + /* FIXME: function/meaning of these registers ? */ + /* FIXME: align width+height to multiples of 4 ?! */ + if (dev->is_em25xx) { + em28xx_write_reg(dev, 0x34, width >> 4); + em28xx_write_reg(dev, 0x35, height >> 4); + } } static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index 1b0ecd6acfe2..622871db04aa 100644 --- a/drivers/media/usb/em28xx/em28xx-reg.h +++ b/drivers/media/usb/em28xx/em28xx-reg.h @@ -48,7 +48,7 @@ #define EM28XX_CHIPCFG2_TS_PACKETSIZE_752 0x03 - /* GPIO/GPO registers */ +/* GPIO/GPO registers */ #define EM2880_R04_GPO 0x04 /* em2880-em2883 only */ #define EM28XX_R08_GPIO 0x08 /* em2820 or upper */ @@ -167,6 +167,13 @@ #define EM28XX_R34_VBI_START_H 0x34 #define EM28XX_R35_VBI_START_V 0x35 +/* + * NOTE: the EM276x (and EM25xx, EM277x/8x ?) (camera bridges) use these + * registers for a different unknown purpose. + * => register 0x34 is set to capture width / 16 + * => register 0x35 is set to capture height / 16 + */ + #define EM28XX_R36_VBI_WIDTH 0x36 #define EM28XX_R37_VBI_HEIGHT 0x37 -- cgit v1.2.3 From b41869711586b047c18435ba84baf334918bae01 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 11 Jan 2013 10:22:39 -0300 Subject: [media] uvcvideo: Return -EINVAL when setting a menu control to an invalid value -ERANGE is the right error code when the value is outside of the menu range, but -EINVAL must be reported for invalid values inside the range. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 61e28dec991d..a2f4501c23ca 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1487,7 +1487,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain, step = mapping->get(mapping, UVC_GET_RES, uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); if (!(step & value)) - return -ERANGE; + return -EINVAL; } break; -- cgit v1.2.3 From 72cc9ba39a046132a638888eaa5a14baf55621b2 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Wed, 27 Mar 2013 16:07:41 -0300 Subject: [media] em28xx: ignore isoc DVB USB endpoints with wMaxPacketSize = 0 bytes for all alt settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some devices without DVB support (such as the "Terratec Grabby" and "Easycap DC-60") provide isochronous DVB USB endpoints with wMaxPacketSize set to 0 bytes for all alt settings. Ignore these endpoints and avoid registering a DVB device node and loading the DVB driver extension. Signed-off-by: Frank Schäfer Tested-by: Timo Teräs Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 54e0362d8e3d..096206334134 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3357,14 +3357,15 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->analog_ep_bulk = e->bEndpointAddress; } else { - has_dvb = true; if (usb_endpoint_xfer_isoc(e)) { dev->dvb_ep_isoc = e->bEndpointAddress; if (size > dev->dvb_max_pkt_size_isoc) { + has_dvb = true; /* see NOTE (~) */ dev->dvb_max_pkt_size_isoc = size; dev->dvb_alt_isoc = i; } } else { + has_dvb = true; dev->dvb_ep_bulk = e->bEndpointAddress; } } @@ -3391,6 +3392,12 @@ static int em28xx_usb_probe(struct usb_interface *interface, * so far. But there might be devices for which this * logic is not sufficient... */ + /* + * NOTE (~): some manufacturers (e.g. Terratec) disable + * endpoints by setting wMaxPacketSize to 0 bytes for + * all alt settings. So far, we've seen this for + * DVB isoc endpoints only. + */ } } -- cgit v1.2.3 From 2d466e1136161527708321b73ded9c0ac4cae668 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Wed, 27 Mar 2013 17:06:28 -0300 Subject: [media] em28xx: fix and separate the board hints for sensor devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current board hint code is mixed together with the sensor detection and initialization code. It actually selects a board depending on the detected sensor type only, with the result that 3 of the 6 webcam boards are currently dead. Separate it and move it to em28xx_hint_board() which already contains the board hints for analog capturing+TV and DVB devices. This way, we have all board hints at a common place which makes it easier to extend the code and reduces the risk of regressions. It also makes it possible again to use the boards EM2750_BOARD_DLCW_130, EM2820_BOARD_VIDEOLOGY_20K14XUSB and EM2860_BOARD_NETGMBH_CAM (using the module parameter "card"). NOTE: the current board hint logic for webcams is preserved. Not more not less. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 40 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 21 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 096206334134..c1397db7c145 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2333,9 +2333,6 @@ static int em28xx_hint_sensor(struct em28xx *dev) switch (version) { case 0x8232: /* mt9v011 640x480 1.3 Mpix sensor */ case 0x8243: /* mt9v011 rev B 640x480 1.3 Mpix sensor */ - dev->model = EM2820_BOARD_SILVERCREST_WEBCAM; - em28xx_set_model(dev); - sensor_name = "mt9v011"; dev->em28xx_sensor = EM28XX_MT9V011; dev->sensor_xres = 640; @@ -2359,9 +2356,6 @@ static int em28xx_hint_sensor(struct em28xx *dev) break; case 0x143a: /* MT9M111 as found in the ECS G200 */ - dev->model = EM2750_BOARD_UNKNOWN; - em28xx_set_model(dev); - sensor_name = "mt9m111"; dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ; dev->em28xx_sensor = EM28XX_MT9M111; @@ -2375,9 +2369,6 @@ static int em28xx_hint_sensor(struct em28xx *dev) break; case 0x8431: - dev->model = EM2750_BOARD_UNKNOWN; - em28xx_set_model(dev); - sensor_name = "mt9m001"; dev->em28xx_sensor = EM28XX_MT9M001; em28xx_initialize_mt9m001(dev); @@ -2394,11 +2385,7 @@ static int em28xx_hint_sensor(struct em28xx *dev) return -EINVAL; } - /* Setup webcam defaults */ - em28xx_pre_card_setup(dev); - - em28xx_errdev("Sensor is %s, using model %s entry.\n", - sensor_name, em28xx_boards[dev->model].name); + em28xx_info("sensor %s detected\n", sensor_name); return 0; } @@ -2628,6 +2615,18 @@ static int em28xx_hint_board(struct em28xx *dev) { int i; + if (dev->board.is_webcam) { + if (dev->em28xx_sensor == EM28XX_MT9V011) { + dev->model = EM2820_BOARD_SILVERCREST_WEBCAM; + } else if (dev->em28xx_sensor == EM28XX_MT9M001 || + dev->em28xx_sensor == EM28XX_MT9M111) { + dev->model = EM2750_BOARD_UNKNOWN; + } + /* FIXME: IMPROVE ! */ + + return 0; + } + /* HINT method: EEPROM * * This method works only for boards with eeprom. @@ -2719,10 +2718,10 @@ static void em28xx_card_setup(struct em28xx *dev) dev->progressive = 1; } - if (!dev->board.is_webcam) { - switch (dev->model) { - case EM2820_BOARD_UNKNOWN: - case EM2800_BOARD_UNKNOWN: + switch (dev->model) { + case EM2750_BOARD_UNKNOWN: + case EM2820_BOARD_UNKNOWN: + case EM2800_BOARD_UNKNOWN: /* * The K-WORLD DVB-T 310U is detected as an MSI Digivox AD. * @@ -2743,9 +2742,8 @@ static void em28xx_card_setup(struct em28xx *dev) em28xx_pre_card_setup(dev); } break; - default: - em28xx_set_model(dev); - } + default: + em28xx_set_model(dev); } em28xx_info("Identified as %s (card=%d)\n", -- cgit v1.2.3 From 484fbbeb3eed224e11f016ee212f07e698a24f97 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Wed, 27 Mar 2013 17:06:29 -0300 Subject: [media] em28xx: separate sensor detection and initialization/configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sensor detection and initialization/configuration are currently mixed together. This works as long as all devices with a particular sensor are working with the same board configuration. In the long run, this will be not sufficient, so separate these both steps to make the code more flexible and future proof. This also makes the code more consistent, because the initialization of the MT9V011 sensor subdevice is already separated. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 122 +++++++++++++++++++------------- 1 file changed, 72 insertions(+), 50 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index c1397db7c145..de15cdff5892 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2335,50 +2335,14 @@ static int em28xx_hint_sensor(struct em28xx *dev) case 0x8243: /* mt9v011 rev B 640x480 1.3 Mpix sensor */ sensor_name = "mt9v011"; dev->em28xx_sensor = EM28XX_MT9V011; - dev->sensor_xres = 640; - dev->sensor_yres = 480; - /* - * FIXME: mt9v011 uses I2S speed as xtal clk - at least with - * the Silvercrest cam I have here for testing - for higher - * resolutions, a high clock cause horizontal artifacts, so we - * need to use a lower xclk frequency. - * Yet, it would be possible to adjust xclk depending on the - * desired resolution, since this affects directly the - * frame rate. - */ - dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ; - dev->sensor_xtal = 4300000; - - /* probably means GRGB 16 bit bayer */ - dev->vinmode = 0x0d; - dev->vinctl = 0x00; - break; - case 0x143a: /* MT9M111 as found in the ECS G200 */ sensor_name = "mt9m111"; - dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ; dev->em28xx_sensor = EM28XX_MT9M111; - em28xx_initialize_mt9m111(dev); - dev->sensor_xres = 640; - dev->sensor_yres = 512; - - dev->vinmode = 0x0a; - dev->vinctl = 0x00; - break; - case 0x8431: sensor_name = "mt9m001"; dev->em28xx_sensor = EM28XX_MT9M001; - em28xx_initialize_mt9m001(dev); - dev->sensor_xres = 1280; - dev->sensor_yres = 1024; - - /* probably means BGGR 16 bit bayer */ - dev->vinmode = 0x0c; - dev->vinctl = 0x00; - break; default: printk("Unknown Micron Sensor 0x%04x\n", version); @@ -2611,6 +2575,76 @@ static void em28xx_tuner_setup(struct em28xx *dev) v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); } +static int em28xx_init_camera(struct em28xx *dev) +{ + switch (dev->em28xx_sensor) { + case EM28XX_MT9V011: + { + struct mt9v011_platform_data pdata; + struct i2c_board_info mt9v011_info = { + .type = "mt9v011", + .addr = dev->i2c_client[dev->def_i2c_bus].addr, + .platform_data = &pdata, + }; + + dev->sensor_xres = 640; + dev->sensor_yres = 480; + + /* + * FIXME: mt9v011 uses I2S speed as xtal clk - at least with + * the Silvercrest cam I have here for testing - for higher + * resolutions, a high clock cause horizontal artifacts, so we + * need to use a lower xclk frequency. + * Yet, it would be possible to adjust xclk depending on the + * desired resolution, since this affects directly the + * frame rate. + */ + dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ; + em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); + dev->sensor_xtal = 4300000; + pdata.xtal = dev->sensor_xtal; + if (NULL == + v4l2_i2c_new_subdev_board(&dev->v4l2_dev, + &dev->i2c_adap[dev->def_i2c_bus], + &mt9v011_info, NULL)) + return -ENODEV; + /* probably means GRGB 16 bit bayer */ + dev->vinmode = 0x0d; + dev->vinctl = 0x00; + + break; + } + case EM28XX_MT9M001: + dev->sensor_xres = 1280; + dev->sensor_yres = 1024; + + em28xx_initialize_mt9m001(dev); + + /* probably means BGGR 16 bit bayer */ + dev->vinmode = 0x0c; + dev->vinctl = 0x00; + + break; + case EM28XX_MT9M111: + dev->sensor_xres = 640; + dev->sensor_yres = 512; + + dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ; + em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); + em28xx_initialize_mt9m111(dev); + + dev->vinmode = 0x0a; + dev->vinctl = 0x00; + + break; + case EM28XX_NOSENSOR: + default: + return -EINVAL; + } + + return 0; +} + static int em28xx_hint_board(struct em28xx *dev) { int i; @@ -2878,20 +2912,6 @@ static void em28xx_card_setup(struct em28xx *dev) v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], "tvp5150", 0, tvp5150_addrs); - if (dev->em28xx_sensor == EM28XX_MT9V011) { - struct mt9v011_platform_data pdata; - struct i2c_board_info mt9v011_info = { - .type = "mt9v011", - .addr = 0xba >> 1, - .platform_data = &pdata, - }; - - pdata.xtal = dev->sensor_xtal; - v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], - &mt9v011_info, NULL); - } - - if (dev->board.adecoder == EM28XX_TVAUDIO) v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus], "tvaudio", dev->board.tvaudio_addr, NULL); @@ -2925,6 +2945,8 @@ static void em28xx_card_setup(struct em28xx *dev) } em28xx_tuner_setup(dev); + + em28xx_init_camera(dev); } -- cgit v1.2.3 From b3944c8f676de2e7ccd78151ae6a0518a9c44df6 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Wed, 27 Mar 2013 17:06:30 -0300 Subject: [media] em28xx: rename em28xx_hint_sensor() to em28xx_detect_sensor() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the board hints and the sensor initialization/configuration have been separated, em28xx_detect_sensor() is the better name for this function. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index de15cdff5892..b745860794b3 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2309,11 +2309,10 @@ static int em28xx_initialize_mt9m001(struct em28xx *dev) return 0; } -/* HINT method: webcam I2C chips - * +/* * This method works for webcams with Micron sensors */ -static int em28xx_hint_sensor(struct em28xx *dev) +static int em28xx_detect_sensor(struct em28xx *dev) { int rc; char *sensor_name; @@ -2746,7 +2745,7 @@ static void em28xx_card_setup(struct em28xx *dev) * If sensor is not found, then it isn't a webcam. */ if (dev->board.is_webcam) { - if (em28xx_hint_sensor(dev) < 0) + if (em28xx_detect_sensor(dev) < 0) dev->board.is_webcam = 0; else dev->progressive = 1; -- cgit v1.2.3 From 855ff38e880f57814ea5c0cbea853da11fcdf42f Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Wed, 27 Mar 2013 17:06:31 -0300 Subject: [media] em28xx: move sensor code to a separate source code file em28xx-camera.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit em28xx-cards.c is very large and the sensor/camera related code is growing, so move this code to a separate source code file em28xx-camera.c. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/Makefile | 2 +- drivers/media/usb/em28xx/em28xx-camera.c | 189 +++++++++++++++++++++++++++++++ drivers/media/usb/em28xx/em28xx-cards.c | 160 -------------------------- drivers/media/usb/em28xx/em28xx.h | 4 + 4 files changed, 194 insertions(+), 161 deletions(-) create mode 100644 drivers/media/usb/em28xx/em28xx-camera.c (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile index 634fb920dd39..ad6d48557940 100644 --- a/drivers/media/usb/em28xx/Makefile +++ b/drivers/media/usb/em28xx/Makefile @@ -1,5 +1,5 @@ em28xx-y += em28xx-video.o em28xx-i2c.o em28xx-cards.o -em28xx-y += em28xx-core.o em28xx-vbi.o +em28xx-y += em28xx-core.o em28xx-vbi.o em28xx-camera.o em28xx-alsa-objs := em28xx-audio.o em28xx-rc-objs := em28xx-input.o diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c new file mode 100644 index 000000000000..28dd8489ac9c --- /dev/null +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -0,0 +1,189 @@ +/* + em28xx-camera.c - driver for Empia EM25xx/27xx/28xx USB video capture devices + + Copyright (C) 2009 Mauro Carvalho Chehab + Copyright (C) 2013 Frank Schäfer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include + +#include "em28xx.h" + + +/* FIXME: Should be replaced by a proper mt9m111 driver */ +static int em28xx_initialize_mt9m111(struct em28xx *dev) +{ + int i; + unsigned char regs[][3] = { + { 0x0d, 0x00, 0x01, }, /* reset and use defaults */ + { 0x0d, 0x00, 0x00, }, + { 0x0a, 0x00, 0x21, }, + { 0x21, 0x04, 0x00, }, /* full readout speed, no row/col skipping */ + }; + + for (i = 0; i < ARRAY_SIZE(regs); i++) + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], + ®s[i][0], 3); + + return 0; +} + + +/* FIXME: Should be replaced by a proper mt9m001 driver */ +static int em28xx_initialize_mt9m001(struct em28xx *dev) +{ + int i; + unsigned char regs[][3] = { + { 0x0d, 0x00, 0x01, }, + { 0x0d, 0x00, 0x00, }, + { 0x04, 0x05, 0x00, }, /* hres = 1280 */ + { 0x03, 0x04, 0x00, }, /* vres = 1024 */ + { 0x20, 0x11, 0x00, }, + { 0x06, 0x00, 0x10, }, + { 0x2b, 0x00, 0x24, }, + { 0x2e, 0x00, 0x24, }, + { 0x35, 0x00, 0x24, }, + { 0x2d, 0x00, 0x20, }, + { 0x2c, 0x00, 0x20, }, + { 0x09, 0x0a, 0xd4, }, + { 0x35, 0x00, 0x57, }, + }; + + for (i = 0; i < ARRAY_SIZE(regs); i++) + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], + ®s[i][0], 3); + + return 0; +} + + +/* + * This method works for webcams with Micron sensors + */ +int em28xx_detect_sensor(struct em28xx *dev) +{ + int ret; + char *name; + u8 reg; + __be16 id_be; + u16 id; + + /* Micron sensor detection */ + dev->i2c_client[dev->def_i2c_bus].addr = 0xba >> 1; + reg = 0; + i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], ®, 1); + ret = i2c_master_recv(&dev->i2c_client[dev->def_i2c_bus], + (char *)&id_be, 2); + if (ret != 2) + return -EINVAL; + + id = be16_to_cpu(id_be); + switch (id) { + case 0x8232: /* mt9v011 640x480 1.3 Mpix sensor */ + case 0x8243: /* mt9v011 rev B 640x480 1.3 Mpix sensor */ + name = "mt9v011"; + dev->em28xx_sensor = EM28XX_MT9V011; + break; + case 0x143a: /* MT9M111 as found in the ECS G200 */ + name = "mt9m111"; + dev->em28xx_sensor = EM28XX_MT9M111; + break; + case 0x8431: + name = "mt9m001"; + dev->em28xx_sensor = EM28XX_MT9M001; + break; + default: + em28xx_info("unknown Micron sensor detected: 0x%04x\n", id); + return -EINVAL; + } + + em28xx_info("sensor %s detected\n", name); + + return 0; +} + +int em28xx_init_camera(struct em28xx *dev) +{ + switch (dev->em28xx_sensor) { + case EM28XX_MT9V011: + { + struct mt9v011_platform_data pdata; + struct i2c_board_info mt9v011_info = { + .type = "mt9v011", + .addr = dev->i2c_client[dev->def_i2c_bus].addr, + .platform_data = &pdata, + }; + + dev->sensor_xres = 640; + dev->sensor_yres = 480; + + /* + * FIXME: mt9v011 uses I2S speed as xtal clk - at least with + * the Silvercrest cam I have here for testing - for higher + * resolutions, a high clock cause horizontal artifacts, so we + * need to use a lower xclk frequency. + * Yet, it would be possible to adjust xclk depending on the + * desired resolution, since this affects directly the + * frame rate. + */ + dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ; + em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); + dev->sensor_xtal = 4300000; + pdata.xtal = dev->sensor_xtal; + if (NULL == + v4l2_i2c_new_subdev_board(&dev->v4l2_dev, + &dev->i2c_adap[dev->def_i2c_bus], + &mt9v011_info, NULL)) + return -ENODEV; + /* probably means GRGB 16 bit bayer */ + dev->vinmode = 0x0d; + dev->vinctl = 0x00; + + break; + } + case EM28XX_MT9M001: + dev->sensor_xres = 1280; + dev->sensor_yres = 1024; + + em28xx_initialize_mt9m001(dev); + + /* probably means BGGR 16 bit bayer */ + dev->vinmode = 0x0c; + dev->vinctl = 0x00; + + break; + case EM28XX_MT9M111: + dev->sensor_xres = 640; + dev->sensor_yres = 512; + + dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ; + em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); + em28xx_initialize_mt9m111(dev); + + dev->vinmode = 0x0a; + dev->vinctl = 0x00; + + break; + case EM28XX_NOSENSOR: + default: + return -EINVAL; + } + + return 0; +} diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index b745860794b3..1d3866f53c9b 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -2264,95 +2263,6 @@ static inline void em28xx_set_model(struct em28xx *dev) dev->def_i2c_bus = dev->board.def_i2c_bus; } - -/* FIXME: Should be replaced by a proper mt9m111 driver */ -static int em28xx_initialize_mt9m111(struct em28xx *dev) -{ - int i; - unsigned char regs[][3] = { - { 0x0d, 0x00, 0x01, }, /* reset and use defaults */ - { 0x0d, 0x00, 0x00, }, - { 0x0a, 0x00, 0x21, }, - { 0x21, 0x04, 0x00, }, /* full readout speed, no row/col skipping */ - }; - - for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], ®s[i][0], 3); - - return 0; -} - - -/* FIXME: Should be replaced by a proper mt9m001 driver */ -static int em28xx_initialize_mt9m001(struct em28xx *dev) -{ - int i; - unsigned char regs[][3] = { - { 0x0d, 0x00, 0x01, }, - { 0x0d, 0x00, 0x00, }, - { 0x04, 0x05, 0x00, }, /* hres = 1280 */ - { 0x03, 0x04, 0x00, }, /* vres = 1024 */ - { 0x20, 0x11, 0x00, }, - { 0x06, 0x00, 0x10, }, - { 0x2b, 0x00, 0x24, }, - { 0x2e, 0x00, 0x24, }, - { 0x35, 0x00, 0x24, }, - { 0x2d, 0x00, 0x20, }, - { 0x2c, 0x00, 0x20, }, - { 0x09, 0x0a, 0xd4, }, - { 0x35, 0x00, 0x57, }, - }; - - for (i = 0; i < ARRAY_SIZE(regs); i++) - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], ®s[i][0], 3); - - return 0; -} - -/* - * This method works for webcams with Micron sensors - */ -static int em28xx_detect_sensor(struct em28xx *dev) -{ - int rc; - char *sensor_name; - unsigned char cmd; - __be16 version_be; - u16 version; - - /* Micron sensor detection */ - dev->i2c_client[dev->def_i2c_bus].addr = 0xba >> 1; - cmd = 0; - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], &cmd, 1); - rc = i2c_master_recv(&dev->i2c_client[dev->def_i2c_bus], (char *)&version_be, 2); - if (rc != 2) - return -EINVAL; - - version = be16_to_cpu(version_be); - switch (version) { - case 0x8232: /* mt9v011 640x480 1.3 Mpix sensor */ - case 0x8243: /* mt9v011 rev B 640x480 1.3 Mpix sensor */ - sensor_name = "mt9v011"; - dev->em28xx_sensor = EM28XX_MT9V011; - break; - case 0x143a: /* MT9M111 as found in the ECS G200 */ - sensor_name = "mt9m111"; - dev->em28xx_sensor = EM28XX_MT9M111; - break; - case 0x8431: - sensor_name = "mt9m001"; - dev->em28xx_sensor = EM28XX_MT9M001; - break; - default: - printk("Unknown Micron Sensor 0x%04x\n", version); - return -EINVAL; - } - - em28xx_info("sensor %s detected\n", sensor_name); - - return 0; -} - /* Since em28xx_pre_card_setup() requires a proper dev->model, * this won't work for boards with generic PCI IDs */ @@ -2574,76 +2484,6 @@ static void em28xx_tuner_setup(struct em28xx *dev) v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); } -static int em28xx_init_camera(struct em28xx *dev) -{ - switch (dev->em28xx_sensor) { - case EM28XX_MT9V011: - { - struct mt9v011_platform_data pdata; - struct i2c_board_info mt9v011_info = { - .type = "mt9v011", - .addr = dev->i2c_client[dev->def_i2c_bus].addr, - .platform_data = &pdata, - }; - - dev->sensor_xres = 640; - dev->sensor_yres = 480; - - /* - * FIXME: mt9v011 uses I2S speed as xtal clk - at least with - * the Silvercrest cam I have here for testing - for higher - * resolutions, a high clock cause horizontal artifacts, so we - * need to use a lower xclk frequency. - * Yet, it would be possible to adjust xclk depending on the - * desired resolution, since this affects directly the - * frame rate. - */ - dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ; - em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); - dev->sensor_xtal = 4300000; - pdata.xtal = dev->sensor_xtal; - if (NULL == - v4l2_i2c_new_subdev_board(&dev->v4l2_dev, - &dev->i2c_adap[dev->def_i2c_bus], - &mt9v011_info, NULL)) - return -ENODEV; - /* probably means GRGB 16 bit bayer */ - dev->vinmode = 0x0d; - dev->vinctl = 0x00; - - break; - } - case EM28XX_MT9M001: - dev->sensor_xres = 1280; - dev->sensor_yres = 1024; - - em28xx_initialize_mt9m001(dev); - - /* probably means BGGR 16 bit bayer */ - dev->vinmode = 0x0c; - dev->vinctl = 0x00; - - break; - case EM28XX_MT9M111: - dev->sensor_xres = 640; - dev->sensor_yres = 512; - - dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ; - em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); - em28xx_initialize_mt9m111(dev); - - dev->vinmode = 0x0a; - dev->vinctl = 0x00; - - break; - case EM28XX_NOSENSOR: - default: - return -EINVAL; - } - - return 0; -} - static int em28xx_hint_board(struct em28xx *dev) { int i; diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 7be008f2d8a1..a14492ff1fd2 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -722,6 +722,10 @@ void em28xx_release_resources(struct em28xx *dev); /* Provided by em28xx-vbi.c */ extern struct vb2_ops em28xx_vbi_qops; +/* Provided by em28xx-camera.c */ +int em28xx_detect_sensor(struct em28xx *dev); +int em28xx_init_camera(struct em28xx *dev); + /* printk macros */ #define em28xx_err(fmt, arg...) do {\ -- cgit v1.2.3 From 176013b19e848204895bfcaea8b9b39fba5b26dd Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Wed, 27 Mar 2013 17:06:32 -0300 Subject: [media] em28xx: detect further Micron sensors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add further Micron chip IDs to be able to identify all Micron sensors listed by Empiatech. Also probe the two alternate i2c addresses used by Micron sensors with 8 bit address and 16 bit register width. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-camera.c | 126 +++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 31 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 28dd8489ac9c..2e4856aebae8 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -26,6 +26,15 @@ #include "em28xx.h" +/* Possible i2c addresses of Micron sensors */ +static unsigned short micron_sensor_addrs[] = { + 0xb8 >> 1, /* MT9V111, MT9V403 */ + 0xba >> 1, /* MT9M001/011/111/112, MT9V011/012/112, MT9D011 */ + 0x90 >> 1, /* MT9V012/112, MT9D011 (alternative address) */ + I2C_CLIENT_END +}; + + /* FIXME: Should be replaced by a proper mt9m111 driver */ static int em28xx_initialize_mt9m111(struct em28xx *dev) { @@ -78,44 +87,99 @@ static int em28xx_initialize_mt9m001(struct em28xx *dev) */ int em28xx_detect_sensor(struct em28xx *dev) { - int ret; + int ret, i; char *name; u8 reg; __be16 id_be; u16 id; - /* Micron sensor detection */ - dev->i2c_client[dev->def_i2c_bus].addr = 0xba >> 1; - reg = 0; - i2c_master_send(&dev->i2c_client[dev->def_i2c_bus], ®, 1); - ret = i2c_master_recv(&dev->i2c_client[dev->def_i2c_bus], - (char *)&id_be, 2); - if (ret != 2) - return -EINVAL; - - id = be16_to_cpu(id_be); - switch (id) { - case 0x8232: /* mt9v011 640x480 1.3 Mpix sensor */ - case 0x8243: /* mt9v011 rev B 640x480 1.3 Mpix sensor */ - name = "mt9v011"; - dev->em28xx_sensor = EM28XX_MT9V011; - break; - case 0x143a: /* MT9M111 as found in the ECS G200 */ - name = "mt9m111"; - dev->em28xx_sensor = EM28XX_MT9M111; - break; - case 0x8431: - name = "mt9m001"; - dev->em28xx_sensor = EM28XX_MT9M001; - break; - default: - em28xx_info("unknown Micron sensor detected: 0x%04x\n", id); - return -EINVAL; + struct i2c_client client = dev->i2c_client[dev->def_i2c_bus]; + + dev->em28xx_sensor = EM28XX_NOSENSOR; + /* Probe Micron sensors with 8 bit address and 16 bit register width */ + for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) { + client.addr = micron_sensor_addrs[i]; + /* NOTE: i2c_smbus_read_word_data() doesn't work with BE data */ + /* Read chip ID from register 0x00 */ + reg = 0x00; + ret = i2c_master_send(&client, ®, 1); + if (ret < 0) { + if (ret != -ENODEV) + em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); + continue; + } + ret = i2c_master_recv(&client, (u8 *)&id_be, 2); + if (ret < 0) { + em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); + continue; + } + id = be16_to_cpu(id_be); + /* Read chip ID from register 0xff */ + reg = 0xff; + ret = i2c_master_send(&client, ®, 1); + if (ret < 0) { + em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); + continue; + } + ret = i2c_master_recv(&client, (u8 *)&id_be, 2); + if (ret < 0) { + em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); + continue; + } + /* Validate chip ID to be sure we have a Micron device */ + if (id != be16_to_cpu(id_be)) + continue; + /* Check chip ID */ + id = be16_to_cpu(id_be); + switch (id) { + case 0x1222: + name = "MT9V012"; /* MI370 */ /* 640x480 */ + break; + case 0x1229: + name = "MT9V112"; /* 640x480 */ + break; + case 0x1433: + name = "MT9M011"; /* 1280x1024 */ + break; + case 0x143a: /* found in the ECS G200 */ + name = "MT9M111"; /* MI1310 */ /* 1280x1024 */ + dev->em28xx_sensor = EM28XX_MT9M111; + break; + case 0x148c: + name = "MT9M112"; /* MI1320 */ /* 1280x1024 */ + break; + case 0x1511: + name = "MT9D011"; /* MI2010 */ /* 1600x1200 */ + break; + case 0x8232: + case 0x8243: /* rev B */ + name = "MT9V011"; /* MI360 */ /* 640x480 */ + dev->em28xx_sensor = EM28XX_MT9V011; + break; + case 0x8431: + name = "MT9M001"; /* 1280x1024 */ + dev->em28xx_sensor = EM28XX_MT9M001; + break; + default: + em28xx_info("unknown Micron sensor detected: 0x%04x\n", + id); + return -EINVAL; + } + + if (dev->em28xx_sensor == EM28XX_NOSENSOR) + em28xx_info("unsupported sensor detected: %s\n", name); + else + em28xx_info("sensor %s detected\n", name); + + dev->i2c_client[dev->def_i2c_bus].addr = client.addr; + return 0; } - em28xx_info("sensor %s detected\n", name); - - return 0; + return -ENODEV; } int em28xx_init_camera(struct em28xx *dev) -- cgit v1.2.3 From 0af0b25a64458c3ee002efe6e7542013b94a268a Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Wed, 27 Mar 2013 17:06:33 -0300 Subject: [media] em28xx: move the probing of Micron sensors to a separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Other sensors like the ones from OmniVision need a different probing procedure, so it makes sense have separate functions for each manufacturer/sensor type. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-camera.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 2e4856aebae8..d744af6f7d08 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -83,9 +83,9 @@ static int em28xx_initialize_mt9m001(struct em28xx *dev) /* - * This method works for webcams with Micron sensors + * Probes Micron sensors with 8 bit address and 16 bit register width */ -int em28xx_detect_sensor(struct em28xx *dev) +static int em28xx_probe_sensor_micron(struct em28xx *dev) { int ret, i; char *name; @@ -96,7 +96,6 @@ int em28xx_detect_sensor(struct em28xx *dev) struct i2c_client client = dev->i2c_client[dev->def_i2c_bus]; dev->em28xx_sensor = EM28XX_NOSENSOR; - /* Probe Micron sensors with 8 bit address and 16 bit register width */ for (i = 0; micron_sensor_addrs[i] != I2C_CLIENT_END; i++) { client.addr = micron_sensor_addrs[i]; /* NOTE: i2c_smbus_read_word_data() doesn't work with BE data */ @@ -167,7 +166,7 @@ int em28xx_detect_sensor(struct em28xx *dev) default: em28xx_info("unknown Micron sensor detected: 0x%04x\n", id); - return -EINVAL; + return 0; } if (dev->em28xx_sensor == EM28XX_NOSENSOR) @@ -182,6 +181,22 @@ int em28xx_detect_sensor(struct em28xx *dev) return -ENODEV; } +/* + * This method works for webcams with Micron sensors + */ +int em28xx_detect_sensor(struct em28xx *dev) +{ + int ret; + + ret = em28xx_probe_sensor_micron(dev); + if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) { + em28xx_info("No sensor detected\n"); + return -ENODEV; + } + + return 0; +} + int em28xx_init_camera(struct em28xx *dev) { switch (dev->em28xx_sensor) { -- cgit v1.2.3 From bde03684323d12b5da0834475bf9964f064a403b Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Wed, 27 Mar 2013 17:06:34 -0300 Subject: [media] em28xx: add probing procedure for OmniVision sensors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OmniVision sensors are used as well in Empiatech based cameras such as the "SpeedLink Vicious And Devine Laplace" webcam (EM2765 + Omnivision OV2640). With this patch applied, OminiVision sensors with 8 bit address and register width are detected (recent models have a 16 bit address width and use different client addresses). The most commonly used sensors (including the ones listed by Empiatech) are detected properly, although there is no support for them yet. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-camera.c | 114 ++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index d744af6f7d08..e8b3322242c0 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -34,6 +34,13 @@ static unsigned short micron_sensor_addrs[] = { I2C_CLIENT_END }; +/* Possible i2c addresses of Omnivision sensors */ +static unsigned short omnivision_sensor_addrs[] = { + 0x42 >> 1, /* OV7725, OV7670/60/48 */ + 0x60 >> 1, /* OV2640, OV9650/53/55 */ + I2C_CLIENT_END +}; + /* FIXME: Should be replaced by a proper mt9m111 driver */ static int em28xx_initialize_mt9m111(struct em28xx *dev) @@ -182,13 +189,118 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) } /* - * This method works for webcams with Micron sensors + * Probes Omnivision sensors with 8 bit address and register width */ +static int em28xx_probe_sensor_omnivision(struct em28xx *dev) +{ + int ret, i; + char *name; + u8 reg; + u16 id; + struct i2c_client client = dev->i2c_client[dev->def_i2c_bus]; + + dev->em28xx_sensor = EM28XX_NOSENSOR; + /* NOTE: these devices have the register auto incrementation disabled + * by default, so we have to use single byte reads ! */ + for (i = 0; omnivision_sensor_addrs[i] != I2C_CLIENT_END; i++) { + client.addr = omnivision_sensor_addrs[i]; + /* Read manufacturer ID from registers 0x1c-0x1d (BE) */ + reg = 0x1c; + ret = i2c_smbus_read_byte_data(&client, reg); + if (ret < 0) { + if (ret != -ENODEV) + em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); + continue; + } + id = ret << 8; + reg = 0x1d; + ret = i2c_smbus_read_byte_data(&client, reg); + if (ret < 0) { + em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); + continue; + } + id += ret; + /* Check manufacturer ID */ + if (id != 0x7fa2) + continue; + /* Read product ID from registers 0x0a-0x0b (BE) */ + reg = 0x0a; + ret = i2c_smbus_read_byte_data(&client, reg); + if (ret < 0) { + em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); + continue; + } + id = ret << 8; + reg = 0x0b; + ret = i2c_smbus_read_byte_data(&client, reg); + if (ret < 0) { + em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); + continue; + } + id += ret; + /* Check product ID */ + switch (id) { + case 0x2642: + name = "OV2640"; + break; + case 0x7648: + name = "OV7648"; + break; + case 0x7660: + name = "OV7660"; + break; + case 0x7673: + name = "OV7670"; + break; + case 0x7720: + name = "OV7720"; + break; + case 0x7721: + name = "OV7725"; + break; + case 0x9648: /* Rev 2 */ + case 0x9649: /* Rev 3 */ + name = "OV9640"; + break; + case 0x9650: + case 0x9652: /* OV9653 */ + name = "OV9650"; + break; + case 0x9656: /* Rev 4 */ + case 0x9657: /* Rev 5 */ + name = "OV9655"; + break; + default: + em28xx_info("unknown OmniVision sensor detected: 0x%04x\n", + id); + return 0; + } + + if (dev->em28xx_sensor == EM28XX_NOSENSOR) + em28xx_info("unsupported sensor detected: %s\n", name); + else + em28xx_info("sensor %s detected\n", name); + + dev->i2c_client[dev->def_i2c_bus].addr = client.addr; + return 0; + } + + return -ENODEV; +} + int em28xx_detect_sensor(struct em28xx *dev) { int ret; ret = em28xx_probe_sensor_micron(dev); + + if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) + ret = em28xx_probe_sensor_omnivision(dev); + if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) { em28xx_info("No sensor detected\n"); return -ENODEV; -- cgit v1.2.3 From 52f1f2303f131d6d287a5316e35a4ec0d8ac8b98 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Wed, 27 Mar 2013 17:06:35 -0300 Subject: [media] em28xx: add comment about Samsung and Kodak sensor probing addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Windows driver also probes at least two further i2c addresses (0x22 >> 1 and 0x66 >> 1). I've got some hints that they are very likely used by Samsung and Kodak sensors, which are known to be used in Empia devices, too. We havn't seen any devices using these sensors yet and don't know how to probe them properly, so leave a comment. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-camera.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index e8b3322242c0..64b70d42da1e 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -301,6 +301,11 @@ int em28xx_detect_sensor(struct em28xx *dev) if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) ret = em28xx_probe_sensor_omnivision(dev); + /* + * NOTE: the Windows driver also probes i2c addresses + * 0x22 (Samsung ?) and 0x66 (Kodak ?) + */ + if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) { em28xx_info("No sensor detected\n"); return -ENODEV; -- cgit v1.2.3 From e4b7131dd51c3efb2656bc5b00aa96bfef17b709 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Wed, 27 Mar 2013 17:06:36 -0300 Subject: [media] em28xx: add basic support for OmniVision OV2640 sensors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This sensor is used by the "SpeedLink Vicious And Devine Laplace webcam" and others. It supports resolutions up to 1600x1200 (at 7-8 fps), but for resolutions higher than 640x480, further driver changes will be necessary, such as sensor output resolution switching (including further configuration changes), bridge xclk adjustment and disabling of 16 bit (12 bit) output formats at high resolutions. Image quality should also needs to be improved. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-camera.c | 49 ++++++++++++++++++++++++++++++++ drivers/media/usb/em28xx/em28xx.h | 1 + 2 files changed, 50 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 64b70d42da1e..73cc50afa5e1 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -20,6 +20,7 @@ */ #include +#include #include #include @@ -42,6 +43,13 @@ static unsigned short omnivision_sensor_addrs[] = { }; +static struct soc_camera_link camlink = { + .bus_id = 0, + .flags = 0, + .module_name = "em28xx", +}; + + /* FIXME: Should be replaced by a proper mt9m111 driver */ static int em28xx_initialize_mt9m111(struct em28xx *dev) { @@ -246,6 +254,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) switch (id) { case 0x2642: name = "OV2640"; + dev->em28xx_sensor = EM28XX_OV2640; break; case 0x7648: name = "OV7648"; @@ -376,6 +385,46 @@ int em28xx_init_camera(struct em28xx *dev) dev->vinctl = 0x00; break; + case EM28XX_OV2640: + { + struct v4l2_subdev *subdev; + struct i2c_board_info ov2640_info = { + .type = "ov2640", + .flags = I2C_CLIENT_SCCB, + .addr = dev->i2c_client[dev->def_i2c_bus].addr, + .platform_data = &camlink, + }; + struct v4l2_mbus_framefmt fmt; + + /* + * FIXME: sensor supports resolutions up to 1600x1200, but + * resolution setting/switching needs to be modified to + * - switch sensor output resolution (including further + * configuration changes) + * - adjust bridge xclk + * - disable 16 bit (12 bit) output formats on high resolutions + */ + dev->sensor_xres = 640; + dev->sensor_yres = 480; + + subdev = + v4l2_i2c_new_subdev_board(&dev->v4l2_dev, + &dev->i2c_adap[dev->def_i2c_bus], + &ov2640_info, NULL); + + fmt.code = V4L2_MBUS_FMT_YUYV8_2X8; + fmt.width = 640; + fmt.height = 480; + v4l2_subdev_call(subdev, video, s_mbus_fmt, &fmt); + + /* NOTE: for UXGA=1600x1200 switch to 12MHz */ + dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ; + em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); + dev->vinmode = 0x08; + dev->vinctl = 0x00; + + break; + } case EM28XX_NOSENSOR: default: return -EINVAL; diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index a14492ff1fd2..a9323b63d8e5 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -364,6 +364,7 @@ enum em28xx_sensor { EM28XX_MT9V011, EM28XX_MT9M001, EM28XX_MT9M111, + EM28XX_OV2640, }; enum em28xx_adecoder { -- cgit v1.2.3 From 6d43be7789db0455a82a3ad4ff5f713cc588c1e2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 26 Mar 2013 08:04:52 -0300 Subject: [media] ioctl numbers are unsigned int ioctl's number is unsigned int. Fix it at vidioc_default. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx18/cx18-ioctl.c | 2 +- drivers/media/pci/ivtv/ivtv-ioctl.c | 2 +- drivers/media/pci/meye/meye.c | 2 +- drivers/media/platform/davinci/vpfe_capture.c | 2 +- drivers/media/radio/radio-si4713.c | 2 +- drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c | 2 +- include/media/v4l2-ioctl.h | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 7dbd5a9451ed..aee7b6dacbfe 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -1110,7 +1110,7 @@ static int cx18_log_status(struct file *file, void *fh) } static long cx18_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) + unsigned int cmd, void *arg) { struct cx18 *cx = fh2id(fh)->cx; diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 50379b26768b..9cbbce0eaedc 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -1807,7 +1807,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) } static long ivtv_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) + unsigned int cmd, void *arg) { struct ivtv *itv = fh2id(fh)->itv; diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index 7859c43479d7..2381b05432e6 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1410,7 +1410,7 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) } static long vidioc_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) + unsigned int cmd, void *arg) { switch (cmd) { case MEYEIOC_G_PARAMS: diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 20db8a077990..8c50d3074866 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1686,7 +1686,7 @@ unlock_out: static long vpfe_param_handler(struct file *file, void *priv, - bool valid_prio, int cmd, void *param) + bool valid_prio, unsigned int cmd, void *param) { struct vpfe_device *vpfe_dev = video_drvdata(file); int ret = 0; diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 2a2d21ed9133..38b3f1541c4e 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -222,7 +222,7 @@ static int radio_si4713_s_frequency(struct file *file, void *p, } static long radio_si4713_default(struct file *file, void *p, - bool valid_prio, int cmd, void *arg) + bool valid_prio, unsigned int cmd, void *arg) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, ioctl, cmd, arg); diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c index 39a8fb2802e4..6c7d20f8f67c 100644 --- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c @@ -1021,7 +1021,7 @@ static int solo_s_parm(struct file *file, void *priv, } static long solo_enc_default(struct file *file, void *fh, - bool valid_prio, int cmd, void *arg) + bool valid_prio, unsigned int cmd, void *arg) { struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_dev *solo_dev = solo_enc->solo_dev; diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 75a7dfc07dec..b273f0e81818 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -275,7 +275,7 @@ struct v4l2_ioctl_ops { /* For other private ioctls */ long (*vidioc_default) (struct file *file, void *fh, - bool valid_prio, int cmd, void *arg); + bool valid_prio, unsigned int cmd, void *arg); }; -- cgit v1.2.3 From 471c4dd38642eb881c4da8372d69e8d11e450a79 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Thu, 28 Mar 2013 17:33:57 -0300 Subject: [media] gspca: remove obsolete Kconfig macros The et61x251 driver was removed in v3.5. Remove the last references to its Kconfig macro now. Signed-off-by: Paul Bolle Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/etoms.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/gspca/etoms.c b/drivers/media/usb/gspca/etoms.c index 948a6357573d..26c9ee1f1045 100644 --- a/drivers/media/usb/gspca/etoms.c +++ b/drivers/media/usb/gspca/etoms.c @@ -766,9 +766,7 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106}, -#if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE {USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX}, -#endif {} }; -- cgit v1.2.3 From 4b0cac5e759552a24dbdc940db268601422d5b0a Mon Sep 17 00:00:00 2001 From: Alexey Klimov Date: Thu, 14 Mar 2013 18:12:06 -0300 Subject: [media] radio-mr800: move clamp_t check inside amradio_set_freq() If i run verbose v4l2-compliance with my radio-mr800 device few times then i get warning about frequency out of range: root@machine:~# v4l2-compliance -r /dev/radio0 -v 2 is radio Driver Info: Driver name : radio-mr800 Card type : AverMedia MR 800 USB FM Radio Bus info : usb-0000:00:1a.0-1.2 Driver version: 3.9.0 Capabilities : 0x80050400 Tuner Radio Device Capabilities Device Caps : 0x00050400 Tuner Radio Compliance test for device /dev/radio0 (not using libv4l2): Required ioctls: test VIDIOC_QUERYCAP: OK Allow for multiple opens: test second radio open: OK test VIDIOC_QUERYCAP: OK test VIDIOC_G/S_PRIORITY: OK Debug ioctls: test VIDIOC_DBG_G_CHIP_IDENT: OK (Not Supported) test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported) test VIDIOC_LOG_STATUS: OK Input ioctls: test VIDIOC_G/S_TUNER: OK warn: v4l2-test-input-output.cpp(234): returned tuner 0 frequency out of range (6550200 not in [1400000...1728000]) test VIDIOC_G/S_FREQUENCY: OK test VIDIOC_S_HW_FREQ_SEEK: OK test VIDIOC_ENUMAUDIO: OK (Not Supported) test VIDIOC_G/S/ENUMINPUT: OK (Not Supported) test VIDIOC_G/S_AUDIO: OK (Not Supported) Inputs: 0 Audio Inputs: 0 Tuners: 1 Output ioctls: test VIDIOC_G/S_MODULATOR: OK (Not Supported) test VIDIOC_G/S_FREQUENCY: OK test VIDIOC_ENUMAUDOUT: OK (Not Supported) test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported) test VIDIOC_G/S_AUDOUT: OK (Not Supported) Outputs: 0 Audio Outputs: 0 Modulators: 0 Control ioctls: info: checking v4l2_queryctrl of control 'User Controls' (0x00980001) info: checking v4l2_queryctrl of control 'Mute' (0x00980909) info: checking v4l2_queryctrl of control 'Mute' (0x00980909) test VIDIOC_QUERYCTRL/MENU: OK info: checking control 'User Controls' (0x00980001) info: checking control 'Mute' (0x00980909) test VIDIOC_G/S_CTRL: OK info: checking extended control 'User Controls' (0x00980001) info: checking extended control 'Mute' (0x00980909) test VIDIOC_G/S/TRY_EXT_CTRLS: OK info: checking control event 'User Controls' (0x00980001) info: checking control event 'Mute' (0x00980909) test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK test VIDIOC_G/S_JPEGCOMP: OK (Not Supported) Standard Controls: 2 Private Controls: 0 Input/Output configuration ioctls: test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported) test VIDIOC_ENUM/G/S/QUERY_DV_PRESETS: OK (Not Supported) test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported) test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported) Format ioctls: test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported) test VIDIOC_G/S_PARM: OK (Not Supported) test VIDIOC_G_FBUF: OK (Not Supported) test VIDIOC_G_FMT: OK (Not Supported) test VIDIOC_TRY_FMT: OK (Not Supported) test VIDIOC_S_FMT: OK (Not Supported) test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported) Codec ioctls: test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported) test VIDIOC_G_ENC_INDEX: OK (Not Supported) test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported) Buffer ioctls: test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported) Total: 38, Succeeded: 38, Failed: 0, Warnings: 1 Some printk() debugging showed that vidioc_s_hw_freq_seek() setups radio->curfreq to out of range value (lines 395-396) and calls amradio_set_freq() to set this frequency on device without any out-of-range checks. Patch protects from setting up frequency on device to incorrect value moving clamp_t check inside amradio_set_freq. With this patch we can call amradio_set_freq() with out of range frequency from any place. Also put comment that sometimes radio->curfreq is set to out of range value in vidioc_s_hw_freq_seek(). Signed-off-by: Alexey Klimov Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-mr800.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index 2ce75d1564dc..a360227ca3ab 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -203,10 +203,14 @@ static int amradio_set_mute(struct amradio_device *radio, bool mute) /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ static int amradio_set_freq(struct amradio_device *radio, int freq) { - unsigned short freq_send = 0x10 + (freq >> 3) / 25; + unsigned short freq_send; u8 buf[3]; int retval; + /* we need to be sure that frequency isn't out of range */ + freq = clamp_t(unsigned, freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL); + freq_send = 0x10 + (freq >> 3) / 25; + /* frequency is calculated from freq_send and placed in first 2 bytes */ buf[0] = (freq_send >> 8) & 0xff; buf[1] = freq_send & 0xff; @@ -329,8 +333,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, if (f->tuner != 0) return -EINVAL; - return amradio_set_freq(radio, clamp_t(unsigned, f->frequency, - FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL)); + return amradio_set_freq(radio, f->frequency); } /* vidioc_g_frequency - get tuner radio frequency */ @@ -389,6 +392,7 @@ static int vidioc_s_hw_freq_seek(struct file *file, void *priv, continue; amradio_send_cmd(radio, AMRADIO_GET_FREQ, 0, NULL, 0, true); if (radio->buffer[1] || radio->buffer[2]) { + /* To check: sometimes radio->curfreq is set to out of range value */ radio->curfreq = (radio->buffer[1] << 8) | radio->buffer[2]; radio->curfreq = (radio->curfreq - 0x10) * 200; amradio_send_cmd(radio, AMRADIO_STOP_SEARCH, -- cgit v1.2.3 From aec330a8cbd373d78c327201ec28fd5f252f3846 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 26 Mar 2013 22:47:23 -0300 Subject: [media] v4l2: Add standard controls for FM receivers This commit introduces new class of standard controls V4L2_CTRL_CLASS_FM_RX. This class is intended to all controls pertaining to FM receiver chips. Also, two controls belonging to said class are added as a part of this commit: V4L2_CID_TUNE_DEEMPHASIS and V4L2_CID_RDS_RECEPTION. This patch is based on the code found in the patch by Manjunatha Halli [1] [1] http://lists-archives.com/linux-kernel/27641307-new-control-class-and-features-for-fm-rx.html Acked-by: Hans Verkuil Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 14 +++++++++++--- include/uapi/linux/v4l2-controls.h | 13 +++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index f662df3bfe2d..ec89fd16361c 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -297,8 +297,8 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Text", NULL }; - static const char * const tune_preemphasis[] = { - "No Preemphasis", + static const char * const tune_emphasis[] = { + "None", "50 Microseconds", "75 Microseconds", NULL, @@ -508,7 +508,9 @@ const char * const *v4l2_ctrl_get_menu(u32 id) case V4L2_CID_SCENE_MODE: return scene_mode; case V4L2_CID_TUNE_PREEMPHASIS: - return tune_preemphasis; + return tune_emphasis; + case V4L2_CID_TUNE_DEEMPHASIS: + return tune_emphasis; case V4L2_CID_FLASH_LED_MODE: return flash_led_mode; case V4L2_CID_FLASH_STROBE_SOURCE: @@ -800,6 +802,9 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_DV_RX_POWER_PRESENT: return "Power Present"; case V4L2_CID_DV_RX_RGB_RANGE: return "Rx RGB Quantization Range"; + case V4L2_CID_FM_RX_CLASS: return "FM Radio Receiver Controls"; + case V4L2_CID_TUNE_DEEMPHASIS: return "De-Emphasis"; + case V4L2_CID_RDS_RECEPTION: return "RDS Reception"; default: return NULL; } @@ -848,6 +853,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: case V4L2_CID_WIDE_DYNAMIC_RANGE: case V4L2_CID_IMAGE_STABILIZATION: + case V4L2_CID_RDS_RECEPTION: *type = V4L2_CTRL_TYPE_BOOLEAN; *min = 0; *max = *step = 1; @@ -906,6 +912,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_DV_TX_RGB_RANGE: case V4L2_CID_DV_RX_RGB_RANGE: case V4L2_CID_TEST_PATTERN: + case V4L2_CID_TUNE_DEEMPHASIS: *type = V4L2_CTRL_TYPE_MENU; break; case V4L2_CID_LINK_FREQ: @@ -928,6 +935,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_IMAGE_SOURCE_CLASS: case V4L2_CID_IMAGE_PROC_CLASS: case V4L2_CID_DV_CLASS: + case V4L2_CID_FM_RX_CLASS: *type = V4L2_CTRL_TYPE_CTRL_CLASS; /* You can neither read not write these */ *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 844dc0205037..7d2604877a73 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -59,6 +59,7 @@ #define V4L2_CTRL_CLASS_IMAGE_SOURCE 0x009e0000 /* Image source controls */ #define V4L2_CTRL_CLASS_IMAGE_PROC 0x009f0000 /* Image processing controls */ #define V4L2_CTRL_CLASS_DV 0x00a00000 /* Digital Video controls */ +#define V4L2_CTRL_CLASS_FM_RX 0x00a10000 /* Digital Video controls */ /* User-class control IDs */ @@ -835,4 +836,16 @@ enum v4l2_dv_rgb_range { #define V4L2_CID_DV_RX_POWER_PRESENT (V4L2_CID_DV_CLASS_BASE + 100) #define V4L2_CID_DV_RX_RGB_RANGE (V4L2_CID_DV_CLASS_BASE + 101) +#define V4L2_CID_FM_RX_CLASS_BASE (V4L2_CTRL_CLASS_FM_RX | 0x900) +#define V4L2_CID_FM_RX_CLASS (V4L2_CTRL_CLASS_FM_RX | 1) + +#define V4L2_CID_TUNE_DEEMPHASIS (V4L2_CID_FM_RX_CLASS_BASE + 1) +enum v4l2_deemphasis { + V4L2_DEEMPHASIS_DISABLED = V4L2_PREEMPHASIS_DISABLED, + V4L2_DEEMPHASIS_50_uS = V4L2_PREEMPHASIS_50_uS, + V4L2_DEEMPHASIS_75_uS = V4L2_PREEMPHASIS_75_uS, +}; + +#define V4L2_CID_RDS_RECEPTION (V4L2_CID_FM_RX_CLASS_BASE + 2) + #endif -- cgit v1.2.3 From 30bac9110455402fa8888740c6819dd3daa2666f Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 26 Mar 2013 22:47:26 -0300 Subject: [media] v4l2: Add a V4L2 driver for SI476X MFD This commit adds a driver that exposes all the radio related functionality of the Si476x series of chips via the V4L2 subsystem. Acked-by: Hans Verkuil Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/si476x.txt | 187 ++++ drivers/media/radio/Kconfig | 17 + drivers/media/radio/Makefile | 1 + drivers/media/radio/radio-si476x.c | 1599 ++++++++++++++++++++++++++++++++++ include/media/si476x.h | 426 +++++++++ 5 files changed, 2230 insertions(+) create mode 100644 Documentation/video4linux/si476x.txt create mode 100644 drivers/media/radio/radio-si476x.c create mode 100644 include/media/si476x.h (limited to 'drivers/media') diff --git a/Documentation/video4linux/si476x.txt b/Documentation/video4linux/si476x.txt new file mode 100644 index 000000000000..d1a08db2cbd9 --- /dev/null +++ b/Documentation/video4linux/si476x.txt @@ -0,0 +1,187 @@ +SI476x Driver Readme +------------------------------------------------ + Copyright (C) 2013 Andrey Smirnov + +TODO for the driver +------------------------------ + +- According to the SiLabs' datasheet it is possible to update the + firmware of the radio chip in the run-time, thus bringing it to the + most recent version. Unfortunately I couldn't find any mentioning of + the said firmware update for the old chips that I tested the driver + against, so for chips like that the driver only exposes the old + functionality. + + +Parameters exposed over debugfs +------------------------------- +SI476x allow user to get multiple characteristics that can be very +useful for EoL testing/RF performance estimation, parameters that have +very little to do with V4L2 subsystem. Such parameters are exposed via +debugfs and can be accessed via regular file I/O operations. + +The drivers exposes following files: + +* /sys/kernel/debug//acf + This file contains ACF(Automatically Controlled Features) status + information. The contents of the file is binary data of the + following layout: + + Offset | Name | Description + ==================================================================== + 0x00 | blend_int | Flag, set when stereo separation has + | | crossed below the blend threshold + -------------------------------------------------------------------- + 0x01 | hblend_int | Flag, set when HiBlend cutoff + | | frequency is lower than threshold + -------------------------------------------------------------------- + 0x02 | hicut_int | Flag, set when HiCut cutoff + | | frequency is lower than threshold + -------------------------------------------------------------------- + 0x03 | chbw_int | Flag, set when channel filter + | | bandwidth is less than threshold + -------------------------------------------------------------------- + 0x04 | softmute_int | Flag indicating that softmute + | | attenuation has increased above + | | softmute threshold + -------------------------------------------------------------------- + 0x05 | smute | 0 - Audio is not soft muted + | | 1 - Audio is soft muted + -------------------------------------------------------------------- + 0x06 | smattn | Soft mute attenuation level in dB + -------------------------------------------------------------------- + 0x07 | chbw | Channel filter bandwidth in kHz + -------------------------------------------------------------------- + 0x08 | hicut | HiCut cutoff frequency in units of + | | 100Hz + -------------------------------------------------------------------- + 0x09 | hiblend | HiBlend cutoff frequency in units + | | of 100 Hz + -------------------------------------------------------------------- + 0x10 | pilot | 0 - Stereo pilot is not present + | | 1 - Stereo pilot is present + -------------------------------------------------------------------- + 0x11 | stblend | Stereo blend in % + -------------------------------------------------------------------- + + +* /sys/kernel/debug//rds_blckcnt + This file contains statistics about RDS receptions. It's binary data + has the following layout: + + Offset | Name | Description + ==================================================================== + 0x00 | expected | Number of expected RDS blocks + -------------------------------------------------------------------- + 0x02 | received | Number of received RDS blocks + -------------------------------------------------------------------- + 0x04 | uncorrectable | Number of uncorrectable RDS blocks + -------------------------------------------------------------------- + +* /sys/kernel/debug//agc + This file contains information about parameters pertaining to + AGC(Automatic Gain Control) + + The layout is: + Offset | Name | Description + ==================================================================== + 0x00 | mxhi | 0 - FM Mixer PD high threshold is + | | not tripped + | | 1 - FM Mixer PD high threshold is + | | tripped + -------------------------------------------------------------------- + 0x01 | mxlo | ditto for FM Mixer PD low + -------------------------------------------------------------------- + 0x02 | lnahi | ditto for FM LNA PD high + -------------------------------------------------------------------- + 0x03 | lnalo | ditto for FM LNA PD low + -------------------------------------------------------------------- + 0x04 | fmagc1 | FMAGC1 attenuator resistance + | | (see datasheet for more detail) + -------------------------------------------------------------------- + 0x05 | fmagc2 | ditto for FMAGC2 + -------------------------------------------------------------------- + 0x06 | pgagain | PGA gain in dB + -------------------------------------------------------------------- + 0x07 | fmwblang | FM/WB LNA Gain in dB + -------------------------------------------------------------------- + +* /sys/kernel/debug//rsq + This file contains information about parameters pertaining to + RSQ(Received Signal Quality) + + The layout is: + Offset | Name | Description + ==================================================================== + 0x00 | multhint | 0 - multipath value has not crossed + | | the Multipath high threshold + | | 1 - multipath value has crossed + | | the Multipath high threshold + -------------------------------------------------------------------- + 0x01 | multlint | ditto for Multipath low threshold + -------------------------------------------------------------------- + 0x02 | snrhint | 0 - received signal's SNR has not + | | crossed high threshold + | | 1 - received signal's SNR has + | | crossed high threshold + -------------------------------------------------------------------- + 0x03 | snrlint | ditto for low threshold + -------------------------------------------------------------------- + 0x04 | rssihint | ditto for RSSI high threshold + -------------------------------------------------------------------- + 0x05 | rssilint | ditto for RSSI low threshold + -------------------------------------------------------------------- + 0x06 | bltf | Flag indicating if seek command + | | reached/wrapped seek band limit + -------------------------------------------------------------------- + 0x07 | snr_ready | Indicates that SNR metrics is ready + -------------------------------------------------------------------- + 0x08 | rssiready | ditto for RSSI metrics + -------------------------------------------------------------------- + 0x09 | injside | 0 - Low-side injection is being used + | | 1 - High-side injection is used + -------------------------------------------------------------------- + 0x10 | afcrl | Flag indicating if AFC rails + -------------------------------------------------------------------- + 0x11 | valid | Flag indicating if channel is valid + -------------------------------------------------------------------- + 0x12 | readfreq | Current tuned frequency + -------------------------------------------------------------------- + 0x14 | freqoff | Singed frequency offset in units of + | | 2ppm + -------------------------------------------------------------------- + 0x15 | rssi | Signed value of RSSI in dBuV + -------------------------------------------------------------------- + 0x16 | snr | Signed RF SNR in dB + -------------------------------------------------------------------- + 0x17 | issi | Signed Image Strength Signal + | | indicator + -------------------------------------------------------------------- + 0x18 | lassi | Signed Low side adjacent Channel + | | Strength indicator + -------------------------------------------------------------------- + 0x19 | hassi | ditto fpr High side + -------------------------------------------------------------------- + 0x20 | mult | Multipath indicator + -------------------------------------------------------------------- + 0x21 | dev | Frequency deviation + -------------------------------------------------------------------- + 0x24 | assi | Adjascent channel SSI + -------------------------------------------------------------------- + 0x25 | usn | Ultrasonic noise indicator + -------------------------------------------------------------------- + 0x26 | pilotdev | Pilot deviation in units of 100 Hz + -------------------------------------------------------------------- + 0x27 | rdsdev | ditto for RDS + -------------------------------------------------------------------- + 0x28 | assidev | ditto for ASSI + -------------------------------------------------------------------- + 0x29 | strongdev | Frequency deviation + -------------------------------------------------------------------- + 0x30 | rdspi | RDS PI code + -------------------------------------------------------------------- + +* /sys/kernel/debug//rsq_primary + This file contains information about parameters pertaining to + RSQ(Received Signal Quality) for primary tuner only. Layout is as + the one above. diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 24e64a09884c..28ded247abc0 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -18,6 +18,23 @@ config RADIO_SI470X source "drivers/media/radio/si470x/Kconfig" +config RADIO_SI476X + tristate "Silicon Laboratories Si476x I2C FM Radio" + depends on I2C && VIDEO_V4L2 + select MFD_CORE + select MFD_SI476X_CORE + select SND_SOC_SI476X + ---help--- + Choose Y here if you have this FM radio chip. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux 2 API. Information on + this API and pointers to "v4l2" programs may be found at + . + + To compile this driver as a module, choose M here: the + module will be called radio-si476x. + config USB_MR800 tristate "AverMedia MR 800 USB FM radio support" depends on USB && VIDEO_V4L2 diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index 303eaebdb85a..0dcdb320cfc7 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o +obj-$(CONFIG_RADIO_SI476X) += radio-si476x.o obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_RADIO_SI470X) += si470x/ diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c new file mode 100644 index 000000000000..0895a0c23787 --- /dev/null +++ b/drivers/media/radio/radio-si476x.c @@ -0,0 +1,1599 @@ +/* + * drivers/media/radio/radio-si476x.c -- V4L2 driver for SI476X chips + * + * Copyright (C) 2012 Innovative Converged Devices(ICD) + * Copyright (C) 2013 Andrey Smirnov + * + * Author: Andrey Smirnov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define FM_FREQ_RANGE_LOW 64000000 +#define FM_FREQ_RANGE_HIGH 108000000 + +#define AM_FREQ_RANGE_LOW 520000 +#define AM_FREQ_RANGE_HIGH 30000000 + +#define PWRLINEFLTR (1 << 8) + +#define FREQ_MUL (10000000 / 625) + +#define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0b10000000 & (status)) + +#define DRIVER_NAME "si476x-radio" +#define DRIVER_CARD "SI476x AM/FM Receiver" + +enum si476x_freq_bands { + SI476X_BAND_FM, + SI476X_BAND_AM, +}; + +static const struct v4l2_frequency_band si476x_bands[] = { + [SI476X_BAND_FM] = { + .type = V4L2_TUNER_RADIO, + .index = SI476X_BAND_FM, + .capability = V4L2_TUNER_CAP_LOW + | V4L2_TUNER_CAP_STEREO + | V4L2_TUNER_CAP_RDS + | V4L2_TUNER_CAP_RDS_BLOCK_IO + | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 64 * FREQ_MUL, + .rangehigh = 108 * FREQ_MUL, + .modulation = V4L2_BAND_MODULATION_FM, + }, + [SI476X_BAND_AM] = { + .type = V4L2_TUNER_RADIO, + .index = SI476X_BAND_AM, + .capability = V4L2_TUNER_CAP_LOW + | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 0.52 * FREQ_MUL, + .rangehigh = 30 * FREQ_MUL, + .modulation = V4L2_BAND_MODULATION_AM, + }, +}; + +static inline bool si476x_radio_freq_is_inside_of_the_band(u32 freq, int band) +{ + return freq >= si476x_bands[band].rangelow && + freq <= si476x_bands[band].rangehigh; +} + +static inline bool si476x_radio_range_is_inside_of_the_band(u32 low, u32 high, + int band) +{ + return low >= si476x_bands[band].rangelow && + high <= si476x_bands[band].rangehigh; +} + +static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl); +static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl); + +enum phase_diversity_modes_idx { + SI476X_IDX_PHDIV_DISABLED, + SI476X_IDX_PHDIV_PRIMARY_COMBINING, + SI476X_IDX_PHDIV_PRIMARY_ANTENNA, + SI476X_IDX_PHDIV_SECONDARY_ANTENNA, + SI476X_IDX_PHDIV_SECONDARY_COMBINING, +}; + +static const char * const phase_diversity_modes[] = { + [SI476X_IDX_PHDIV_DISABLED] = "Disabled", + [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = "Primary with Secondary", + [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = "Primary Antenna", + [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = "Secondary Antenna", + [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = "Secondary with Primary", +}; + +static inline enum phase_diversity_modes_idx +si476x_phase_diversity_mode_to_idx(enum si476x_phase_diversity_mode mode) +{ + switch (mode) { + default: /* FALLTHROUGH */ + case SI476X_PHDIV_DISABLED: + return SI476X_IDX_PHDIV_DISABLED; + case SI476X_PHDIV_PRIMARY_COMBINING: + return SI476X_IDX_PHDIV_PRIMARY_COMBINING; + case SI476X_PHDIV_PRIMARY_ANTENNA: + return SI476X_IDX_PHDIV_PRIMARY_ANTENNA; + case SI476X_PHDIV_SECONDARY_ANTENNA: + return SI476X_IDX_PHDIV_SECONDARY_ANTENNA; + case SI476X_PHDIV_SECONDARY_COMBINING: + return SI476X_IDX_PHDIV_SECONDARY_COMBINING; + } +} + +static inline enum si476x_phase_diversity_mode +si476x_phase_diversity_idx_to_mode(enum phase_diversity_modes_idx idx) +{ + static const int idx_to_value[] = { + [SI476X_IDX_PHDIV_DISABLED] = SI476X_PHDIV_DISABLED, + [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = SI476X_PHDIV_PRIMARY_COMBINING, + [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = SI476X_PHDIV_PRIMARY_ANTENNA, + [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = SI476X_PHDIV_SECONDARY_ANTENNA, + [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = SI476X_PHDIV_SECONDARY_COMBINING, + }; + + return idx_to_value[idx]; +} + +static const struct v4l2_ctrl_ops si476x_ctrl_ops = { + .g_volatile_ctrl = si476x_radio_g_volatile_ctrl, + .s_ctrl = si476x_radio_s_ctrl, +}; + + +enum si476x_ctrl_idx { + SI476X_IDX_RSSI_THRESHOLD, + SI476X_IDX_SNR_THRESHOLD, + SI476X_IDX_MAX_TUNE_ERROR, + SI476X_IDX_HARMONICS_COUNT, + SI476X_IDX_DIVERSITY_MODE, + SI476X_IDX_INTERCHIP_LINK, +}; +static struct v4l2_ctrl_config si476x_ctrls[] = { + + /** + * SI476X during its station seeking(or tuning) process uses several + * parameters to detrmine if "the station" is valid: + * + * - Signal's SNR(in dBuV) must be lower than + * #V4L2_CID_SI476X_SNR_THRESHOLD + * - Signal's RSSI(in dBuV) must be greater than + * #V4L2_CID_SI476X_RSSI_THRESHOLD + * - Signal's frequency deviation(in units of 2ppm) must not be + * more than #V4L2_CID_SI476X_MAX_TUNE_ERROR + */ + [SI476X_IDX_RSSI_THRESHOLD] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_RSSI_THRESHOLD, + .name = "Valid RSSI Threshold", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = -128, + .max = 127, + .step = 1, + }, + [SI476X_IDX_SNR_THRESHOLD] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_SNR_THRESHOLD, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Valid SNR Threshold", + .min = -128, + .max = 127, + .step = 1, + }, + [SI476X_IDX_MAX_TUNE_ERROR] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_MAX_TUNE_ERROR, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Max Tune Errors", + .min = 0, + .max = 126 * 2, + .step = 2, + }, + + /** + * #V4L2_CID_SI476X_HARMONICS_COUNT -- number of harmonics + * built-in power-line noise supression filter is to reject + * during AM-mode operation. + */ + [SI476X_IDX_HARMONICS_COUNT] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_HARMONICS_COUNT, + .type = V4L2_CTRL_TYPE_INTEGER, + + .name = "Count of Harmonics to Reject", + .min = 0, + .max = 20, + .step = 1, + }, + + /** + * #V4L2_CID_SI476X_DIVERSITY_MODE -- configuration which + * two tuners working in diversity mode are to work in. + * + * - #SI476X_IDX_PHDIV_DISABLED diversity mode disabled + * - #SI476X_IDX_PHDIV_PRIMARY_COMBINING diversity mode is + * on, primary tuner's antenna is the main one. + * - #SI476X_IDX_PHDIV_PRIMARY_ANTENNA diversity mode is + * off, primary tuner's antenna is the main one. + * - #SI476X_IDX_PHDIV_SECONDARY_ANTENNA diversity mode is + * off, secondary tuner's antenna is the main one. + * - #SI476X_IDX_PHDIV_SECONDARY_COMBINING diversity mode is + * on, secondary tuner's antenna is the main one. + */ + [SI476X_IDX_DIVERSITY_MODE] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_DIVERSITY_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Phase Diversity Mode", + .qmenu = phase_diversity_modes, + .min = 0, + .max = ARRAY_SIZE(phase_diversity_modes) - 1, + }, + + /** + * #V4L2_CID_SI476X_INTERCHIP_LINK -- inter-chip link in + * diversity mode indicator. Allows user to determine if two + * chips working in diversity mode have established a link + * between each other and if the system as a whole uses + * signals from both antennas to receive FM radio. + */ + [SI476X_IDX_INTERCHIP_LINK] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_INTERCHIP_LINK, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, + .name = "Inter-Chip Link", + .min = 0, + .max = 1, + .step = 1, + }, +}; + +struct si476x_radio; + +/** + * struct si476x_radio_ops - vtable of tuner functions + * + * This table holds pointers to functions implementing particular + * operations depending on the mode in which the tuner chip was + * configured to start in. If the function is not supported + * corresponding element is set to #NULL. + * + * @tune_freq: Tune chip to a specific frequency + * @seek_start: Star station seeking + * @rsq_status: Get Recieved Signal Quality(RSQ) status + * @rds_blckcnt: Get recived RDS blocks count + * @phase_diversity: Change phase diversity mode of the tuner + * @phase_div_status: Get phase diversity mode status + * @acf_status: Get the status of Automatically Controlled + * Features(ACF) + * @agc_status: Get Automatic Gain Control(AGC) status + */ +struct si476x_radio_ops { + int (*tune_freq)(struct si476x_core *, struct si476x_tune_freq_args *); + int (*seek_start)(struct si476x_core *, bool, bool); + int (*rsq_status)(struct si476x_core *, struct si476x_rsq_status_args *, + struct si476x_rsq_status_report *); + int (*rds_blckcnt)(struct si476x_core *, bool, + struct si476x_rds_blockcount_report *); + + int (*phase_diversity)(struct si476x_core *, + enum si476x_phase_diversity_mode); + int (*phase_div_status)(struct si476x_core *); + int (*acf_status)(struct si476x_core *, + struct si476x_acf_status_report *); + int (*agc_status)(struct si476x_core *, + struct si476x_agc_status_report *); +}; + +/** + * struct si476x_radio - radio device + * + * @core: Pointer to underlying core device + * @videodev: Pointer to video device created by V4L2 subsystem + * @ops: Vtable of functions. See struct si476x_radio_ops for details + * @kref: Reference counter + * @core_lock: An r/w semaphore to brebvent the deletion of underlying + * core structure is the radio device is being used + */ +struct si476x_radio { + struct v4l2_device v4l2dev; + struct video_device videodev; + struct v4l2_ctrl_handler ctrl_handler; + + struct si476x_core *core; + /* This field should not be accesses unless core lock is held */ + const struct si476x_radio_ops *ops; + + struct dentry *debugfs; + u32 audmode; +}; + +static inline struct si476x_radio * +v4l2_dev_to_radio(struct v4l2_device *d) +{ + return container_of(d, struct si476x_radio, v4l2dev); +} + +static inline struct si476x_radio * +v4l2_ctrl_handler_to_radio(struct v4l2_ctrl_handler *d) +{ + return container_of(d, struct si476x_radio, ctrl_handler); +} + +/* + * si476x_vidioc_querycap - query device capabilities + */ +static int si476x_radio_querycap(struct file *file, void *priv, + struct v4l2_capability *capability) +{ + struct si476x_radio *radio = video_drvdata(file); + + strlcpy(capability->driver, radio->v4l2dev.name, + sizeof(capability->driver)); + strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); + snprintf(capability->bus_info, sizeof(capability->bus_info), + "platform:%s", radio->v4l2dev.name); + + capability->device_caps = V4L2_CAP_TUNER + | V4L2_CAP_RADIO + | V4L2_CAP_HW_FREQ_SEEK; + + si476x_core_lock(radio->core); + if (!si476x_core_is_a_secondary_tuner(radio->core)) + capability->device_caps |= V4L2_CAP_RDS_CAPTURE + | V4L2_CAP_READWRITE; + si476x_core_unlock(radio->core); + + capability->capabilities = capability->device_caps + | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int si476x_radio_enum_freq_bands(struct file *file, void *priv, + struct v4l2_frequency_band *band) +{ + int err; + struct si476x_radio *radio = video_drvdata(file); + + if (band->tuner != 0) + return -EINVAL; + + switch (radio->core->chip_id) { + /* AM/FM tuners -- all bands are supported */ + case SI476X_CHIP_SI4761: + case SI476X_CHIP_SI4764: + if (band->index < ARRAY_SIZE(si476x_bands)) { + *band = si476x_bands[band->index]; + err = 0; + } else { + err = -EINVAL; + } + break; + /* FM companion tuner chips -- only FM bands are + * supported */ + case SI476X_CHIP_SI4768: + if (band->index == SI476X_BAND_FM) { + *band = si476x_bands[band->index]; + err = 0; + } else { + err = -EINVAL; + } + break; + default: + err = -EINVAL; + } + + return err; +} + +static int si476x_radio_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + int err; + struct si476x_rsq_status_report report; + struct si476x_radio *radio = video_drvdata(file); + + struct si476x_rsq_status_args args = { + .primary = false, + .rsqack = false, + .attune = false, + .cancel = false, + .stcack = false, + }; + + if (tuner->index != 0) + return -EINVAL; + + tuner->type = V4L2_TUNER_RADIO; + tuner->capability = V4L2_TUNER_CAP_LOW /* Measure frequencies + * in multiples of + * 62.5 Hz */ + | V4L2_TUNER_CAP_STEREO + | V4L2_TUNER_CAP_HWSEEK_BOUNDED + | V4L2_TUNER_CAP_HWSEEK_WRAP + | V4L2_TUNER_CAP_HWSEEK_PROG_LIM; + + si476x_core_lock(radio->core); + + if (si476x_core_is_a_secondary_tuner(radio->core)) { + strlcpy(tuner->name, "FM (secondary)", sizeof(tuner->name)); + tuner->rxsubchans = 0; + tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; + } else if (si476x_core_has_am(radio->core)) { + if (si476x_core_is_a_primary_tuner(radio->core)) + strlcpy(tuner->name, "AM/FM (primary)", + sizeof(tuner->name)); + else + strlcpy(tuner->name, "AM/FM", sizeof(tuner->name)); + + tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO + | V4L2_TUNER_SUB_RDS; + tuner->capability |= V4L2_TUNER_CAP_RDS + | V4L2_TUNER_CAP_RDS_BLOCK_IO + | V4L2_TUNER_CAP_FREQ_BANDS; + + tuner->rangelow = si476x_bands[SI476X_BAND_AM].rangelow; + } else { + strlcpy(tuner->name, "FM", sizeof(tuner->name)); + tuner->rxsubchans = V4L2_TUNER_SUB_RDS; + tuner->capability |= V4L2_TUNER_CAP_RDS + | V4L2_TUNER_CAP_RDS_BLOCK_IO + | V4L2_TUNER_CAP_FREQ_BANDS; + tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; + } + + tuner->audmode = radio->audmode; + + tuner->afc = 1; + tuner->rangehigh = si476x_bands[SI476X_BAND_FM].rangehigh; + + err = radio->ops->rsq_status(radio->core, + &args, &report); + if (err < 0) { + tuner->signal = 0; + } else { + /* + * tuner->signal value range: 0x0000 .. 0xFFFF, + * report.rssi: -128 .. 127 + */ + tuner->signal = (report.rssi + 128) * 257; + } + si476x_core_unlock(radio->core); + + return err; +} + +static int si476x_radio_s_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + struct si476x_radio *radio = video_drvdata(file); + + if (tuner->index != 0) + return -EINVAL; + + if (tuner->audmode == V4L2_TUNER_MODE_MONO || + tuner->audmode == V4L2_TUNER_MODE_STEREO) + radio->audmode = tuner->audmode; + else + radio->audmode = V4L2_TUNER_MODE_STEREO; + + return 0; +} + +static int si476x_radio_init_vtable(struct si476x_radio *radio, + enum si476x_func func) +{ + static const struct si476x_radio_ops fm_ops = { + .tune_freq = si476x_core_cmd_fm_tune_freq, + .seek_start = si476x_core_cmd_fm_seek_start, + .rsq_status = si476x_core_cmd_fm_rsq_status, + .rds_blckcnt = si476x_core_cmd_fm_rds_blockcount, + .phase_diversity = si476x_core_cmd_fm_phase_diversity, + .phase_div_status = si476x_core_cmd_fm_phase_div_status, + .acf_status = si476x_core_cmd_fm_acf_status, + .agc_status = si476x_core_cmd_agc_status, + }; + + static const struct si476x_radio_ops am_ops = { + .tune_freq = si476x_core_cmd_am_tune_freq, + .seek_start = si476x_core_cmd_am_seek_start, + .rsq_status = si476x_core_cmd_am_rsq_status, + .rds_blckcnt = NULL, + .phase_diversity = NULL, + .phase_div_status = NULL, + .acf_status = si476x_core_cmd_am_acf_status, + .agc_status = NULL, + }; + + switch (func) { + case SI476X_FUNC_FM_RECEIVER: + radio->ops = &fm_ops; + return 0; + + case SI476X_FUNC_AM_RECEIVER: + radio->ops = &am_ops; + return 0; + default: + WARN(1, "Unexpected tuner function value\n"); + return -EINVAL; + } +} + +static int si476x_radio_pretune(struct si476x_radio *radio, + enum si476x_func func) +{ + int retval; + + struct si476x_tune_freq_args args = { + .zifsr = false, + .hd = false, + .injside = SI476X_INJSIDE_AUTO, + .tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE, + .smoothmetrics = SI476X_SM_INITIALIZE_AUDIO, + .antcap = 0, + }; + + switch (func) { + case SI476X_FUNC_FM_RECEIVER: + args.freq = v4l2_to_si476x(radio->core, + 92 * FREQ_MUL); + retval = radio->ops->tune_freq(radio->core, &args); + break; + case SI476X_FUNC_AM_RECEIVER: + args.freq = v4l2_to_si476x(radio->core, + 0.6 * FREQ_MUL); + retval = radio->ops->tune_freq(radio->core, &args); + break; + default: + WARN(1, "Unexpected tuner function value\n"); + retval = -EINVAL; + } + + return retval; +} +static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio, + enum si476x_func func) +{ + int err; + + /* regcache_mark_dirty(radio->core->regmap); */ + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE, + SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT); + if (err < 0) + return err; + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_AUDIO_DEEMPHASIS, + SI476X_PROP_AUDIO_PWR_LINE_FILTER); + if (err < 0) + return err; + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_INT_CTL_ENABLE, + SI476X_PROP_INT_CTL_ENABLE); + if (err < 0) + return err; + + /* + * Is there any point in restoring SNR and the like + * when switching between AM/FM? + */ + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_VALID_MAX_TUNE_ERROR, + SI476X_PROP_VALID_MAX_TUNE_ERROR); + if (err < 0) + return err; + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_VALID_SNR_THRESHOLD, + SI476X_PROP_VALID_RSSI_THRESHOLD); + if (err < 0) + return err; + + if (func == SI476X_FUNC_FM_RECEIVER) { + if (si476x_core_has_diversity(radio->core)) { + err = si476x_core_cmd_fm_phase_diversity(radio->core, + radio->core->diversity_mode); + if (err < 0) + return err; + } + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, + SI476X_PROP_FM_RDS_CONFIG); + if (err < 0) + return err; + } + + return si476x_radio_init_vtable(radio, func); + +} + +static int si476x_radio_change_func(struct si476x_radio *radio, + enum si476x_func func) +{ + int err; + bool soft; + /* + * Since power/up down is a very time consuming operation, + * try to avoid doing it if the requested mode matches the one + * the tuner is in + */ + if (func == radio->core->power_up_parameters.func) + return 0; + + soft = true; + err = si476x_core_stop(radio->core, soft); + if (err < 0) { + /* + * OK, if the chip does not want to play nice let's + * try to reset it in more brutal way + */ + soft = false; + err = si476x_core_stop(radio->core, soft); + if (err < 0) + return err; + } + /* + Set the desired radio tuner function + */ + radio->core->power_up_parameters.func = func; + + err = si476x_core_start(radio->core, soft); + if (err < 0) + return err; + + /* + * No need to do the rest of manipulations for the bootlader + * mode + */ + if (func != SI476X_FUNC_FM_RECEIVER && + func != SI476X_FUNC_AM_RECEIVER) + return err; + + return si476x_radio_do_post_powerup_init(radio, func); +} + +static int si476x_radio_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + int err; + struct si476x_radio *radio = video_drvdata(file); + + if (f->tuner != 0 || + f->type != V4L2_TUNER_RADIO) + return -EINVAL; + + si476x_core_lock(radio->core); + + if (radio->ops->rsq_status) { + struct si476x_rsq_status_report report; + struct si476x_rsq_status_args args = { + .primary = false, + .rsqack = false, + .attune = true, + .cancel = false, + .stcack = false, + }; + + err = radio->ops->rsq_status(radio->core, &args, &report); + if (!err) + f->frequency = si476x_to_v4l2(radio->core, + report.readfreq); + } else { + err = -EINVAL; + } + + si476x_core_unlock(radio->core); + + return err; +} + +static int si476x_radio_s_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + int err; + struct si476x_tune_freq_args args; + struct si476x_radio *radio = video_drvdata(file); + + const u32 midrange = (si476x_bands[SI476X_BAND_AM].rangehigh + + si476x_bands[SI476X_BAND_FM].rangelow) / 2; + const int band = (f->frequency > midrange) ? + SI476X_BAND_FM : SI476X_BAND_AM; + const enum si476x_func func = (band == SI476X_BAND_AM) ? + SI476X_FUNC_AM_RECEIVER : SI476X_FUNC_FM_RECEIVER; + + if (f->tuner != 0 || + f->type != V4L2_TUNER_RADIO) + return -EINVAL; + + si476x_core_lock(radio->core); + + f->frequency = clamp(f->frequency, + si476x_bands[band].rangelow, + si476x_bands[band].rangehigh); + + if (si476x_radio_freq_is_inside_of_the_band(f->frequency, + SI476X_BAND_AM) && + (!si476x_core_has_am(radio->core) || + si476x_core_is_a_secondary_tuner(radio->core))) { + err = -EINVAL; + goto unlock; + } + + err = si476x_radio_change_func(radio, func); + if (err < 0) + goto unlock; + + args.zifsr = false; + args.hd = false; + args.injside = SI476X_INJSIDE_AUTO; + args.freq = v4l2_to_si476x(radio->core, + f->frequency); + args.tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE; + args.smoothmetrics = SI476X_SM_INITIALIZE_AUDIO; + args.antcap = 0; + + err = radio->ops->tune_freq(radio->core, &args); + +unlock: + si476x_core_unlock(radio->core); + return err; +} + +static int si476x_radio_s_hw_freq_seek(struct file *file, void *priv, + const struct v4l2_hw_freq_seek *seek) +{ + int err; + enum si476x_func func; + u32 rangelow, rangehigh; + struct si476x_radio *radio = video_drvdata(file); + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + if (seek->tuner != 0 || + seek->type != V4L2_TUNER_RADIO) + return -EINVAL; + + si476x_core_lock(radio->core); + + if (!seek->rangelow) { + err = regmap_read(radio->core->regmap, + SI476X_PROP_SEEK_BAND_BOTTOM, + &rangelow); + if (!err) + rangelow = si476x_to_v4l2(radio->core, rangelow); + else + goto unlock; + } + if (!seek->rangehigh) { + err = regmap_read(radio->core->regmap, + SI476X_PROP_SEEK_BAND_TOP, + &rangehigh); + if (!err) + rangehigh = si476x_to_v4l2(radio->core, rangehigh); + else + goto unlock; + } + + if (rangelow > rangehigh) { + err = -EINVAL; + goto unlock; + } + + if (si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, + SI476X_BAND_FM)) { + func = SI476X_FUNC_FM_RECEIVER; + + } else if (si476x_core_has_am(radio->core) && + si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, + SI476X_BAND_AM)) { + func = SI476X_FUNC_AM_RECEIVER; + } else { + err = -EINVAL; + goto unlock; + } + + err = si476x_radio_change_func(radio, func); + if (err < 0) + goto unlock; + + if (seek->rangehigh) { + err = regmap_write(radio->core->regmap, + SI476X_PROP_SEEK_BAND_TOP, + v4l2_to_si476x(radio->core, + seek->rangehigh)); + if (err) + goto unlock; + } + if (seek->rangelow) { + err = regmap_write(radio->core->regmap, + SI476X_PROP_SEEK_BAND_BOTTOM, + v4l2_to_si476x(radio->core, + seek->rangelow)); + if (err) + goto unlock; + } + if (seek->spacing) { + err = regmap_write(radio->core->regmap, + SI476X_PROP_SEEK_FREQUENCY_SPACING, + v4l2_to_si476x(radio->core, + seek->spacing)); + if (err) + goto unlock; + } + + err = radio->ops->seek_start(radio->core, + seek->seek_upward, + seek->wrap_around); +unlock: + si476x_core_unlock(radio->core); + + + + return err; +} + +static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + int retval; + struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); + + si476x_core_lock(radio->core); + + switch (ctrl->id) { + case V4L2_CID_SI476X_INTERCHIP_LINK: + if (si476x_core_has_diversity(radio->core)) { + if (radio->ops->phase_diversity) { + retval = radio->ops->phase_div_status(radio->core); + if (retval < 0) + break; + + ctrl->val = !!SI476X_PHDIV_STATUS_LINK_LOCKED(retval); + retval = 0; + break; + } else { + retval = -ENOTTY; + break; + } + } + retval = -EINVAL; + break; + default: + retval = -EINVAL; + break; + } + si476x_core_unlock(radio->core); + return retval; + +} + +static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl) +{ + int retval; + enum si476x_phase_diversity_mode mode; + struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); + + si476x_core_lock(radio->core); + + switch (ctrl->id) { + case V4L2_CID_SI476X_HARMONICS_COUNT: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_HARMONICS_MASK, + ctrl->val); + break; + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (ctrl->val) { + case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_ENABLE_MASK, + 0); + break; + case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_GRID_MASK, + SI476X_PROP_PWR_GRID_50HZ); + break; + case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_GRID_MASK, + SI476X_PROP_PWR_GRID_60HZ); + break; + default: + retval = -EINVAL; + break; + } + break; + case V4L2_CID_SI476X_RSSI_THRESHOLD: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_VALID_RSSI_THRESHOLD, + ctrl->val); + break; + case V4L2_CID_SI476X_SNR_THRESHOLD: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_VALID_SNR_THRESHOLD, + ctrl->val); + break; + case V4L2_CID_SI476X_MAX_TUNE_ERROR: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_VALID_MAX_TUNE_ERROR, + ctrl->val); + break; + case V4L2_CID_RDS_RECEPTION: + /* + * It looks like RDS related properties are + * inaccesable when tuner is in AM mode, so cache the + * changes + */ + if (si476x_core_is_in_am_receiver_mode(radio->core)) + regcache_cache_only(radio->core->regmap, true); + + if (ctrl->val) { + retval = regmap_write(radio->core->regmap, + SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT, + radio->core->rds_fifo_depth); + if (retval < 0) + break; + + if (radio->core->client->irq) { + retval = regmap_write(radio->core->regmap, + SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, + SI476X_RDSRECV); + if (retval < 0) + break; + } + + /* Drain RDS FIFO before enabling RDS processing */ + retval = si476x_core_cmd_fm_rds_status(radio->core, + false, + true, + true, + NULL); + if (retval < 0) + break; + + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_FM_RDS_CONFIG, + SI476X_PROP_RDSEN_MASK, + SI476X_PROP_RDSEN); + } else { + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_FM_RDS_CONFIG, + SI476X_PROP_RDSEN_MASK, + !SI476X_PROP_RDSEN); + } + + if (si476x_core_is_in_am_receiver_mode(radio->core)) + regcache_cache_only(radio->core->regmap, false); + break; + case V4L2_CID_TUNE_DEEMPHASIS: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_AUDIO_DEEMPHASIS, + ctrl->val); + break; + + case V4L2_CID_SI476X_DIVERSITY_MODE: + mode = si476x_phase_diversity_idx_to_mode(ctrl->val); + + if (mode == radio->core->diversity_mode) { + retval = 0; + break; + } + + if (si476x_core_is_in_am_receiver_mode(radio->core)) { + /* + * Diversity cannot be configured while tuner + * is in AM mode so save the changes and carry on. + */ + radio->core->diversity_mode = mode; + retval = 0; + } else { + retval = radio->ops->phase_diversity(radio->core, mode); + if (!retval) + radio->core->diversity_mode = mode; + } + break; + + default: + retval = -EINVAL; + break; + } + + si476x_core_unlock(radio->core); + + return retval; +} + +static int si476x_radio_g_chip_ident(struct file *file, void *fh, + struct v4l2_dbg_chip_ident *chip) +{ + if (chip->match.type == V4L2_CHIP_MATCH_HOST && + v4l2_chip_match_host(&chip->match)) + return 0; + return -EINVAL; +} + + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int si476x_radio_g_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg) +{ + int err; + unsigned int value; + struct si476x_radio *radio = video_drvdata(file); + + si476x_core_lock(radio->core); + reg->size = 2; + err = regmap_read(radio->core->regmap, + (unsigned int)reg->reg, &value); + reg->val = value; + si476x_core_unlock(radio->core); + + return err; +} +static int si476x_radio_s_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg) +{ + + int err; + struct si476x_radio *radio = video_drvdata(file); + + si476x_core_lock(radio->core); + err = regmap_write(radio->core->regmap, + (unsigned int)reg->reg, + (unsigned int)reg->val); + si476x_core_unlock(radio->core); + + return err; +} +#endif + +static int si476x_radio_fops_open(struct file *file) +{ + struct si476x_radio *radio = video_drvdata(file); + int err; + + err = v4l2_fh_open(file); + if (err) + return err; + + if (v4l2_fh_is_singular_file(file)) { + si476x_core_lock(radio->core); + err = si476x_core_set_power_state(radio->core, + SI476X_POWER_UP_FULL); + if (err < 0) + goto done; + + err = si476x_radio_do_post_powerup_init(radio, + radio->core->power_up_parameters.func); + if (err < 0) + goto power_down; + + err = si476x_radio_pretune(radio, + radio->core->power_up_parameters.func); + if (err < 0) + goto power_down; + + si476x_core_unlock(radio->core); + /*Must be done after si476x_core_unlock to prevent a deadlock*/ + v4l2_ctrl_handler_setup(&radio->ctrl_handler); + } + + return err; + +power_down: + si476x_core_set_power_state(radio->core, + SI476X_POWER_DOWN); +done: + si476x_core_unlock(radio->core); + v4l2_fh_release(file); + + return err; +} + +static int si476x_radio_fops_release(struct file *file) +{ + int err; + struct si476x_radio *radio = video_drvdata(file); + + if (v4l2_fh_is_singular_file(file) && + atomic_read(&radio->core->is_alive)) + si476x_core_set_power_state(radio->core, + SI476X_POWER_DOWN); + + err = v4l2_fh_release(file); + + return err; +} + +static ssize_t si476x_radio_fops_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t rval; + size_t fifo_len; + unsigned int copied; + + struct si476x_radio *radio = video_drvdata(file); + + /* block if no new data available */ + if (kfifo_is_empty(&radio->core->rds_fifo)) { + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + + rval = wait_event_interruptible(radio->core->rds_read_queue, + (!kfifo_is_empty(&radio->core->rds_fifo) || + !atomic_read(&radio->core->is_alive))); + if (rval < 0) + return -EINTR; + + if (!atomic_read(&radio->core->is_alive)) + return -ENODEV; + } + + fifo_len = kfifo_len(&radio->core->rds_fifo); + + if (kfifo_to_user(&radio->core->rds_fifo, buf, + min(fifo_len, count), + &copied) != 0) { + dev_warn(&radio->videodev.dev, + "Error during FIFO to userspace copy\n"); + rval = -EIO; + } else { + rval = (ssize_t)copied; + } + + return rval; +} + +static unsigned int si476x_radio_fops_poll(struct file *file, + struct poll_table_struct *pts) +{ + struct si476x_radio *radio = video_drvdata(file); + unsigned long req_events = poll_requested_events(pts); + unsigned int err = v4l2_ctrl_poll(file, pts); + + if (req_events & (POLLIN | POLLRDNORM)) { + if (atomic_read(&radio->core->is_alive)) + poll_wait(file, &radio->core->rds_read_queue, pts); + + if (!atomic_read(&radio->core->is_alive)) + err = POLLHUP; + + if (!kfifo_is_empty(&radio->core->rds_fifo)) + err = POLLIN | POLLRDNORM; + } + + return err; +} + +static const struct v4l2_file_operations si476x_fops = { + .owner = THIS_MODULE, + .read = si476x_radio_fops_read, + .poll = si476x_radio_fops_poll, + .unlocked_ioctl = video_ioctl2, + .open = si476x_radio_fops_open, + .release = si476x_radio_fops_release, +}; + + +static const struct v4l2_ioctl_ops si4761_ioctl_ops = { + .vidioc_querycap = si476x_radio_querycap, + .vidioc_g_tuner = si476x_radio_g_tuner, + .vidioc_s_tuner = si476x_radio_s_tuner, + + .vidioc_g_frequency = si476x_radio_g_frequency, + .vidioc_s_frequency = si476x_radio_s_frequency, + .vidioc_s_hw_freq_seek = si476x_radio_s_hw_freq_seek, + .vidioc_enum_freq_bands = si476x_radio_enum_freq_bands, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_g_chip_ident = si476x_radio_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = si476x_radio_g_register, + .vidioc_s_register = si476x_radio_s_register, +#endif +}; + + +static const struct video_device si476x_viddev_template = { + .fops = &si476x_fops, + .name = DRIVER_NAME, + .release = video_device_release_empty, +}; + + + +static ssize_t si476x_radio_read_acf_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_acf_status_report report; + + si476x_core_lock(radio->core); + if (radio->ops->acf_status) + err = radio->ops->acf_status(radio->core, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_acf_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_acf_blob, +}; + +static ssize_t si476x_radio_read_rds_blckcnt_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_rds_blockcount_report report; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->rds_blckcnt(radio->core, true, + &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_rds_blckcnt_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_rds_blckcnt_blob, +}; + +static ssize_t si476x_radio_read_agc_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_agc_status_report report; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->agc_status(radio->core, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_agc_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_agc_blob, +}; + +static ssize_t si476x_radio_read_rsq_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_rsq_status_report report; + struct si476x_rsq_status_args args = { + .primary = false, + .rsqack = false, + .attune = false, + .cancel = false, + .stcack = false, + }; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->rsq_status(radio->core, &args, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_rsq_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_rsq_blob, +}; + +static ssize_t si476x_radio_read_rsq_primary_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_rsq_status_report report; + struct si476x_rsq_status_args args = { + .primary = true, + .rsqack = false, + .attune = false, + .cancel = false, + .stcack = false, + }; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->rsq_status(radio->core, &args, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_rsq_primary_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_rsq_primary_blob, +}; + + +static int si476x_radio_init_debugfs(struct si476x_radio *radio) +{ + struct dentry *dentry; + int ret; + + dentry = debugfs_create_dir(dev_name(radio->v4l2dev.dev), NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto exit; + } + radio->debugfs = dentry; + + dentry = debugfs_create_file("acf", S_IRUGO, + radio->debugfs, radio, &radio_acf_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("rds_blckcnt", S_IRUGO, + radio->debugfs, radio, + &radio_rds_blckcnt_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("agc", S_IRUGO, + radio->debugfs, radio, &radio_agc_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("rsq", S_IRUGO, + radio->debugfs, radio, &radio_rsq_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("rsq_primary", S_IRUGO, + radio->debugfs, radio, + &radio_rsq_primary_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + return 0; +cleanup: + debugfs_remove_recursive(radio->debugfs); +exit: + return ret; +} + + +static int si476x_radio_add_new_custom(struct si476x_radio *radio, + enum si476x_ctrl_idx idx) +{ + int rval; + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_new_custom(&radio->ctrl_handler, + &si476x_ctrls[idx], + NULL); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) + dev_err(radio->v4l2dev.dev, + "Could not initialize '%s' control %d\n", + si476x_ctrls[idx].name, rval); + + return rval; +} + +static int si476x_radio_probe(struct platform_device *pdev) +{ + int rval; + struct si476x_radio *radio; + struct v4l2_ctrl *ctrl; + + static atomic_t instance = ATOMIC_INIT(0); + + radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL); + if (!radio) + return -ENOMEM; + + radio->core = i2c_mfd_cell_to_core(&pdev->dev); + + v4l2_device_set_name(&radio->v4l2dev, DRIVER_NAME, &instance); + + rval = v4l2_device_register(&pdev->dev, &radio->v4l2dev); + if (rval) { + dev_err(&pdev->dev, "Cannot register v4l2_device.\n"); + return rval; + } + + memcpy(&radio->videodev, &si476x_viddev_template, + sizeof(struct video_device)); + + radio->videodev.v4l2_dev = &radio->v4l2dev; + radio->videodev.ioctl_ops = &si4761_ioctl_ops; + + video_set_drvdata(&radio->videodev, radio); + platform_set_drvdata(pdev, radio); + + set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags); + + radio->v4l2dev.ctrl_handler = &radio->ctrl_handler; + v4l2_ctrl_handler_init(&radio->ctrl_handler, + 1 + ARRAY_SIZE(si476x_ctrls)); + + if (si476x_core_has_am(radio->core)) { + ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, + &si476x_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, + 0, 0); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) { + dev_err(&pdev->dev, "Could not initialize V4L2_CID_POWER_LINE_FREQUENCY control %d\n", + rval); + goto exit; + } + + rval = si476x_radio_add_new_custom(radio, + SI476X_IDX_HARMONICS_COUNT); + if (rval < 0) + goto exit; + } + + rval = si476x_radio_add_new_custom(radio, SI476X_IDX_RSSI_THRESHOLD); + if (rval < 0) + goto exit; + + rval = si476x_radio_add_new_custom(radio, SI476X_IDX_SNR_THRESHOLD); + if (rval < 0) + goto exit; + + rval = si476x_radio_add_new_custom(radio, SI476X_IDX_MAX_TUNE_ERROR); + if (rval < 0) + goto exit; + + ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, + &si476x_ctrl_ops, + V4L2_CID_TUNE_DEEMPHASIS, + V4L2_DEEMPHASIS_75_uS, 0, 0); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) { + dev_err(&pdev->dev, "Could not initialize V4L2_CID_TUNE_DEEMPHASIS control %d\n", + rval); + goto exit; + } + + ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &si476x_ctrl_ops, + V4L2_CID_RDS_RECEPTION, + 0, 1, 1, 1); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) { + dev_err(&pdev->dev, "Could not initialize V4L2_CID_RDS_RECEPTION control %d\n", + rval); + goto exit; + } + + if (si476x_core_has_diversity(radio->core)) { + si476x_ctrls[SI476X_IDX_DIVERSITY_MODE].def = + si476x_phase_diversity_mode_to_idx(radio->core->diversity_mode); + si476x_radio_add_new_custom(radio, SI476X_IDX_DIVERSITY_MODE); + if (rval < 0) + goto exit; + + si476x_radio_add_new_custom(radio, SI476X_IDX_INTERCHIP_LINK); + if (rval < 0) + goto exit; + } + + /* register video device */ + rval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, -1); + if (rval < 0) { + dev_err(&pdev->dev, "Could not register video device\n"); + goto exit; + } + + rval = si476x_radio_init_debugfs(radio); + if (rval < 0) { + dev_err(&pdev->dev, "Could not creat debugfs interface\n"); + goto exit; + } + + return 0; +exit: + v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); + return rval; +} + +static int si476x_radio_remove(struct platform_device *pdev) +{ + struct si476x_radio *radio = platform_get_drvdata(pdev); + + v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); + video_unregister_device(&radio->videodev); + v4l2_device_unregister(&radio->v4l2dev); + debugfs_remove_recursive(radio->debugfs); + + return 0; +} + +MODULE_ALIAS("platform:si476x-radio"); + +static struct platform_driver si476x_radio_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = si476x_radio_probe, + .remove = si476x_radio_remove, +}; +module_platform_driver(si476x_radio_driver); + +MODULE_AUTHOR("Andrey Smirnov "); +MODULE_DESCRIPTION("Driver for Si4761/64/68 AM/FM Radio MFD Cell"); +MODULE_LICENSE("GPL"); diff --git a/include/media/si476x.h b/include/media/si476x.h new file mode 100644 index 000000000000..beb6433d6958 --- /dev/null +++ b/include/media/si476x.h @@ -0,0 +1,426 @@ +/* + * include/media/si476x.h -- Common definitions for si476x driver + * + * Copyright (C) 2012 Innovative Converged Devices(ICD) + * Copyright (C) 2013 Andrey Smirnov + * + * Author: Andrey Smirnov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#ifndef SI476X_H +#define SI476X_H + +#include +#include + +struct si476x_device; + +/* It is possible to select one of the four adresses using pins A0 + * and A1 on SI476x */ +#define SI476X_I2C_ADDR_1 0x60 +#define SI476X_I2C_ADDR_2 0x61 +#define SI476X_I2C_ADDR_3 0x62 +#define SI476X_I2C_ADDR_4 0x63 + +enum si476x_iqclk_config { + SI476X_IQCLK_NOOP = 0, + SI476X_IQCLK_TRISTATE = 1, + SI476X_IQCLK_IQ = 21, +}; +enum si476x_iqfs_config { + SI476X_IQFS_NOOP = 0, + SI476X_IQFS_TRISTATE = 1, + SI476X_IQFS_IQ = 21, +}; +enum si476x_iout_config { + SI476X_IOUT_NOOP = 0, + SI476X_IOUT_TRISTATE = 1, + SI476X_IOUT_OUTPUT = 22, +}; +enum si476x_qout_config { + SI476X_QOUT_NOOP = 0, + SI476X_QOUT_TRISTATE = 1, + SI476X_QOUT_OUTPUT = 22, +}; + +enum si476x_dclk_config { + SI476X_DCLK_NOOP = 0, + SI476X_DCLK_TRISTATE = 1, + SI476X_DCLK_DAUDIO = 10, +}; + +enum si476x_dfs_config { + SI476X_DFS_NOOP = 0, + SI476X_DFS_TRISTATE = 1, + SI476X_DFS_DAUDIO = 10, +}; + +enum si476x_dout_config { + SI476X_DOUT_NOOP = 0, + SI476X_DOUT_TRISTATE = 1, + SI476X_DOUT_I2S_OUTPUT = 12, + SI476X_DOUT_I2S_INPUT = 13, +}; + +enum si476x_xout_config { + SI476X_XOUT_NOOP = 0, + SI476X_XOUT_TRISTATE = 1, + SI476X_XOUT_I2S_INPUT = 13, + SI476X_XOUT_MODE_SELECT = 23, +}; + + +enum si476x_icin_config { + SI476X_ICIN_NOOP = 0, + SI476X_ICIN_TRISTATE = 1, + SI476X_ICIN_GPO1_HIGH = 2, + SI476X_ICIN_GPO1_LOW = 3, + SI476X_ICIN_IC_LINK = 30, +}; + +enum si476x_icip_config { + SI476X_ICIP_NOOP = 0, + SI476X_ICIP_TRISTATE = 1, + SI476X_ICIP_GPO2_HIGH = 2, + SI476X_ICIP_GPO2_LOW = 3, + SI476X_ICIP_IC_LINK = 30, +}; + +enum si476x_icon_config { + SI476X_ICON_NOOP = 0, + SI476X_ICON_TRISTATE = 1, + SI476X_ICON_I2S = 10, + SI476X_ICON_IC_LINK = 30, +}; + +enum si476x_icop_config { + SI476X_ICOP_NOOP = 0, + SI476X_ICOP_TRISTATE = 1, + SI476X_ICOP_I2S = 10, + SI476X_ICOP_IC_LINK = 30, +}; + + +enum si476x_lrout_config { + SI476X_LROUT_NOOP = 0, + SI476X_LROUT_TRISTATE = 1, + SI476X_LROUT_AUDIO = 2, + SI476X_LROUT_MPX = 3, +}; + + +enum si476x_intb_config { + SI476X_INTB_NOOP = 0, + SI476X_INTB_TRISTATE = 1, + SI476X_INTB_DAUDIO = 10, + SI476X_INTB_IRQ = 40, +}; + +enum si476x_a1_config { + SI476X_A1_NOOP = 0, + SI476X_A1_TRISTATE = 1, + SI476X_A1_IRQ = 40, +}; + +enum si476x_part_revisions { + SI476X_REVISION_A10 = 0, + SI476X_REVISION_A20 = 1, + SI476X_REVISION_A30 = 2, +}; + +struct si476x_pinmux { + enum si476x_dclk_config dclk; + enum si476x_dfs_config dfs; + enum si476x_dout_config dout; + enum si476x_xout_config xout; + + enum si476x_iqclk_config iqclk; + enum si476x_iqfs_config iqfs; + enum si476x_iout_config iout; + enum si476x_qout_config qout; + + enum si476x_icin_config icin; + enum si476x_icip_config icip; + enum si476x_icon_config icon; + enum si476x_icop_config icop; + + enum si476x_lrout_config lrout; + + enum si476x_intb_config intb; + enum si476x_a1_config a1; +}; + +/** + * enum si476x_phase_diversity_mode - possbile phase diversity modes + * for SI4764/5/6/7 chips. + * + * @SI476X_PHDIV_DISABLED: Phase diversity feature is + * disabled. + * @SI476X_PHDIV_PRIMARY_COMBINING: Tuner works as a primary tuner + * in combination with a + * secondary one. + * @SI476X_PHDIV_PRIMARY_ANTENNA: Tuner works as a primary tuner + * using only its own antenna. + * @SI476X_PHDIV_SECONDARY_ANTENNA: Tuner works as a primary tuner + * usning seconary tuner's antenna. + * @SI476X_PHDIV_SECONDARY_COMBINING: Tuner works as a secondary + * tuner in combination with the + * primary one. + */ +enum si476x_phase_diversity_mode { + SI476X_PHDIV_DISABLED = 0, + SI476X_PHDIV_PRIMARY_COMBINING = 1, + SI476X_PHDIV_PRIMARY_ANTENNA = 2, + SI476X_PHDIV_SECONDARY_ANTENNA = 3, + SI476X_PHDIV_SECONDARY_COMBINING = 5, +}; + +enum si476x_ibias6x { + SI476X_IBIAS6X_OTHER = 0, + SI476X_IBIAS6X_RCVR1_NON_4MHZ_CLK = 1, +}; + +enum si476x_xstart { + SI476X_XSTART_MULTIPLE_TUNER = 0x11, + SI476X_XSTART_NORMAL = 0x77, +}; + +enum si476x_freq { + SI476X_FREQ_4_MHZ = 0, + SI476X_FREQ_37P209375_MHZ = 1, + SI476X_FREQ_36P4_MHZ = 2, + SI476X_FREQ_37P8_MHZ = 3, +}; + +enum si476x_xmode { + SI476X_XMODE_CRYSTAL_RCVR1 = 1, + SI476X_XMODE_EXT_CLOCK = 2, + SI476X_XMODE_CRYSTAL_RCVR2_3 = 3, +}; + +enum si476x_xbiashc { + SI476X_XBIASHC_SINGLE_RECEIVER = 0, + SI476X_XBIASHC_MULTIPLE_RECEIVER = 1, +}; + +enum si476x_xbias { + SI476X_XBIAS_RCVR2_3 = 0, + SI476X_XBIAS_4MHZ_RCVR1 = 3, + SI476X_XBIAS_RCVR1 = 7, +}; + +enum si476x_func { + SI476X_FUNC_BOOTLOADER = 0, + SI476X_FUNC_FM_RECEIVER = 1, + SI476X_FUNC_AM_RECEIVER = 2, + SI476X_FUNC_WB_RECEIVER = 3, +}; + + +/** + * @xcload: Selects the amount of additional on-chip capacitance to + * be connected between XTAL1 and gnd and between XTAL2 and + * GND. One half of the capacitance value shown here is the + * additional load capacitance presented to the xtal. The + * minimum step size is 0.277 pF. Recommended value is 0x28 + * but it will be layout dependent. Range is 0–0x3F i.e. + * (0–16.33 pF) + * @ctsien: enable CTSINT(interrupt request when CTS condition + * arises) when set + * @intsel: when set A1 pin becomes the interrupt pin; otherwise, + * INTB is the interrupt pin + * @func: selects the boot function of the device. I.e. + * SI476X_BOOTLOADER - Boot loader + * SI476X_FM_RECEIVER - FM receiver + * SI476X_AM_RECEIVER - AM receiver + * SI476X_WB_RECEIVER - Weatherband receiver + * @freq: oscillator's crystal frequency: + * SI476X_XTAL_37P209375_MHZ - 37.209375 Mhz + * SI476X_XTAL_36P4_MHZ - 36.4 Mhz + * SI476X_XTAL_37P8_MHZ - 37.8 Mhz + */ +struct si476x_power_up_args { + enum si476x_ibias6x ibias6x; + enum si476x_xstart xstart; + u8 xcload; + bool fastboot; + enum si476x_xbiashc xbiashc; + enum si476x_xbias xbias; + enum si476x_func func; + enum si476x_freq freq; + enum si476x_xmode xmode; +}; + + +enum si476x_ctrl_id { + V4L2_CID_SI476X_RSSI_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 1), + V4L2_CID_SI476X_SNR_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 2), + V4L2_CID_SI476X_MAX_TUNE_ERROR = (V4L2_CID_USER_SI476X_BASE + 3), + V4L2_CID_SI476X_HARMONICS_COUNT = (V4L2_CID_USER_SI476X_BASE + 4), + V4L2_CID_SI476X_DIVERSITY_MODE = (V4L2_CID_USER_SI476X_BASE + 5), + V4L2_CID_SI476X_INTERCHIP_LINK = (V4L2_CID_USER_SI476X_BASE + 6), +}; + +/* + * Platform dependent definition + */ +struct si476x_platform_data { + int gpio_reset; /* < 0 if not used */ + + struct si476x_power_up_args power_up_parameters; + enum si476x_phase_diversity_mode diversity_mode; + + struct si476x_pinmux pinmux; +}; + +/** + * struct si476x_rsq_status - structure containing received signal + * quality + * @multhint: Multipath Detect High. + * true - Indicatedes that the value is below + * FM_RSQ_MULTIPATH_HIGH_THRESHOLD + * false - Indicatedes that the value is above + * FM_RSQ_MULTIPATH_HIGH_THRESHOLD + * @multlint: Multipath Detect Low. + * true - Indicatedes that the value is below + * FM_RSQ_MULTIPATH_LOW_THRESHOLD + * false - Indicatedes that the value is above + * FM_RSQ_MULTIPATH_LOW_THRESHOLD + * @snrhint: SNR Detect High. + * true - Indicatedes that the value is below + * FM_RSQ_SNR_HIGH_THRESHOLD + * false - Indicatedes that the value is above + * FM_RSQ_SNR_HIGH_THRESHOLD + * @snrlint: SNR Detect Low. + * true - Indicatedes that the value is below + * FM_RSQ_SNR_LOW_THRESHOLD + * false - Indicatedes that the value is above + * FM_RSQ_SNR_LOW_THRESHOLD + * @rssihint: RSSI Detect High. + * true - Indicatedes that the value is below + * FM_RSQ_RSSI_HIGH_THRESHOLD + * false - Indicatedes that the value is above + * FM_RSQ_RSSI_HIGH_THRESHOLD + * @rssilint: RSSI Detect Low. + * true - Indicatedes that the value is below + * FM_RSQ_RSSI_LOW_THRESHOLD + * false - Indicatedes that the value is above + * FM_RSQ_RSSI_LOW_THRESHOLD + * @bltf: Band Limit. + * Set if seek command hits the band limit or wrapped to + * the original frequency. + * @snr_ready: SNR measurement in progress. + * @rssiready: RSSI measurement in progress. + * @afcrl: Set if FREQOFF >= MAX_TUNE_ERROR + * @valid: Set if the channel is valid + * rssi < FM_VALID_RSSI_THRESHOLD + * snr < FM_VALID_SNR_THRESHOLD + * tune_error < FM_VALID_MAX_TUNE_ERROR + * @readfreq: Current tuned frequency. + * @freqoff: Signed frequency offset. + * @rssi: Received Signal Strength Indicator(dBuV). + * @snr: RF SNR Indicator(dB). + * @lassi: + * @hassi: Low/High side Adjacent(100 kHz) Channel Strength Indicator + * @mult: Multipath indicator + * @dev: Who knows? But values may vary. + * @readantcap: Antenna tuning capacity value. + * @assi: Adjacent Channel(+/- 200kHz) Strength Indicator + * @usn: Ultrasonic Noise Inticator in -DBFS + */ +struct si476x_rsq_status_report { + __u8 multhint, multlint; + __u8 snrhint, snrlint; + __u8 rssihint, rssilint; + __u8 bltf; + __u8 snr_ready; + __u8 rssiready; + __u8 injside; + __u8 afcrl; + __u8 valid; + + __u16 readfreq; + __s8 freqoff; + __s8 rssi; + __s8 snr; + __s8 issi; + __s8 lassi, hassi; + __s8 mult; + __u8 dev; + __u16 readantcap; + __s8 assi; + __s8 usn; + + __u8 pilotdev; + __u8 rdsdev; + __u8 assidev; + __u8 strongdev; + __u16 rdspi; +} __packed; + +/** + * si476x_acf_status_report - ACF report results + * + * @blend_int: If set, indicates that stereo separation has crossed + * below the blend threshold as set by FM_ACF_BLEND_THRESHOLD + * @hblend_int: If set, indicates that HiBlend cutoff frequency is + * lower than threshold as set by FM_ACF_HBLEND_THRESHOLD + * @hicut_int: If set, indicates that HiCut cutoff frequency is lower + * than the threshold set by ACF_ + + */ +struct si476x_acf_status_report { + __u8 blend_int; + __u8 hblend_int; + __u8 hicut_int; + __u8 chbw_int; + __u8 softmute_int; + __u8 smute; + __u8 smattn; + __u8 chbw; + __u8 hicut; + __u8 hiblend; + __u8 pilot; + __u8 stblend; +} __packed; + +enum si476x_fmagc { + SI476X_FMAGC_10K_OHM = 0, + SI476X_FMAGC_800_OHM = 1, + SI476X_FMAGC_400_OHM = 2, + SI476X_FMAGC_200_OHM = 4, + SI476X_FMAGC_100_OHM = 8, + SI476X_FMAGC_50_OHM = 16, + SI476X_FMAGC_25_OHM = 32, + SI476X_FMAGC_12P5_OHM = 64, + SI476X_FMAGC_6P25_OHM = 128, +}; + +struct si476x_agc_status_report { + __u8 mxhi; + __u8 mxlo; + __u8 lnahi; + __u8 lnalo; + __u8 fmagc1; + __u8 fmagc2; + __u8 pgagain; + __u8 fmwblang; +} __packed; + +struct si476x_rds_blockcount_report { + __u16 expected; + __u16 received; + __u16 uncorrectable; +} __packed; + +#endif /* SI476X_H*/ -- cgit v1.2.3 From 38a46c2128ade2a0c6ee4438297180b09a01c309 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 29 Mar 2013 09:43:14 -0300 Subject: [media] radio-si476x: vidioc_s* now uses a const parameter vidioc_s_tuner, vidioc_s_frequency and vidioc_s_register now uses a constant argument. So, the driver reports warnings: drivers/media/radio/radio-si476x.c:1196:2: warning: initialization from incompatible pointer type [enabled by default] drivers/media/radio/radio-si476x.c:1196:2: warning: (near initialization for 'si4761_ioctl_ops.vidioc_s_tuner') [enabled by default] drivers/media/radio/radio-si476x.c:1199:2: warning: initialization from incompatible pointer type [enabled by default] drivers/media/radio/radio-si476x.c:1199:2: warning: (near initialization for 'si4761_ioctl_ops.vidioc_s_frequency') [enabled by default] drivers/media/radio/radio-si476x.c:1209:2: warning: initialization from incompatible pointer type [enabled by default] drivers/media/radio/radio-si476x.c:1209:2: warning: (near initialization for 'si4761_ioctl_ops.vidioc_s_register') [enabled by default] This is due to a (soft) merge conflict, as both this driver and the const patches were applied for the same Kernel version. Cc: Hans Verkuil Cc: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si476x.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index 0895a0c23787..9430c6a29937 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -472,7 +472,7 @@ static int si476x_radio_g_tuner(struct file *file, void *priv, } static int si476x_radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) + const struct v4l2_tuner *tuner) { struct si476x_radio *radio = video_drvdata(file); @@ -699,15 +699,16 @@ static int si476x_radio_g_frequency(struct file *file, void *priv, } static int si476x_radio_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + const struct v4l2_frequency *f) { int err; + u32 freq = f->frequency; struct si476x_tune_freq_args args; struct si476x_radio *radio = video_drvdata(file); const u32 midrange = (si476x_bands[SI476X_BAND_AM].rangehigh + si476x_bands[SI476X_BAND_FM].rangelow) / 2; - const int band = (f->frequency > midrange) ? + const int band = (freq > midrange) ? SI476X_BAND_FM : SI476X_BAND_AM; const enum si476x_func func = (band == SI476X_BAND_AM) ? SI476X_FUNC_AM_RECEIVER : SI476X_FUNC_FM_RECEIVER; @@ -718,11 +719,11 @@ static int si476x_radio_s_frequency(struct file *file, void *priv, si476x_core_lock(radio->core); - f->frequency = clamp(f->frequency, - si476x_bands[band].rangelow, - si476x_bands[band].rangehigh); + freq = clamp(freq, + si476x_bands[band].rangelow, + si476x_bands[band].rangehigh); - if (si476x_radio_freq_is_inside_of_the_band(f->frequency, + if (si476x_radio_freq_is_inside_of_the_band(freq, SI476X_BAND_AM) && (!si476x_core_has_am(radio->core) || si476x_core_is_a_secondary_tuner(radio->core))) { @@ -737,8 +738,7 @@ static int si476x_radio_s_frequency(struct file *file, void *priv, args.zifsr = false; args.hd = false; args.injside = SI476X_INJSIDE_AUTO; - args.freq = v4l2_to_si476x(radio->core, - f->frequency); + args.freq = v4l2_to_si476x(radio->core, freq); args.tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE; args.smoothmetrics = SI476X_SM_INITIALIZE_AUDIO; args.antcap = 0; @@ -1046,7 +1046,7 @@ static int si476x_radio_g_register(struct file *file, void *fh, return err; } static int si476x_radio_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { int err; -- cgit v1.2.3 From 79a63c60a6a2ae589e44529401e0ab1150e9408a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Mar 2013 06:43:12 -0300 Subject: [media] media: move dvb-usb-v2/cypress_firmware.c to media/common Loading the cypress firmware is not dvb specific and should be common functionality. Move the source to media/common and make it a standalone module. As a result we can remove the dependency on dvb-usb in go7007, which has nothing to do with dvb. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/Kconfig | 3 + drivers/media/common/Makefile | 1 + drivers/media/common/cypress_firmware.c | 132 +++++++++++++++++++++++ drivers/media/common/cypress_firmware.h | 28 +++++ drivers/media/usb/dvb-usb-v2/Kconfig | 6 +- drivers/media/usb/dvb-usb-v2/Makefile | 5 +- drivers/media/usb/dvb-usb-v2/az6007.c | 2 +- drivers/media/usb/dvb-usb-v2/cypress_firmware.c | 133 ------------------------ drivers/media/usb/dvb-usb-v2/cypress_firmware.h | 31 ------ drivers/staging/media/go7007/Kconfig | 3 +- drivers/staging/media/go7007/Makefile | 6 +- drivers/staging/media/go7007/go7007-loader.c | 4 +- 12 files changed, 172 insertions(+), 182 deletions(-) create mode 100644 drivers/media/common/cypress_firmware.c create mode 100644 drivers/media/common/cypress_firmware.h delete mode 100644 drivers/media/usb/dvb-usb-v2/cypress_firmware.c delete mode 100644 drivers/media/usb/dvb-usb-v2/cypress_firmware.h (limited to 'drivers/media') diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index 56c25e6299e9..ba666c707d58 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -16,6 +16,9 @@ config VIDEO_TVEEPROM tristate depends on I2C +config CYPRESS_FIRMWARE + tristate "Cypress firmware helper routines" + source "drivers/media/common/b2c2/Kconfig" source "drivers/media/common/saa7146/Kconfig" source "drivers/media/common/siano/Kconfig" diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index 8f8d18755d15..d208de3b7cc0 100644 --- a/drivers/media/common/Makefile +++ b/drivers/media/common/Makefile @@ -2,3 +2,4 @@ obj-y += b2c2/ saa7146/ siano/ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o +obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o diff --git a/drivers/media/common/cypress_firmware.c b/drivers/media/common/cypress_firmware.c new file mode 100644 index 000000000000..577e82058fdc --- /dev/null +++ b/drivers/media/common/cypress_firmware.c @@ -0,0 +1,132 @@ +/* cypress_firmware.c is part of the DVB USB library. + * + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for downloading the firmware to Cypress FX 1 + * and 2 based devices. + * + */ + +#include +#include +#include +#include +#include "cypress_firmware.h" + +struct usb_cypress_controller { + u8 id; + const char *name; /* name of the usb controller */ + u16 cs_reg; /* needs to be restarted, + * when the firmware has been downloaded */ +}; + +static const struct usb_cypress_controller cypress[] = { + { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cs_reg = 0x7f92 }, + { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cs_reg = 0x7f92 }, + { .id = CYPRESS_FX2, .name = "Cypress FX2", .cs_reg = 0xe600 }, +}; + +/* + * load a firmware packet to the device + */ +static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data, + u8 len) +{ + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); +} + +static int cypress_get_hexline(const struct firmware *fw, + struct hexline *hx, int *pos) +{ + u8 *b = (u8 *) &fw->data[*pos]; + int data_offs = 4; + + if (*pos >= fw->size) + return 0; + + memset(hx, 0, sizeof(struct hexline)); + hx->len = b[0]; + + if ((*pos + hx->len + 4) >= fw->size) + return -EINVAL; + + hx->addr = b[1] | (b[2] << 8); + hx->type = b[3]; + + if (hx->type == 0x04) { + /* b[4] and b[5] are the Extended linear address record data + * field */ + hx->addr |= (b[4] << 24) | (b[5] << 16); + } + + memcpy(hx->data, &b[data_offs], hx->len); + hx->chk = b[hx->len + data_offs]; + *pos += hx->len + 5; + + return *pos; +} + +int cypress_load_firmware(struct usb_device *udev, + const struct firmware *fw, int type) +{ + struct hexline *hx; + int ret, pos = 0; + + hx = kmalloc(sizeof(struct hexline), GFP_KERNEL); + if (!hx) { + dev_err(&udev->dev, "%s: kmalloc() failed\n", KBUILD_MODNAME); + return -ENOMEM; + } + + /* stop the CPU */ + hx->data[0] = 1; + ret = usb_cypress_writemem(udev, cypress[type].cs_reg, hx->data, 1); + if (ret != 1) { + dev_err(&udev->dev, "%s: CPU stop failed=%d\n", + KBUILD_MODNAME, ret); + ret = -EIO; + goto err_kfree; + } + + /* write firmware to memory */ + for (;;) { + ret = cypress_get_hexline(fw, hx, &pos); + if (ret < 0) + goto err_kfree; + else if (ret == 0) + break; + + ret = usb_cypress_writemem(udev, hx->addr, hx->data, hx->len); + if (ret < 0) { + goto err_kfree; + } else if (ret != hx->len) { + dev_err(&udev->dev, + "%s: error while transferring firmware (transferred size=%d, block size=%d)\n", + KBUILD_MODNAME, ret, hx->len); + ret = -EIO; + goto err_kfree; + } + } + + /* start the CPU */ + hx->data[0] = 0; + ret = usb_cypress_writemem(udev, cypress[type].cs_reg, hx->data, 1); + if (ret != 1) { + dev_err(&udev->dev, "%s: CPU start failed=%d\n", + KBUILD_MODNAME, ret); + ret = -EIO; + goto err_kfree; + } + + ret = 0; +err_kfree: + kfree(hx); + return ret; +} +EXPORT_SYMBOL(cypress_load_firmware); + +MODULE_AUTHOR("Antti Palosaari "); +MODULE_DESCRIPTION("Cypress firmware download"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/cypress_firmware.h b/drivers/media/common/cypress_firmware.h new file mode 100644 index 000000000000..e493cbc7a528 --- /dev/null +++ b/drivers/media/common/cypress_firmware.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) + * see dvb-usb-init.c for copyright information. + * + * This file contains functions for downloading the firmware to Cypress FX 1 + * and 2 based devices. + * + */ + +#ifndef CYPRESS_FIRMWARE_H +#define CYPRESS_FIRMWARE_H + +#define CYPRESS_AN2135 0 +#define CYPRESS_AN2235 1 +#define CYPRESS_FX2 2 + +/* commonly used firmware download types and function */ +struct hexline { + u8 len; + u32 addr; + u8 type; + u8 data[255]; + u8 chk; +}; + +int cypress_load_firmware(struct usb_device *, const struct firmware *, int); + +#endif diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 2d4abfa75043..9aff03555464 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -13,10 +13,6 @@ config DVB_USB_V2 Say Y if you own a USB DVB device. -config DVB_USB_CYPRESS_FIRMWARE - tristate "Cypress firmware helper routines" - depends on DVB_USB_V2 - config DVB_USB_AF9015 tristate "Afatech AF9015 DVB-T USB2.0 support" depends on DVB_USB_V2 @@ -73,7 +69,7 @@ config DVB_USB_AU6610 config DVB_USB_AZ6007 tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support" depends on DVB_USB_V2 - select DVB_USB_CYPRESS_FIRMWARE + select CYPRESS_FIRMWARE select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT help diff --git a/drivers/media/usb/dvb-usb-v2/Makefile b/drivers/media/usb/dvb-usb-v2/Makefile index b76f58e6c64f..2c06714b9ef0 100644 --- a/drivers/media/usb/dvb-usb-v2/Makefile +++ b/drivers/media/usb/dvb-usb-v2/Makefile @@ -1,9 +1,6 @@ dvb_usb_v2-objs := dvb_usb_core.o dvb_usb_urb.o usb_urb.o obj-$(CONFIG_DVB_USB_V2) += dvb_usb_v2.o -dvb_usb_cypress_firmware-objs := cypress_firmware.o -obj-$(CONFIG_DVB_USB_CYPRESS_FIRMWARE) += dvb_usb_cypress_firmware.o - dvb-usb-af9015-objs := af9015.o obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o @@ -46,4 +43,4 @@ obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends ccflags-y += -I$(srctree)/drivers/media/tuners - +ccflags-y += -I$(srctree)/drivers/media/common diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c index 70ec80d8be71..44c64ef361bf 100644 --- a/drivers/media/usb/dvb-usb-v2/az6007.c +++ b/drivers/media/usb/dvb-usb-v2/az6007.c @@ -842,7 +842,7 @@ static int az6007_download_firmware(struct dvb_usb_device *d, { pr_debug("Loading az6007 firmware\n"); - return usbv2_cypress_load_firmware(d->udev, fw, CYPRESS_FX2); + return cypress_load_firmware(d->udev, fw, CYPRESS_FX2); } /* DVB USB Driver stuff */ diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.c b/drivers/media/usb/dvb-usb-v2/cypress_firmware.c deleted file mode 100644 index cfb1733519c2..000000000000 --- a/drivers/media/usb/dvb-usb-v2/cypress_firmware.c +++ /dev/null @@ -1,133 +0,0 @@ -/* cypress_firmware.c is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for downloading the firmware to Cypress FX 1 - * and 2 based devices. - * - */ - -#include "dvb_usb.h" -#include "cypress_firmware.h" - -struct usb_cypress_controller { - u8 id; - const char *name; /* name of the usb controller */ - u16 cs_reg; /* needs to be restarted, - * when the firmware has been downloaded */ -}; - -static const struct usb_cypress_controller cypress[] = { - { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cs_reg = 0x7f92 }, - { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cs_reg = 0x7f92 }, - { .id = CYPRESS_FX2, .name = "Cypress FX2", .cs_reg = 0xe600 }, -}; - -/* - * load a firmware packet to the device - */ -static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data, - u8 len) -{ - dvb_usb_dbg_usb_control_msg(udev, - 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len); - - return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000); -} - -int usbv2_cypress_load_firmware(struct usb_device *udev, - const struct firmware *fw, int type) -{ - struct hexline *hx; - int ret, pos = 0; - - hx = kmalloc(sizeof(struct hexline), GFP_KERNEL); - if (!hx) { - dev_err(&udev->dev, "%s: kmalloc() failed\n", KBUILD_MODNAME); - return -ENOMEM; - } - - /* stop the CPU */ - hx->data[0] = 1; - ret = usb_cypress_writemem(udev, cypress[type].cs_reg, hx->data, 1); - if (ret != 1) { - dev_err(&udev->dev, "%s: CPU stop failed=%d\n", - KBUILD_MODNAME, ret); - ret = -EIO; - goto err_kfree; - } - - /* write firmware to memory */ - for (;;) { - ret = dvb_usbv2_get_hexline(fw, hx, &pos); - if (ret < 0) - goto err_kfree; - else if (ret == 0) - break; - - ret = usb_cypress_writemem(udev, hx->addr, hx->data, hx->len); - if (ret < 0) { - goto err_kfree; - } else if (ret != hx->len) { - dev_err(&udev->dev, - "%s: error while transferring firmware (transferred size=%d, block size=%d)\n", - KBUILD_MODNAME, ret, hx->len); - ret = -EIO; - goto err_kfree; - } - } - - /* start the CPU */ - hx->data[0] = 0; - ret = usb_cypress_writemem(udev, cypress[type].cs_reg, hx->data, 1); - if (ret != 1) { - dev_err(&udev->dev, "%s: CPU start failed=%d\n", - KBUILD_MODNAME, ret); - ret = -EIO; - goto err_kfree; - } - - ret = 0; -err_kfree: - kfree(hx); - return ret; -} -EXPORT_SYMBOL(usbv2_cypress_load_firmware); - -int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx, - int *pos) -{ - u8 *b = (u8 *) &fw->data[*pos]; - int data_offs = 4; - - if (*pos >= fw->size) - return 0; - - memset(hx, 0, sizeof(struct hexline)); - hx->len = b[0]; - - if ((*pos + hx->len + 4) >= fw->size) - return -EINVAL; - - hx->addr = b[1] | (b[2] << 8); - hx->type = b[3]; - - if (hx->type == 0x04) { - /* b[4] and b[5] are the Extended linear address record data - * field */ - hx->addr |= (b[4] << 24) | (b[5] << 16); - } - - memcpy(hx->data, &b[data_offs], hx->len); - hx->chk = b[hx->len + data_offs]; - *pos += hx->len + 5; - - return *pos; -} -EXPORT_SYMBOL(dvb_usbv2_get_hexline); - -MODULE_AUTHOR("Antti Palosaari "); -MODULE_DESCRIPTION("Cypress firmware download"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.h b/drivers/media/usb/dvb-usb-v2/cypress_firmware.h deleted file mode 100644 index 80085fd4132c..000000000000 --- a/drivers/media/usb/dvb-usb-v2/cypress_firmware.h +++ /dev/null @@ -1,31 +0,0 @@ -/* cypress_firmware.h is part of the DVB USB library. - * - * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de) - * see dvb-usb-init.c for copyright information. - * - * This file contains functions for downloading the firmware to Cypress FX 1 - * and 2 based devices. - * - */ - -#ifndef CYPRESS_FIRMWARE_H -#define CYPRESS_FIRMWARE_H - -#define CYPRESS_AN2135 0 -#define CYPRESS_AN2235 1 -#define CYPRESS_FX2 2 - -/* commonly used firmware download types and function */ -struct hexline { - u8 len; - u32 addr; - u8 type; - u8 data[255]; - u8 chk; -}; -extern int usbv2_cypress_load_firmware(struct usb_device *, - const struct firmware *, int); -extern int dvb_usbv2_get_hexline(const struct firmware *, - struct hexline *, int *); - -#endif diff --git a/drivers/staging/media/go7007/Kconfig b/drivers/staging/media/go7007/Kconfig index b10f99684ffb..6cdc6ba3b1e4 100644 --- a/drivers/staging/media/go7007/Kconfig +++ b/drivers/staging/media/go7007/Kconfig @@ -4,6 +4,7 @@ config VIDEO_GO7007 depends on SND select VIDEOBUF2_VMALLOC select VIDEO_TUNER + select CYPRESS_FIRMWARE select SND_PCM select VIDEO_SONY_BTF_MPX if MEDIA_SUBDRV_AUTOSELECT select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT @@ -33,7 +34,7 @@ config VIDEO_GO7007_USB config VIDEO_GO7007_LOADER tristate "WIS GO7007 Loader support" - depends on VIDEO_GO7007 && DVB_USB + depends on VIDEO_GO7007 default y ---help--- This is a go7007 firmware loader driver for the WIS GO7007 diff --git a/drivers/staging/media/go7007/Makefile b/drivers/staging/media/go7007/Makefile index bbc8a32027ec..9c6ad4a263ec 100644 --- a/drivers/staging/media/go7007/Makefile +++ b/drivers/staging/media/go7007/Makefile @@ -12,8 +12,4 @@ s2250-y := s2250-board.o #obj-$(CONFIG_VIDEO_SAA7134) += saa7134-go7007.o #ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/pci/saa7134 -# go7007-loader needs cypress ezusb loader from dvb-usb-v2 -ccflags-$(CONFIG_VIDEO_GO7007_LOADER:m=y) += -Idrivers/media/usb/dvb-usb-v2 - -ccflags-y += -Idrivers/media/dvb-frontends -ccflags-y += -Idrivers/media/dvb-core +ccflags-$(CONFIG_VIDEO_GO7007_LOADER:m=y) += -Idrivers/media/common diff --git a/drivers/staging/media/go7007/go7007-loader.c b/drivers/staging/media/go7007/go7007-loader.c index 4ce53d6e8528..f846ad5819dc 100644 --- a/drivers/staging/media/go7007/go7007-loader.c +++ b/drivers/staging/media/go7007/go7007-loader.c @@ -85,7 +85,7 @@ static int go7007_loader_probe(struct usb_interface *interface, "unable to load firmware from file \"%s\"\n", fw1); goto failed2; } - ret = usbv2_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); + ret = cypress_load_firmware(usbdev, fw, CYPRESS_FX2); release_firmware(fw); if (0 != ret) { dev_err(&interface->dev, "loader download failed\n"); @@ -100,7 +100,7 @@ static int go7007_loader_probe(struct usb_interface *interface, "unable to load firmware from file \"%s\"\n", fw2); goto failed2; } - ret = usbv2_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); + ret = cypress_load_firmware(usbdev, fw, CYPRESS_FX2); release_firmware(fw); if (0 != ret) { dev_err(&interface->dev, "firmware download failed\n"); -- cgit v1.2.3 From 99fd133f907afdb430942d8d2ae53faa438adfe8 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 26 Sep 2012 05:24:03 -0300 Subject: [media] Add a V4L2 OF parser Add a V4L2 OF parser, implementing bindings documented in Documentation/devicetree/bindings/media/video-interfaces.txt. [s.nawrocki@samsung.com: various corrections and improvements since the initial version] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/Makefile | 3 + drivers/media/v4l2-core/v4l2-of.c | 267 ++++++++++++++++++++++++++++++++++++++ include/media/v4l2-of.h | 111 ++++++++++++++++ 3 files changed, 381 insertions(+) create mode 100644 drivers/media/v4l2-core/v4l2-of.c create mode 100644 include/media/v4l2-of.h (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index a9d355230e8e..00c4a1993d58 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -9,6 +9,9 @@ videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \ ifeq ($(CONFIG_COMPAT),y) videodev-objs += v4l2-compat-ioctl32.o endif +ifeq ($(CONFIG_OF),y) + videodev-objs += v4l2-of.o +endif obj-$(CONFIG_VIDEO_DEV) += videodev.o obj-$(CONFIG_VIDEO_V4L2_INT_DEVICE) += v4l2-int-device.o diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c new file mode 100644 index 000000000000..e38e21064b5f --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-of.c @@ -0,0 +1,267 @@ +/* + * V4L2 OF binding parsing library + * + * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * Copyright (C) 2012 Renesas Electronics Corp. + * Author: Guennadi Liakhovetski + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include + +#include + +static void v4l2_of_parse_csi_bus(const struct device_node *node, + struct v4l2_of_endpoint *endpoint) +{ + struct v4l2_of_bus_mipi_csi2 *bus = &endpoint->bus.mipi_csi2; + u32 data_lanes[ARRAY_SIZE(bus->data_lanes)]; + struct property *prop; + bool have_clk_lane = false; + unsigned int flags = 0; + u32 v; + + prop = of_find_property(node, "data-lanes", NULL); + if (prop) { + const __be32 *lane = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(data_lanes); i++) { + lane = of_prop_next_u32(prop, lane, &data_lanes[i]); + if (!lane) + break; + } + bus->num_data_lanes = i; + while (i--) + bus->data_lanes[i] = data_lanes[i]; + } + + if (!of_property_read_u32(node, "clock-lanes", &v)) { + bus->clock_lane = v; + have_clk_lane = true; + } + + if (of_get_property(node, "clock-noncontinuous", &v)) + flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK; + else if (have_clk_lane || bus->num_data_lanes > 0) + flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + + bus->flags = flags; + endpoint->bus_type = V4L2_MBUS_CSI2; +} + +static void v4l2_of_parse_parallel_bus(const struct device_node *node, + struct v4l2_of_endpoint *endpoint) +{ + struct v4l2_of_bus_parallel *bus = &endpoint->bus.parallel; + unsigned int flags = 0; + u32 v; + + if (!of_property_read_u32(node, "hsync-active", &v)) + flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH : + V4L2_MBUS_HSYNC_ACTIVE_LOW; + + if (!of_property_read_u32(node, "vsync-active", &v)) + flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH : + V4L2_MBUS_VSYNC_ACTIVE_LOW; + + if (!of_property_read_u32(node, "pclk-sample", &v)) + flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING : + V4L2_MBUS_PCLK_SAMPLE_FALLING; + + if (!of_property_read_u32(node, "field-even-active", &v)) + flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH : + V4L2_MBUS_FIELD_EVEN_LOW; + if (flags) + endpoint->bus_type = V4L2_MBUS_PARALLEL; + else + endpoint->bus_type = V4L2_MBUS_BT656; + + if (!of_property_read_u32(node, "data-active", &v)) + flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH : + V4L2_MBUS_DATA_ACTIVE_LOW; + + if (of_get_property(node, "slave-mode", &v)) + flags |= V4L2_MBUS_SLAVE; + else + flags |= V4L2_MBUS_MASTER; + + if (!of_property_read_u32(node, "bus-width", &v)) + bus->bus_width = v; + + if (!of_property_read_u32(node, "data-shift", &v)) + bus->data_shift = v; + + bus->flags = flags; + +} +EXPORT_SYMBOL(v4l2_of_parse_parallel_bus); + +/** + * v4l2_of_parse_endpoint() - parse all endpoint node properties + * @node: pointer to endpoint device_node + * @endpoint: pointer to the V4L2 OF endpoint data structure + * + * All properties are optional. If none are found, we don't set any flags. + * This means the port has a static configuration and no properties have + * to be specified explicitly. + * If any properties that identify the bus as parallel are found and + * slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if we recognise + * the bus as serial CSI-2 and clock-noncontinuous isn't set, we set the + * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. + * The caller should hold a reference to @node. + */ +void v4l2_of_parse_endpoint(const struct device_node *node, + struct v4l2_of_endpoint *endpoint) +{ + struct device_node *port_node = of_get_parent(node); + + memset(endpoint, 0, offsetof(struct v4l2_of_endpoint, head)); + + endpoint->local_node = node; + /* + * It doesn't matter whether the two calls below succeed. + * If they don't then the default value 0 is used. + */ + of_property_read_u32(port_node, "reg", &endpoint->port); + of_property_read_u32(node, "reg", &endpoint->id); + + v4l2_of_parse_csi_bus(node, endpoint); + /* + * Parse the parallel video bus properties only if none + * of the MIPI CSI-2 specific properties were found. + */ + if (endpoint->bus.mipi_csi2.flags == 0) + v4l2_of_parse_parallel_bus(node, endpoint); + + of_node_put(port_node); +} +EXPORT_SYMBOL(v4l2_of_parse_endpoint); + +/** + * v4l2_of_get_next_endpoint() - get next endpoint node + * @parent: pointer to the parent device node + * @prev: previous endpoint node, or NULL to get first + * + * Return: An 'endpoint' node pointer with refcount incremented. Refcount + * of the passed @prev node is not decremented, the caller have to use + * of_node_put() on it when done. + */ +struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent, + struct device_node *prev) +{ + struct device_node *endpoint; + struct device_node *port = NULL; + + if (!parent) + return NULL; + + if (!prev) { + struct device_node *node; + /* + * It's the first call, we have to find a port subnode + * within this node or within an optional 'ports' node. + */ + node = of_get_child_by_name(parent, "ports"); + if (node) + parent = node; + + for_each_child_of_node(parent, node) { + if (!of_node_cmp(node->name, "port")) { + port = node; + break; + } + } + if (port) { + /* Found a port, get an endpoint. */ + endpoint = of_get_next_child(port, NULL); + of_node_put(port); + } else { + endpoint = NULL; + } + + if (!endpoint) + pr_err("%s(): no endpoint nodes specified for %s\n", + __func__, parent->full_name); + } else { + port = of_get_parent(prev); + if (!port) + /* Hm, has someone given us the root node ?... */ + return NULL; + + /* Avoid dropping prev node refcount to 0. */ + of_node_get(prev); + endpoint = of_get_next_child(port, prev); + if (endpoint) { + of_node_put(port); + return endpoint; + } + + /* No more endpoints under this port, try the next one. */ + do { + port = of_get_next_child(parent, port); + if (!port) + return NULL; + } while (of_node_cmp(port->name, "port")); + + /* Pick up the first endpoint in this port. */ + endpoint = of_get_next_child(port, NULL); + of_node_put(port); + } + + return endpoint; +} +EXPORT_SYMBOL(v4l2_of_get_next_endpoint); + +/** + * v4l2_of_get_remote_port_parent() - get remote port's parent node + * @node: pointer to a local endpoint device_node + * + * Return: Remote device node associated with remote endpoint node linked + * to @node. Use of_node_put() on it when done. + */ +struct device_node *v4l2_of_get_remote_port_parent( + const struct device_node *node) +{ + struct device_node *np; + unsigned int depth; + + /* Get remote endpoint node. */ + np = of_parse_phandle(node, "remote-endpoint", 0); + + /* Walk 3 levels up only if there is 'ports' node. */ + for (depth = 3; depth && np; depth--) { + np = of_get_next_parent(np); + if (depth == 2 && of_node_cmp(np->name, "ports")) + break; + } + return np; +} +EXPORT_SYMBOL(v4l2_of_get_remote_port_parent); + +/** + * v4l2_of_get_remote_port() - get remote port node + * @node: pointer to a local endpoint device_node + * + * Return: Remote port node associated with remote endpoint node linked + * to @node. Use of_node_put() on it when done. + */ +struct device_node *v4l2_of_get_remote_port(const struct device_node *node) +{ + struct device_node *np; + + /* Get remote endpoint node. */ + np = of_parse_phandle(node, "remote-endpoint", 0); + if (!np) + return NULL; + return of_get_parent(np); +} +EXPORT_SYMBOL(v4l2_of_get_remote_port); diff --git a/include/media/v4l2-of.h b/include/media/v4l2-of.h new file mode 100644 index 000000000000..00f91473498c --- /dev/null +++ b/include/media/v4l2-of.h @@ -0,0 +1,111 @@ +/* + * V4L2 OF binding parsing library + * + * Copyright (C) 2012 Renesas Electronics Corp. + * Author: Guennadi Liakhovetski + * + * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + */ +#ifndef _V4L2_OF_H +#define _V4L2_OF_H + +#include +#include +#include + +#include + +struct device_node; + +/** + * struct v4l2_of_bus_mipi_csi2 - MIPI CSI-2 bus data structure + * @flags: media bus (V4L2_MBUS_*) flags + * @data_lanes: an array of physical data lane indexes + * @clock_lane: physical lane index of the clock lane + * @num_data_lanes: number of data lanes + */ +struct v4l2_of_bus_mipi_csi2 { + unsigned int flags; + unsigned char data_lanes[4]; + unsigned char clock_lane; + unsigned short num_data_lanes; +}; + +/** + * struct v4l2_of_bus_parallel - parallel data bus data structure + * @flags: media bus (V4L2_MBUS_*) flags + * @bus_width: bus width in bits + * @data_shift: data shift in bits + */ +struct v4l2_of_bus_parallel { + unsigned int flags; + unsigned char bus_width; + unsigned char data_shift; +}; + +/** + * struct v4l2_of_endpoint - the endpoint data structure + * @port: identifier (value of reg property) of a port this endpoint belongs to + * @id: identifier (value of reg property) of this endpoint + * @local_node: pointer to device_node of this endpoint + * @remote: phandle to remote endpoint node + * @bus_type: bus type + * @bus: bus configuration data structure + * @head: list head for this structure + */ +struct v4l2_of_endpoint { + unsigned int port; + unsigned int id; + const struct device_node *local_node; + const __be32 *remote; + enum v4l2_mbus_type bus_type; + union { + struct v4l2_of_bus_parallel parallel; + struct v4l2_of_bus_mipi_csi2 mipi_csi2; + } bus; + struct list_head head; +}; + +#ifdef CONFIG_OF +void v4l2_of_parse_endpoint(const struct device_node *node, + struct v4l2_of_endpoint *link); +struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent, + struct device_node *previous); +struct device_node *v4l2_of_get_remote_port_parent( + const struct device_node *node); +struct device_node *v4l2_of_get_remote_port(const struct device_node *node); +#else /* CONFIG_OF */ + +static inline int v4l2_of_parse_endpoint(const struct device_node *node, + struct v4l2_of_endpoint *link) +{ + return -ENOSYS; +} + +static inline struct device_node *v4l2_of_get_next_endpoint( + const struct device_node *parent, + struct device_node *previous) +{ + return NULL; +} + +static inline struct device_node *v4l2_of_get_remote_port_parent( + const struct device_node *node) +{ + return NULL; +} + +static inline struct device_node *v4l2_of_get_remote_port( + const struct device_node *node) +{ + return NULL; +} + +#endif /* CONFIG_OF */ + +#endif /* _V4L2_OF_H */ -- cgit v1.2.3 From 95c4a17f79232a61546c7359ede1a5d1042f1b76 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 20 Mar 2013 10:35:43 -0300 Subject: [media] s5p-fimc: Use video entity for marking media pipeline as streaming It doesn't matter whether we start from the sensor of from the video node entity. Remove use of pipeline->subdevs array where possible, so we can partly drop dependency on struct fimc_pipeline in the fimc-lite module, which is also used by the exynos5-is driver. Also make sure we revert any media entity pipeline operations when vb2_streamon() function fails. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-capture.c | 27 ++++++++++++++++---------- drivers/media/platform/s5p-fimc/fimc-lite.c | 9 ++++----- 2 files changed, 21 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index 87b68420f771..257afc161919 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c @@ -1230,36 +1230,43 @@ static int fimc_cap_streamon(struct file *file, void *priv, { struct fimc_dev *fimc = video_drvdata(file); struct fimc_pipeline *p = &fimc->pipeline; - struct v4l2_subdev *sd = p->subdevs[IDX_SENSOR]; + struct fimc_vid_cap *vc = &fimc->vid_cap; + struct media_entity *entity = &vc->vfd.entity; int ret; if (fimc_capture_active(fimc)) return -EBUSY; - ret = media_entity_pipeline_start(&sd->entity, p->m_pipeline); + ret = media_entity_pipeline_start(entity, p->m_pipeline); if (ret < 0) return ret; - if (fimc->vid_cap.user_subdev_api) { + if (vc->user_subdev_api) { ret = fimc_pipeline_validate(fimc); - if (ret < 0) { - media_entity_pipeline_stop(&sd->entity); - return ret; - } + if (ret < 0) + goto err_p_stop; } - return vb2_streamon(&fimc->vid_cap.vbq, type); + + ret = vb2_streamon(&vc->vbq, type); + if (!ret) + return ret; + +err_p_stop: + media_entity_pipeline_stop(entity); + return ret; } static int fimc_cap_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { struct fimc_dev *fimc = video_drvdata(file); - struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR]; int ret; ret = vb2_streamoff(&fimc->vid_cap.vbq, type); + if (ret == 0) - media_entity_pipeline_stop(&sd->entity); + media_entity_pipeline_stop(&fimc->vid_cap.vfd.entity); + return ret; } diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index 47fbf7bcf608..d8afbbc3999b 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite.c @@ -800,20 +800,20 @@ static int fimc_lite_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { struct fimc_lite *fimc = video_drvdata(file); - struct v4l2_subdev *sensor = fimc->pipeline.subdevs[IDX_SENSOR]; + struct media_entity *entity = &fimc->vfd.entity; struct fimc_pipeline *p = &fimc->pipeline; int ret; if (fimc_lite_active(fimc)) return -EBUSY; - ret = media_entity_pipeline_start(&sensor->entity, p->m_pipeline); + ret = media_entity_pipeline_start(entity, p->m_pipeline); if (ret < 0) return ret; ret = fimc_pipeline_validate(fimc); if (ret) { - media_entity_pipeline_stop(&sensor->entity); + media_entity_pipeline_stop(entity); return ret; } @@ -824,12 +824,11 @@ static int fimc_lite_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { struct fimc_lite *fimc = video_drvdata(file); - struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR]; int ret; ret = vb2_streamoff(&fimc->vb_queue, type); if (ret == 0) - media_entity_pipeline_stop(&sd->entity); + media_entity_pipeline_stop(&fimc->vfd.entity); return ret; } -- cgit v1.2.3 From c444914af9261b57c9a559cc324dcadce7765bd2 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 25 Mar 2013 16:36:35 -0300 Subject: [media] s5p-fimc: Use vb2 ioctl/fop helpers in FIMC capture driver mmap/poll file operation and several ioctl handlers are replaced with the vb2 helper functions. Some helpers are used indirectly to maintain the buffer queue ownership. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-capture.c | 153 ++++++------------------- drivers/media/platform/s5p-fimc/fimc-m2m.c | 9 +- 2 files changed, 36 insertions(+), 126 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index 257afc161919..e9928cda6387 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c @@ -454,24 +454,12 @@ static void buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&fimc->slock, flags); } -static void fimc_lock(struct vb2_queue *vq) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vq); - mutex_lock(&ctx->fimc_dev->lock); -} - -static void fimc_unlock(struct vb2_queue *vq) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vq); - mutex_unlock(&ctx->fimc_dev->lock); -} - static struct vb2_ops fimc_capture_qops = { .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, - .wait_prepare = fimc_unlock, - .wait_finish = fimc_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; @@ -530,7 +518,7 @@ static int fimc_capture_open(struct file *file) goto unlock; } - if (++fimc->vid_cap.refcnt == 1) { + if (v4l2_fh_is_singular_file(file)) { ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, &fimc->vid_cap.vfd.entity, true); @@ -543,8 +531,9 @@ static int fimc_capture_open(struct file *file) if (ret < 0) { clear_bit(ST_CAPT_BUSY, &fimc->state); pm_runtime_put_sync(&fimc->pdev->dev); - fimc->vid_cap.refcnt--; v4l2_fh_release(file); + } else { + fimc->vid_cap.refcnt++; } } unlock: @@ -553,7 +542,7 @@ unlock: return ret; } -static int fimc_capture_close(struct file *file) +static int fimc_capture_release(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); int ret; @@ -562,50 +551,20 @@ static int fimc_capture_close(struct file *file) mutex_lock(&fimc->lock); - if (--fimc->vid_cap.refcnt == 0) { + if (v4l2_fh_is_singular_file(file)) { clear_bit(ST_CAPT_BUSY, &fimc->state); fimc_stop_capture(fimc, false); fimc_pipeline_call(fimc, close, &fimc->pipeline); clear_bit(ST_CAPT_SUSPENDED, &fimc->state); + fimc->vid_cap.refcnt--; } pm_runtime_put(&fimc->pdev->dev); - if (fimc->vid_cap.refcnt == 0) { - vb2_queue_release(&fimc->vid_cap.vbq); + if (v4l2_fh_is_singular_file(file)) fimc_ctrls_delete(fimc->vid_cap.ctx); - } - - ret = v4l2_fh_release(file); - - mutex_unlock(&fimc->lock); - return ret; -} - -static unsigned int fimc_capture_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct fimc_dev *fimc = video_drvdata(file); - int ret; - if (mutex_lock_interruptible(&fimc->lock)) - return POLL_ERR; - - ret = vb2_poll(&fimc->vid_cap.vbq, file, wait); - mutex_unlock(&fimc->lock); - - return ret; -} - -static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct fimc_dev *fimc = video_drvdata(file); - int ret; - - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - - ret = vb2_mmap(&fimc->vid_cap.vbq, vma); + ret = vb2_fop_release(file); mutex_unlock(&fimc->lock); return ret; @@ -614,10 +573,10 @@ static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma) static const struct v4l2_file_operations fimc_capture_fops = { .owner = THIS_MODULE, .open = fimc_capture_open, - .release = fimc_capture_close, - .poll = fimc_capture_poll, + .release = fimc_capture_release, + .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, - .mmap = fimc_capture_mmap, + .mmap = vb2_fop_mmap, }; /* @@ -1247,7 +1206,7 @@ static int fimc_cap_streamon(struct file *file, void *priv, goto err_p_stop; } - ret = vb2_streamon(&vc->vbq, type); + ret = vb2_ioctl_streamon(file, priv, type); if (!ret) return ret; @@ -1262,7 +1221,7 @@ static int fimc_cap_streamoff(struct file *file, void *priv, struct fimc_dev *fimc = video_drvdata(file); int ret; - ret = vb2_streamoff(&fimc->vid_cap.vbq, type); + ret = vb2_ioctl_streamoff(file, priv, type); if (ret == 0) media_entity_pipeline_stop(&fimc->vid_cap.vfd.entity); @@ -1274,59 +1233,14 @@ static int fimc_cap_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *reqbufs) { struct fimc_dev *fimc = video_drvdata(file); - int ret = vb2_reqbufs(&fimc->vid_cap.vbq, reqbufs); + int ret; + + ret = vb2_ioctl_reqbufs(file, priv, reqbufs); if (!ret) fimc->vid_cap.reqbufs_count = reqbufs->count; - return ret; -} - -static int fimc_cap_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct fimc_dev *fimc = video_drvdata(file); - - return vb2_querybuf(&fimc->vid_cap.vbq, buf); -} - -static int fimc_cap_qbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct fimc_dev *fimc = video_drvdata(file); - - return vb2_qbuf(&fimc->vid_cap.vbq, buf); -} - -static int fimc_cap_expbuf(struct file *file, void *priv, - struct v4l2_exportbuffer *eb) -{ - struct fimc_dev *fimc = video_drvdata(file); - - return vb2_expbuf(&fimc->vid_cap.vbq, eb); -} - -static int fimc_cap_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct fimc_dev *fimc = video_drvdata(file); - - return vb2_dqbuf(&fimc->vid_cap.vbq, buf, file->f_flags & O_NONBLOCK); -} - -static int fimc_cap_create_bufs(struct file *file, void *priv, - struct v4l2_create_buffers *create) -{ - struct fimc_dev *fimc = video_drvdata(file); - - return vb2_create_bufs(&fimc->vid_cap.vbq, create); -} - -static int fimc_cap_prepare_buf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct fimc_dev *fimc = video_drvdata(file); - return vb2_prepare_buf(&fimc->vid_cap.vbq, b); + return ret; } static int fimc_cap_g_selection(struct file *file, void *fh, @@ -1425,14 +1339,12 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { .vidioc_g_fmt_vid_cap_mplane = fimc_cap_g_fmt_mplane, .vidioc_reqbufs = fimc_cap_reqbufs, - .vidioc_querybuf = fimc_cap_querybuf, - - .vidioc_qbuf = fimc_cap_qbuf, - .vidioc_dqbuf = fimc_cap_dqbuf, - .vidioc_expbuf = fimc_cap_expbuf, - - .vidioc_prepare_buf = fimc_cap_prepare_buf, - .vidioc_create_bufs = fimc_cap_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, .vidioc_streamon = fimc_cap_streamon, .vidioc_streamoff = fimc_cap_streamoff, @@ -1759,9 +1671,9 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, struct v4l2_device *v4l2_dev) { struct video_device *vfd = &fimc->vid_cap.vfd; - struct fimc_vid_cap *vid_cap; + struct vb2_queue *q = &fimc->vid_cap.vbq; struct fimc_ctx *ctx; - struct vb2_queue *q; + struct fimc_vid_cap *vid_cap; int ret = -ENOMEM; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); @@ -1783,28 +1695,27 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, vfd->v4l2_dev = v4l2_dev; vfd->minor = -1; vfd->release = video_device_release_empty; + vfd->queue = q; vfd->lock = &fimc->lock; video_set_drvdata(vfd, fimc); - vid_cap = &fimc->vid_cap; vid_cap->active_buf_cnt = 0; - vid_cap->reqbufs_count = 0; - vid_cap->refcnt = 0; + vid_cap->reqbufs_count = 0; + vid_cap->ctx = ctx; INIT_LIST_HEAD(&vid_cap->pending_buf_q); INIT_LIST_HEAD(&vid_cap->active_buf_q); - vid_cap->ctx = ctx; - q = &fimc->vid_cap.vbq; memset(q, 0, sizeof(*q)); q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - q->drv_priv = fimc->vid_cap.ctx; + q->drv_priv = ctx; q->ops = &fimc_capture_qops; q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct fimc_vid_buffer); q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &fimc->lock; ret = vb2_queue_init(q); if (ret) diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c index f3d535cdd87f..c8509dd1776d 100644 --- a/drivers/media/platform/s5p-fimc/fimc-m2m.c +++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c @@ -667,16 +667,15 @@ static int fimc_m2m_open(struct file *file) struct fimc_ctx *ctx; int ret = -EBUSY; - dbg("pid: %d, state: 0x%lx, refcnt: %d", - task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt); + pr_debug("pid: %d, state: %#lx\n", task_pid_nr(current), fimc->state); if (mutex_lock_interruptible(&fimc->lock)) return -ERESTARTSYS; /* - * Return if the corresponding video capture node - * is already opened. + * Don't allow simultaneous open() of the mem-to-mem and the + * capture video node that belong to same FIMC IP instance. */ - if (fimc->vid_cap.refcnt > 0) + if (test_bit(ST_CAPT_BUSY, &fimc->state)) goto unlock; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); -- cgit v1.2.3 From ee12b049104118a58ac13da207a84c867191b17a Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 25 Mar 2013 16:43:08 -0300 Subject: [media] s5p-fimc: Use vb2 ioctl helpers in fimc-lite Replace some ioctl, file and video buffer queue operation handlers with the videobuf2 helpers. This allows to get rid of significant amount of boilerplate. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-lite.c | 170 ++++++++-------------------- 1 file changed, 45 insertions(+), 125 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index d8afbbc3999b..b64297ba35d3 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite.c @@ -425,24 +425,12 @@ static void buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&fimc->slock, flags); } -static void fimc_lock(struct vb2_queue *vq) -{ - struct fimc_lite *fimc = vb2_get_drv_priv(vq); - mutex_lock(&fimc->lock); -} - -static void fimc_unlock(struct vb2_queue *vq) -{ - struct fimc_lite *fimc = vb2_get_drv_priv(vq); - mutex_unlock(&fimc->lock); -} - static const struct vb2_ops fimc_lite_qops = { .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, - .wait_prepare = fimc_unlock, - .wait_finish = fimc_lock, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, .start_streaming = start_streaming, .stop_streaming = stop_streaming, }; @@ -467,99 +455,69 @@ static int fimc_lite_open(struct file *file) mutex_lock(&fimc->lock); if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) { ret = -EBUSY; - goto done; + goto unlock; } set_bit(ST_FLITE_IN_USE, &fimc->state); ret = pm_runtime_get_sync(&fimc->pdev->dev); if (ret < 0) - goto done; + goto unlock; ret = v4l2_fh_open(file); if (ret < 0) - goto done; + goto err_pm; - if (++fimc->ref_count == 1 && - atomic_read(&fimc->out_path) == FIMC_IO_DMA) { - ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, - &fimc->vfd.entity, true); - if (ret < 0) { - pm_runtime_put_sync(&fimc->pdev->dev); - fimc->ref_count--; - v4l2_fh_release(file); - clear_bit(ST_FLITE_IN_USE, &fimc->state); - } + if (!v4l2_fh_is_singular_file(file) || + atomic_read(&fimc->out_path) != FIMC_IO_DMA) + goto unlock; + ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, + me, true); + if (!ret) { fimc_lite_clear_event_counters(fimc); + fimc->ref_count++; + goto unlock; } -done: + + v4l2_fh_release(file); +err_pm: + pm_runtime_put_sync(&fimc->pdev->dev); + clear_bit(ST_FLITE_IN_USE, &fimc->state); +unlock: mutex_unlock(&fimc->lock); mutex_unlock(&me->parent->graph_mutex); return ret; } -static int fimc_lite_close(struct file *file) +static int fimc_lite_release(struct file *file) { struct fimc_lite *fimc = video_drvdata(file); - int ret; mutex_lock(&fimc->lock); - if (--fimc->ref_count == 0 && + if (v4l2_fh_is_singular_file(file) && atomic_read(&fimc->out_path) == FIMC_IO_DMA) { clear_bit(ST_FLITE_IN_USE, &fimc->state); fimc_lite_stop_capture(fimc, false); fimc_pipeline_call(fimc, close, &fimc->pipeline); - clear_bit(ST_FLITE_SUSPENDED, &fimc->state); + fimc->ref_count--; } + vb2_fop_release(file); pm_runtime_put(&fimc->pdev->dev); + clear_bit(ST_FLITE_SUSPENDED, &fimc->state); - if (fimc->ref_count == 0) - vb2_queue_release(&fimc->vb_queue); - - ret = v4l2_fh_release(file); - - mutex_unlock(&fimc->lock); - return ret; -} - -static unsigned int fimc_lite_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct fimc_lite *fimc = video_drvdata(file); - int ret; - - if (mutex_lock_interruptible(&fimc->lock)) - return POLL_ERR; - - ret = vb2_poll(&fimc->vb_queue, file, wait); - mutex_unlock(&fimc->lock); - - return ret; -} - -static int fimc_lite_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct fimc_lite *fimc = video_drvdata(file); - int ret; - - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - - ret = vb2_mmap(&fimc->vb_queue, vma); mutex_unlock(&fimc->lock); - - return ret; + return 0; } static const struct v4l2_file_operations fimc_lite_fops = { .owner = THIS_MODULE, .open = fimc_lite_open, - .release = fimc_lite_close, - .poll = fimc_lite_poll, + .release = fimc_lite_release, + .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2, - .mmap = fimc_lite_mmap, + .mmap = vb2_fop_mmap, }; /* @@ -720,7 +678,6 @@ static int fimc_lite_try_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { struct fimc_lite *fimc = video_drvdata(file); - return fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, NULL); } @@ -812,12 +769,15 @@ static int fimc_lite_streamon(struct file *file, void *priv, return ret; ret = fimc_pipeline_validate(fimc); - if (ret) { - media_entity_pipeline_stop(entity); - return ret; - } + if (ret < 0) + goto err_p_stop; - return vb2_streamon(&fimc->vb_queue, type); + ret = vb2_ioctl_streamon(file, priv, type); + if (!ret) + return ret; +err_p_stop: + media_entity_pipeline_stop(entity); + return 0; } static int fimc_lite_streamoff(struct file *file, void *priv, @@ -826,7 +786,7 @@ static int fimc_lite_streamoff(struct file *file, void *priv, struct fimc_lite *fimc = video_drvdata(file); int ret; - ret = vb2_streamoff(&fimc->vb_queue, type); + ret = vb2_ioctl_streamoff(file, priv, type); if (ret == 0) media_entity_pipeline_stop(&fimc->vfd.entity); return ret; @@ -839,53 +799,13 @@ static int fimc_lite_reqbufs(struct file *file, void *priv, int ret; reqbufs->count = max_t(u32, FLITE_REQ_BUFS_MIN, reqbufs->count); - ret = vb2_reqbufs(&fimc->vb_queue, reqbufs); + ret = vb2_ioctl_reqbufs(file, priv, reqbufs); if (!ret) fimc->reqbufs_count = reqbufs->count; return ret; } -static int fimc_lite_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct fimc_lite *fimc = video_drvdata(file); - - return vb2_querybuf(&fimc->vb_queue, buf); -} - -static int fimc_lite_qbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct fimc_lite *fimc = video_drvdata(file); - - return vb2_qbuf(&fimc->vb_queue, buf); -} - -static int fimc_lite_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct fimc_lite *fimc = video_drvdata(file); - - return vb2_dqbuf(&fimc->vb_queue, buf, file->f_flags & O_NONBLOCK); -} - -static int fimc_lite_create_bufs(struct file *file, void *priv, - struct v4l2_create_buffers *create) -{ - struct fimc_lite *fimc = video_drvdata(file); - - return vb2_create_bufs(&fimc->vb_queue, create); -} - -static int fimc_lite_prepare_buf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct fimc_lite *fimc = video_drvdata(file); - - return vb2_prepare_buf(&fimc->vb_queue, b); -} - /* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) { @@ -965,11 +885,11 @@ static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = { .vidioc_g_selection = fimc_lite_g_selection, .vidioc_s_selection = fimc_lite_s_selection, .vidioc_reqbufs = fimc_lite_reqbufs, - .vidioc_querybuf = fimc_lite_querybuf, - .vidioc_prepare_buf = fimc_lite_prepare_buf, - .vidioc_create_bufs = fimc_lite_create_bufs, - .vidioc_qbuf = fimc_lite_qbuf, - .vidioc_dqbuf = fimc_lite_dqbuf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, .vidioc_streamon = fimc_lite_streamon, .vidioc_streamoff = fimc_lite_streamoff, }; @@ -1310,8 +1230,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) vfd->v4l2_dev = sd->v4l2_dev; vfd->minor = -1; vfd->release = video_device_release_empty; - vfd->lock = &fimc->lock; - fimc->ref_count = 0; + vfd->queue = q; fimc->reqbufs_count = 0; INIT_LIST_HEAD(&fimc->pending_buf_q); @@ -1325,6 +1244,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) q->buf_struct_size = sizeof(struct flite_buffer); q->drv_priv = fimc; q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &fimc->lock; ret = vb2_queue_init(q); if (ret < 0) -- cgit v1.2.3 From 02399e35e6bb716ce9636eba006b792362270034 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 26 Mar 2013 08:20:30 -0300 Subject: [media] s5p-csis: Add device tree support This patch support for binding the driver to the MIPI-CSIS devices instantiated from device tree and parsing the SoC and board specific properties. The MIPI CSI-2 channel is determined by the value of reg property placed in csis' port subnode. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/samsung-mipi-csis.txt | 81 +++++++++++ drivers/media/platform/s5p-fimc/mipi-csis.c | 155 ++++++++++++++++----- drivers/media/platform/s5p-fimc/mipi-csis.h | 1 + include/media/s5p_fimc.h | 13 ++ 4 files changed, 215 insertions(+), 35 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/samsung-mipi-csis.txt (limited to 'drivers/media') diff --git a/Documentation/devicetree/bindings/media/samsung-mipi-csis.txt b/Documentation/devicetree/bindings/media/samsung-mipi-csis.txt new file mode 100644 index 000000000000..5f8e28e2484f --- /dev/null +++ b/Documentation/devicetree/bindings/media/samsung-mipi-csis.txt @@ -0,0 +1,81 @@ +Samsung S5P/EXYNOS SoC series MIPI CSI-2 receiver (MIPI CSIS) +------------------------------------------------------------- + +Required properties: + +- compatible : "samsung,s5pv210-csis" for S5PV210 (S5PC110), + "samsung,exynos4210-csis" for Exynos4210 (S5PC210), + "samsung,exynos4212-csis" for Exynos4212/Exynos4412 + SoC series; +- reg : offset and length of the register set for the device; +- interrupts : should contain MIPI CSIS interrupt; the format of the + interrupt specifier depends on the interrupt controller; +- bus-width : maximum number of data lanes supported (SoC specific); +- vddio-supply : MIPI CSIS I/O and PLL voltage supply (e.g. 1.8V); +- vddcore-supply : MIPI CSIS Core voltage supply (e.g. 1.1V); +- clocks : list of clock specifiers, corresponding to entries in + clock-names property; +- clock-names : must contain "csis", "sclk_csis" entries, matching entries + in the clocks property. + +Optional properties: + +- clock-frequency : The IP's main (system bus) clock frequency in Hz, default + value when this property is not specified is 166 MHz; +- samsung,csis-wclk : CSI-2 wrapper clock selection. If this property is present + external clock from CMU will be used, or the bus clock if + if it's not specified. + +The device node should contain one 'port' child node with one child 'endpoint' +node, according to the bindings defined in Documentation/devicetree/bindings/ +media/video-interfaces.txt. The following are properties specific to those nodes. + +port node +--------- + +- reg : (required) must be 3 for camera C input (CSIS0) or 4 for + camera D input (CSIS1); + +endpoint node +------------- + +- data-lanes : (required) an array specifying active physical MIPI-CSI2 + data input lanes and their mapping to logical lanes; the + array's content is unused, only its length is meaningful; + +- samsung,csis-hs-settle : (optional) differential receiver (HS-RX) settle time; + + +Example: + + reg0: regulator@0 { + }; + + reg1: regulator@1 { + }; + +/* SoC properties */ + + csis_0: csis@11880000 { + compatible = "samsung,exynos4210-csis"; + reg = <0x11880000 0x1000>; + interrupts = <0 78 0>; + #address-cells = <1>; + #size-cells = <0>; + }; + +/* Board properties */ + + csis_0: csis@11880000 { + clock-frequency = <166000000>; + vddio-supply = <®0>; + vddcore-supply = <®1>; + port { + reg = <3>; /* 3 - CSIS0, 4 - CSIS1 */ + csis0_ep: endpoint { + remote-endpoint = <...>; + data-lanes = <1>, <2>; + samsung,csis-hs-settle = <12>; + }; + }; + }; diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c index 981863d05aaa..8636bcddde1b 100644 --- a/drivers/media/platform/s5p-fimc/mipi-csis.c +++ b/drivers/media/platform/s5p-fimc/mipi-csis.c @@ -19,14 +19,18 @@ #include #include #include +#include +#include #include #include #include #include #include #include +#include +#include #include -#include + #include "mipi-csis.h" static int debug; @@ -113,6 +117,7 @@ static char *csi_clock_name[] = { [CSIS_CLK_GATE] = "csis", }; #define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name) +#define DEFAULT_SCLK_CSIS_FREQ 166000000UL static const char * const csis_supply_name[] = { "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */ @@ -167,6 +172,11 @@ struct csis_pktbuf { * @clock: CSIS clocks * @irq: requested s5p-mipi-csis irq number * @flags: the state variable for power and streaming control + * @clock_frequency: device bus clock frequency + * @hs_settle: HS-RX settle time + * @num_lanes: number of MIPI-CSI data lanes used + * @max_num_lanes: maximum number of MIPI-CSI data lanes supported + * @wclk_ext: CSI wrapper clock: 0 - bus clock, 1 - external SCLK_CAM * @csis_fmt: current CSIS pixel format * @format: common media bus format for the source and sink pad * @slock: spinlock protecting structure members below @@ -184,6 +194,13 @@ struct csis_state { struct clk *clock[NUM_CSIS_CLOCKS]; int irq; u32 flags; + + u32 clk_frequency; + u32 hs_settle; + u32 num_lanes; + u32 max_num_lanes; + u8 wclk_ext; + const struct csis_pix_format *csis_fmt; struct v4l2_mbus_framefmt format; @@ -273,7 +290,6 @@ static void s5pcsis_reset(struct csis_state *state) static void s5pcsis_system_enable(struct csis_state *state, int on) { - struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data; u32 val, mask; val = s5pcsis_read(state, S5PCSIS_CTRL); @@ -286,7 +302,7 @@ static void s5pcsis_system_enable(struct csis_state *state, int on) val = s5pcsis_read(state, S5PCSIS_DPHYCTRL); val &= ~S5PCSIS_DPHYCTRL_ENABLE; if (on) { - mask = (1 << (pdata->lanes + 1)) - 1; + mask = (1 << (state->num_lanes + 1)) - 1; val |= (mask & S5PCSIS_DPHYCTRL_ENABLE); } s5pcsis_write(state, S5PCSIS_DPHYCTRL, val); @@ -321,15 +337,14 @@ static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle) static void s5pcsis_set_params(struct csis_state *state) { - struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data; u32 val; val = s5pcsis_read(state, S5PCSIS_CONFIG); - val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (pdata->lanes - 1); + val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (state->num_lanes - 1); s5pcsis_write(state, S5PCSIS_CONFIG, val); __s5pcsis_set_format(state); - s5pcsis_set_hsync_settle(state, pdata->hs_settle); + s5pcsis_set_hsync_settle(state, state->hs_settle); val = s5pcsis_read(state, S5PCSIS_CTRL); if (state->csis_fmt->data_alignment == 32) @@ -338,7 +353,7 @@ static void s5pcsis_set_params(struct csis_state *state) val &= ~S5PCSIS_CTRL_ALIGN_32BIT; val &= ~S5PCSIS_CTRL_WCLK_EXTCLK; - if (pdata->wclk_source) + if (state->wclk_ext) val |= S5PCSIS_CTRL_WCLK_EXTCLK; s5pcsis_write(state, S5PCSIS_CTRL, val); @@ -701,52 +716,111 @@ static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static int s5pcsis_get_platform_data(struct platform_device *pdev, + struct csis_state *state) +{ + struct s5p_platform_mipi_csis *pdata = pdev->dev.platform_data; + + if (pdata == NULL) { + dev_err(&pdev->dev, "Platform data not specified\n"); + return -EINVAL; + } + + state->clk_frequency = pdata->clk_rate; + state->num_lanes = pdata->lanes; + state->hs_settle = pdata->hs_settle; + state->index = max(0, pdev->id); + state->max_num_lanes = state->index ? CSIS1_MAX_LANES : + CSIS0_MAX_LANES; + return 0; +} + +#ifdef CONFIG_OF +static int s5pcsis_parse_dt(struct platform_device *pdev, + struct csis_state *state) +{ + struct device_node *node = pdev->dev.of_node; + struct v4l2_of_endpoint endpoint; + + if (of_property_read_u32(node, "clock-frequency", + &state->clk_frequency)) + state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; + if (of_property_read_u32(node, "bus-width", + &state->max_num_lanes)) + return -EINVAL; + + node = v4l2_of_get_next_endpoint(node, NULL); + if (!node) { + dev_err(&pdev->dev, "No port node at %s\n", + node->full_name); + return -EINVAL; + } + /* Get port node and validate MIPI-CSI channel id. */ + v4l2_of_parse_endpoint(node, &endpoint); + + state->index = endpoint.port - FIMC_INPUT_MIPI_CSI2_0; + if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES) + return -ENXIO; + + /* Get MIPI CSI-2 bus configration from the endpoint node. */ + of_property_read_u32(node, "samsung,csis-hs-settle", + &state->hs_settle); + state->wclk_ext = of_property_read_bool(node, + "samsung,csis-wclk"); + + state->num_lanes = endpoint.bus.mipi_csi2.num_data_lanes; + + of_node_put(node); + return 0; +} +#else +#define s5pcsis_parse_dt(pdev, state) (-ENOSYS) +#endif + static int s5pcsis_probe(struct platform_device *pdev) { - struct s5p_platform_mipi_csis *pdata; + struct device *dev = &pdev->dev; struct resource *mem_res; struct csis_state *state; int ret = -ENOMEM; int i; - state = devm_kzalloc(&pdev->dev, sizeof(*state), GFP_KERNEL); + state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; mutex_init(&state->lock); spin_lock_init(&state->slock); - state->pdev = pdev; - state->index = max(0, pdev->id); - pdata = pdev->dev.platform_data; - if (pdata == NULL) { - dev_err(&pdev->dev, "Platform data not fully specified\n"); - return -EINVAL; - } + if (dev->of_node) + ret = s5pcsis_parse_dt(pdev, state); + else + ret = s5pcsis_get_platform_data(pdev, state); + if (ret < 0) + return ret; - if ((state->index == 1 && pdata->lanes > CSIS1_MAX_LANES) || - pdata->lanes > CSIS0_MAX_LANES) { - dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n", - pdata->lanes); + if (state->num_lanes == 0 || state->num_lanes > state->max_num_lanes) { + dev_err(dev, "Unsupported number of data lanes: %d (max. %d)\n", + state->num_lanes, state->max_num_lanes); return -EINVAL; } mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - state->regs = devm_ioremap_resource(&pdev->dev, mem_res); + state->regs = devm_ioremap_resource(dev, mem_res); if (IS_ERR(state->regs)) return PTR_ERR(state->regs); state->irq = platform_get_irq(pdev, 0); if (state->irq < 0) { - dev_err(&pdev->dev, "Failed to get irq\n"); + dev_err(dev, "Failed to get irq\n"); return state->irq; } for (i = 0; i < CSIS_NUM_SUPPLIES; i++) state->supplies[i].supply = csis_supply_name[i]; - ret = devm_regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES, + ret = devm_regulator_bulk_get(dev, CSIS_NUM_SUPPLIES, state->supplies); if (ret) return ret; @@ -755,11 +829,11 @@ static int s5pcsis_probe(struct platform_device *pdev) if (ret < 0) return ret; - if (pdata->clk_rate) + if (state->clk_frequency) ret = clk_set_rate(state->clock[CSIS_CLK_MUX], - pdata->clk_rate); + state->clk_frequency); else - dev_WARN(&pdev->dev, "No clock frequency specified!\n"); + dev_WARN(dev, "No clock frequency specified!\n"); if (ret < 0) goto e_clkput; @@ -767,16 +841,17 @@ static int s5pcsis_probe(struct platform_device *pdev) if (ret < 0) goto e_clkput; - ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler, - 0, dev_name(&pdev->dev), state); + ret = devm_request_irq(dev, state->irq, s5pcsis_irq_handler, + 0, dev_name(dev), state); if (ret) { - dev_err(&pdev->dev, "Interrupt request failed\n"); + dev_err(dev, "Interrupt request failed\n"); goto e_clkdis; } v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops); state->sd.owner = THIS_MODULE; - strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name)); + snprintf(state->sd.name, sizeof(state->sd.name), "%s.%d", + CSIS_SUBDEV_NAME, state->index); state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; state->csis_fmt = &s5pcsis_formats[0]; @@ -796,10 +871,12 @@ static int s5pcsis_probe(struct platform_device *pdev) /* .. and a pointer to the subdev. */ platform_set_drvdata(pdev, &state->sd); - memcpy(state->events, s5pcsis_events, sizeof(state->events)); + pm_runtime_enable(dev); - pm_runtime_enable(&pdev->dev); + dev_info(&pdev->dev, "lanes: %d, hs_settle: %d, wclk: %d, freq: %u\n", + state->num_lanes, state->hs_settle, state->wclk_ext, + state->clk_frequency); return 0; e_clkdis: @@ -923,13 +1000,21 @@ static const struct dev_pm_ops s5pcsis_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume) }; +static const struct of_device_id s5pcsis_of_match[] = { + { .compatible = "samsung,s5pv210-csis" }, + { .compatible = "samsung,exynos4210-csis" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, s5pcsis_of_match); + static struct platform_driver s5pcsis_driver = { .probe = s5pcsis_probe, .remove = s5pcsis_remove, .driver = { - .name = CSIS_DRIVER_NAME, - .owner = THIS_MODULE, - .pm = &s5pcsis_pm_ops, + .of_match_table = s5pcsis_of_match, + .name = CSIS_DRIVER_NAME, + .owner = THIS_MODULE, + .pm = &s5pcsis_pm_ops, }, }; diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.h b/drivers/media/platform/s5p-fimc/mipi-csis.h index 2709286396e1..28c11c4085d8 100644 --- a/drivers/media/platform/s5p-fimc/mipi-csis.h +++ b/drivers/media/platform/s5p-fimc/mipi-csis.h @@ -11,6 +11,7 @@ #define S5P_MIPI_CSIS_H_ #define CSIS_DRIVER_NAME "s5p-mipi-csis" +#define CSIS_SUBDEV_NAME CSIS_DRIVER_NAME #define CSIS_MAX_ENTITIES 2 #define CSIS0_MAX_LANES 4 #define CSIS1_MAX_LANES 2 diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index 28f3590aa031..d6dbb791f423 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -14,6 +14,19 @@ #include +/* + * Enumeration of data inputs to the camera subsystem. + */ +enum fimc_input { + FIMC_INPUT_PARALLEL_0 = 1, + FIMC_INPUT_PARALLEL_1, + FIMC_INPUT_MIPI_CSI2_0 = 3, + FIMC_INPUT_MIPI_CSI2_1, + FIMC_INPUT_WRITEBACK_A = 5, + FIMC_INPUT_WRITEBACK_B, + FIMC_INPUT_WRITEBACK_ISP = 5, +}; + /* * Enumeration of the FIMC data bus types. */ -- cgit v1.2.3 From e80cb1fae55ceb01b6e886e5499461c07b69c454 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 26 Mar 2013 08:22:21 -0300 Subject: [media] s5p-fimc: Add device tree support for FIMC device driver This patch adds device tree support for FIMC driver on S5PV210 and Exynos4 SoCs. The FIMC IP block's features and quirks encoded statically in the driver are now parsed from the device tree. Once all relevant platforms are converted to device tree based booting the FIMC variant data structures will all be removed from the driver. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/samsung-fimc.txt | 101 +++++++++ drivers/media/platform/s5p-fimc/fimc-capture.c | 6 +- drivers/media/platform/s5p-fimc/fimc-core.c | 238 ++++++++++++--------- drivers/media/platform/s5p-fimc/fimc-core.h | 21 +- drivers/media/platform/s5p-fimc/fimc-m2m.c | 2 +- drivers/media/platform/s5p-fimc/fimc-reg.c | 6 +- 6 files changed, 260 insertions(+), 114 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/samsung-fimc.txt (limited to 'drivers/media') diff --git a/Documentation/devicetree/bindings/media/samsung-fimc.txt b/Documentation/devicetree/bindings/media/samsung-fimc.txt new file mode 100644 index 000000000000..22e2889162c3 --- /dev/null +++ b/Documentation/devicetree/bindings/media/samsung-fimc.txt @@ -0,0 +1,101 @@ +Samsung S5P/EXYNOS SoC Camera Subsystem (FIMC) +---------------------------------------------- + +The S5P/Exynos SoC Camera subsystem comprises of multiple sub-devices +represented by separate device tree nodes. Currently this includes: FIMC (in +the S5P SoCs series known as CAMIF), MIPI CSIS, FIMC-LITE and FIMC-IS (ISP). + +The sub-subdevices are defined as child nodes of the common 'camera' node which +also includes common properties of the whole subsystem not really specific to +any single sub-device, like common camera port pins or the CAMCLK clock outputs +for external image sensors attached to an SoC. + +Common 'camera' node +-------------------- + +Required properties: + +- compatible : must be "samsung,fimc", "simple-bus" +- clocks : list of clock specifiers, corresponding to entries in + clock-names property; +- clock-names : must contain "fimc", "sclk_fimc" entries, matching entries + in the clocks property. + +The 'camera' node must include at least one 'fimc' child node. + + +'fimc' device nodes +------------------- + +Required properties: + +- compatible: "samsung,s5pv210-fimc" for S5PV210, "samsung,exynos4210-fimc" + for Exynos4210 and "samsung,exynos4212-fimc" for Exynos4x12 SoCs; +- reg: physical base address and length of the registers set for the device; +- interrupts: should contain FIMC interrupt; +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names; +- clock-names: must include "fimc", "sclk_fimc", "mux" entries and optionally + "parent" entry. +- samsung,pix-limits: an array of maximum supported image sizes in pixels, for + details refer to Table 2-1 in the S5PV210 SoC User Manual; The meaning of + each cell is as follows: + 0 - scaler input horizontal size, + 1 - input horizontal size for the scaler bypassed, + 2 - REAL_WIDTH without input rotation, + 3 - REAL_HEIGHT with input rotation, +- samsung,sysreg: a phandle to the SYSREG node. + +Each FIMC device should have an alias in the aliases node, in the form of +fimc, where is an integer specifying the IP block instance. + +Optional properties: + +- clock-frequency: maximum FIMC local clock (LCLK) frequency; +- samsung,min-pix-sizes: an array specyfing minimum image size in pixels at + the FIMC input and output DMA, in the first and second cell respectively. + Default value when this property is not present is <16 16>; +- samsung,min-pix-alignment: minimum supported image height alignment (first + cell) and the horizontal image offset (second cell). The values are in pixels + and default to <2 1> when this property is not present; +- samsung,mainscaler-ext: a boolean property indicating whether the FIMC IP + supports extended image size and has CIEXTEN register; +- samsung,rotators: a bitmask specifying whether this IP has the input and + the output rotator. Bits 4 and 0 correspond to input and output rotator + respectively. If a rotator is present its corresponding bit should be set. + Default value when this property is not specified is 0x11. +- samsung,cam-if: a bolean property indicating whether the IP block includes + the camera input interface. +- samsung,isp-wb: this property must be present if the IP block has the ISP + writeback input. +- samsung,lcd-wb: this property must be present if the IP block has the LCD + writeback input. + + +Example: + + aliases { + fimc0 = &fimc_0; + }; + + camera { + compatible = "samsung,fimc", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + status = "okay"; + + fimc_0: fimc@11800000 { + compatible = "samsung,exynos4210-fimc"; + reg = <0x11800000 0x1000>; + interrupts = <0 85 0>; + status = "okay"; + }; + + csis_0: csis@11880000 { + compatible = "samsung,exynos4210-csis"; + reg = <0x11880000 0x1000>; + interrupts = <0 78 0>; + }; + }; + +The MIPI-CSIS device binding is defined in samsung-mipi-csis.txt. diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index e9928cda6387..724cd8b4933d 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c @@ -65,7 +65,7 @@ static int fimc_capture_hw_init(struct fimc_dev *fimc) fimc_hw_set_effect(ctx); fimc_hw_set_output_path(ctx); fimc_hw_set_out_dma(ctx); - if (fimc->variant->has_alpha) + if (fimc->drv_data->alpha_color) fimc_hw_set_rgb_alpha(ctx); clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); } @@ -168,7 +168,7 @@ static int fimc_capture_config_update(struct fimc_ctx *ctx) fimc_hw_set_effect(ctx); fimc_prepare_dma_offset(ctx, &ctx->d_frame); fimc_hw_set_out_dma(ctx); - if (fimc->variant->has_alpha) + if (fimc->drv_data->alpha_color) fimc_hw_set_rgb_alpha(ctx); clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); @@ -1802,7 +1802,7 @@ int fimc_initialize_capture_subdev(struct fimc_dev *fimc) v4l2_subdev_init(sd, &fimc_subdev_ops); sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->pdev->id); + snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->id); fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index e3916bde45cf..d39e47abb229 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include #include @@ -440,14 +442,14 @@ void fimc_set_yuv_order(struct fimc_ctx *ctx) void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f) { - const struct fimc_variant *variant = ctx->fimc_dev->variant; + bool pix_hoff = ctx->fimc_dev->drv_data->dma_pix_hoff; u32 i, depth = 0; for (i = 0; i < f->fmt->colplanes; i++) depth += f->fmt->depth[i]; f->dma_offset.y_h = f->offs_h; - if (!variant->pix_hoff) + if (!pix_hoff) f->dma_offset.y_h *= (depth >> 3); f->dma_offset.y_v = f->offs_v; @@ -458,7 +460,7 @@ void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f) f->dma_offset.cr_h = f->offs_h; f->dma_offset.cr_v = f->offs_v; - if (!variant->pix_hoff) { + if (!pix_hoff) { if (f->fmt->colplanes == 3) { f->dma_offset.cb_h >>= 1; f->dma_offset.cr_h >>= 1; @@ -589,7 +591,6 @@ static const struct v4l2_ctrl_ops fimc_ctrl_ops = { int fimc_ctrls_create(struct fimc_ctx *ctx) { - const struct fimc_variant *variant = ctx->fimc_dev->variant; unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt); struct fimc_ctrls *ctrls = &ctx->ctrls; struct v4l2_ctrl_handler *handler = &ctrls->handler; @@ -606,7 +607,7 @@ int fimc_ctrls_create(struct fimc_ctx *ctx) ctrls->vflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); - if (variant->has_alpha) + if (ctx->fimc_dev->drv_data->alpha_color) ctrls->alpha = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT, 0, max_alpha, 1, 0); @@ -677,7 +678,7 @@ void fimc_alpha_ctrl_update(struct fimc_ctx *ctx) struct fimc_dev *fimc = ctx->fimc_dev; struct v4l2_ctrl *ctrl = ctx->ctrls.alpha; - if (ctrl == NULL || !fimc->variant->has_alpha) + if (ctrl == NULL || !fimc->drv_data->alpha_color) return; v4l2_ctrl_lock(ctrl); @@ -863,43 +864,109 @@ static int fimc_m2m_resume(struct fimc_dev *fimc) return 0; } +static const struct of_device_id fimc_of_match[]; + +static int fimc_parse_dt(struct fimc_dev *fimc, u32 *clk_freq) +{ + struct device *dev = &fimc->pdev->dev; + struct device_node *node = dev->of_node; + const struct of_device_id *of_id; + struct fimc_variant *v; + struct fimc_pix_limit *lim; + u32 args[FIMC_PIX_LIMITS_MAX]; + int ret; + + if (of_property_read_bool(node, "samsung,lcd-wb")) + return -ENODEV; + + v = devm_kzalloc(dev, sizeof(*v) + sizeof(*lim), GFP_KERNEL); + if (!v) + return -ENOMEM; + + of_id = of_match_node(fimc_of_match, node); + if (!of_id) + return -EINVAL; + fimc->drv_data = of_id->data; + ret = of_property_read_u32_array(node, "samsung,pix-limits", + args, FIMC_PIX_LIMITS_MAX); + if (ret < 0) + return ret; + + lim = (struct fimc_pix_limit *)&v[1]; + + lim->scaler_en_w = args[0]; + lim->scaler_dis_w = args[1]; + lim->out_rot_en_w = args[2]; + lim->out_rot_dis_w = args[3]; + v->pix_limit = lim; + + ret = of_property_read_u32_array(node, "samsung,min-pix-sizes", + args, 2); + v->min_inp_pixsize = ret ? FIMC_DEF_MIN_SIZE : args[0]; + v->min_out_pixsize = ret ? FIMC_DEF_MIN_SIZE : args[1]; + ret = of_property_read_u32_array(node, "samsung,min-pix-alignment", + args, 2); + v->min_vsize_align = ret ? FIMC_DEF_HEIGHT_ALIGN : args[0]; + v->hor_offs_align = ret ? FIMC_DEF_HOR_OFFS_ALIGN : args[1]; + + ret = of_property_read_u32(node, "samsung,rotators", &args[1]); + v->has_inp_rot = ret ? 1 : args[1] & 0x01; + v->has_out_rot = ret ? 1 : args[1] & 0x10; + v->has_mainscaler_ext = of_property_read_bool(node, + "samsung,mainscaler-ext"); + + v->has_isp_wb = of_property_read_bool(node, "samsung,isp-wb"); + v->has_cam_if = of_property_read_bool(node, "samsung,cam-if"); + of_property_read_u32(node, "clock-frequency", clk_freq); + fimc->id = of_alias_get_id(node, "fimc"); + + fimc->variant = v; + return 0; +} + static int fimc_probe(struct platform_device *pdev) { - const struct fimc_drvdata *drv_data = fimc_get_drvdata(pdev); - struct s5p_platform_fimc *pdata; + struct device *dev = &pdev->dev; + u32 lclk_freq = 0; struct fimc_dev *fimc; struct resource *res; int ret = 0; - if (pdev->id >= drv_data->num_entities) { - dev_err(&pdev->dev, "Invalid platform device id: %d\n", - pdev->id); - return -EINVAL; - } - - fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL); + fimc = devm_kzalloc(dev, sizeof(*fimc), GFP_KERNEL); if (!fimc) return -ENOMEM; - fimc->id = pdev->id; - - fimc->variant = drv_data->variant[fimc->id]; fimc->pdev = pdev; - pdata = pdev->dev.platform_data; - fimc->pdata = pdata; + + if (dev->of_node) { + ret = fimc_parse_dt(fimc, &lclk_freq); + if (ret < 0) + return ret; + } else { + fimc->drv_data = fimc_get_drvdata(pdev); + fimc->id = pdev->id; + } + if (!fimc->drv_data || fimc->id >= fimc->drv_data->num_entities || + fimc->id < 0) { + dev_err(dev, "Invalid driver data or device id (%d/%d)\n", + fimc->id, fimc->drv_data->num_entities); + return -EINVAL; + } + if (!dev->of_node) + fimc->variant = fimc->drv_data->variant[fimc->id]; init_waitqueue_head(&fimc->irq_queue); spin_lock_init(&fimc->slock); mutex_init(&fimc->lock); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - fimc->regs = devm_ioremap_resource(&pdev->dev, res); + fimc->regs = devm_ioremap_resource(dev, res); if (IS_ERR(fimc->regs)) return PTR_ERR(fimc->regs); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { - dev_err(&pdev->dev, "Failed to get IRQ resource\n"); + dev_err(dev, "Failed to get IRQ resource\n"); return -ENXIO; } @@ -907,7 +974,10 @@ static int fimc_probe(struct platform_device *pdev) if (ret) return ret; - ret = clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency); + if (lclk_freq == 0) + lclk_freq = fimc->drv_data->lclk_frequency; + + ret = clk_set_rate(fimc->clock[CLK_BUS], lclk_freq); if (ret < 0) return ret; @@ -915,10 +985,10 @@ static int fimc_probe(struct platform_device *pdev) if (ret < 0) return ret; - ret = devm_request_irq(&pdev->dev, res->start, fimc_irq_handler, - 0, dev_name(&pdev->dev), fimc); + ret = devm_request_irq(dev, res->start, fimc_irq_handler, + 0, dev_name(dev), fimc); if (ret) { - dev_err(&pdev->dev, "failed to install irq (%d)\n", ret); + dev_err(dev, "failed to install irq (%d)\n", ret); goto err_clk; } @@ -927,23 +997,23 @@ static int fimc_probe(struct platform_device *pdev) goto err_clk; platform_set_drvdata(pdev, fimc); - pm_runtime_enable(&pdev->dev); - ret = pm_runtime_get_sync(&pdev->dev); + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); if (ret < 0) goto err_sd; /* Initialize contiguous memory allocator */ - fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(fimc->alloc_ctx)) { ret = PTR_ERR(fimc->alloc_ctx); goto err_pm; } - dev_dbg(&pdev->dev, "FIMC.%d registered successfully\n", fimc->id); + dev_dbg(dev, "FIMC.%d registered successfully\n", fimc->id); - pm_runtime_put(&pdev->dev); + pm_runtime_put(dev); return 0; err_pm: - pm_runtime_put(&pdev->dev); + pm_runtime_put(dev); err_sd: fimc_unregister_capture_subdev(fimc); err_clk: @@ -1046,24 +1116,18 @@ static const struct fimc_pix_limit s5p_pix_limit[4] = { [0] = { .scaler_en_w = 3264, .scaler_dis_w = 8192, - .in_rot_en_h = 1920, - .in_rot_dis_w = 8192, .out_rot_en_w = 1920, .out_rot_dis_w = 4224, }, [1] = { .scaler_en_w = 4224, .scaler_dis_w = 8192, - .in_rot_en_h = 1920, - .in_rot_dis_w = 8192, .out_rot_en_w = 1920, .out_rot_dis_w = 4224, }, [2] = { .scaler_en_w = 1920, .scaler_dis_w = 8192, - .in_rot_en_h = 1280, - .in_rot_dis_w = 8192, .out_rot_en_w = 1280, .out_rot_dis_w = 1920, }, @@ -1085,7 +1149,6 @@ static const struct fimc_variant fimc0_variant_s5p = { .min_out_pixsize = 16, .hor_offs_align = 8, .min_vsize_align = 16, - .out_buf_count = 4, .pix_limit = &s5p_pix_limit[0], }; @@ -1095,12 +1158,10 @@ static const struct fimc_variant fimc2_variant_s5p = { .min_out_pixsize = 16, .hor_offs_align = 8, .min_vsize_align = 16, - .out_buf_count = 4, .pix_limit = &s5p_pix_limit[1], }; static const struct fimc_variant fimc0_variant_s5pv210 = { - .pix_hoff = 1, .has_inp_rot = 1, .has_out_rot = 1, .has_cam_if = 1, @@ -1108,12 +1169,10 @@ static const struct fimc_variant fimc0_variant_s5pv210 = { .min_out_pixsize = 16, .hor_offs_align = 8, .min_vsize_align = 16, - .out_buf_count = 4, .pix_limit = &s5p_pix_limit[1], }; static const struct fimc_variant fimc1_variant_s5pv210 = { - .pix_hoff = 1, .has_inp_rot = 1, .has_out_rot = 1, .has_cam_if = 1, @@ -1122,80 +1181,39 @@ static const struct fimc_variant fimc1_variant_s5pv210 = { .min_out_pixsize = 16, .hor_offs_align = 1, .min_vsize_align = 1, - .out_buf_count = 4, .pix_limit = &s5p_pix_limit[2], }; static const struct fimc_variant fimc2_variant_s5pv210 = { .has_cam_if = 1, - .pix_hoff = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 8, .min_vsize_align = 16, - .out_buf_count = 4, .pix_limit = &s5p_pix_limit[2], }; static const struct fimc_variant fimc0_variant_exynos4210 = { - .pix_hoff = 1, .has_inp_rot = 1, .has_out_rot = 1, .has_cam_if = 1, - .has_cistatus2 = 1, .has_mainscaler_ext = 1, - .has_alpha = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 2, .min_vsize_align = 1, - .out_buf_count = 32, .pix_limit = &s5p_pix_limit[1], }; static const struct fimc_variant fimc3_variant_exynos4210 = { - .pix_hoff = 1, - .has_cistatus2 = 1, .has_mainscaler_ext = 1, - .has_alpha = 1, .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 2, .min_vsize_align = 1, - .out_buf_count = 32, .pix_limit = &s5p_pix_limit[3], }; -static const struct fimc_variant fimc0_variant_exynos4x12 = { - .pix_hoff = 1, - .has_inp_rot = 1, - .has_out_rot = 1, - .has_cam_if = 1, - .has_isp_wb = 1, - .has_cistatus2 = 1, - .has_mainscaler_ext = 1, - .has_alpha = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 2, - .min_vsize_align = 1, - .out_buf_count = 32, - .pix_limit = &s5p_pix_limit[1], -}; - -static const struct fimc_variant fimc3_variant_exynos4x12 = { - .pix_hoff = 1, - .has_cistatus2 = 1, - .has_mainscaler_ext = 1, - .has_alpha = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 2, - .min_vsize_align = 1, - .out_buf_count = 32, - .pix_limit = &s5p_pix_limit[3], -}; - /* S5PC100 */ static const struct fimc_drvdata fimc_drvdata_s5p = { .variant = { @@ -1203,8 +1221,9 @@ static const struct fimc_drvdata fimc_drvdata_s5p = { [1] = &fimc0_variant_s5p, [2] = &fimc2_variant_s5p, }, - .num_entities = 3, + .num_entities = 3, .lclk_frequency = 133000000UL, + .out_buf_count = 4, }; /* S5PV210, S5PC110 */ @@ -1214,8 +1233,10 @@ static const struct fimc_drvdata fimc_drvdata_s5pv210 = { [1] = &fimc1_variant_s5pv210, [2] = &fimc2_variant_s5pv210, }, - .num_entities = 3, - .lclk_frequency = 166000000UL, + .num_entities = 3, + .lclk_frequency = 166000000UL, + .out_buf_count = 4, + .dma_pix_hoff = 1, }; /* EXYNOS4210, S5PV310, S5PC210 */ @@ -1226,20 +1247,22 @@ static const struct fimc_drvdata fimc_drvdata_exynos4210 = { [2] = &fimc0_variant_exynos4210, [3] = &fimc3_variant_exynos4210, }, - .num_entities = 4, + .num_entities = 4, .lclk_frequency = 166000000UL, + .dma_pix_hoff = 1, + .cistatus2 = 1, + .alpha_color = 1, + .out_buf_count = 32, }; /* EXYNOS4212, EXYNOS4412 */ static const struct fimc_drvdata fimc_drvdata_exynos4x12 = { - .variant = { - [0] = &fimc0_variant_exynos4x12, - [1] = &fimc0_variant_exynos4x12, - [2] = &fimc0_variant_exynos4x12, - [3] = &fimc3_variant_exynos4x12, - }, - .num_entities = 4, - .lclk_frequency = 166000000UL, + .num_entities = 4, + .lclk_frequency = 166000000UL, + .dma_pix_hoff = 1, + .cistatus2 = 1, + .alpha_color = 1, + .out_buf_count = 32, }; static const struct platform_device_id fimc_driver_ids[] = { @@ -1256,10 +1279,24 @@ static const struct platform_device_id fimc_driver_ids[] = { .name = "exynos4x12-fimc", .driver_data = (unsigned long)&fimc_drvdata_exynos4x12, }, - {}, + { }, }; MODULE_DEVICE_TABLE(platform, fimc_driver_ids); +static const struct of_device_id fimc_of_match[] = { + { + .compatible = "samsung,s5pv210-fimc", + .data = &fimc_drvdata_s5pv210, + }, { + .compatible = "samsung,exynos4210-fimc", + .data = &fimc_drvdata_exynos4210, + }, { + .compatible = "samsung,exynos4212-fimc", + .data = &fimc_drvdata_exynos4x12, + }, + { /* sentinel */ }, +}; + static const struct dev_pm_ops fimc_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume) SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL) @@ -1270,9 +1307,10 @@ static struct platform_driver fimc_driver = { .remove = fimc_remove, .id_table = fimc_driver_ids, .driver = { - .name = FIMC_MODULE_NAME, - .owner = THIS_MODULE, - .pm = &fimc_pm_ops, + .of_match_table = fimc_of_match, + .name = FIMC_MODULE_NAME, + .owner = THIS_MODULE, + .pm = &fimc_pm_ops, } }; diff --git a/drivers/media/platform/s5p-fimc/fimc-core.h b/drivers/media/platform/s5p-fimc/fimc-core.h index 412d50708f75..145b8cc77af0 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.h +++ b/drivers/media/platform/s5p-fimc/fimc-core.h @@ -42,6 +42,10 @@ #define FIMC_CAMIF_MAX_HEIGHT 0x2000 #define FIMC_MAX_JPEG_BUF_SIZE (10 * SZ_1M) #define FIMC_MAX_PLANES 3 +#define FIMC_PIX_LIMITS_MAX 4 +#define FIMC_DEF_MIN_SIZE 16 +#define FIMC_DEF_HEIGHT_ALIGN 2 +#define FIMC_DEF_HOR_OFFS_ALIGN 1 /* indices to the clocks array */ enum { @@ -365,10 +369,8 @@ struct fimc_pix_limit { /** * struct fimc_variant - FIMC device variant information - * @pix_hoff: indicate whether horizontal offset is in pixels or in bytes * @has_inp_rot: set if has input rotator * @has_out_rot: set if has output rotator - * @has_cistatus2: 1 if CISTATUS2 register is present in this IP revision * @has_mainscaler_ext: 1 if extended mainscaler ratios in CIEXTEN register * are present in this IP revision * @has_cam_if: set if this instance has a camera input interface @@ -378,23 +380,18 @@ struct fimc_pix_limit { * @min_out_pixsize: minimum output pixel size * @hor_offs_align: horizontal pixel offset aligment * @min_vsize_align: minimum vertical pixel size alignment - * @out_buf_count: the number of buffers in output DMA sequence */ struct fimc_variant { - unsigned int pix_hoff:1; unsigned int has_inp_rot:1; unsigned int has_out_rot:1; - unsigned int has_cistatus2:1; unsigned int has_mainscaler_ext:1; unsigned int has_cam_if:1; unsigned int has_isp_wb:1; - unsigned int has_alpha:1; const struct fimc_pix_limit *pix_limit; u16 min_inp_pixsize; u16 min_out_pixsize; u16 hor_offs_align; u16 min_vsize_align; - u16 out_buf_count; }; /** @@ -402,11 +399,20 @@ struct fimc_variant { * @variant: variant information for this device * @num_entities: number of fimc instances available in a SoC * @lclk_frequency: local bus clock frequency + * @cistatus2: 1 if the FIMC IPs have CISTATUS2 register + * @dma_pix_hoff: the horizontal DMA offset unit: 1 - pixels, 0 - bytes + * @alpha_color: 1 if alpha color component is supported + * @out_buf_count: maximum number of output DMA buffers supported */ struct fimc_drvdata { const struct fimc_variant *variant[FIMC_MAX_DEVS]; int num_entities; unsigned long lclk_frequency; + /* Fields common to all FIMC IP instances */ + u8 cistatus2; + u8 dma_pix_hoff; + u8 alpha_color; + u8 out_buf_count; }; #define fimc_get_drvdata(_pdev) \ @@ -438,6 +444,7 @@ struct fimc_dev { struct platform_device *pdev; struct s5p_platform_fimc *pdata; const struct fimc_variant *variant; + const struct fimc_drvdata *drv_data; u16 id; struct clk *clock[MAX_FIMC_CLOCKS]; void __iomem *regs; diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c index c8509dd1776d..a224dac36b3a 100644 --- a/drivers/media/platform/s5p-fimc/fimc-m2m.c +++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c @@ -152,7 +152,7 @@ static void fimc_device_run(void *priv) fimc_hw_set_rotation(ctx); fimc_hw_set_effect(ctx); fimc_hw_set_out_dma(ctx); - if (fimc->variant->has_alpha) + if (fimc->drv_data->alpha_color) fimc_hw_set_rgb_alpha(ctx); fimc_hw_set_output_path(ctx); } diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.c b/drivers/media/platform/s5p-fimc/fimc-reg.c index 50b97c75b956..4d2fc69d2cba 100644 --- a/drivers/media/platform/s5p-fimc/fimc-reg.c +++ b/drivers/media/platform/s5p-fimc/fimc-reg.c @@ -35,7 +35,7 @@ void fimc_hw_reset(struct fimc_dev *dev) cfg &= ~FIMC_REG_CIGCTRL_SWRST; writel(cfg, dev->regs + FIMC_REG_CIGCTRL); - if (dev->variant->out_buf_count > 4) + if (dev->drv_data->out_buf_count > 4) fimc_hw_set_dma_seq(dev, 0xF); } @@ -747,7 +747,7 @@ s32 fimc_hw_get_frame_index(struct fimc_dev *dev) { s32 reg; - if (dev->variant->has_cistatus2) { + if (dev->drv_data->cistatus2) { reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3f; return reg - 1; } @@ -763,7 +763,7 @@ s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev) { s32 reg; - if (!dev->variant->has_cistatus2) + if (!dev->drv_data->cistatus2) return -1; reg = readl(dev->regs + FIMC_REG_CISTATUS2); -- cgit v1.2.3 From eb62d9e9d6327322a5fd3894bfecb3a3aa9391ba Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 26 Mar 2013 09:33:54 -0300 Subject: [media] s5p-fimc: Add device tree support for FIMC-LITE device driver This patch adds the device tree support for FIMC-LITE device driver. The bindings include compatible property for the Exynos5 SoC series, however the actual implementation for these SoCs will be added in a separate patch. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/exynos-fimc-lite.txt | 14 +++++ drivers/media/platform/s5p-fimc/fimc-lite.c | 63 +++++++++++++++------- 2 files changed, 59 insertions(+), 18 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/exynos-fimc-lite.txt (limited to 'drivers/media') diff --git a/Documentation/devicetree/bindings/media/exynos-fimc-lite.txt b/Documentation/devicetree/bindings/media/exynos-fimc-lite.txt new file mode 100644 index 000000000000..3f62adfb3e0b --- /dev/null +++ b/Documentation/devicetree/bindings/media/exynos-fimc-lite.txt @@ -0,0 +1,14 @@ +Exynos4x12/Exynos5 SoC series camera host interface (FIMC-LITE) + +Required properties: + +- compatible : should be "samsung,exynos4212-fimc" for Exynos4212 and + Exynos4412 SoCs; +- reg : physical base address and size of the device memory mapped + registers; +- interrupts : should contain FIMC-LITE interrupt; +- clocks : FIMC LITE gate clock should be specified in this property. +- clock-names : should contain "flite" entry. + +Each FIMC device should have an alias in the aliases node, in the form of +fimc-lite, where is an integer specifying the IP block instance. diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index b64297ba35d3..65082fe2578c 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1400,18 +1401,34 @@ static int fimc_lite_clk_get(struct fimc_lite *fimc) return ret; } +static const struct of_device_id flite_of_match[]; + static int fimc_lite_probe(struct platform_device *pdev) { - struct flite_drvdata *drv_data = fimc_lite_get_drvdata(pdev); + struct flite_drvdata *drv_data = NULL; + struct device *dev = &pdev->dev; + const struct of_device_id *of_id; struct fimc_lite *fimc; struct resource *res; int ret; - fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL); + fimc = devm_kzalloc(dev, sizeof(*fimc), GFP_KERNEL); if (!fimc) return -ENOMEM; - fimc->index = pdev->id; + if (dev->of_node) { + of_id = of_match_node(flite_of_match, dev->of_node); + if (of_id) + drv_data = (struct flite_drvdata *)of_id->data; + fimc->index = of_alias_get_id(dev->of_node, "fimc-lite"); + } else { + drv_data = fimc_lite_get_drvdata(pdev); + fimc->index = pdev->id; + } + + if (!drv_data || fimc->index < 0 || fimc->index >= FIMC_LITE_MAX_DEVS) + return -EINVAL; + fimc->variant = drv_data->variant[fimc->index]; fimc->pdev = pdev; @@ -1420,13 +1437,13 @@ static int fimc_lite_probe(struct platform_device *pdev) mutex_init(&fimc->lock); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - fimc->regs = devm_ioremap_resource(&pdev->dev, res); + fimc->regs = devm_ioremap_resource(dev, res); if (IS_ERR(fimc->regs)) return PTR_ERR(fimc->regs); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { - dev_err(&pdev->dev, "Failed to get IRQ resource\n"); + dev_err(dev, "Failed to get IRQ resource\n"); return -ENXIO; } @@ -1434,10 +1451,10 @@ static int fimc_lite_probe(struct platform_device *pdev) if (ret) return ret; - ret = devm_request_irq(&pdev->dev, res->start, flite_irq_handler, - 0, dev_name(&pdev->dev), fimc); + ret = devm_request_irq(dev, res->start, flite_irq_handler, + 0, dev_name(dev), fimc); if (ret) { - dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret); + dev_err(dev, "Failed to install irq (%d)\n", ret); goto err_clk; } @@ -1447,23 +1464,23 @@ static int fimc_lite_probe(struct platform_device *pdev) goto err_clk; platform_set_drvdata(pdev, fimc); - pm_runtime_enable(&pdev->dev); - ret = pm_runtime_get_sync(&pdev->dev); + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); if (ret < 0) goto err_sd; - fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(fimc->alloc_ctx)) { ret = PTR_ERR(fimc->alloc_ctx); goto err_pm; } - pm_runtime_put(&pdev->dev); + pm_runtime_put(dev); - dev_dbg(&pdev->dev, "FIMC-LITE.%d registered successfully\n", + dev_dbg(dev, "FIMC-LITE.%d registered successfully\n", fimc->index); return 0; err_pm: - pm_runtime_put(&pdev->dev); + pm_runtime_put(dev); err_sd: fimc_lite_unregister_capture_subdev(fimc); err_clk: @@ -1554,6 +1571,12 @@ static int fimc_lite_remove(struct platform_device *pdev) return 0; } +static const struct dev_pm_ops fimc_lite_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(fimc_lite_suspend, fimc_lite_resume) + SET_RUNTIME_PM_OPS(fimc_lite_runtime_suspend, fimc_lite_runtime_resume, + NULL) +}; + static struct flite_variant fimc_lite0_variant_exynos4 = { .max_width = 8192, .max_height = 8192, @@ -1579,17 +1602,21 @@ static struct platform_device_id fimc_lite_driver_ids[] = { }; MODULE_DEVICE_TABLE(platform, fimc_lite_driver_ids); -static const struct dev_pm_ops fimc_lite_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(fimc_lite_suspend, fimc_lite_resume) - SET_RUNTIME_PM_OPS(fimc_lite_runtime_suspend, fimc_lite_runtime_resume, - NULL) +static const struct of_device_id flite_of_match[] = { + { + .compatible = "samsung,exynos4212-fimc-lite", + .data = &fimc_lite_drvdata_exynos4, + }, + { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, flite_of_match); static struct platform_driver fimc_lite_driver = { .probe = fimc_lite_probe, .remove = fimc_lite_remove, .id_table = fimc_lite_driver_ids, .driver = { + .of_match_table = flite_of_match, .name = FIMC_LITE_DRV_NAME, .owner = THIS_MODULE, .pm = &fimc_lite_pm_ops, -- cgit v1.2.3 From e2985a260e6615503b4fa8e66788708e750c7750 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 8 Mar 2013 12:59:33 -0300 Subject: [media] s5p-fimc: Add device tree support for the media device driver This patch adds changes required for the main camera media device driver corresponding to the top level 'camera' device node. The drivers of devices corresponding to child nodes of the 'camera' node are looked up and and registered as sub-devices to the top level driver. The main driver's probing is deferred if any of the sub-device drivers is not yet initialized and ready. Signed-off-by: Sylwester Nawrocki Signed-off-by: Andrzej Hajda Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-core.c | 1 - drivers/media/platform/s5p-fimc/fimc-mdevice.c | 108 +++++++++++++++++++++---- drivers/media/platform/s5p-fimc/fimc-mdevice.h | 5 ++ include/media/s5p_fimc.h | 1 + 4 files changed, 98 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index d39e47abb229..6a8098c42cc8 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -1281,7 +1281,6 @@ static const struct platform_device_id fimc_driver_ids[] = { }, { }, }; -MODULE_DEVICE_TABLE(platform, fimc_driver_ids); static const struct of_device_id fimc_of_match[] = { { diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index a17fcb2d5d41..d34106c66427 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -17,11 +17,16 @@ #include #include #include +#include +#include +#include +#include #include #include #include #include #include +#include #include #include @@ -264,6 +269,21 @@ static void fimc_md_unregister_sensor(struct v4l2_subdev *sd) i2c_put_adapter(adapter); } +#ifdef CONFIG_OF +static int __of_get_csis_id(struct device_node *np) +{ + u32 reg = 0; + + np = of_get_child_by_name(np, "port"); + if (!np) + return -EINVAL; + of_property_read_u32(np, "reg", ®); + return reg - FIMC_INPUT_MIPI_CSI2_0; +} +#else +#define __of_get_csis_id(np) (-ENOSYS) +#endif + static int fimc_md_register_sensor_entities(struct fimc_md *fmd) { struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data; @@ -368,13 +388,13 @@ static int register_csis_entity(struct fimc_md *fmd, struct device_node *node = pdev->dev.of_node; int id, ret; - id = node ? of_alias_get_id(node, "csis") : max(0, pdev->id); + id = node ? __of_get_csis_id(node) : max(0, pdev->id); - if (WARN_ON(id >= CSIS_MAX_ENTITIES || fmd->csis[id].sd)) - return -EBUSY; + if (WARN_ON(id < 0 || id >= CSIS_MAX_ENTITIES)) + return -ENOENT; - if (WARN_ON(id >= CSIS_MAX_ENTITIES)) - return 0; + if (WARN_ON(fmd->csis[id].sd)) + return -EBUSY; sd->grp_id = GRP_ID_CSIS; ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); @@ -457,6 +477,45 @@ static int fimc_md_pdev_match(struct device *dev, void *data) return 0; } +/* Register FIMC, FIMC-LITE and CSIS media entities */ +#ifdef CONFIG_OF +static int fimc_md_register_of_platform_entities(struct fimc_md *fmd, + struct device_node *parent) +{ + struct device_node *node; + int ret = 0; + + for_each_available_child_of_node(parent, node) { + struct platform_device *pdev; + int plat_entity = -1; + + pdev = of_find_device_by_node(node); + if (!pdev) + continue; + + /* If driver of any entity isn't ready try all again later. */ + if (!strcmp(node->name, CSIS_OF_NODE_NAME)) + plat_entity = IDX_CSIS; + else if (!strcmp(node->name, FIMC_LITE_OF_NODE_NAME)) + plat_entity = IDX_FLITE; + else if (!strcmp(node->name, FIMC_OF_NODE_NAME) && + !of_property_read_bool(node, "samsung,lcd-wb")) + plat_entity = IDX_FIMC; + + if (plat_entity >= 0) + ret = fimc_md_register_platform_entity(fmd, pdev, + plat_entity); + put_device(&pdev->dev); + if (ret < 0) + break; + } + + return ret; +} +#else +#define fimc_md_register_of_platform_entities(fmd, node) (-ENOSYS) +#endif + static void fimc_md_unregister_entities(struct fimc_md *fmd) { int i; @@ -929,11 +988,12 @@ static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO, static int fimc_md_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct v4l2_device *v4l2_dev; struct fimc_md *fmd; int ret; - fmd = devm_kzalloc(&pdev->dev, sizeof(*fmd), GFP_KERNEL); + fmd = devm_kzalloc(dev, sizeof(*fmd), GFP_KERNEL); if (!fmd) return -ENOMEM; @@ -943,15 +1003,14 @@ static int fimc_md_probe(struct platform_device *pdev) strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC", sizeof(fmd->media_dev.model)); fmd->media_dev.link_notify = fimc_md_link_notify; - fmd->media_dev.dev = &pdev->dev; + fmd->media_dev.dev = dev; v4l2_dev = &fmd->v4l2_dev; v4l2_dev->mdev = &fmd->media_dev; v4l2_dev->notify = fimc_sensor_notify; - snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s", - dev_name(&pdev->dev)); + strlcpy(v4l2_dev->name, "s5p-fimc-md", sizeof(v4l2_dev->name)); - ret = v4l2_device_register(&pdev->dev, &fmd->v4l2_dev); + ret = v4l2_device_register(dev, &fmd->v4l2_dev); if (ret < 0) { v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); return ret; @@ -965,21 +1024,25 @@ static int fimc_md_probe(struct platform_device *pdev) if (ret) goto err_clk; - fmd->user_subdev_api = false; + fmd->user_subdev_api = (dev->of_node != NULL); /* Protect the media graph while we're registering entities */ mutex_lock(&fmd->media_dev.graph_mutex); - ret = bus_for_each_dev(&platform_bus_type, NULL, fmd, - fimc_md_pdev_match); + if (dev->of_node) + ret = fimc_md_register_of_platform_entities(fmd, dev->of_node); + else + ret = bus_for_each_dev(&platform_bus_type, NULL, fmd, + fimc_md_pdev_match); if (ret) goto err_unlock; - if (pdev->dev.platform_data) { + if (dev->platform_data) { ret = fimc_md_register_sensor_entities(fmd); if (ret) goto err_unlock; } + ret = fimc_md_create_links(fmd); if (ret) goto err_unlock; @@ -1019,12 +1082,25 @@ static int fimc_md_remove(struct platform_device *pdev) return 0; } +static struct platform_device_id fimc_driver_ids[] __always_unused = { + { .name = "s5p-fimc-md" }, + { }, +}; +MODULE_DEVICE_TABLE(platform, fimc_driver_ids); + +static const struct of_device_id fimc_md_of_match[] = { + { .compatible = "samsung,fimc" }, + { }, +}; +MODULE_DEVICE_TABLE(of, fimc_md_of_match); + static struct platform_driver fimc_md_driver = { .probe = fimc_md_probe, .remove = fimc_md_remove, .driver = { - .name = "s5p-fimc-md", - .owner = THIS_MODULE, + .of_match_table = of_match_ptr(fimc_md_of_match), + .name = "s5p-fimc-md", + .owner = THIS_MODULE, } }; diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.h b/drivers/media/platform/s5p-fimc/fimc-mdevice.h index 06b0d8276fd2..b6ceb5984664 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.h +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.h @@ -21,6 +21,11 @@ #include "fimc-lite.h" #include "mipi-csis.h" +#define FIMC_OF_NODE_NAME "fimc" +#define FIMC_LITE_OF_NODE_NAME "fimc-lite" +#define FIMC_IS_OF_NODE_NAME "fimc-is" +#define CSIS_OF_NODE_NAME "csis" + /* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */ #define GRP_ID_SENSOR (1 << 8) #define GRP_ID_FIMC_IS_SENSOR (1 << 9) diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index d6dbb791f423..e2c598962698 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -94,6 +94,7 @@ enum fimc_subdev_index { IDX_SENSOR, IDX_CSIS, IDX_FLITE, + IDX_IS_ISP, IDX_FIMC, IDX_MAX, }; -- cgit v1.2.3 From 2b13f7d4e3822ed4de37b73b009ff81932e884bb Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 29 Mar 2013 14:12:39 -0300 Subject: [media] s5p-fimc: Add device tree based sensors registration The sensor (I2C and/or SPI client) devices are instantiated by their corresponding control bus drivers. Since the I2C client's master clock is often provided by a video bus receiver (host interface) or other than I2C/SPI controller device, the drivers of those client devices are not accessing hardware in their driver's probe() callback. Instead, after enabling clock, the host driver calls back into a sub-device when it wants to activate them. This pattern is used by some in-tree drivers and this patch also uses it for DT case. This patch is intended as a first step for adding device tree support to the S5P/Exynos SoC camera drivers. The second one is adding support for asynchronous sub-devices registration and clock control from sub-device driver level. The bindings shall not change when asynchronous probing support is added. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/samsung-fimc.txt | 86 ++++++++ drivers/media/platform/s5p-fimc/fimc-mdevice.c | 240 ++++++++++++++++++--- include/media/s5p_fimc.h | 3 + 3 files changed, 303 insertions(+), 26 deletions(-) (limited to 'drivers/media') diff --git a/Documentation/devicetree/bindings/media/samsung-fimc.txt b/Documentation/devicetree/bindings/media/samsung-fimc.txt index 22e2889162c3..bcb0de7462a2 100644 --- a/Documentation/devicetree/bindings/media/samsung-fimc.txt +++ b/Documentation/devicetree/bindings/media/samsung-fimc.txt @@ -72,18 +72,95 @@ Optional properties: writeback input. +'parallel-ports' node +--------------------- + +This node should contain child 'port' nodes specifying active parallel video +input ports. It includes camera A and camera B inputs. 'reg' property in the +port nodes specifies data input - 0, 1 indicates input A, B respectively. + +Optional properties + +- samsung,camclk-out : specifies clock output for remote sensor, + 0 - CAM_A_CLKOUT, 1 - CAM_B_CLKOUT; + +Image sensor nodes +------------------ + +The sensor device nodes should be added to their control bus controller (e.g. +I2C0) nodes and linked to a port node in the csis or the parallel-ports node, +using the common video interfaces bindings, defined in video-interfaces.txt. +The implementation of this bindings requires clock-frequency property to be +present in the sensor device nodes. + Example: aliases { fimc0 = &fimc_0; }; + /* Parallel bus IF sensor */ + i2c_0: i2c@13860000 { + s5k6aa: sensor@3c { + compatible = "samsung,s5k6aafx"; + reg = <0x3c>; + vddio-supply = <...>; + + clock-frequency = <24000000>; + clocks = <...>; + clock-names = "mclk"; + + port { + s5k6aa_ep: endpoint { + remote-endpoint = <&fimc0_ep>; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <1>; + pclk-sample = <1>; + }; + }; + }; + }; + + /* MIPI CSI-2 bus IF sensor */ + s5c73m3: sensor@0x1a { + compatible = "samsung,s5c73m3"; + reg = <0x1a>; + vddio-supply = <...>; + + clock-frequency = <24000000>; + clocks = <...>; + clock-names = "mclk"; + + port { + s5c73m3_1: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&csis0_ep>; + }; + }; + }; + camera { compatible = "samsung,fimc", "simple-bus"; #address-cells = <1>; #size-cells = <1>; status = "okay"; + /* parallel camera ports */ + parallel-ports { + /* camera A input */ + port@0 { + reg = <0>; + fimc0_ep: endpoint { + remote-endpoint = <&s5k6aa_ep>; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <1>; + pclk-sample = <1>; + }; + }; + }; + fimc_0: fimc@11800000 { compatible = "samsung,exynos4210-fimc"; reg = <0x11800000 0x1000>; @@ -95,6 +172,15 @@ Example: compatible = "samsung,exynos4210-csis"; reg = <0x11880000 0x1000>; interrupts = <0 78 0>; + /* camera C input */ + port@3 { + reg = <3>; + csis0_ep: endpoint { + remote-endpoint = <&s5c73m3_ep>; + data-lanes = <1 2 3 4>; + samsung,csis-hs-settle = <12>; + }; + }; }; }; diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index d34106c66427..bfa02abd94c8 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -251,7 +251,7 @@ static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd, sd->grp_id = GRP_ID_SENSOR; v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice %s\n", - s_info->pdata.board_info->type); + sd->name); return sd; } @@ -263,13 +263,191 @@ static void fimc_md_unregister_sensor(struct v4l2_subdev *sd) if (!client) return; v4l2_device_unregister_subdev(sd); - adapter = client->adapter; - i2c_unregister_device(client); - if (adapter) - i2c_put_adapter(adapter); + + if (!client->dev.of_node) { + adapter = client->adapter; + i2c_unregister_device(client); + if (adapter) + i2c_put_adapter(adapter); + } } #ifdef CONFIG_OF +/* Register I2C client subdev associated with @node. */ +static int fimc_md_of_add_sensor(struct fimc_md *fmd, + struct device_node *node, int index) +{ + struct fimc_sensor_info *si; + struct i2c_client *client; + struct v4l2_subdev *sd; + int ret; + + if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor))) + return -EINVAL; + si = &fmd->sensor[index]; + + client = of_find_i2c_device_by_node(node); + if (!client) + return -EPROBE_DEFER; + + device_lock(&client->dev); + + if (!client->driver || + !try_module_get(client->driver->driver.owner)) { + ret = -EPROBE_DEFER; + v4l2_info(&fmd->v4l2_dev, "No driver found for %s\n", + node->full_name); + goto dev_put; + } + + /* Enable sensor's master clock */ + ret = __fimc_md_set_camclk(fmd, si, true); + if (ret < 0) + goto mod_put; + sd = i2c_get_clientdata(client); + + ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); + __fimc_md_set_camclk(fmd, si, false); + if (ret < 0) + goto mod_put; + + v4l2_set_subdev_hostdata(sd, si); + sd->grp_id = GRP_ID_SENSOR; + si->subdev = sd; + v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice: %s (%d)\n", + sd->name, fmd->num_sensors); + fmd->num_sensors++; + +mod_put: + module_put(client->driver->driver.owner); +dev_put: + device_unlock(&client->dev); + put_device(&client->dev); + return ret; +} + +/* Parse port node and register as a sub-device any sensor specified there. */ +static int fimc_md_parse_port_node(struct fimc_md *fmd, + struct device_node *port, + unsigned int index) +{ + struct device_node *rem, *ep, *np; + struct fimc_source_info *pd; + struct v4l2_of_endpoint endpoint; + int ret; + u32 val; + + pd = &fmd->sensor[index].pdata; + + /* Assume here a port node can have only one endpoint node. */ + ep = of_get_next_child(port, NULL); + if (!ep) + return 0; + + v4l2_of_parse_endpoint(ep, &endpoint); + if (WARN_ON(endpoint.port == 0) || index >= FIMC_MAX_SENSORS) + return -EINVAL; + + pd->mux_id = (endpoint.port - 1) & 0x1; + + rem = v4l2_of_get_remote_port_parent(ep); + of_node_put(ep); + if (rem == NULL) { + v4l2_info(&fmd->v4l2_dev, "Remote device at %s not found\n", + ep->full_name); + return 0; + } + if (!of_property_read_u32(rem, "samsung,camclk-out", &val)) + pd->clk_id = val; + + if (!of_property_read_u32(rem, "clock-frequency", &val)) + pd->clk_frequency = val; + + if (pd->clk_frequency == 0) { + v4l2_err(&fmd->v4l2_dev, "Wrong clock frequency at node %s\n", + rem->full_name); + of_node_put(rem); + return -EINVAL; + } + + if (fimc_input_is_parallel(endpoint.port)) { + if (endpoint.bus_type == V4L2_MBUS_PARALLEL) + pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_601; + else + pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_656; + pd->flags = endpoint.bus.parallel.flags; + } else if (fimc_input_is_mipi_csi(endpoint.port)) { + /* + * MIPI CSI-2: only input mux selection and + * the sensor's clock frequency is needed. + */ + pd->sensor_bus_type = FIMC_BUS_TYPE_MIPI_CSI2; + } else { + v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %s\n", + endpoint.port, rem->full_name); + } + /* + * For FIMC-IS handled sensors, that are placed under i2c-isp device + * node, FIMC is connected to the FIMC-IS through its ISP Writeback + * input. Sensors are attached to the FIMC-LITE hostdata interface + * directly or through MIPI-CSIS, depending on the external media bus + * used. This needs to be handled in a more reliable way, not by just + * checking parent's node name. + */ + np = of_get_parent(rem); + + if (np && !of_node_cmp(np->name, "i2c-isp")) + pd->fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK; + else + pd->fimc_bus_type = pd->sensor_bus_type; + + ret = fimc_md_of_add_sensor(fmd, rem, index); + of_node_put(rem); + + return ret; +} + +/* Register all SoC external sub-devices */ +static int fimc_md_of_sensors_register(struct fimc_md *fmd, + struct device_node *np) +{ + struct device_node *parent = fmd->pdev->dev.of_node; + struct device_node *node, *ports; + int index = 0; + int ret; + + /* Attach sensors linked to MIPI CSI-2 receivers */ + for_each_available_child_of_node(parent, node) { + struct device_node *port; + + if (of_node_cmp(node->name, "csis")) + continue; + /* The csis node can have only port subnode. */ + port = of_get_next_child(node, NULL); + if (!port) + continue; + + ret = fimc_md_parse_port_node(fmd, port, index); + if (ret < 0) + return ret; + index++; + } + + /* Attach sensors listed in the parallel-ports node */ + ports = of_get_child_by_name(parent, "parallel-ports"); + if (!ports) + return 0; + + for_each_child_of_node(ports, node) { + ret = fimc_md_parse_port_node(fmd, node, index); + if (ret < 0) + break; + index++; + } + + return 0; +} + static int __of_get_csis_id(struct device_node *np) { u32 reg = 0; @@ -281,14 +459,17 @@ static int __of_get_csis_id(struct device_node *np) return reg - FIMC_INPUT_MIPI_CSI2_0; } #else +#define fimc_md_of_sensors_register(fmd, np) (-ENOSYS) #define __of_get_csis_id(np) (-ENOSYS) #endif static int fimc_md_register_sensor_entities(struct fimc_md *fmd) { struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data; + struct device_node *of_node = fmd->pdev->dev.of_node; struct fimc_dev *fd = NULL; - int num_clients, ret, i; + int num_clients = 0; + int ret, i; /* * Runtime resume one of the FIMC entities to make sure @@ -299,34 +480,41 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) fd = fmd->fimc[i]; if (!fd) return -ENXIO; + ret = pm_runtime_get_sync(&fd->pdev->dev); if (ret < 0) return ret; - WARN_ON(pdata->num_clients > ARRAY_SIZE(fmd->sensor)); - num_clients = min_t(u32, pdata->num_clients, ARRAY_SIZE(fmd->sensor)); + if (of_node) { + fmd->num_sensors = 0; + ret = fimc_md_of_sensors_register(fmd, of_node); + } else if (pdata) { + WARN_ON(pdata->num_clients > ARRAY_SIZE(fmd->sensor)); + num_clients = min_t(u32, pdata->num_clients, + ARRAY_SIZE(fmd->sensor)); + fmd->num_sensors = num_clients; - fmd->num_sensors = num_clients; - for (i = 0; i < num_clients; i++) { - struct v4l2_subdev *sd; + for (i = 0; i < num_clients; i++) { + struct v4l2_subdev *sd; - fmd->sensor[i].pdata = pdata->source_info[i]; - ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], true); - if (ret) - break; - sd = fimc_md_register_sensor(fmd, &fmd->sensor[i]); - ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], false); - - if (!IS_ERR(sd)) { + fmd->sensor[i].pdata = pdata->source_info[i]; + ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], true); + if (ret) + break; + sd = fimc_md_register_sensor(fmd, &fmd->sensor[i]); + ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], false); + + if (IS_ERR(sd)) { + fmd->sensor[i].subdev = NULL; + ret = PTR_ERR(sd); + break; + } fmd->sensor[i].subdev = sd; - } else { - fmd->sensor[i].subdev = NULL; - ret = PTR_ERR(sd); - break; + if (ret) + break; } - if (ret) - break; } + pm_runtime_put(&fd->pdev->dev); return ret; } @@ -1037,7 +1225,7 @@ static int fimc_md_probe(struct platform_device *pdev) if (ret) goto err_unlock; - if (dev->platform_data) { + if (dev->platform_data || dev->of_node) { ret = fimc_md_register_sensor_entities(fmd); if (ret) goto err_unlock; diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index e2c598962698..e2434bb0b308 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -45,6 +45,9 @@ enum fimc_bus_type { FIMC_BUS_TYPE_ISP_WRITEBACK = FIMC_BUS_TYPE_LCD_WRITEBACK_B, }; +#define fimc_input_is_parallel(x) ((x) == 1 || (x) == 2) +#define fimc_input_is_mipi_csi(x) ((x) == 3 || (x) == 4) + struct i2c_board_info; /** -- cgit v1.2.3 From 4163851f7b997e24602cad8e0eae96d31a252548 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 8 Mar 2013 10:41:47 -0300 Subject: [media] s5p-fimc: Use pinctrl API for camera ports configuration Before the camera ports can be used the pinmux needs to be configured properly. This patch adds a function to set the camera ports pinctrl to a default state within the media driver's probe(). The camera port(s) are then configured for the video bus operation. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/samsung-fimc.txt | 12 ++++++++++ drivers/media/platform/s5p-fimc/fimc-mdevice.c | 26 ++++++++++++++++++++++ drivers/media/platform/s5p-fimc/fimc-mdevice.h | 11 +++++++++ 3 files changed, 49 insertions(+) (limited to 'drivers/media') diff --git a/Documentation/devicetree/bindings/media/samsung-fimc.txt b/Documentation/devicetree/bindings/media/samsung-fimc.txt index bcb0de7462a2..2a63ddd23d16 100644 --- a/Documentation/devicetree/bindings/media/samsung-fimc.txt +++ b/Documentation/devicetree/bindings/media/samsung-fimc.txt @@ -21,6 +21,15 @@ Required properties: - clock-names : must contain "fimc", "sclk_fimc" entries, matching entries in the clocks property. +The pinctrl bindings defined in ../pinctrl/pinctrl-bindings.txt must be used +to define a required pinctrl state named "default" and optional pinctrl states: +"idle", "active-a", active-b". These optional states can be used to switch the +camera port pinmux at runtime. The "idle" state should configure both the camera +ports A and B into high impedance state, especially the CAMCLK clock output +should be inactive. For the "active-a" state the camera port A must be activated +and the port B deactivated and for the state "active-b" it should be the other +way around. + The 'camera' node must include at least one 'fimc' child node. @@ -146,6 +155,9 @@ Example: #size-cells = <1>; status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&cam_port_a_clk_active>; + /* parallel camera ports */ parallel-ports { /* camera A input */ diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index bfa02abd94c8..5e96775fca8d 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -1174,6 +1174,25 @@ static ssize_t fimc_md_sysfs_store(struct device *dev, static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO, fimc_md_sysfs_show, fimc_md_sysfs_store); +static int fimc_md_get_pinctrl(struct fimc_md *fmd) +{ + struct device *dev = &fmd->pdev->dev; + struct fimc_pinctrl *pctl = &fmd->pinctl; + + pctl->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(pctl->pinctrl)) + return PTR_ERR(pctl->pinctrl); + + pctl->state_default = pinctrl_lookup_state(pctl->pinctrl, + PINCTRL_STATE_DEFAULT); + if (IS_ERR(pctl->state_default)) + return PTR_ERR(pctl->state_default); + + pctl->state_idle = pinctrl_lookup_state(pctl->pinctrl, + PINCTRL_STATE_IDLE); + return 0; +} + static int fimc_md_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1217,6 +1236,13 @@ static int fimc_md_probe(struct platform_device *pdev) /* Protect the media graph while we're registering entities */ mutex_lock(&fmd->media_dev.graph_mutex); + ret = fimc_md_get_pinctrl(fmd); + if (ret < 0) { + if (ret != EPROBE_DEFER) + dev_err(dev, "Failed to get pinctrl: %d\n", ret); + goto err_unlock; + } + if (dev->of_node) ret = fimc_md_register_of_platform_entities(fmd, dev->of_node); else diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.h b/drivers/media/platform/s5p-fimc/fimc-mdevice.h index b6ceb5984664..5d6146e76802 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.h +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,8 @@ #define FIMC_IS_OF_NODE_NAME "fimc-is" #define CSIS_OF_NODE_NAME "csis" +#define PINCTRL_STATE_IDLE "idle" + /* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */ #define GRP_ID_SENSOR (1 << 8) #define GRP_ID_FIMC_IS_SENSOR (1 << 9) @@ -73,6 +76,9 @@ struct fimc_sensor_info { * @media_dev: top level media device * @v4l2_dev: top level v4l2_device holding up the subdevs * @pdev: platform device this media device is hooked up into + * @pinctrl: camera port pinctrl handle + * @state_default: pinctrl default state handle + * @state_idle: pinctrl idle state handle * @user_subdev_api: true if subdevs are not configured by the host driver * @slock: spinlock protecting @sensor array */ @@ -86,6 +92,11 @@ struct fimc_md { struct media_device media_dev; struct v4l2_device v4l2_dev; struct platform_device *pdev; + struct fimc_pinctrl { + struct pinctrl *pinctrl; + struct pinctrl_state *state_default; + struct pinctrl_state *state_idle; + } pinctl; bool user_subdev_api; spinlock_t slock; }; -- cgit v1.2.3 From fc39f46b54b600f053bf9bab757023344e97925e Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Mar 2013 07:01:24 -0300 Subject: [media] V4L: Add MATRIX option to V4L2_CID_EXPOSURE_METERING control This patch adds a menu option to the V4L2_CID_EXPOSURE_METERING control for multi-zone metering. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 7 +++++++ drivers/media/v4l2-core/v4l2-ctrls.c | 1 + include/uapi/linux/v4l2-controls.h | 1 + 3 files changed, 9 insertions(+) (limited to 'drivers/media') diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index c8eb6c222274..8d7a77928d49 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -3142,6 +3142,13 @@ giving priority to the center of the metered area. V4L2_EXPOSURE_METERING_SPOT  Measure only very small area at the center of the frame. + + V4L2_EXPOSURE_METERING_MATRIX  + A multi-zone metering. The light intensity is measured +in several points of the frame and the the results are combined. The +algorithm of the zones selection and their significance in calculating the +final value is device dependant. + diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index ec89fd16361c..ebb8e48619a2 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -234,6 +234,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Average", "Center Weighted", "Spot", + "Matrix", NULL }; static const char * const camera_auto_focus_range[] = { diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 7da22cec30cd..69bd5bb0d5af 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -658,6 +658,7 @@ enum v4l2_exposure_metering { V4L2_EXPOSURE_METERING_AVERAGE = 0, V4L2_EXPOSURE_METERING_CENTER_WEIGHTED = 1, V4L2_EXPOSURE_METERING_SPOT = 2, + V4L2_EXPOSURE_METERING_MATRIX = 3, }; #define V4L2_CID_SCENE_MODE (V4L2_CID_CAMERA_CLASS_BASE+26) -- cgit v1.2.3 From 76323e5016e2f923e87efbee715a7ccf16b942b0 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Wed, 27 Feb 2013 08:13:59 -0300 Subject: [media] s5p-fimc: Add error checks for pipeline stream on callbacks set_stream error for pipelines is logged or reported to user space if possible. Signed-off-by: Andrzej Hajda Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-capture.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index 724cd8b4933d..ff9ca6384636 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c @@ -286,8 +286,8 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) fimc_activate_capture(ctx); if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) - fimc_pipeline_call(fimc, set_stream, - &fimc->pipeline, 1); + return fimc_pipeline_call(fimc, set_stream, + &fimc->pipeline, 1); } return 0; @@ -443,12 +443,17 @@ static void buffer_queue(struct vb2_buffer *vb) if (vb2_is_streaming(&vid_cap->vbq) && vid_cap->active_buf_cnt >= min_bufs && !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) { + int ret; + fimc_activate_capture(ctx); spin_unlock_irqrestore(&fimc->slock, flags); - if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) - fimc_pipeline_call(fimc, set_stream, - &fimc->pipeline, 1); + if (test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) + return; + + ret = fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 1); + if (ret < 0) + v4l2_err(&vid_cap->vfd, "stream on failed: %d\n", ret); return; } spin_unlock_irqrestore(&fimc->slock, flags); -- cgit v1.2.3 From 39bb6df6e35d406ccbe953f1595f650eb6bb88ce Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 8 Mar 2013 08:58:34 -0300 Subject: [media] s5p-fimc: Update graph traversal for entities with multiple source pads We cannot assume that the passed entity the fimc_pipeline_prepare() function is supposed to start the media graph traversal from will always have its sink pad at pad index 0. Find the starting media entity's sink pad by iterating over its all pads and checking the pad flags. This ensures proper handling of FIMC, FIMC-LITE and FIMC-IS-ISP subdevs that have more than one sink and one source pad. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-mdevice.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index 5e96775fca8d..6972f52ba43f 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -40,14 +40,13 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd, bool on); /** * fimc_pipeline_prepare - update pipeline information with subdevice pointers - * @fimc: fimc device terminating the pipeline + * @me: media entity terminating the pipeline * * Caller holds the graph mutex. */ static void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me) { - struct media_pad *pad = &me->pads[0]; struct v4l2_subdev *sd; int i; @@ -55,15 +54,21 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p, p->subdevs[i] = NULL; while (1) { - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - break; + struct media_pad *pad = NULL; + + /* Find remote source pad */ + for (i = 0; i < me->num_pads; i++) { + struct media_pad *spad = &me->pads[i]; + if (!(spad->flags & MEDIA_PAD_FL_SINK)) + continue; + pad = media_entity_remote_source(spad); + if (pad) + break; + } - /* source pad */ - pad = media_entity_remote_source(pad); if (pad == NULL || media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) break; - sd = media_entity_to_v4l2_subdev(pad->entity); switch (sd->grp_id) { @@ -84,8 +89,9 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p, pr_warn("%s: Unknown subdev grp_id: %#x\n", __func__, sd->grp_id); } - /* sink pad */ - pad = &sd->entity.pads[0]; + me = &sd->entity; + if (me->num_pads == 1) + break; } } -- cgit v1.2.3 From 056f4f3036394892ed591932326c11613b6584c1 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 21 Mar 2013 14:43:17 -0300 Subject: [media] s5p-fimc: Add support for PIXELASYNCMx clocks This patch ads handling of clocks for the CAMBLK subsystem which is a glue logic for FIMC-IS or LCD controller and FIMC IP. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-mdevice.c | 83 ++++++++++++++++++++++---- drivers/media/platform/s5p-fimc/fimc-mdevice.h | 10 ++++ 2 files changed, 82 insertions(+), 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index 6972f52ba43f..c4a39782d55e 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -151,26 +151,48 @@ static int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state) * __fimc_pipeline_open - update the pipeline information, enable power * of all pipeline subdevs and the sensor clock * @me: media entity to start graph walk with - * @prep: true to acquire sensor (and csis) subdevs + * @prepare: true to walk the current pipeline and acquire all subdevs * * Called with the graph mutex held. */ static int __fimc_pipeline_open(struct fimc_pipeline *p, - struct media_entity *me, bool prep) + struct media_entity *me, bool prepare) { + struct fimc_md *fmd = entity_to_fimc_mdev(me); + struct v4l2_subdev *sd; int ret; - if (prep) + if (WARN_ON(p == NULL || me == NULL)) + return -EINVAL; + + if (prepare) fimc_pipeline_prepare(p, me); - if (p->subdevs[IDX_SENSOR] == NULL) + sd = p->subdevs[IDX_SENSOR]; + if (sd == NULL) return -EINVAL; - ret = fimc_md_set_camclk(p->subdevs[IDX_SENSOR], true); - if (ret) - return ret; + /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */ + if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) { + ret = clk_prepare_enable(fmd->wbclk[CLK_IDX_WB_B]); + if (ret < 0) + return ret; + } + ret = fimc_md_set_camclk(sd, true); + if (ret < 0) + goto err_wbclk; + + ret = fimc_pipeline_s_power(p, 1); + if (!ret) + return 0; + + fimc_md_set_camclk(sd, false); - return fimc_pipeline_s_power(p, 1); +err_wbclk: + if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) + clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); + + return ret; } /** @@ -181,15 +203,24 @@ static int __fimc_pipeline_open(struct fimc_pipeline *p, */ static int __fimc_pipeline_close(struct fimc_pipeline *p) { + struct v4l2_subdev *sd = p ? p->subdevs[IDX_SENSOR] : NULL; + struct fimc_md *fmd; int ret = 0; - if (!p || !p->subdevs[IDX_SENSOR]) + if (WARN_ON(sd == NULL)) return -EINVAL; if (p->subdevs[IDX_SENSOR]) { ret = fimc_pipeline_s_power(p, 0); - fimc_md_set_camclk(p->subdevs[IDX_SENSOR], false); + fimc_md_set_camclk(sd, false); } + + fmd = entity_to_fimc_mdev(&sd->entity); + + /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */ + if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) + clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); + return ret == -ENXIO ? 0 : ret; } @@ -959,7 +990,7 @@ static int fimc_md_create_links(struct fimc_md *fmd) } /* - * The peripheral sensor clock management. + * The peripheral sensor and CAM_BLK (PIXELASYNCMx) clocks management. */ static void fimc_md_put_clocks(struct fimc_md *fmd) { @@ -972,6 +1003,14 @@ static void fimc_md_put_clocks(struct fimc_md *fmd) clk_put(fmd->camclk[i].clock); fmd->camclk[i].clock = ERR_PTR(-EINVAL); } + + /* Writeback (PIXELASYNCMx) clocks */ + for (i = 0; i < FIMC_MAX_WBCLKS; i++) { + if (IS_ERR(fmd->wbclk[i])) + continue; + clk_put(fmd->wbclk[i]); + fmd->wbclk[i] = ERR_PTR(-EINVAL); + } } static int fimc_md_get_clocks(struct fimc_md *fmd) @@ -1008,6 +1047,28 @@ static int fimc_md_get_clocks(struct fimc_md *fmd) if (ret) fimc_md_put_clocks(fmd); + if (!fmd->use_isp) + return 0; + /* + * For now get only PIXELASYNCM1 clock (Writeback B/ISP), + * leave PIXELASYNCM0 out for the LCD Writeback driver. + */ + fmd->wbclk[CLK_IDX_WB_A] = ERR_PTR(-EINVAL); + + for (i = CLK_IDX_WB_B; i < FIMC_MAX_WBCLKS; i++) { + snprintf(clk_name, sizeof(clk_name), "pxl_async%u", i); + clock = clk_get(dev, clk_name); + if (IS_ERR(clock)) { + v4l2_err(&fmd->v4l2_dev, "Failed to get clock: %s\n", + clk_name); + ret = PTR_ERR(clock); + break; + } + fmd->wbclk[i] = clock; + } + if (ret) + fimc_md_put_clocks(fmd); + return ret; } diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.h b/drivers/media/platform/s5p-fimc/fimc-mdevice.h index 5d6146e76802..46f3b82e0446 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.h +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.h @@ -41,6 +41,13 @@ #define FIMC_MAX_SENSORS 8 #define FIMC_MAX_CAMCLKS 2 +/* LCD/ISP Writeback clocks (PIXELASYNCMx) */ +enum { + CLK_IDX_WB_A, + CLK_IDX_WB_B, + FIMC_MAX_WBCLKS +}; + struct fimc_csis_info { struct v4l2_subdev *sd; int id; @@ -73,6 +80,7 @@ struct fimc_sensor_info { * @num_sensors: actual number of registered sensors * @camclk: external sensor clock information * @fimc: array of registered fimc devices + * @use_isp: set to true when FIMC-IS subsystem is used * @media_dev: top level media device * @v4l2_dev: top level v4l2_device holding up the subdevs * @pdev: platform device this media device is hooked up into @@ -87,8 +95,10 @@ struct fimc_md { struct fimc_sensor_info sensor[FIMC_MAX_SENSORS]; int num_sensors; struct fimc_camclk_info camclk[FIMC_MAX_CAMCLKS]; + struct clk *wbclk[FIMC_MAX_WBCLKS]; struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS]; struct fimc_dev *fimc[FIMC_MAX_DEVS]; + bool use_isp; struct media_device media_dev; struct v4l2_device v4l2_dev; struct platform_device *pdev; -- cgit v1.2.3 From 88fa8311ee36602362a1d6b61117dc3ac76ff8ad Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 20 Mar 2013 10:44:39 -0300 Subject: [media] s5p-fimc: Add support for ISP Writeback data input bus type A second sink pad is added to each FIMC.N subdev that will be used to link it to the FIMC-IS-ISP subdev. Only V4L2_MBUS_FMT_YUV10_1X30 format is supported at this pad (FIMC_SD_PAD_SINK_FIFO). The routine checking for mismatch in the image formats at sides of the links is updated to account for the fact FIMC.X subdevs now have sink pads at the pad indexes 0, 1 and source pad at pad index 2. If link to FIMC.X pad 1 is activated we switch FIMC input data bus type to the ISP Writeback. Only a single active link to FIMC.X pad 0 or 1 will be allowed at any time. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/Kconfig | 1 + drivers/media/platform/s5p-fimc/fimc-capture.c | 177 ++++++++++++++++--------- drivers/media/platform/s5p-fimc/fimc-core.c | 10 ++ drivers/media/platform/s5p-fimc/fimc-core.h | 19 ++- drivers/media/platform/s5p-fimc/fimc-mdevice.c | 7 +- drivers/media/platform/s5p-fimc/fimc-reg.c | 75 +++++++++-- drivers/media/platform/s5p-fimc/fimc-reg.h | 11 ++ 7 files changed, 221 insertions(+), 79 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-fimc/Kconfig b/drivers/media/platform/s5p-fimc/Kconfig index f997a5203b7c..c5caf08ed3c4 100644 --- a/drivers/media/platform/s5p-fimc/Kconfig +++ b/drivers/media/platform/s5p-fimc/Kconfig @@ -2,6 +2,7 @@ config VIDEO_SAMSUNG_S5P_FIMC bool "Samsung S5P/EXYNOS SoC camera interface driver (experimental)" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && PLAT_S5P && PM_RUNTIME + depends on MFD_SYSCON help Say Y here to enable camera host interface devices for Samsung S5P and EXYNOS SoC series. diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index ff9ca6384636..1675d385d900 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c @@ -33,26 +33,27 @@ static int fimc_capture_hw_init(struct fimc_dev *fimc) { + struct fimc_source_info *si = &fimc->vid_cap.source_config; struct fimc_ctx *ctx = fimc->vid_cap.ctx; - struct fimc_pipeline *p = &fimc->pipeline; - struct fimc_sensor_info *sensor; + int ret; unsigned long flags; - int ret = 0; - if (p->subdevs[IDX_SENSOR] == NULL || ctx == NULL) - return -ENXIO; - if (ctx->s_frame.fmt == NULL) + if (ctx == NULL || ctx->s_frame.fmt == NULL) return -EINVAL; - sensor = v4l2_get_subdev_hostdata(p->subdevs[IDX_SENSOR]); + if (si->fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) { + ret = fimc_hw_camblk_cfg_writeback(fimc); + if (ret < 0) + return ret; + } spin_lock_irqsave(&fimc->slock, flags); fimc_prepare_dma_offset(ctx, &ctx->d_frame); fimc_set_yuv_order(ctx); - fimc_hw_set_camera_polarity(fimc, &sensor->pdata); - fimc_hw_set_camera_type(fimc, &sensor->pdata); - fimc_hw_set_camera_source(fimc, &sensor->pdata); + fimc_hw_set_camera_polarity(fimc, si); + fimc_hw_set_camera_type(fimc, si); + fimc_hw_set_camera_source(fimc, si); fimc_hw_set_camera_offset(fimc, &ctx->s_frame); ret = fimc_set_scaler_info(ctx); @@ -606,18 +607,22 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, fimc_fmt_is_user_defined(ctx->s_frame.fmt->color)) *code = ctx->s_frame.fmt->mbus_code; - if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad != FIMC_SD_PAD_SINK) + if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad == FIMC_SD_PAD_SOURCE) mask |= FMT_FLAGS_M2M; + if (pad == FIMC_SD_PAD_SINK_FIFO) + mask = FMT_FLAGS_WRITEBACK; + ffmt = fimc_find_format(fourcc, code, mask, 0); if (WARN_ON(!ffmt)) return NULL; + if (code) *code = ffmt->mbus_code; if (fourcc) *fourcc = ffmt->fourcc; - if (pad == FIMC_SD_PAD_SINK) { + if (pad != FIMC_SD_PAD_SOURCE) { max_w = fimc_fmt_is_user_defined(ffmt->color) ? pl->scaler_dis_w : pl->scaler_en_w; /* Apply the camera input interface pixel constraints */ @@ -851,7 +856,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, tfmt->width = mf->width; tfmt->height = mf->height; ffmt = fimc_capture_try_format(ctx, &tfmt->width, &tfmt->height, - NULL, &fcc, FIMC_SD_PAD_SINK); + NULL, &fcc, FIMC_SD_PAD_SINK_CAM); ffmt = fimc_capture_try_format(ctx, &tfmt->width, &tfmt->height, NULL, &fcc, FIMC_SD_PAD_SOURCE); if (ffmt && ffmt->mbus_code) @@ -938,7 +943,7 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, if (fimc_jpeg_fourcc(pix->pixelformat)) { fimc_capture_try_format(ctx, &pix->width, &pix->height, NULL, &pix->pixelformat, - FIMC_SD_PAD_SINK); + FIMC_SD_PAD_SINK_CAM); ctx->s_frame.f_width = pix->width; ctx->s_frame.f_height = pix->height; } @@ -992,7 +997,7 @@ static int __fimc_capture_set_format(struct fimc_dev *fimc, { struct fimc_ctx *ctx = fimc->vid_cap.ctx; struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.mf; + struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.ci_fmt; struct fimc_frame *ff = &ctx->d_frame; struct fimc_fmt *s_fmt = NULL; int ret, i; @@ -1004,7 +1009,7 @@ static int __fimc_capture_set_format(struct fimc_dev *fimc, if (fimc_jpeg_fourcc(pix->pixelformat)) { fimc_capture_try_format(ctx, &pix->width, &pix->height, NULL, &pix->pixelformat, - FIMC_SD_PAD_SINK); + FIMC_SD_PAD_SINK_CAM); ctx->s_frame.f_width = pix->width; ctx->s_frame.f_height = pix->height; } @@ -1121,44 +1126,51 @@ static int fimc_cap_g_input(struct file *file, void *priv, unsigned int *i) static int fimc_pipeline_validate(struct fimc_dev *fimc) { struct v4l2_subdev_format sink_fmt, src_fmt; - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - struct v4l2_subdev *sd; - struct media_pad *pad; - int ret; - - /* Start with the video capture node pad */ - pad = media_entity_remote_source(&vid_cap->vd_pad); - if (pad == NULL) - return -EPIPE; - /* FIMC.{N} subdevice */ - sd = media_entity_to_v4l2_subdev(pad->entity); + struct fimc_vid_cap *vc = &fimc->vid_cap; + struct v4l2_subdev *sd = &vc->subdev; + struct media_pad *sink_pad, *src_pad; + int i, ret; while (1) { - /* Retrieve format at the sink pad */ - pad = &sd->entity.pads[0]; - if (!(pad->flags & MEDIA_PAD_FL_SINK)) + /* + * Find current entity sink pad and any remote sink pad linked + * to it. We stop if there is no sink pad in current entity or + * it is not linked to any other remote entity. + */ + src_pad = NULL; + + for (i = 0; i < sd->entity.num_pads; i++) { + struct media_pad *p = &sd->entity.pads[i]; + + if (p->flags & MEDIA_PAD_FL_SINK) { + sink_pad = p; + src_pad = media_entity_remote_source(sink_pad); + if (src_pad) + break; + } + } + + if (src_pad == NULL || + media_entity_type(src_pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) break; + /* Don't call FIMC subdev operation to avoid nested locking */ - if (sd == &fimc->vid_cap.subdev) { - struct fimc_frame *ff = &vid_cap->ctx->s_frame; + if (sd == &vc->subdev) { + struct fimc_frame *ff = &vc->ctx->s_frame; sink_fmt.format.width = ff->f_width; sink_fmt.format.height = ff->f_height; sink_fmt.format.code = ff->fmt ? ff->fmt->mbus_code : 0; } else { - sink_fmt.pad = pad->index; + sink_fmt.pad = sink_pad->index; sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt); if (ret < 0 && ret != -ENOIOCTLCMD) return -EPIPE; } - /* Retrieve format at the source pad */ - pad = media_entity_remote_source(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - break; - sd = media_entity_to_v4l2_subdev(pad->entity); - src_fmt.pad = pad->index; + /* Retrieve format at the source pad */ + sd = media_entity_to_v4l2_subdev(src_pad->entity); + src_fmt.pad = src_pad->index; src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt); if (ret < 0 && ret != -ENOIOCTLCMD) @@ -1172,7 +1184,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) if (sd == fimc->pipeline.subdevs[IDX_SENSOR] && fimc_user_defined_mbus_fmt(src_fmt.format.code)) { struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES]; - struct fimc_frame *frame = &vid_cap->ctx->d_frame; + struct fimc_frame *frame = &vc->ctx->d_frame; unsigned int i; ret = fimc_get_sensor_frame_desc(sd, plane_fmt, @@ -1196,6 +1208,8 @@ static int fimc_cap_streamon(struct file *file, void *priv, struct fimc_pipeline *p = &fimc->pipeline; struct fimc_vid_cap *vc = &fimc->vid_cap; struct media_entity *entity = &vc->vfd.entity; + struct fimc_source_info *si = NULL; + struct v4l2_subdev *sd; int ret; if (fimc_capture_active(fimc)) @@ -1205,6 +1219,23 @@ static int fimc_cap_streamon(struct file *file, void *priv, if (ret < 0) return ret; + sd = p->subdevs[IDX_SENSOR]; + if (sd) + si = v4l2_get_subdev_hostdata(sd); + + if (si == NULL) { + ret = -EPIPE; + goto err_p_stop; + } + /* + * Save configuration data related to currently attached image + * sensor or other data source, e.g. FIMC-IS. + */ + vc->source_config = *si; + + if (vc->input == GRP_ID_FIMC_IS) + vc->source_config.fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK; + if (vc->user_subdev_api) { ret = fimc_pipeline_validate(fimc); if (ret < 0) @@ -1461,25 +1492,37 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct fimc_frame *ff = &ctx->s_frame; struct v4l2_mbus_framefmt *mf; - struct fimc_frame *ff; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { mf = v4l2_subdev_get_try_format(fh, fmt->pad); fmt->format = *mf; return 0; } - mf = &fmt->format; - mf->colorspace = V4L2_COLORSPACE_JPEG; - ff = fmt->pad == FIMC_SD_PAD_SINK ? &ctx->s_frame : &ctx->d_frame; + mf = &fmt->format; mutex_lock(&fimc->lock); - /* The pixel code is same on both input and output pad */ - if (!WARN_ON(ctx->s_frame.fmt == NULL)) - mf->code = ctx->s_frame.fmt->mbus_code; - mf->width = ff->f_width; - mf->height = ff->f_height; + + switch (fmt->pad) { + case FIMC_SD_PAD_SOURCE: + if (!WARN_ON(ff->fmt == NULL)) + mf->code = ff->fmt->mbus_code; + /* Sink pads crop rectangle size */ + mf->width = ff->width; + mf->height = ff->height; + break; + case FIMC_SD_PAD_SINK_FIFO: + *mf = fimc->vid_cap.wb_fmt; + break; + case FIMC_SD_PAD_SINK_CAM: + default: + *mf = fimc->vid_cap.ci_fmt; + break; + } + mutex_unlock(&fimc->lock); + mf->colorspace = V4L2_COLORSPACE_JPEG; return 0; } @@ -1490,15 +1533,15 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf = &fmt->format; - struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct fimc_vid_cap *vc = &fimc->vid_cap; + struct fimc_ctx *ctx = vc->ctx; struct fimc_frame *ff; struct fimc_fmt *ffmt; dbg("pad%d: code: 0x%x, %dx%d", fmt->pad, mf->code, mf->width, mf->height); - if (fmt->pad == FIMC_SD_PAD_SOURCE && - vb2_is_busy(&fimc->vid_cap.vbq)) + if (fmt->pad == FIMC_SD_PAD_SOURCE && vb2_is_busy(&vc->vbq)) return -EBUSY; mutex_lock(&fimc->lock); @@ -1520,21 +1563,32 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, fimc_alpha_ctrl_update(ctx); fimc_capture_mark_jpeg_xfer(ctx, ffmt->color); - - ff = fmt->pad == FIMC_SD_PAD_SINK ? - &ctx->s_frame : &ctx->d_frame; + if (fmt->pad == FIMC_SD_PAD_SOURCE) { + ff = &ctx->d_frame; + /* Sink pads crop rectangle size */ + mf->width = ctx->s_frame.width; + mf->height = ctx->s_frame.height; + } else { + ff = &ctx->s_frame; + } mutex_lock(&fimc->lock); set_frame_bounds(ff, mf->width, mf->height); - fimc->vid_cap.mf = *mf; + + if (fmt->pad == FIMC_SD_PAD_SINK_FIFO) + vc->wb_fmt = *mf; + else if (fmt->pad == FIMC_SD_PAD_SINK_CAM) + vc->ci_fmt = *mf; + ff->fmt = ffmt; /* Reset the crop rectangle if required. */ if (!(fmt->pad == FIMC_SD_PAD_SOURCE && (ctx->state & FIMC_COMPOSE))) set_frame_crop(ff, 0, 0, mf->width, mf->height); - if (fmt->pad == FIMC_SD_PAD_SINK) + if (fmt->pad != FIMC_SD_PAD_SOURCE) ctx->state &= ~FIMC_COMPOSE; + mutex_unlock(&fimc->lock); return 0; } @@ -1549,7 +1603,7 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd, struct v4l2_rect *r = &sel->r; struct v4l2_rect *try_sel; - if (sel->pad != FIMC_SD_PAD_SINK) + if (sel->pad == FIMC_SD_PAD_SOURCE) return -EINVAL; mutex_lock(&fimc->lock); @@ -1605,7 +1659,7 @@ static int fimc_subdev_set_selection(struct v4l2_subdev *sd, struct v4l2_rect *try_sel; unsigned long flags; - if (sel->pad != FIMC_SD_PAD_SINK) + if (sel->pad == FIMC_SD_PAD_SOURCE) return -EINVAL; mutex_lock(&fimc->lock); @@ -1809,7 +1863,8 @@ int fimc_initialize_capture_subdev(struct fimc_dev *fimc) sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->id); - fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_CAM].flags = MEDIA_PAD_FL_SINK; + fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_FIFO].flags = MEDIA_PAD_FL_SINK; fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM, fimc->vid_cap.sd_pads, 0); diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index 6a8098c42cc8..1edd3aa8f3f3 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ b/drivers/media/platform/s5p-fimc/fimc-core.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,10 @@ static struct fimc_fmt fimc_formats[] = { .memplanes = 1, .colplanes = 1, .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA, + }, { + .name = "YUV 4:4:4", + .mbus_code = V4L2_MBUS_FMT_YUV10_1X30, + .flags = FMT_FLAGS_WRITEBACK, }, { .name = "YUV 4:2:2 packed, YCbYCr", .fourcc = V4L2_PIX_FMT_YUYV, @@ -959,6 +964,11 @@ static int fimc_probe(struct platform_device *pdev) spin_lock_init(&fimc->slock); mutex_init(&fimc->lock); + fimc->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, + "samsung,sysreg"); + if (IS_ERR(fimc->sysreg)) + return PTR_ERR(fimc->sysreg); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); fimc->regs = devm_ioremap_resource(dev, res); if (IS_ERR(fimc->regs)) diff --git a/drivers/media/platform/s5p-fimc/fimc-core.h b/drivers/media/platform/s5p-fimc/fimc-core.h index 145b8cc77af0..6355b3387b96 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.h +++ b/drivers/media/platform/s5p-fimc/fimc-core.h @@ -12,6 +12,7 @@ /*#define DEBUG*/ #include +#include #include #include #include @@ -163,6 +164,7 @@ struct fimc_fmt { #define FMT_FLAGS_M2M (1 << 1 | 1 << 2) #define FMT_HAS_ALPHA (1 << 3) #define FMT_FLAGS_COMPRESSED (1 << 4) +#define FMT_FLAGS_WRITEBACK (1 << 5) }; /** @@ -303,9 +305,10 @@ struct fimc_m2m_device { int refcnt; }; -#define FIMC_SD_PAD_SINK 0 -#define FIMC_SD_PAD_SOURCE 1 -#define FIMC_SD_PADS_NUM 2 +#define FIMC_SD_PAD_SINK_CAM 0 +#define FIMC_SD_PAD_SINK_FIFO 1 +#define FIMC_SD_PAD_SOURCE 2 +#define FIMC_SD_PADS_NUM 3 /** * struct fimc_vid_cap - camera capture device information @@ -314,7 +317,9 @@ struct fimc_m2m_device { * @subdev: subdev exposing the FIMC processing block * @vd_pad: fimc video capture node pad * @sd_pads: fimc video processing block pads - * @mf: media bus format at the FIMC camera input (and the scaler output) pad + * @ci_fmt: image format at the FIMC camera input (and the scaler output) + * @wb_fmt: image format at the FIMC ISP Writeback input + * @source_config: external image source related configuration structure * @pending_buf_q: the pending buffer queue head * @active_buf_q: the queue head of buffers scheduled in hardware * @vbq: the capture am video buffer queue @@ -333,8 +338,10 @@ struct fimc_vid_cap { struct video_device vfd; struct v4l2_subdev subdev; struct media_pad vd_pad; - struct v4l2_mbus_framefmt mf; struct media_pad sd_pads[FIMC_SD_PADS_NUM]; + struct v4l2_mbus_framefmt ci_fmt; + struct v4l2_mbus_framefmt wb_fmt; + struct fimc_source_info source_config; struct list_head pending_buf_q; struct list_head active_buf_q; struct vb2_queue vbq; @@ -426,6 +433,7 @@ struct fimc_ctx; * @lock: the mutex protecting this data structure * @pdev: pointer to the FIMC platform device * @pdata: pointer to the device platform data + * @sysreg: pointer to the SYSREG regmap * @variant: the IP variant information * @id: FIMC device index (0..FIMC_MAX_DEVS) * @clock: clocks required for FIMC operation @@ -443,6 +451,7 @@ struct fimc_dev { struct mutex lock; struct platform_device *pdev; struct s5p_platform_fimc *pdata; + struct regmap *sysreg; const struct fimc_variant *variant; const struct fimc_drvdata *drv_data; u16 id; diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index c4a39782d55e..1f29f51b256b 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -267,6 +267,11 @@ static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd, if (!s_info || !fmd) return NULL; + /* + * If FIMC bus type is not Writeback FIFO assume it is same + * as sensor_bus_type. + */ + s_info->pdata.fimc_bus_type = s_info->pdata.sensor_bus_type; adapter = i2c_get_adapter(s_info->pdata.i2c_bus_num); if (!adapter) { @@ -807,7 +812,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, sink = &fmd->fimc[i]->vid_cap.subdev.entity; ret = media_entity_create_link(source, pad, sink, - FIMC_SD_PAD_SINK, flags); + FIMC_SD_PAD_SINK_CAM, flags); if (ret) return ret; diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.c b/drivers/media/platform/s5p-fimc/fimc-reg.c index 4d2fc69d2cba..ee88b94682d0 100644 --- a/drivers/media/platform/s5p-fimc/fimc-reg.c +++ b/drivers/media/platform/s5p-fimc/fimc-reg.c @@ -1,22 +1,24 @@ /* * Register interface file for Samsung Camera Interface (FIMC) driver * - * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki, + * Copyright (C) 2010 - 2013 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#include #include +#include +#include + #include +#include "fimc-mdevice.h" #include "fimc-reg.h" #include "fimc-core.h" - void fimc_hw_reset(struct fimc_dev *dev) { u32 cfg; @@ -598,7 +600,8 @@ static const struct mbus_pixfmt_desc pix_desc[] = { int fimc_hw_set_camera_source(struct fimc_dev *fimc, struct fimc_source_info *source) { - struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame; + struct fimc_vid_cap *vc = &fimc->vid_cap; + struct fimc_frame *f = &vc->ctx->s_frame; u32 bus_width, cfg = 0; int i; @@ -606,7 +609,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc, case FIMC_BUS_TYPE_ITU_601: case FIMC_BUS_TYPE_ITU_656: for (i = 0; i < ARRAY_SIZE(pix_desc); i++) { - if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) { + if (vc->ci_fmt.code == pix_desc[i].pixelcode) { cfg = pix_desc[i].cisrcfmt; bus_width = pix_desc[i].bus_width; break; @@ -614,9 +617,9 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc, } if (i == ARRAY_SIZE(pix_desc)) { - v4l2_err(&fimc->vid_cap.vfd, + v4l2_err(&vc->vfd, "Camera color format not supported: %d\n", - fimc->vid_cap.mf.code); + vc->ci_fmt.code); return -EINVAL; } @@ -631,6 +634,10 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc, if (fimc_fmt_is_user_defined(f->fmt->color)) cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; break; + default: + case FIMC_BUS_TYPE_ISP_WRITEBACK: + /* Anything to do here ? */ + break; } cfg |= (f->o_width << 16) | f->o_height; @@ -660,16 +667,17 @@ void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f) int fimc_hw_set_camera_type(struct fimc_dev *fimc, struct fimc_source_info *source) { - u32 cfg, tmp; struct fimc_vid_cap *vid_cap = &fimc->vid_cap; u32 csis_data_alignment = 32; + u32 cfg, tmp; cfg = readl(fimc->regs + FIMC_REG_CIGCTRL); /* Select ITU B interface, disable Writeback path and test pattern. */ cfg &= ~(FIMC_REG_CIGCTRL_TESTPAT_MASK | FIMC_REG_CIGCTRL_SELCAM_ITU_A | FIMC_REG_CIGCTRL_SELCAM_MIPI | FIMC_REG_CIGCTRL_CAMIF_SELWB | - FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG); + FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG | + FIMC_REG_CIGCTRL_SELWB_A); switch (source->fimc_bus_type) { case FIMC_BUS_TYPE_MIPI_CSI2: @@ -679,7 +687,7 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI_A; /* TODO: add remaining supported formats. */ - switch (vid_cap->mf.code) { + switch (vid_cap->ci_fmt.code) { case V4L2_MBUS_FMT_VYUY8_2X8: tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT; break; @@ -691,7 +699,7 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, default: v4l2_err(&vid_cap->vfd, "Not supported camera pixel format: %#x\n", - vid_cap->mf.code); + vid_cap->ci_fmt.code); return -EINVAL; } tmp |= (csis_data_alignment == 32) << 8; @@ -704,6 +712,12 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc, break; case FIMC_BUS_TYPE_LCD_WRITEBACK_A: cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; + /* fall through */ + case FIMC_BUS_TYPE_ISP_WRITEBACK: + if (fimc->variant->has_isp_wb) + cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; + else + WARN_ONCE(1, "ISP Writeback input is not supported\n"); break; default: v4l2_err(&vid_cap->vfd, "Invalid FIMC bus type selected: %d\n", @@ -784,3 +798,40 @@ void fimc_deactivate_capture(struct fimc_dev *fimc) fimc_hw_enable_scaler(fimc, false); fimc_hw_en_lastirq(fimc, false); } + +int fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc) +{ + struct regmap *map = fimc->sysreg; + unsigned int mask, val, camblk_cfg; + int ret; + + ret = regmap_read(map, SYSREG_CAMBLK, &camblk_cfg); + if (ret < 0 || ((camblk_cfg & 0x00700000) >> 20 != 0x3)) + return ret; + + if (!WARN(fimc->id >= 3, "not supported id: %d\n", fimc->id)) + val = 0x1 << (fimc->id + 20); + else + val = 0; + + mask = SYSREG_CAMBLK_FIFORST_ISP | SYSREG_CAMBLK_ISPWB_FULL_EN; + ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val); + if (ret < 0) + return ret; + + usleep_range(1000, 2000); + + val |= SYSREG_CAMBLK_FIFORST_ISP; + ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val); + if (ret < 0) + return ret; + + mask = SYSREG_ISPBLK_FIFORST_CAM_BLK; + ret = regmap_update_bits(map, SYSREG_ISPBLK, mask, ~mask); + if (ret < 0) + return ret; + + usleep_range(1000, 2000); + + return regmap_update_bits(map, SYSREG_ISPBLK, mask, mask); +} diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.h b/drivers/media/platform/s5p-fimc/fimc-reg.h index 1a40df6d1a80..01da7f3622bf 100644 --- a/drivers/media/platform/s5p-fimc/fimc-reg.h +++ b/drivers/media/platform/s5p-fimc/fimc-reg.h @@ -52,6 +52,8 @@ #define FIMC_REG_CIGCTRL_IRQ_CLR (1 << 19) #define FIMC_REG_CIGCTRL_IRQ_ENABLE (1 << 16) #define FIMC_REG_CIGCTRL_SHDW_DISABLE (1 << 12) +/* 0 - selects Writeback A (LCD), 1 - selects Writeback B (LCD/ISP) */ +#define FIMC_REG_CIGCTRL_SELWB_A (1 << 10) #define FIMC_REG_CIGCTRL_CAM_JPEG (1 << 8) #define FIMC_REG_CIGCTRL_SELCAM_MIPI_A (1 << 7) #define FIMC_REG_CIGCTRL_CAMIF_SELWB (1 << 6) @@ -276,6 +278,14 @@ /* Output frame buffer sequence mask */ #define FIMC_REG_CIFCNTSEQ 0x1fc +/* SYSREG ISP Writeback register address offsets */ +#define SYSREG_ISPBLK 0x020c +#define SYSREG_ISPBLK_FIFORST_CAM_BLK (1 << 7) + +#define SYSREG_CAMBLK 0x0218 +#define SYSREG_CAMBLK_FIFORST_ISP (1 << 15) +#define SYSREG_CAMBLK_ISPWB_FULL_EN (7 << 20) + /* * Function declarations */ @@ -309,6 +319,7 @@ void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on); void fimc_hw_disable_capture(struct fimc_dev *dev); s32 fimc_hw_get_frame_index(struct fimc_dev *dev); s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev); +int fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc); void fimc_activate_capture(struct fimc_ctx *ctx); void fimc_deactivate_capture(struct fimc_dev *fimc); -- cgit v1.2.3 From 3e20c345a6dac13a1545bd748f9d0a6336856ee7 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 21 Mar 2013 14:47:17 -0300 Subject: [media] s5p-fimc: Ensure CAMCLK clock can be enabled by FIMC-LITE devices In configurations where FIMC-LITE is used to capture image signal from an external sensor only we need to ensure one of FIMC devices is in active power state and the "fimc" gate clock is enabled. Otherwise the CAMCLK clock output signal will be masked off preventing an external sensor's operation. This affect processing pipelines like: - sensor -> FIMC-LITE -> memory - sensor -> MIPI-CSIS -> FIMC-LITE -> memory Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-mdevice.c | 18 ++++++++++-------- drivers/media/platform/s5p-fimc/fimc-mdevice.h | 2 ++ 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index 1f29f51b256b..e7164ce373db 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -509,7 +509,6 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) { struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data; struct device_node *of_node = fmd->pdev->dev.of_node; - struct fimc_dev *fd = NULL; int num_clients = 0; int ret, i; @@ -517,13 +516,10 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) * Runtime resume one of the FIMC entities to make sure * the sclk_cam clocks are not globally disabled. */ - for (i = 0; !fd && i < ARRAY_SIZE(fmd->fimc); i++) - if (fmd->fimc[i]) - fd = fmd->fimc[i]; - if (!fd) + if (!fmd->pmf) return -ENXIO; - ret = pm_runtime_get_sync(&fd->pdev->dev); + ret = pm_runtime_get_sync(fmd->pmf); if (ret < 0) return ret; @@ -557,7 +553,7 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) } } - pm_runtime_put(&fd->pdev->dev); + pm_runtime_put(fmd->pmf); return ret; } @@ -602,6 +598,8 @@ static int register_fimc_entity(struct fimc_md *fmd, struct fimc_dev *fimc) ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); if (!ret) { + if (!fmd->pmf && fimc->pdev) + fmd->pmf = &fimc->pdev->dev; fmd->fimc[fimc->id] = fimc; fimc->vid_cap.user_subdev_api = fmd->user_subdev_api; } else { @@ -1085,7 +1083,7 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd, struct fimc_camclk_info *camclk; int ret = 0; - if (WARN_ON(pdata->clk_id >= FIMC_MAX_CAMCLKS) || fmd == NULL) + if (WARN_ON(pdata->clk_id >= FIMC_MAX_CAMCLKS) || !fmd || !fmd->pmf) return -EINVAL; camclk = &fmd->camclk[pdata->clk_id]; @@ -1101,6 +1099,9 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd, if (camclk->use_count++ == 0) { clk_set_rate(camclk->clock, pdata->clk_frequency); camclk->frequency = pdata->clk_frequency; + ret = pm_runtime_get_sync(fmd->pmf); + if (ret < 0) + return ret; ret = clk_enable(camclk->clock); dbg("Enabled camclk %d: f: %lu", pdata->clk_id, clk_get_rate(camclk->clock)); @@ -1113,6 +1114,7 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd, if (--camclk->use_count == 0) { clk_disable(camclk->clock); + pm_runtime_put(fmd->pmf); dbg("Disabled camclk %d", pdata->clk_id); } return ret; diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.h b/drivers/media/platform/s5p-fimc/fimc-mdevice.h index 46f3b82e0446..1d5cea5a6bbe 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.h +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.h @@ -81,6 +81,7 @@ struct fimc_sensor_info { * @camclk: external sensor clock information * @fimc: array of registered fimc devices * @use_isp: set to true when FIMC-IS subsystem is used + * @pmf: handle to the CAMCLK clock control FIMC helper device * @media_dev: top level media device * @v4l2_dev: top level v4l2_device holding up the subdevs * @pdev: platform device this media device is hooked up into @@ -99,6 +100,7 @@ struct fimc_md { struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS]; struct fimc_dev *fimc[FIMC_MAX_DEVS]; bool use_isp; + struct device *pmf; struct media_device media_dev; struct v4l2_device v4l2_dev; struct platform_device *pdev; -- cgit v1.2.3 From 8d274e7c0a111e91a7a3f25877af8103ddf05261 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 13 Nov 2012 14:35:22 -0300 Subject: [media] s5p-fimc: Ensure proper s_stream() call order in the ISP datapaths Since the FIMC-IS firmware communicates with an image sensor directly through the ISP I2C bus controllers data streaming cannot be simply enabled from left to right or disabled from right to left along the processing pipeline. Thus a subdev index to call s_stream() on is looked up from a table, rather than doing the op call based on increasing/decreasing indexes. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-mdevice.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index e7164ce373db..b22489907295 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -225,28 +225,36 @@ static int __fimc_pipeline_close(struct fimc_pipeline *p) } /** - * __fimc_pipeline_s_stream - invoke s_stream on pipeline subdevs + * __fimc_pipeline_s_stream - call s_stream() on pipeline subdevs * @pipeline: video pipeline structure - * @on: passed as the s_stream call argument + * @on: passed as the s_stream() callback argument */ static int __fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on) { - int i, ret; + static const u8 seq[2][IDX_MAX] = { + { IDX_FIMC, IDX_SENSOR, IDX_IS_ISP, IDX_CSIS, IDX_FLITE }, + { IDX_CSIS, IDX_FLITE, IDX_FIMC, IDX_SENSOR, IDX_IS_ISP }, + }; + int i, ret = 0; if (p->subdevs[IDX_SENSOR] == NULL) return -ENODEV; for (i = 0; i < IDX_MAX; i++) { - unsigned int idx = on ? (IDX_MAX - 1) - i : i; + unsigned int idx = seq[on][i]; ret = v4l2_subdev_call(p->subdevs[idx], video, s_stream, on); if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) - return ret; + goto error; } - return 0; - +error: + for (; i >= 0; i--) { + unsigned int idx = seq[on][i]; + v4l2_subdev_call(p->subdevs[idx], video, s_stream, !on); + } + return ret; } /* Media pipeline operations for the FIMC/FIMC-LITE video device driver */ -- cgit v1.2.3 From f8bca4f52947f0d6c10299b10e4ccf5711688acc Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 20 Nov 2012 08:54:22 -0300 Subject: [media] s5p-fimc: Ensure proper s_power() call order in the ISP datapaths Since the FIMC-IS firmware communicates with an image sensor directly through the ISP I2C bus controllers the sub-devices power supplies cannot be simply enabled from left to right or disabled from right to left along the processing pipeline. Thus a subdev index to call s_power() on is looked up from a table, rather than doing the op call based on increasing/decreasing indexes. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-mdevice.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index b22489907295..77075a4d1145 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -128,23 +128,33 @@ static int __subdev_set_power(struct v4l2_subdev *sd, int on) * * Needs to be called with the graph mutex held. */ -static int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state) +static int fimc_pipeline_s_power(struct fimc_pipeline *p, bool on) { - unsigned int i; - int ret; + static const u8 seq[2][IDX_MAX - 1] = { + { IDX_IS_ISP, IDX_SENSOR, IDX_CSIS, IDX_FLITE }, + { IDX_CSIS, IDX_FLITE, IDX_SENSOR, IDX_IS_ISP }, + }; + int i, ret = 0; if (p->subdevs[IDX_SENSOR] == NULL) return -ENXIO; - for (i = 0; i < IDX_MAX; i++) { - unsigned int idx = state ? (IDX_MAX - 1) - i : i; + for (i = 0; i < IDX_MAX - 1; i++) { + unsigned int idx = seq[on][i]; + + ret = __subdev_set_power(p->subdevs[idx], on); + - ret = __subdev_set_power(p->subdevs[idx], state); if (ret < 0 && ret != -ENXIO) - return ret; + goto error; } - return 0; +error: + for (; i >= 0; i--) { + unsigned int idx = seq[on][i]; + __subdev_set_power(p->subdevs[idx], !on); + } + return ret; } /** -- cgit v1.2.3 From 80f958f40d702ab322947f648bbd42174facf19d Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 25 Feb 2013 13:20:21 -0300 Subject: [media] s5p-fimc: Remove dependency on fimc-core.h in fimc-lite driver Drop fimc-lite.h header inclusion to make the exynos-fimc-lite module independent on other modules. Move struct fimc_fmt declaration to the driver's private headers as it is used in multiple modules. Reported-by: Shaik Ameer Basha Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-fimc/fimc-core.h | 31 -------------------------- drivers/media/platform/s5p-fimc/fimc-lite.c | 1 - drivers/media/platform/s5p-fimc/fimc-lite.h | 3 +-- include/media/s5p_fimc.h | 34 +++++++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 34 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-fimc/fimc-core.h b/drivers/media/platform/s5p-fimc/fimc-core.h index 6355b3387b96..793333a33b24 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.h +++ b/drivers/media/platform/s5p-fimc/fimc-core.h @@ -136,37 +136,6 @@ enum fimc_color_fmt { /* Y (16 ~ 235), Cb/Cr (16 ~ 240) */ #define FIMC_COLOR_RANGE_NARROW (1 << 3) -/** - * struct fimc_fmt - the driver's internal color format data - * @mbus_code: Media Bus pixel code, -1 if not applicable - * @name: format description - * @fourcc: the fourcc code for this format, 0 if not applicable - * @color: the corresponding fimc_color_fmt - * @memplanes: number of physically non-contiguous data planes - * @colplanes: number of physically contiguous data planes - * @depth: per plane driver's private 'number of bits per pixel' - * @mdataplanes: bitmask indicating meta data plane(s), (1 << plane_no) - * @flags: flags indicating which operation mode format applies to - */ -struct fimc_fmt { - enum v4l2_mbus_pixelcode mbus_code; - char *name; - u32 fourcc; - u32 color; - u16 memplanes; - u16 colplanes; - u8 depth[VIDEO_MAX_PLANES]; - u16 mdataplanes; - u16 flags; -#define FMT_FLAGS_CAM (1 << 0) -#define FMT_FLAGS_M2M_IN (1 << 1) -#define FMT_FLAGS_M2M_OUT (1 << 2) -#define FMT_FLAGS_M2M (1 << 1 | 1 << 2) -#define FMT_HAS_ALPHA (1 << 3) -#define FMT_FLAGS_COMPRESSED (1 << 4) -#define FMT_FLAGS_WRITEBACK (1 << 5) -}; - /** * struct fimc_dma_offset - pixel offset information for DMA * @y_h: y value horizontal offset diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index 65082fe2578c..a37282e27cb0 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite.c @@ -32,7 +32,6 @@ #include #include "fimc-mdevice.h" -#include "fimc-core.h" #include "fimc-lite.h" #include "fimc-lite-reg.h" diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.h b/drivers/media/platform/s5p-fimc/fimc-lite.h index 7085761f8c4b..4c2345086366 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.h +++ b/drivers/media/platform/s5p-fimc/fimc-lite.h @@ -20,12 +20,11 @@ #include #include +#include #include #include #include -#include "fimc-core.h" - #define FIMC_LITE_DRV_NAME "exynos-fimc-lite" #define FLITE_CLK_NAME "flite" #define FIMC_LITE_MAX_DEVS 2 diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index e2434bb0b308..2363aff24df7 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -13,6 +13,7 @@ #define S5P_FIMC_H_ #include +#include /* * Enumeration of data inputs to the camera subsystem. @@ -93,6 +94,39 @@ struct s5p_platform_fimc { */ #define S5P_FIMC_TX_END_NOTIFY _IO('e', 0) +#define FIMC_MAX_PLANES 3 + +/** + * struct fimc_fmt - color format data structure + * @mbus_code: media bus pixel code, -1 if not applicable + * @name: format description + * @fourcc: fourcc code for this format, 0 if not applicable + * @color: the driver's private color format id + * @memplanes: number of physically non-contiguous data planes + * @colplanes: number of physically contiguous data planes + * @depth: per plane driver's private 'number of bits per pixel' + * @mdataplanes: bitmask indicating meta data plane(s), (1 << plane_no) + * @flags: flags indicating which operation mode format applies to + */ +struct fimc_fmt { + enum v4l2_mbus_pixelcode mbus_code; + char *name; + u32 fourcc; + u32 color; + u16 memplanes; + u16 colplanes; + u8 depth[FIMC_MAX_PLANES]; + u16 mdataplanes; + u16 flags; +#define FMT_FLAGS_CAM (1 << 0) +#define FMT_FLAGS_M2M_IN (1 << 1) +#define FMT_FLAGS_M2M_OUT (1 << 2) +#define FMT_FLAGS_M2M (1 << 1 | 1 << 2) +#define FMT_HAS_ALPHA (1 << 3) +#define FMT_FLAGS_COMPRESSED (1 << 4) +#define FMT_FLAGS_WRITEBACK (1 << 5) +}; + enum fimc_subdev_index { IDX_SENSOR, IDX_CSIS, -- cgit v1.2.3 From 56fa1a6a6a7da91e7ece8b01b0ae8adb2926e434 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Sun, 24 Mar 2013 16:54:25 +0100 Subject: [media] s5p-fimc: Change the driver directory name to exynos4-is The s5p-fimc directory now contains drivers for multiple IP blocks found in multiple Samsung application processors. This includes FIMC (CAMIF), MIPI CSIS and FIMC LITE. FIMC-IS (Imaging Subsystem) driver is going to be put into same directory. Hence we rename it to exynos4-is as s5p-fimc was only relevant for early version of this driver, when it only supported FIMC IP block. The imaging subsystem drivers for Exynos4 SoC series and S5PV210 will be included in drivers/media/platform/exynos4-is directory, with some modules shared with exynos5 series, while the rest of exynos5 specific modules will find their home in drivers/media/platform/exynos5-is. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 2 +- drivers/media/platform/Makefile | 2 +- drivers/media/platform/exynos4-is/Kconfig | 49 + drivers/media/platform/exynos4-is/Makefile | 7 + drivers/media/platform/exynos4-is/fimc-capture.c | 1887 +++++++++++++++++++++ drivers/media/platform/exynos4-is/fimc-core.c | 1334 +++++++++++++++ drivers/media/platform/exynos4-is/fimc-core.h | 718 ++++++++ drivers/media/platform/exynos4-is/fimc-lite-reg.c | 302 ++++ drivers/media/platform/exynos4-is/fimc-lite-reg.h | 150 ++ drivers/media/platform/exynos4-is/fimc-lite.c | 1626 ++++++++++++++++++ drivers/media/platform/exynos4-is/fimc-lite.h | 217 +++ drivers/media/platform/exynos4-is/fimc-m2m.c | 863 ++++++++++ drivers/media/platform/exynos4-is/fimc-reg.c | 837 +++++++++ drivers/media/platform/exynos4-is/fimc-reg.h | 338 ++++ drivers/media/platform/exynos4-is/media-dev.c | 1437 ++++++++++++++++ drivers/media/platform/exynos4-is/media-dev.h | 142 ++ drivers/media/platform/exynos4-is/mipi-csis.c | 1025 +++++++++++ drivers/media/platform/exynos4-is/mipi-csis.h | 26 + drivers/media/platform/s5p-fimc/Kconfig | 49 - drivers/media/platform/s5p-fimc/Makefile | 7 - drivers/media/platform/s5p-fimc/fimc-capture.c | 1887 --------------------- drivers/media/platform/s5p-fimc/fimc-core.c | 1334 --------------- drivers/media/platform/s5p-fimc/fimc-core.h | 718 -------- drivers/media/platform/s5p-fimc/fimc-lite-reg.c | 302 ---- drivers/media/platform/s5p-fimc/fimc-lite-reg.h | 150 -- drivers/media/platform/s5p-fimc/fimc-lite.c | 1626 ------------------ drivers/media/platform/s5p-fimc/fimc-lite.h | 217 --- drivers/media/platform/s5p-fimc/fimc-m2m.c | 864 ---------- drivers/media/platform/s5p-fimc/fimc-mdevice.c | 1437 ---------------- drivers/media/platform/s5p-fimc/fimc-mdevice.h | 142 -- drivers/media/platform/s5p-fimc/fimc-reg.c | 837 --------- drivers/media/platform/s5p-fimc/fimc-reg.h | 338 ---- drivers/media/platform/s5p-fimc/mipi-csis.c | 1025 ----------- drivers/media/platform/s5p-fimc/mipi-csis.h | 26 - 34 files changed, 10960 insertions(+), 10961 deletions(-) create mode 100644 drivers/media/platform/exynos4-is/Kconfig create mode 100644 drivers/media/platform/exynos4-is/Makefile create mode 100644 drivers/media/platform/exynos4-is/fimc-capture.c create mode 100644 drivers/media/platform/exynos4-is/fimc-core.c create mode 100644 drivers/media/platform/exynos4-is/fimc-core.h create mode 100644 drivers/media/platform/exynos4-is/fimc-lite-reg.c create mode 100644 drivers/media/platform/exynos4-is/fimc-lite-reg.h create mode 100644 drivers/media/platform/exynos4-is/fimc-lite.c create mode 100644 drivers/media/platform/exynos4-is/fimc-lite.h create mode 100644 drivers/media/platform/exynos4-is/fimc-m2m.c create mode 100644 drivers/media/platform/exynos4-is/fimc-reg.c create mode 100644 drivers/media/platform/exynos4-is/fimc-reg.h create mode 100644 drivers/media/platform/exynos4-is/media-dev.c create mode 100644 drivers/media/platform/exynos4-is/media-dev.h create mode 100644 drivers/media/platform/exynos4-is/mipi-csis.c create mode 100644 drivers/media/platform/exynos4-is/mipi-csis.h delete mode 100644 drivers/media/platform/s5p-fimc/Kconfig delete mode 100644 drivers/media/platform/s5p-fimc/Makefile delete mode 100644 drivers/media/platform/s5p-fimc/fimc-capture.c delete mode 100644 drivers/media/platform/s5p-fimc/fimc-core.c delete mode 100644 drivers/media/platform/s5p-fimc/fimc-core.h delete mode 100644 drivers/media/platform/s5p-fimc/fimc-lite-reg.c delete mode 100644 drivers/media/platform/s5p-fimc/fimc-lite-reg.h delete mode 100644 drivers/media/platform/s5p-fimc/fimc-lite.c delete mode 100644 drivers/media/platform/s5p-fimc/fimc-lite.h delete mode 100644 drivers/media/platform/s5p-fimc/fimc-m2m.c delete mode 100644 drivers/media/platform/s5p-fimc/fimc-mdevice.c delete mode 100644 drivers/media/platform/s5p-fimc/fimc-mdevice.h delete mode 100644 drivers/media/platform/s5p-fimc/fimc-reg.c delete mode 100644 drivers/media/platform/s5p-fimc/fimc-reg.h delete mode 100644 drivers/media/platform/s5p-fimc/mipi-csis.c delete mode 100644 drivers/media/platform/s5p-fimc/mipi-csis.h (limited to 'drivers/media') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 42c62aa33e11..ae8954591c51 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -122,7 +122,7 @@ config VIDEO_S3C_CAMIF will be called s3c-camif. source "drivers/media/platform/soc_camera/Kconfig" -source "drivers/media/platform/s5p-fimc/Kconfig" +source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" endif # V4L_PLATFORM_DRIVERS diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 42089ba3600f..eee28dd78d7d 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -30,7 +30,7 @@ obj-$(CONFIG_VIDEO_SH_VEU) += sh_veu.o obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o obj-$(CONFIG_VIDEO_S3C_CAMIF) += s3c-camif/ -obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ +obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS) += exynos4-is/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV) += s5p-tv/ diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig new file mode 100644 index 000000000000..91dbd4b22362 --- /dev/null +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -0,0 +1,49 @@ + +config VIDEO_SAMSUNG_EXYNOS4_IS + bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && PLAT_S5P && PM_RUNTIME + depends on MFD_SYSCON + help + Say Y here to enable camera host interface devices for + Samsung S5P and EXYNOS SoC series. + +if VIDEO_SAMSUNG_EXYNOS4_IS + +config VIDEO_S5P_FIMC + tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver" + depends on I2C + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + help + This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC camera host + interface and video postprocessor (FIMC) devices. + + To compile this driver as a module, choose M here: the + module will be called s5p-fimc. + +config VIDEO_S5P_MIPI_CSIS + tristate "S5P/EXYNOS MIPI-CSI2 receiver (MIPI-CSIS) driver" + depends on REGULATOR + select S5P_SETUP_MIPIPHY + help + This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC MIPI-CSI2 + receiver (MIPI-CSIS) devices. + + To compile this driver as a module, choose M here: the + module will be called s5p-csis. + +if SOC_EXYNOS4212 || SOC_EXYNOS4412 || SOC_EXYNOS5250 + +config VIDEO_EXYNOS_FIMC_LITE + tristate "EXYNOS FIMC-LITE camera interface driver" + depends on I2C + select VIDEOBUF2_DMA_CONTIG + help + This is a V4L2 driver for Samsung EXYNOS4/5 SoC FIMC-LITE camera + host interface. + + To compile this driver as a module, choose M here: the + module will be called exynos-fimc-lite. +endif + +endif # VIDEO_SAMSUNG_S5P_FIMC diff --git a/drivers/media/platform/exynos4-is/Makefile b/drivers/media/platform/exynos4-is/Makefile new file mode 100644 index 000000000000..8c67441558f7 --- /dev/null +++ b/drivers/media/platform/exynos4-is/Makefile @@ -0,0 +1,7 @@ +s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-m2m.o fimc-capture.o media-dev.o +exynos-fimc-lite-objs += fimc-lite-reg.o fimc-lite.o +s5p-csis-objs := mipi-csis.o + +obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS) += s5p-csis.o +obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE) += exynos-fimc-lite.o +obj-$(CONFIG_VIDEO_S5P_FIMC) += s5p-fimc.o diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c new file mode 100644 index 000000000000..965b07f36e3c --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -0,0 +1,1887 @@ +/* + * Samsung S5P/EXYNOS4 SoC series camera interface (camera capture) driver + * + * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "media-dev.h" +#include "fimc-core.h" +#include "fimc-reg.h" + +static int fimc_capture_hw_init(struct fimc_dev *fimc) +{ + struct fimc_source_info *si = &fimc->vid_cap.source_config; + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + int ret; + unsigned long flags; + + if (ctx == NULL || ctx->s_frame.fmt == NULL) + return -EINVAL; + + if (si->fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) { + ret = fimc_hw_camblk_cfg_writeback(fimc); + if (ret < 0) + return ret; + } + + spin_lock_irqsave(&fimc->slock, flags); + fimc_prepare_dma_offset(ctx, &ctx->d_frame); + fimc_set_yuv_order(ctx); + + fimc_hw_set_camera_polarity(fimc, si); + fimc_hw_set_camera_type(fimc, si); + fimc_hw_set_camera_source(fimc, si); + fimc_hw_set_camera_offset(fimc, &ctx->s_frame); + + ret = fimc_set_scaler_info(ctx); + if (!ret) { + fimc_hw_set_input_path(ctx); + fimc_hw_set_prescaler(ctx); + fimc_hw_set_mainscaler(ctx); + fimc_hw_set_target_format(ctx); + fimc_hw_set_rotation(ctx); + fimc_hw_set_effect(ctx); + fimc_hw_set_output_path(ctx); + fimc_hw_set_out_dma(ctx); + if (fimc->drv_data->alpha_color) + fimc_hw_set_rgb_alpha(ctx); + clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); + } + spin_unlock_irqrestore(&fimc->slock, flags); + return ret; +} + +/* + * Reinitialize the driver so it is ready to start the streaming again. + * Set fimc->state to indicate stream off and the hardware shut down state. + * If not suspending (@suspend is false), return any buffers to videobuf2. + * Otherwise put any owned buffers onto the pending buffers queue, so they + * can be re-spun when the device is being resumed. Also perform FIMC + * software reset and disable streaming on the whole pipeline if required. + */ +static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend) +{ + struct fimc_vid_cap *cap = &fimc->vid_cap; + struct fimc_vid_buffer *buf; + unsigned long flags; + bool streaming; + + spin_lock_irqsave(&fimc->slock, flags); + streaming = fimc->state & (1 << ST_CAPT_ISP_STREAM); + + fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_SHUT | + 1 << ST_CAPT_STREAM | 1 << ST_CAPT_ISP_STREAM); + if (suspend) + fimc->state |= (1 << ST_CAPT_SUSPENDED); + else + fimc->state &= ~(1 << ST_CAPT_PEND | 1 << ST_CAPT_SUSPENDED); + + /* Release unused buffers */ + while (!suspend && !list_empty(&cap->pending_buf_q)) { + buf = fimc_pending_queue_pop(cap); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + /* If suspending put unused buffers onto pending queue */ + while (!list_empty(&cap->active_buf_q)) { + buf = fimc_active_queue_pop(cap); + if (suspend) + fimc_pending_queue_add(cap, buf); + else + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + + fimc_hw_reset(fimc); + cap->buf_index = 0; + + spin_unlock_irqrestore(&fimc->slock, flags); + + if (streaming) + return fimc_pipeline_call(fimc, set_stream, + &fimc->pipeline, 0); + else + return 0; +} + +static int fimc_stop_capture(struct fimc_dev *fimc, bool suspend) +{ + unsigned long flags; + + if (!fimc_capture_active(fimc)) + return 0; + + spin_lock_irqsave(&fimc->slock, flags); + set_bit(ST_CAPT_SHUT, &fimc->state); + fimc_deactivate_capture(fimc); + spin_unlock_irqrestore(&fimc->slock, flags); + + wait_event_timeout(fimc->irq_queue, + !test_bit(ST_CAPT_SHUT, &fimc->state), + (2*HZ/10)); /* 200 ms */ + + return fimc_capture_state_cleanup(fimc, suspend); +} + +/** + * fimc_capture_config_update - apply the camera interface configuration + * + * To be called from within the interrupt handler with fimc.slock + * spinlock held. It updates the camera pixel crop, rotation and + * image flip in H/W. + */ +static int fimc_capture_config_update(struct fimc_ctx *ctx) +{ + struct fimc_dev *fimc = ctx->fimc_dev; + int ret; + + fimc_hw_set_camera_offset(fimc, &ctx->s_frame); + + ret = fimc_set_scaler_info(ctx); + if (ret) + return ret; + + fimc_hw_set_prescaler(ctx); + fimc_hw_set_mainscaler(ctx); + fimc_hw_set_target_format(ctx); + fimc_hw_set_rotation(ctx); + fimc_hw_set_effect(ctx); + fimc_prepare_dma_offset(ctx, &ctx->d_frame); + fimc_hw_set_out_dma(ctx); + if (fimc->drv_data->alpha_color) + fimc_hw_set_rgb_alpha(ctx); + + clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); + return ret; +} + +void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) +{ + struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS]; + struct fimc_vid_cap *cap = &fimc->vid_cap; + struct fimc_frame *f = &cap->ctx->d_frame; + struct fimc_vid_buffer *v_buf; + struct timeval *tv; + struct timespec ts; + + if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) { + wake_up(&fimc->irq_queue); + goto done; + } + + if (!list_empty(&cap->active_buf_q) && + test_bit(ST_CAPT_RUN, &fimc->state) && deq_buf) { + ktime_get_real_ts(&ts); + + v_buf = fimc_active_queue_pop(cap); + + tv = &v_buf->vb.v4l2_buf.timestamp; + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; + v_buf->vb.v4l2_buf.sequence = cap->frame_count++; + + vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); + } + + if (!list_empty(&cap->pending_buf_q)) { + + v_buf = fimc_pending_queue_pop(cap); + fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index); + v_buf->index = cap->buf_index; + + /* Move the buffer to the capture active queue */ + fimc_active_queue_add(cap, v_buf); + + dbg("next frame: %d, done frame: %d", + fimc_hw_get_frame_index(fimc), v_buf->index); + + if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) + cap->buf_index = 0; + } + /* + * Set up a buffer at MIPI-CSIS if current image format + * requires the frame embedded data capture. + */ + if (f->fmt->mdataplanes && !list_empty(&cap->active_buf_q)) { + unsigned int plane = ffs(f->fmt->mdataplanes) - 1; + unsigned int size = f->payload[plane]; + s32 index = fimc_hw_get_frame_index(fimc); + void *vaddr; + + list_for_each_entry(v_buf, &cap->active_buf_q, list) { + if (v_buf->index != index) + continue; + vaddr = vb2_plane_vaddr(&v_buf->vb, plane); + v4l2_subdev_call(csis, video, s_rx_buffer, + vaddr, &size); + break; + } + } + + if (cap->active_buf_cnt == 0) { + if (deq_buf) + clear_bit(ST_CAPT_RUN, &fimc->state); + + if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) + cap->buf_index = 0; + } else { + set_bit(ST_CAPT_RUN, &fimc->state); + } + + if (test_bit(ST_CAPT_APPLY_CFG, &fimc->state)) + fimc_capture_config_update(cap->ctx); +done: + if (cap->active_buf_cnt == 1) { + fimc_deactivate_capture(fimc); + clear_bit(ST_CAPT_STREAM, &fimc->state); + } + + dbg("frame: %d, active_buf_cnt: %d", + fimc_hw_get_frame_index(fimc), cap->active_buf_cnt); +} + + +static int start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct fimc_ctx *ctx = q->drv_priv; + struct fimc_dev *fimc = ctx->fimc_dev; + struct fimc_vid_cap *vid_cap = &fimc->vid_cap; + int min_bufs; + int ret; + + vid_cap->frame_count = 0; + + ret = fimc_capture_hw_init(fimc); + if (ret) { + fimc_capture_state_cleanup(fimc, false); + return ret; + } + + set_bit(ST_CAPT_PEND, &fimc->state); + + min_bufs = fimc->vid_cap.reqbufs_count > 1 ? 2 : 1; + + if (vid_cap->active_buf_cnt >= min_bufs && + !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) { + fimc_activate_capture(ctx); + + if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) + return fimc_pipeline_call(fimc, set_stream, + &fimc->pipeline, 1); + } + + return 0; +} + +static int stop_streaming(struct vb2_queue *q) +{ + struct fimc_ctx *ctx = q->drv_priv; + struct fimc_dev *fimc = ctx->fimc_dev; + + if (!fimc_capture_active(fimc)) + return -EINVAL; + + return fimc_stop_capture(fimc, false); +} + +int fimc_capture_suspend(struct fimc_dev *fimc) +{ + bool suspend = fimc_capture_busy(fimc); + + int ret = fimc_stop_capture(fimc, suspend); + if (ret) + return ret; + return fimc_pipeline_call(fimc, close, &fimc->pipeline); +} + +static void buffer_queue(struct vb2_buffer *vb); + +int fimc_capture_resume(struct fimc_dev *fimc) +{ + struct fimc_vid_cap *vid_cap = &fimc->vid_cap; + struct fimc_vid_buffer *buf; + int i; + + if (!test_and_clear_bit(ST_CAPT_SUSPENDED, &fimc->state)) + return 0; + + INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); + vid_cap->buf_index = 0; + fimc_pipeline_call(fimc, open, &fimc->pipeline, + &vid_cap->vfd.entity, false); + fimc_capture_hw_init(fimc); + + clear_bit(ST_CAPT_SUSPENDED, &fimc->state); + + for (i = 0; i < vid_cap->reqbufs_count; i++) { + if (list_empty(&vid_cap->pending_buf_q)) + break; + buf = fimc_pending_queue_pop(vid_cap); + buffer_queue(&buf->vb); + } + return 0; + +} + +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *allocators[]) +{ + const struct v4l2_pix_format_mplane *pixm = NULL; + struct fimc_ctx *ctx = vq->drv_priv; + struct fimc_frame *frame = &ctx->d_frame; + struct fimc_fmt *fmt = frame->fmt; + unsigned long wh; + int i; + + if (pfmt) { + pixm = &pfmt->fmt.pix_mp; + fmt = fimc_find_format(&pixm->pixelformat, NULL, + FMT_FLAGS_CAM | FMT_FLAGS_M2M, -1); + wh = pixm->width * pixm->height; + } else { + wh = frame->f_width * frame->f_height; + } + + if (fmt == NULL) + return -EINVAL; + + *num_planes = fmt->memplanes; + + for (i = 0; i < fmt->memplanes; i++) { + unsigned int size = (wh * fmt->depth[i]) / 8; + if (pixm) + sizes[i] = max(size, pixm->plane_fmt[i].sizeimage); + else if (fimc_fmt_is_user_defined(fmt->color)) + sizes[i] = frame->payload[i]; + else + sizes[i] = max_t(u32, size, frame->payload[i]); + + allocators[i] = ctx->fimc_dev->alloc_ctx; + } + + return 0; +} + +static int buffer_prepare(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct fimc_ctx *ctx = vq->drv_priv; + int i; + + if (ctx->d_frame.fmt == NULL) + return -EINVAL; + + for (i = 0; i < ctx->d_frame.fmt->memplanes; i++) { + unsigned long size = ctx->d_frame.payload[i]; + + if (vb2_plane_size(vb, i) < size) { + v4l2_err(&ctx->fimc_dev->vid_cap.vfd, + "User buffer too small (%ld < %ld)\n", + vb2_plane_size(vb, i), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, i, size); + } + + return 0; +} + +static void buffer_queue(struct vb2_buffer *vb) +{ + struct fimc_vid_buffer *buf + = container_of(vb, struct fimc_vid_buffer, vb); + struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct fimc_dev *fimc = ctx->fimc_dev; + struct fimc_vid_cap *vid_cap = &fimc->vid_cap; + unsigned long flags; + int min_bufs; + + spin_lock_irqsave(&fimc->slock, flags); + fimc_prepare_addr(ctx, &buf->vb, &ctx->d_frame, &buf->paddr); + + if (!test_bit(ST_CAPT_SUSPENDED, &fimc->state) && + !test_bit(ST_CAPT_STREAM, &fimc->state) && + vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) { + /* Setup the buffer directly for processing. */ + int buf_id = (vid_cap->reqbufs_count == 1) ? -1 : + vid_cap->buf_index; + + fimc_hw_set_output_addr(fimc, &buf->paddr, buf_id); + buf->index = vid_cap->buf_index; + fimc_active_queue_add(vid_cap, buf); + + if (++vid_cap->buf_index >= FIMC_MAX_OUT_BUFS) + vid_cap->buf_index = 0; + } else { + fimc_pending_queue_add(vid_cap, buf); + } + + min_bufs = vid_cap->reqbufs_count > 1 ? 2 : 1; + + + if (vb2_is_streaming(&vid_cap->vbq) && + vid_cap->active_buf_cnt >= min_bufs && + !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) { + int ret; + + fimc_activate_capture(ctx); + spin_unlock_irqrestore(&fimc->slock, flags); + + if (test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) + return; + + ret = fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 1); + if (ret < 0) + v4l2_err(&vid_cap->vfd, "stream on failed: %d\n", ret); + return; + } + spin_unlock_irqrestore(&fimc->slock, flags); +} + +static struct vb2_ops fimc_capture_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, +}; + +/** + * fimc_capture_ctrls_create - initialize the control handler + * Initialize the capture video node control handler and fill it + * with the FIMC controls. Inherit any sensor's controls if the + * 'user_subdev_api' flag is false (default behaviour). + * This function need to be called with the graph mutex held. + */ +int fimc_capture_ctrls_create(struct fimc_dev *fimc) +{ + struct fimc_vid_cap *vid_cap = &fimc->vid_cap; + struct v4l2_subdev *sensor = fimc->pipeline.subdevs[IDX_SENSOR]; + int ret; + + if (WARN_ON(vid_cap->ctx == NULL)) + return -ENXIO; + if (vid_cap->ctx->ctrls.ready) + return 0; + + ret = fimc_ctrls_create(vid_cap->ctx); + + if (ret || vid_cap->user_subdev_api || !sensor || + !vid_cap->ctx->ctrls.ready) + return ret; + + return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrls.handler, + sensor->ctrl_handler, NULL); +} + +static int fimc_capture_set_default_format(struct fimc_dev *fimc); + +static int fimc_capture_open(struct file *file) +{ + struct fimc_dev *fimc = video_drvdata(file); + int ret = -EBUSY; + + dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); + + fimc_md_graph_lock(fimc); + mutex_lock(&fimc->lock); + + if (fimc_m2m_active(fimc)) + goto unlock; + + set_bit(ST_CAPT_BUSY, &fimc->state); + ret = pm_runtime_get_sync(&fimc->pdev->dev); + if (ret < 0) + goto unlock; + + ret = v4l2_fh_open(file); + if (ret) { + pm_runtime_put(&fimc->pdev->dev); + goto unlock; + } + + if (v4l2_fh_is_singular_file(file)) { + ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, + &fimc->vid_cap.vfd.entity, true); + + if (!ret && !fimc->vid_cap.user_subdev_api) + ret = fimc_capture_set_default_format(fimc); + + if (!ret) + ret = fimc_capture_ctrls_create(fimc); + + if (ret < 0) { + clear_bit(ST_CAPT_BUSY, &fimc->state); + pm_runtime_put_sync(&fimc->pdev->dev); + v4l2_fh_release(file); + } else { + fimc->vid_cap.refcnt++; + } + } +unlock: + mutex_unlock(&fimc->lock); + fimc_md_graph_unlock(fimc); + return ret; +} + +static int fimc_capture_release(struct file *file) +{ + struct fimc_dev *fimc = video_drvdata(file); + int ret; + + dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); + + mutex_lock(&fimc->lock); + + if (v4l2_fh_is_singular_file(file)) { + clear_bit(ST_CAPT_BUSY, &fimc->state); + fimc_stop_capture(fimc, false); + fimc_pipeline_call(fimc, close, &fimc->pipeline); + clear_bit(ST_CAPT_SUSPENDED, &fimc->state); + fimc->vid_cap.refcnt--; + } + + pm_runtime_put(&fimc->pdev->dev); + + if (v4l2_fh_is_singular_file(file)) + fimc_ctrls_delete(fimc->vid_cap.ctx); + + ret = vb2_fop_release(file); + mutex_unlock(&fimc->lock); + + return ret; +} + +static const struct v4l2_file_operations fimc_capture_fops = { + .owner = THIS_MODULE, + .open = fimc_capture_open, + .release = fimc_capture_release, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +/* + * Format and crop negotiation helpers + */ + +static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, + u32 *width, u32 *height, + u32 *code, u32 *fourcc, int pad) +{ + bool rotation = ctx->rotation == 90 || ctx->rotation == 270; + struct fimc_dev *fimc = ctx->fimc_dev; + const struct fimc_variant *var = fimc->variant; + const struct fimc_pix_limit *pl = var->pix_limit; + struct fimc_frame *dst = &ctx->d_frame; + u32 depth, min_w, max_w, min_h, align_h = 3; + u32 mask = FMT_FLAGS_CAM; + struct fimc_fmt *ffmt; + + /* Conversion from/to JPEG or User Defined format is not supported */ + if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE && + fimc_fmt_is_user_defined(ctx->s_frame.fmt->color)) + *code = ctx->s_frame.fmt->mbus_code; + + if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad == FIMC_SD_PAD_SOURCE) + mask |= FMT_FLAGS_M2M; + + if (pad == FIMC_SD_PAD_SINK_FIFO) + mask = FMT_FLAGS_WRITEBACK; + + ffmt = fimc_find_format(fourcc, code, mask, 0); + if (WARN_ON(!ffmt)) + return NULL; + + if (code) + *code = ffmt->mbus_code; + if (fourcc) + *fourcc = ffmt->fourcc; + + if (pad != FIMC_SD_PAD_SOURCE) { + max_w = fimc_fmt_is_user_defined(ffmt->color) ? + pl->scaler_dis_w : pl->scaler_en_w; + /* Apply the camera input interface pixel constraints */ + v4l_bound_align_image(width, max_t(u32, *width, 32), max_w, 4, + height, max_t(u32, *height, 32), + FIMC_CAMIF_MAX_HEIGHT, + fimc_fmt_is_user_defined(ffmt->color) ? + 3 : 1, + 0); + return ffmt; + } + /* Can't scale or crop in transparent (JPEG) transfer mode */ + if (fimc_fmt_is_user_defined(ffmt->color)) { + *width = ctx->s_frame.f_width; + *height = ctx->s_frame.f_height; + return ffmt; + } + /* Apply the scaler and the output DMA constraints */ + max_w = rotation ? pl->out_rot_en_w : pl->out_rot_dis_w; + if (ctx->state & FIMC_COMPOSE) { + min_w = dst->offs_h + dst->width; + min_h = dst->offs_v + dst->height; + } else { + min_w = var->min_out_pixsize; + min_h = var->min_out_pixsize; + } + if (var->min_vsize_align == 1 && !rotation) + align_h = fimc_fmt_is_rgb(ffmt->color) ? 0 : 1; + + depth = fimc_get_format_depth(ffmt); + v4l_bound_align_image(width, min_w, max_w, + ffs(var->min_out_pixsize) - 1, + height, min_h, FIMC_CAMIF_MAX_HEIGHT, + align_h, + 64/(ALIGN(depth, 8))); + + dbg("pad%d: code: 0x%x, %dx%d. dst fmt: %dx%d", + pad, code ? *code : 0, *width, *height, + dst->f_width, dst->f_height); + + return ffmt; +} + +static void fimc_capture_try_selection(struct fimc_ctx *ctx, + struct v4l2_rect *r, + int target) +{ + bool rotate = ctx->rotation == 90 || ctx->rotation == 270; + struct fimc_dev *fimc = ctx->fimc_dev; + const struct fimc_variant *var = fimc->variant; + const struct fimc_pix_limit *pl = var->pix_limit; + struct fimc_frame *sink = &ctx->s_frame; + u32 max_w, max_h, min_w = 0, min_h = 0, min_sz; + u32 align_sz = 0, align_h = 4; + u32 max_sc_h, max_sc_v; + + /* In JPEG transparent transfer mode cropping is not supported */ + if (fimc_fmt_is_user_defined(ctx->d_frame.fmt->color)) { + r->width = sink->f_width; + r->height = sink->f_height; + r->left = r->top = 0; + return; + } + if (target == V4L2_SEL_TGT_COMPOSE) { + if (ctx->rotation != 90 && ctx->rotation != 270) + align_h = 1; + max_sc_h = min(SCALER_MAX_HRATIO, 1 << (ffs(sink->width) - 3)); + max_sc_v = min(SCALER_MAX_VRATIO, 1 << (ffs(sink->height) - 1)); + min_sz = var->min_out_pixsize; + } else { + u32 depth = fimc_get_format_depth(sink->fmt); + align_sz = 64/ALIGN(depth, 8); + min_sz = var->min_inp_pixsize; + min_w = min_h = min_sz; + max_sc_h = max_sc_v = 1; + } + /* + * For the compose rectangle the following constraints must be met: + * - it must fit in the sink pad format rectangle (f_width/f_height); + * - maximum downscaling ratio is 64; + * - maximum crop size depends if the rotator is used or not; + * - the sink pad format width/height must be 4 multiple of the + * prescaler ratios determined by sink pad size and source pad crop, + * the prescaler ratio is returned by fimc_get_scaler_factor(). + */ + max_w = min_t(u32, + rotate ? pl->out_rot_en_w : pl->out_rot_dis_w, + rotate ? sink->f_height : sink->f_width); + max_h = min_t(u32, FIMC_CAMIF_MAX_HEIGHT, sink->f_height); + + if (target == V4L2_SEL_TGT_COMPOSE) { + min_w = min_t(u32, max_w, sink->f_width / max_sc_h); + min_h = min_t(u32, max_h, sink->f_height / max_sc_v); + if (rotate) { + swap(max_sc_h, max_sc_v); + swap(min_w, min_h); + } + } + v4l_bound_align_image(&r->width, min_w, max_w, ffs(min_sz) - 1, + &r->height, min_h, max_h, align_h, + align_sz); + /* Adjust left/top if crop/compose rectangle is out of bounds */ + r->left = clamp_t(u32, r->left, 0, sink->f_width - r->width); + r->top = clamp_t(u32, r->top, 0, sink->f_height - r->height); + r->left = round_down(r->left, var->hor_offs_align); + + dbg("target %#x: (%d,%d)/%dx%d, sink fmt: %dx%d", + target, r->left, r->top, r->width, r->height, + sink->f_width, sink->f_height); +} + +/* + * The video node ioctl operations + */ +static int fimc_vidioc_querycap_capture(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct fimc_dev *fimc = video_drvdata(file); + + strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1); + strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1); + cap->bus_info[0] = 0; + cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE; + + return 0; +} + +static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct fimc_fmt *fmt; + + fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM | FMT_FLAGS_M2M, + f->index); + if (!fmt) + return -EINVAL; + strncpy(f->description, fmt->name, sizeof(f->description) - 1); + f->pixelformat = fmt->fourcc; + if (fmt->fourcc == V4L2_MBUS_FMT_JPEG_1X8) + f->flags |= V4L2_FMT_FLAG_COMPRESSED; + return 0; +} + +static struct media_entity *fimc_pipeline_get_head(struct media_entity *me) +{ + struct media_pad *pad = &me->pads[0]; + + while (!(pad->flags & MEDIA_PAD_FL_SOURCE)) { + pad = media_entity_remote_source(pad); + if (!pad) + break; + me = pad->entity; + pad = &me->pads[0]; + } + + return me; +} + +/** + * fimc_pipeline_try_format - negotiate and/or set formats at pipeline + * elements + * @ctx: FIMC capture context + * @tfmt: media bus format to try/set on subdevs + * @fmt_id: fimc pixel format id corresponding to returned @tfmt (output) + * @set: true to set format on subdevs, false to try only + */ +static int fimc_pipeline_try_format(struct fimc_ctx *ctx, + struct v4l2_mbus_framefmt *tfmt, + struct fimc_fmt **fmt_id, + bool set) +{ + struct fimc_dev *fimc = ctx->fimc_dev; + struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR]; + struct v4l2_subdev_format sfmt; + struct v4l2_mbus_framefmt *mf = &sfmt.format; + struct media_entity *me; + struct fimc_fmt *ffmt; + struct media_pad *pad; + int ret, i = 1; + u32 fcc; + + if (WARN_ON(!sd || !tfmt)) + return -EINVAL; + + memset(&sfmt, 0, sizeof(sfmt)); + sfmt.format = *tfmt; + sfmt.which = set ? V4L2_SUBDEV_FORMAT_ACTIVE : V4L2_SUBDEV_FORMAT_TRY; + + me = fimc_pipeline_get_head(&sd->entity); + + while (1) { + ffmt = fimc_find_format(NULL, mf->code != 0 ? &mf->code : NULL, + FMT_FLAGS_CAM, i++); + if (ffmt == NULL) { + /* + * Notify user-space if common pixel code for + * host and sensor does not exist. + */ + return -EINVAL; + } + mf->code = tfmt->code = ffmt->mbus_code; + + /* set format on all pipeline subdevs */ + while (me != &fimc->vid_cap.subdev.entity) { + sd = media_entity_to_v4l2_subdev(me); + + sfmt.pad = 0; + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sfmt); + if (ret) + return ret; + + if (me->pads[0].flags & MEDIA_PAD_FL_SINK) { + sfmt.pad = me->num_pads - 1; + mf->code = tfmt->code; + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, + &sfmt); + if (ret) + return ret; + } + + pad = media_entity_remote_source(&me->pads[sfmt.pad]); + if (!pad) + return -EINVAL; + me = pad->entity; + } + + if (mf->code != tfmt->code) + continue; + + fcc = ffmt->fourcc; + tfmt->width = mf->width; + tfmt->height = mf->height; + ffmt = fimc_capture_try_format(ctx, &tfmt->width, &tfmt->height, + NULL, &fcc, FIMC_SD_PAD_SINK_CAM); + ffmt = fimc_capture_try_format(ctx, &tfmt->width, &tfmt->height, + NULL, &fcc, FIMC_SD_PAD_SOURCE); + if (ffmt && ffmt->mbus_code) + mf->code = ffmt->mbus_code; + if (mf->width != tfmt->width || mf->height != tfmt->height) + continue; + tfmt->code = mf->code; + break; + } + + if (fmt_id && ffmt) + *fmt_id = ffmt; + *tfmt = *mf; + + return 0; +} + +/** + * fimc_get_sensor_frame_desc - query the sensor for media bus frame parameters + * @sensor: pointer to the sensor subdev + * @plane_fmt: provides plane sizes corresponding to the frame layout entries + * @try: true to set the frame parameters, false to query only + * + * This function is used by this driver only for compressed/blob data formats. + */ +static int fimc_get_sensor_frame_desc(struct v4l2_subdev *sensor, + struct v4l2_plane_pix_format *plane_fmt, + unsigned int num_planes, bool try) +{ + struct v4l2_mbus_frame_desc fd; + int i, ret; + int pad; + + for (i = 0; i < num_planes; i++) + fd.entry[i].length = plane_fmt[i].sizeimage; + + pad = sensor->entity.num_pads - 1; + if (try) + ret = v4l2_subdev_call(sensor, pad, set_frame_desc, pad, &fd); + else + ret = v4l2_subdev_call(sensor, pad, get_frame_desc, pad, &fd); + + if (ret < 0) + return ret; + + if (num_planes != fd.num_entries) + return -EINVAL; + + for (i = 0; i < num_planes; i++) + plane_fmt[i].sizeimage = fd.entry[i].length; + + if (fd.entry[0].length > FIMC_MAX_JPEG_BUF_SIZE) { + v4l2_err(sensor->v4l2_dev, "Unsupported buffer size: %u\n", + fd.entry[0].length); + + return -EINVAL; + } + + return 0; +} + +static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct fimc_dev *fimc = video_drvdata(file); + + __fimc_get_format(&fimc->vid_cap.ctx->d_frame, f); + return 0; +} + +static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct v4l2_mbus_framefmt mf; + struct fimc_fmt *ffmt = NULL; + int ret = 0; + + fimc_md_graph_lock(fimc); + mutex_lock(&fimc->lock); + + if (fimc_jpeg_fourcc(pix->pixelformat)) { + fimc_capture_try_format(ctx, &pix->width, &pix->height, + NULL, &pix->pixelformat, + FIMC_SD_PAD_SINK_CAM); + ctx->s_frame.f_width = pix->width; + ctx->s_frame.f_height = pix->height; + } + ffmt = fimc_capture_try_format(ctx, &pix->width, &pix->height, + NULL, &pix->pixelformat, + FIMC_SD_PAD_SOURCE); + if (!ffmt) { + ret = -EINVAL; + goto unlock; + } + + if (!fimc->vid_cap.user_subdev_api) { + mf.width = pix->width; + mf.height = pix->height; + mf.code = ffmt->mbus_code; + fimc_pipeline_try_format(ctx, &mf, &ffmt, false); + pix->width = mf.width; + pix->height = mf.height; + if (ffmt) + pix->pixelformat = ffmt->fourcc; + } + + fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix); + + if (ffmt->flags & FMT_FLAGS_COMPRESSED) + fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], + pix->plane_fmt, ffmt->memplanes, true); +unlock: + mutex_unlock(&fimc->lock); + fimc_md_graph_unlock(fimc); + + return ret; +} + +static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, + enum fimc_color_fmt color) +{ + bool jpeg = fimc_fmt_is_user_defined(color); + + ctx->scaler.enabled = !jpeg; + fimc_ctrls_activate(ctx, !jpeg); + + if (jpeg) + set_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state); + else + clear_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state); +} + +static int __fimc_capture_set_format(struct fimc_dev *fimc, + struct v4l2_format *f) +{ + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; + struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.ci_fmt; + struct fimc_frame *ff = &ctx->d_frame; + struct fimc_fmt *s_fmt = NULL; + int ret, i; + + if (vb2_is_busy(&fimc->vid_cap.vbq)) + return -EBUSY; + + /* Pre-configure format at camera interface input, for JPEG only */ + if (fimc_jpeg_fourcc(pix->pixelformat)) { + fimc_capture_try_format(ctx, &pix->width, &pix->height, + NULL, &pix->pixelformat, + FIMC_SD_PAD_SINK_CAM); + ctx->s_frame.f_width = pix->width; + ctx->s_frame.f_height = pix->height; + } + /* Try the format at the scaler and the DMA output */ + ff->fmt = fimc_capture_try_format(ctx, &pix->width, &pix->height, + NULL, &pix->pixelformat, + FIMC_SD_PAD_SOURCE); + if (!ff->fmt) + return -EINVAL; + + /* Update RGB Alpha control state and value range */ + fimc_alpha_ctrl_update(ctx); + + /* Try to match format at the host and the sensor */ + if (!fimc->vid_cap.user_subdev_api) { + mf->code = ff->fmt->mbus_code; + mf->width = pix->width; + mf->height = pix->height; + ret = fimc_pipeline_try_format(ctx, mf, &s_fmt, true); + if (ret) + return ret; + + pix->width = mf->width; + pix->height = mf->height; + } + + fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix); + + if (ff->fmt->flags & FMT_FLAGS_COMPRESSED) { + ret = fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], + pix->plane_fmt, ff->fmt->memplanes, + true); + if (ret < 0) + return ret; + } + + for (i = 0; i < ff->fmt->memplanes; i++) { + ff->bytesperline[i] = pix->plane_fmt[i].bytesperline; + ff->payload[i] = pix->plane_fmt[i].sizeimage; + } + + set_frame_bounds(ff, pix->width, pix->height); + /* Reset the composition rectangle if not yet configured */ + if (!(ctx->state & FIMC_COMPOSE)) + set_frame_crop(ff, 0, 0, pix->width, pix->height); + + fimc_capture_mark_jpeg_xfer(ctx, ff->fmt->color); + + /* Reset cropping and set format at the camera interface input */ + if (!fimc->vid_cap.user_subdev_api) { + ctx->s_frame.fmt = s_fmt; + set_frame_bounds(&ctx->s_frame, pix->width, pix->height); + set_frame_crop(&ctx->s_frame, 0, 0, pix->width, pix->height); + } + + return ret; +} + +static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct fimc_dev *fimc = video_drvdata(file); + int ret; + + fimc_md_graph_lock(fimc); + mutex_lock(&fimc->lock); + /* + * The graph is walked within __fimc_capture_set_format() to set + * the format at subdevs thus the graph mutex needs to be held at + * this point and acquired before the video mutex, to avoid AB-BA + * deadlock when fimc_md_link_notify() is called by other thread. + * Ideally the graph walking and setting format at the whole pipeline + * should be removed from this driver and handled in userspace only. + */ + ret = __fimc_capture_set_format(fimc, f); + + mutex_unlock(&fimc->lock); + fimc_md_graph_unlock(fimc); + return ret; +} + +static int fimc_cap_enum_input(struct file *file, void *priv, + struct v4l2_input *i) +{ + struct fimc_dev *fimc = video_drvdata(file); + struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR]; + + if (i->index != 0) + return -EINVAL; + + i->type = V4L2_INPUT_TYPE_CAMERA; + if (sd) + strlcpy(i->name, sd->name, sizeof(i->name)); + return 0; +} + +static int fimc_cap_s_input(struct file *file, void *priv, unsigned int i) +{ + return i == 0 ? i : -EINVAL; +} + +static int fimc_cap_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +/** + * fimc_pipeline_validate - check for formats inconsistencies + * between source and sink pad of each link + * + * Return 0 if all formats match or -EPIPE otherwise. + */ +static int fimc_pipeline_validate(struct fimc_dev *fimc) +{ + struct v4l2_subdev_format sink_fmt, src_fmt; + struct fimc_vid_cap *vc = &fimc->vid_cap; + struct v4l2_subdev *sd = &vc->subdev; + struct media_pad *sink_pad, *src_pad; + int i, ret; + + while (1) { + /* + * Find current entity sink pad and any remote sink pad linked + * to it. We stop if there is no sink pad in current entity or + * it is not linked to any other remote entity. + */ + src_pad = NULL; + + for (i = 0; i < sd->entity.num_pads; i++) { + struct media_pad *p = &sd->entity.pads[i]; + + if (p->flags & MEDIA_PAD_FL_SINK) { + sink_pad = p; + src_pad = media_entity_remote_source(sink_pad); + if (src_pad) + break; + } + } + + if (src_pad == NULL || + media_entity_type(src_pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + /* Don't call FIMC subdev operation to avoid nested locking */ + if (sd == &vc->subdev) { + struct fimc_frame *ff = &vc->ctx->s_frame; + sink_fmt.format.width = ff->f_width; + sink_fmt.format.height = ff->f_height; + sink_fmt.format.code = ff->fmt ? ff->fmt->mbus_code : 0; + } else { + sink_fmt.pad = sink_pad->index; + sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt); + if (ret < 0 && ret != -ENOIOCTLCMD) + return -EPIPE; + } + + /* Retrieve format at the source pad */ + sd = media_entity_to_v4l2_subdev(src_pad->entity); + src_fmt.pad = src_pad->index; + src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt); + if (ret < 0 && ret != -ENOIOCTLCMD) + return -EPIPE; + + if (src_fmt.format.width != sink_fmt.format.width || + src_fmt.format.height != sink_fmt.format.height || + src_fmt.format.code != sink_fmt.format.code) + return -EPIPE; + + if (sd == fimc->pipeline.subdevs[IDX_SENSOR] && + fimc_user_defined_mbus_fmt(src_fmt.format.code)) { + struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES]; + struct fimc_frame *frame = &vc->ctx->d_frame; + unsigned int i; + + ret = fimc_get_sensor_frame_desc(sd, plane_fmt, + frame->fmt->memplanes, + false); + if (ret < 0) + return -EPIPE; + + for (i = 0; i < frame->fmt->memplanes; i++) + if (frame->payload[i] < plane_fmt[i].sizeimage) + return -EPIPE; + } + } + return 0; +} + +static int fimc_cap_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_pipeline *p = &fimc->pipeline; + struct fimc_vid_cap *vc = &fimc->vid_cap; + struct media_entity *entity = &vc->vfd.entity; + struct fimc_source_info *si = NULL; + struct v4l2_subdev *sd; + int ret; + + if (fimc_capture_active(fimc)) + return -EBUSY; + + ret = media_entity_pipeline_start(entity, p->m_pipeline); + if (ret < 0) + return ret; + + sd = p->subdevs[IDX_SENSOR]; + if (sd) + si = v4l2_get_subdev_hostdata(sd); + + if (si == NULL) { + ret = -EPIPE; + goto err_p_stop; + } + /* + * Save configuration data related to currently attached image + * sensor or other data source, e.g. FIMC-IS. + */ + vc->source_config = *si; + + if (vc->input == GRP_ID_FIMC_IS) + vc->source_config.fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK; + + if (vc->user_subdev_api) { + ret = fimc_pipeline_validate(fimc); + if (ret < 0) + goto err_p_stop; + } + + ret = vb2_ioctl_streamon(file, priv, type); + if (!ret) + return ret; + +err_p_stop: + media_entity_pipeline_stop(entity); + return ret; +} + +static int fimc_cap_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct fimc_dev *fimc = video_drvdata(file); + int ret; + + ret = vb2_ioctl_streamoff(file, priv, type); + + if (ret == 0) + media_entity_pipeline_stop(&fimc->vid_cap.vfd.entity); + + return ret; +} + +static int fimc_cap_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) +{ + struct fimc_dev *fimc = video_drvdata(file); + int ret; + + ret = vb2_ioctl_reqbufs(file, priv, reqbufs); + + if (!ret) + fimc->vid_cap.reqbufs_count = reqbufs->count; + + return ret; +} + +static int fimc_cap_g_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct fimc_frame *f = &ctx->s_frame; + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + f = &ctx->d_frame; + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + s->r.left = 0; + s->r.top = 0; + s->r.width = f->o_width; + s->r.height = f->o_height; + return 0; + + case V4L2_SEL_TGT_COMPOSE: + f = &ctx->d_frame; + case V4L2_SEL_TGT_CROP: + s->r.left = f->offs_h; + s->r.top = f->offs_v; + s->r.width = f->width; + s->r.height = f->height; + return 0; + } + + return -EINVAL; +} + +/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ +static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) +{ + if (a->left < b->left || a->top < b->top) + return 0; + if (a->left + a->width > b->left + b->width) + return 0; + if (a->top + a->height > b->top + b->height) + return 0; + + return 1; +} + +static int fimc_cap_s_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct v4l2_rect rect = s->r; + struct fimc_frame *f; + unsigned long flags; + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + if (s->target == V4L2_SEL_TGT_COMPOSE) + f = &ctx->d_frame; + else if (s->target == V4L2_SEL_TGT_CROP) + f = &ctx->s_frame; + else + return -EINVAL; + + fimc_capture_try_selection(ctx, &rect, s->target); + + if (s->flags & V4L2_SEL_FLAG_LE && + !enclosed_rectangle(&rect, &s->r)) + return -ERANGE; + + if (s->flags & V4L2_SEL_FLAG_GE && + !enclosed_rectangle(&s->r, &rect)) + return -ERANGE; + + s->r = rect; + spin_lock_irqsave(&fimc->slock, flags); + set_frame_crop(f, s->r.left, s->r.top, s->r.width, + s->r.height); + spin_unlock_irqrestore(&fimc->slock, flags); + + set_bit(ST_CAPT_APPLY_CFG, &fimc->state); + return 0; +} + +static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { + .vidioc_querycap = fimc_vidioc_querycap_capture, + + .vidioc_enum_fmt_vid_cap_mplane = fimc_cap_enum_fmt_mplane, + .vidioc_try_fmt_vid_cap_mplane = fimc_cap_try_fmt_mplane, + .vidioc_s_fmt_vid_cap_mplane = fimc_cap_s_fmt_mplane, + .vidioc_g_fmt_vid_cap_mplane = fimc_cap_g_fmt_mplane, + + .vidioc_reqbufs = fimc_cap_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + + .vidioc_streamon = fimc_cap_streamon, + .vidioc_streamoff = fimc_cap_streamoff, + + .vidioc_g_selection = fimc_cap_g_selection, + .vidioc_s_selection = fimc_cap_s_selection, + + .vidioc_enum_input = fimc_cap_enum_input, + .vidioc_s_input = fimc_cap_s_input, + .vidioc_g_input = fimc_cap_g_input, +}; + +/* Capture subdev media entity operations */ +static int fimc_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct fimc_dev *fimc = v4l2_get_subdevdata(sd); + + if (media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + return -EINVAL; + + if (WARN_ON(fimc == NULL)) + return 0; + + dbg("%s --> %s, flags: 0x%x. input: 0x%x", + local->entity->name, remote->entity->name, flags, + fimc->vid_cap.input); + + if (flags & MEDIA_LNK_FL_ENABLED) { + if (fimc->vid_cap.input != 0) + return -EBUSY; + fimc->vid_cap.input = sd->grp_id; + return 0; + } + + fimc->vid_cap.input = 0; + return 0; +} + +static const struct media_entity_operations fimc_sd_media_ops = { + .link_setup = fimc_link_setup, +}; + +/** + * fimc_sensor_notify - v4l2_device notification from a sensor subdev + * @sd: pointer to a subdev generating the notification + * @notification: the notification type, must be S5P_FIMC_TX_END_NOTIFY + * @arg: pointer to an u32 type integer that stores the frame payload value + * + * The End Of Frame notification sent by sensor subdev in its still capture + * mode. If there is only a single VSYNC generated by the sensor at the + * beginning of a frame transmission, FIMC does not issue the LastIrq + * (end of frame) interrupt. And this notification is used to complete the + * frame capture and returning a buffer to user-space. Subdev drivers should + * call this notification from their last 'End of frame capture' interrupt. + */ +void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification, + void *arg) +{ + struct fimc_sensor_info *sensor; + struct fimc_vid_buffer *buf; + struct fimc_md *fmd; + struct fimc_dev *fimc; + unsigned long flags; + + if (sd == NULL) + return; + + sensor = v4l2_get_subdev_hostdata(sd); + fmd = entity_to_fimc_mdev(&sd->entity); + + spin_lock_irqsave(&fmd->slock, flags); + fimc = sensor ? sensor->host : NULL; + + if (fimc && arg && notification == S5P_FIMC_TX_END_NOTIFY && + test_bit(ST_CAPT_PEND, &fimc->state)) { + unsigned long irq_flags; + spin_lock_irqsave(&fimc->slock, irq_flags); + if (!list_empty(&fimc->vid_cap.active_buf_q)) { + buf = list_entry(fimc->vid_cap.active_buf_q.next, + struct fimc_vid_buffer, list); + vb2_set_plane_payload(&buf->vb, 0, *((u32 *)arg)); + } + fimc_capture_irq_handler(fimc, 1); + fimc_deactivate_capture(fimc); + spin_unlock_irqrestore(&fimc->slock, irq_flags); + } + spin_unlock_irqrestore(&fmd->slock, flags); +} + +static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct fimc_fmt *fmt; + + fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, code->index); + if (!fmt) + return -EINVAL; + code->code = fmt->mbus_code; + return 0; +} + +static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct fimc_dev *fimc = v4l2_get_subdevdata(sd); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct fimc_frame *ff = &ctx->s_frame; + struct v4l2_mbus_framefmt *mf; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(fh, fmt->pad); + fmt->format = *mf; + return 0; + } + + mf = &fmt->format; + mutex_lock(&fimc->lock); + + switch (fmt->pad) { + case FIMC_SD_PAD_SOURCE: + if (!WARN_ON(ff->fmt == NULL)) + mf->code = ff->fmt->mbus_code; + /* Sink pads crop rectangle size */ + mf->width = ff->width; + mf->height = ff->height; + break; + case FIMC_SD_PAD_SINK_FIFO: + *mf = fimc->vid_cap.wb_fmt; + break; + case FIMC_SD_PAD_SINK_CAM: + default: + *mf = fimc->vid_cap.ci_fmt; + break; + } + + mutex_unlock(&fimc->lock); + mf->colorspace = V4L2_COLORSPACE_JPEG; + + return 0; +} + +static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct fimc_dev *fimc = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf = &fmt->format; + struct fimc_vid_cap *vc = &fimc->vid_cap; + struct fimc_ctx *ctx = vc->ctx; + struct fimc_frame *ff; + struct fimc_fmt *ffmt; + + dbg("pad%d: code: 0x%x, %dx%d", + fmt->pad, mf->code, mf->width, mf->height); + + if (fmt->pad == FIMC_SD_PAD_SOURCE && vb2_is_busy(&vc->vbq)) + return -EBUSY; + + mutex_lock(&fimc->lock); + ffmt = fimc_capture_try_format(ctx, &mf->width, &mf->height, + &mf->code, NULL, fmt->pad); + mutex_unlock(&fimc->lock); + mf->colorspace = V4L2_COLORSPACE_JPEG; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(fh, fmt->pad); + *mf = fmt->format; + return 0; + } + /* There must be a bug in the driver if this happens */ + if (WARN_ON(ffmt == NULL)) + return -EINVAL; + + /* Update RGB Alpha control state and value range */ + fimc_alpha_ctrl_update(ctx); + + fimc_capture_mark_jpeg_xfer(ctx, ffmt->color); + if (fmt->pad == FIMC_SD_PAD_SOURCE) { + ff = &ctx->d_frame; + /* Sink pads crop rectangle size */ + mf->width = ctx->s_frame.width; + mf->height = ctx->s_frame.height; + } else { + ff = &ctx->s_frame; + } + + mutex_lock(&fimc->lock); + set_frame_bounds(ff, mf->width, mf->height); + + if (fmt->pad == FIMC_SD_PAD_SINK_FIFO) + vc->wb_fmt = *mf; + else if (fmt->pad == FIMC_SD_PAD_SINK_CAM) + vc->ci_fmt = *mf; + + ff->fmt = ffmt; + + /* Reset the crop rectangle if required. */ + if (!(fmt->pad == FIMC_SD_PAD_SOURCE && (ctx->state & FIMC_COMPOSE))) + set_frame_crop(ff, 0, 0, mf->width, mf->height); + + if (fmt->pad != FIMC_SD_PAD_SOURCE) + ctx->state &= ~FIMC_COMPOSE; + + mutex_unlock(&fimc->lock); + return 0; +} + +static int fimc_subdev_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) +{ + struct fimc_dev *fimc = v4l2_get_subdevdata(sd); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct fimc_frame *f = &ctx->s_frame; + struct v4l2_rect *r = &sel->r; + struct v4l2_rect *try_sel; + + if (sel->pad == FIMC_SD_PAD_SOURCE) + return -EINVAL; + + mutex_lock(&fimc->lock); + + switch (sel->target) { + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + f = &ctx->d_frame; + case V4L2_SEL_TGT_CROP_BOUNDS: + r->width = f->o_width; + r->height = f->o_height; + r->left = 0; + r->top = 0; + mutex_unlock(&fimc->lock); + return 0; + + case V4L2_SEL_TGT_CROP: + try_sel = v4l2_subdev_get_try_crop(fh, sel->pad); + break; + case V4L2_SEL_TGT_COMPOSE: + try_sel = v4l2_subdev_get_try_compose(fh, sel->pad); + f = &ctx->d_frame; + break; + default: + mutex_unlock(&fimc->lock); + return -EINVAL; + } + + if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { + sel->r = *try_sel; + } else { + r->left = f->offs_h; + r->top = f->offs_v; + r->width = f->width; + r->height = f->height; + } + + dbg("target %#x: l:%d, t:%d, %dx%d, f_w: %d, f_h: %d", + sel->pad, r->left, r->top, r->width, r->height, + f->f_width, f->f_height); + + mutex_unlock(&fimc->lock); + return 0; +} + +static int fimc_subdev_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) +{ + struct fimc_dev *fimc = v4l2_get_subdevdata(sd); + struct fimc_ctx *ctx = fimc->vid_cap.ctx; + struct fimc_frame *f = &ctx->s_frame; + struct v4l2_rect *r = &sel->r; + struct v4l2_rect *try_sel; + unsigned long flags; + + if (sel->pad == FIMC_SD_PAD_SOURCE) + return -EINVAL; + + mutex_lock(&fimc->lock); + fimc_capture_try_selection(ctx, r, V4L2_SEL_TGT_CROP); + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + try_sel = v4l2_subdev_get_try_crop(fh, sel->pad); + break; + case V4L2_SEL_TGT_COMPOSE: + try_sel = v4l2_subdev_get_try_compose(fh, sel->pad); + f = &ctx->d_frame; + break; + default: + mutex_unlock(&fimc->lock); + return -EINVAL; + } + + if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { + *try_sel = sel->r; + } else { + spin_lock_irqsave(&fimc->slock, flags); + set_frame_crop(f, r->left, r->top, r->width, r->height); + set_bit(ST_CAPT_APPLY_CFG, &fimc->state); + if (sel->target == V4L2_SEL_TGT_COMPOSE) + ctx->state |= FIMC_COMPOSE; + spin_unlock_irqrestore(&fimc->slock, flags); + } + + dbg("target %#x: (%d,%d)/%dx%d", sel->target, r->left, r->top, + r->width, r->height); + + mutex_unlock(&fimc->lock); + return 0; +} + +static struct v4l2_subdev_pad_ops fimc_subdev_pad_ops = { + .enum_mbus_code = fimc_subdev_enum_mbus_code, + .get_selection = fimc_subdev_get_selection, + .set_selection = fimc_subdev_set_selection, + .get_fmt = fimc_subdev_get_fmt, + .set_fmt = fimc_subdev_set_fmt, +}; + +static struct v4l2_subdev_ops fimc_subdev_ops = { + .pad = &fimc_subdev_pad_ops, +}; + +/* Set default format at the sensor and host interface */ +static int fimc_capture_set_default_format(struct fimc_dev *fimc) +{ + struct v4l2_format fmt = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .fmt.pix_mp = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_YUYV, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_JPEG, + }, + }; + + return __fimc_capture_set_format(fimc, &fmt); +} + +/* fimc->lock must be already initialized */ +static int fimc_register_capture_device(struct fimc_dev *fimc, + struct v4l2_device *v4l2_dev) +{ + struct video_device *vfd = &fimc->vid_cap.vfd; + struct vb2_queue *q = &fimc->vid_cap.vbq; + struct fimc_ctx *ctx; + struct fimc_vid_cap *vid_cap; + int ret = -ENOMEM; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->fimc_dev = fimc; + ctx->in_path = FIMC_IO_CAMERA; + ctx->out_path = FIMC_IO_DMA; + ctx->state = FIMC_CTX_CAP; + ctx->s_frame.fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0); + ctx->d_frame.fmt = ctx->s_frame.fmt; + + memset(vfd, 0, sizeof(*vfd)); + snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.capture", fimc->id); + + vfd->fops = &fimc_capture_fops; + vfd->ioctl_ops = &fimc_capture_ioctl_ops; + vfd->v4l2_dev = v4l2_dev; + vfd->minor = -1; + vfd->release = video_device_release_empty; + vfd->queue = q; + vfd->lock = &fimc->lock; + + video_set_drvdata(vfd, fimc); + vid_cap = &fimc->vid_cap; + vid_cap->active_buf_cnt = 0; + vid_cap->reqbufs_count = 0; + vid_cap->ctx = ctx; + + INIT_LIST_HEAD(&vid_cap->pending_buf_q); + INIT_LIST_HEAD(&vid_cap->active_buf_q); + + memset(q, 0, sizeof(*q)); + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + q->drv_priv = ctx; + q->ops = &fimc_capture_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct fimc_vid_buffer); + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &fimc->lock; + + ret = vb2_queue_init(q); + if (ret) + goto err_ent; + + vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0); + if (ret) + goto err_ent; + /* + * For proper order of acquiring/releasing the video + * and the graph mutex. + */ + v4l2_disable_ioctl_locking(vfd, VIDIOC_TRY_FMT); + v4l2_disable_ioctl_locking(vfd, VIDIOC_S_FMT); + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); + if (ret) + goto err_vd; + + v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n", + vfd->name, video_device_node_name(vfd)); + + vfd->ctrl_handler = &ctx->ctrls.handler; + return 0; + +err_vd: + media_entity_cleanup(&vfd->entity); +err_ent: + kfree(ctx); + return ret; +} + +static int fimc_capture_subdev_registered(struct v4l2_subdev *sd) +{ + struct fimc_dev *fimc = v4l2_get_subdevdata(sd); + int ret; + + if (fimc == NULL) + return -ENXIO; + + ret = fimc_register_m2m_device(fimc, sd->v4l2_dev); + if (ret) + return ret; + + fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd); + + ret = fimc_register_capture_device(fimc, sd->v4l2_dev); + if (ret) { + fimc_unregister_m2m_device(fimc); + fimc->pipeline_ops = NULL; + } + + return ret; +} + +static void fimc_capture_subdev_unregistered(struct v4l2_subdev *sd) +{ + struct fimc_dev *fimc = v4l2_get_subdevdata(sd); + + if (fimc == NULL) + return; + + fimc_unregister_m2m_device(fimc); + + if (video_is_registered(&fimc->vid_cap.vfd)) { + video_unregister_device(&fimc->vid_cap.vfd); + media_entity_cleanup(&fimc->vid_cap.vfd.entity); + fimc->pipeline_ops = NULL; + } + kfree(fimc->vid_cap.ctx); + fimc->vid_cap.ctx = NULL; +} + +static const struct v4l2_subdev_internal_ops fimc_capture_sd_internal_ops = { + .registered = fimc_capture_subdev_registered, + .unregistered = fimc_capture_subdev_unregistered, +}; + +int fimc_initialize_capture_subdev(struct fimc_dev *fimc) +{ + struct v4l2_subdev *sd = &fimc->vid_cap.subdev; + int ret; + + v4l2_subdev_init(sd, &fimc_subdev_ops); + sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->id); + + fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_CAM].flags = MEDIA_PAD_FL_SINK; + fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_FIFO].flags = MEDIA_PAD_FL_SINK; + fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM, + fimc->vid_cap.sd_pads, 0); + if (ret) + return ret; + + sd->entity.ops = &fimc_sd_media_ops; + sd->internal_ops = &fimc_capture_sd_internal_ops; + v4l2_set_subdevdata(sd, fimc); + return 0; +} + +void fimc_unregister_capture_subdev(struct fimc_dev *fimc) +{ + struct v4l2_subdev *sd = &fimc->vid_cap.subdev; + + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_set_subdevdata(sd, NULL); +} diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c new file mode 100644 index 000000000000..1248cdd35c29 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -0,0 +1,1334 @@ +/* + * Samsung S5P/EXYNOS4 SoC series FIMC (CAMIF) driver + * + * Copyright (C) 2010-2012 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 2 of the License, + * or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fimc-core.h" +#include "fimc-reg.h" +#include "media-dev.h" + +static char *fimc_clocks[MAX_FIMC_CLOCKS] = { + "sclk_fimc", "fimc" +}; + +static struct fimc_fmt fimc_formats[] = { + { + .name = "RGB565", + .fourcc = V4L2_PIX_FMT_RGB565, + .depth = { 16 }, + .color = FIMC_FMT_RGB565, + .memplanes = 1, + .colplanes = 1, + .flags = FMT_FLAGS_M2M, + }, { + .name = "BGR666", + .fourcc = V4L2_PIX_FMT_BGR666, + .depth = { 32 }, + .color = FIMC_FMT_RGB666, + .memplanes = 1, + .colplanes = 1, + .flags = FMT_FLAGS_M2M, + }, { + .name = "ARGB8888, 32 bpp", + .fourcc = V4L2_PIX_FMT_RGB32, + .depth = { 32 }, + .color = FIMC_FMT_RGB888, + .memplanes = 1, + .colplanes = 1, + .flags = FMT_FLAGS_M2M | FMT_HAS_ALPHA, + }, { + .name = "ARGB1555", + .fourcc = V4L2_PIX_FMT_RGB555, + .depth = { 16 }, + .color = FIMC_FMT_RGB555, + .memplanes = 1, + .colplanes = 1, + .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA, + }, { + .name = "ARGB4444", + .fourcc = V4L2_PIX_FMT_RGB444, + .depth = { 16 }, + .color = FIMC_FMT_RGB444, + .memplanes = 1, + .colplanes = 1, + .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA, + }, { + .name = "YUV 4:4:4", + .mbus_code = V4L2_MBUS_FMT_YUV10_1X30, + .flags = FMT_FLAGS_WRITEBACK, + }, { + .name = "YUV 4:2:2 packed, YCbYCr", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = { 16 }, + .color = FIMC_FMT_YCBYCR422, + .memplanes = 1, + .colplanes = 1, + .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, + }, { + .name = "YUV 4:2:2 packed, CbYCrY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = { 16 }, + .color = FIMC_FMT_CBYCRY422, + .memplanes = 1, + .colplanes = 1, + .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, + .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, + }, { + .name = "YUV 4:2:2 packed, CrYCbY", + .fourcc = V4L2_PIX_FMT_VYUY, + .depth = { 16 }, + .color = FIMC_FMT_CRYCBY422, + .memplanes = 1, + .colplanes = 1, + .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8, + .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, + }, { + .name = "YUV 4:2:2 packed, YCrYCb", + .fourcc = V4L2_PIX_FMT_YVYU, + .depth = { 16 }, + .color = FIMC_FMT_YCRYCB422, + .memplanes = 1, + .colplanes = 1, + .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8, + .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, + }, { + .name = "YUV 4:2:2 planar, Y/Cb/Cr", + .fourcc = V4L2_PIX_FMT_YUV422P, + .depth = { 12 }, + .color = FIMC_FMT_YCBYCR422, + .memplanes = 1, + .colplanes = 3, + .flags = FMT_FLAGS_M2M, + }, { + .name = "YUV 4:2:2 planar, Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV16, + .depth = { 16 }, + .color = FIMC_FMT_YCBYCR422, + .memplanes = 1, + .colplanes = 2, + .flags = FMT_FLAGS_M2M, + }, { + .name = "YUV 4:2:2 planar, Y/CrCb", + .fourcc = V4L2_PIX_FMT_NV61, + .depth = { 16 }, + .color = FIMC_FMT_YCRYCB422, + .memplanes = 1, + .colplanes = 2, + .flags = FMT_FLAGS_M2M, + }, { + .name = "YUV 4:2:0 planar, YCbCr", + .fourcc = V4L2_PIX_FMT_YUV420, + .depth = { 12 }, + .color = FIMC_FMT_YCBCR420, + .memplanes = 1, + .colplanes = 3, + .flags = FMT_FLAGS_M2M, + }, { + .name = "YUV 4:2:0 planar, Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV12, + .depth = { 12 }, + .color = FIMC_FMT_YCBCR420, + .memplanes = 1, + .colplanes = 2, + .flags = FMT_FLAGS_M2M, + }, { + .name = "YUV 4:2:0 non-contig. 2p, Y/CbCr", + .fourcc = V4L2_PIX_FMT_NV12M, + .color = FIMC_FMT_YCBCR420, + .depth = { 8, 4 }, + .memplanes = 2, + .colplanes = 2, + .flags = FMT_FLAGS_M2M, + }, { + .name = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr", + .fourcc = V4L2_PIX_FMT_YUV420M, + .color = FIMC_FMT_YCBCR420, + .depth = { 8, 2, 2 }, + .memplanes = 3, + .colplanes = 3, + .flags = FMT_FLAGS_M2M, + }, { + .name = "YUV 4:2:0 non-contig. 2p, tiled", + .fourcc = V4L2_PIX_FMT_NV12MT, + .color = FIMC_FMT_YCBCR420, + .depth = { 8, 4 }, + .memplanes = 2, + .colplanes = 2, + .flags = FMT_FLAGS_M2M, + }, { + .name = "JPEG encoded data", + .fourcc = V4L2_PIX_FMT_JPEG, + .color = FIMC_FMT_JPEG, + .depth = { 8 }, + .memplanes = 1, + .colplanes = 1, + .mbus_code = V4L2_MBUS_FMT_JPEG_1X8, + .flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED, + }, { + .name = "S5C73MX interleaved UYVY/JPEG", + .fourcc = V4L2_PIX_FMT_S5C_UYVY_JPG, + .color = FIMC_FMT_YUYV_JPEG, + .depth = { 8 }, + .memplanes = 2, + .colplanes = 1, + .mdataplanes = 0x2, /* plane 1 holds frame meta data */ + .mbus_code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8, + .flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED, + }, +}; + +struct fimc_fmt *fimc_get_format(unsigned int index) +{ + if (index >= ARRAY_SIZE(fimc_formats)) + return NULL; + + return &fimc_formats[index]; +} + +int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh, + int dw, int dh, int rotation) +{ + if (rotation == 90 || rotation == 270) + swap(dw, dh); + + if (!ctx->scaler.enabled) + return (sw == dw && sh == dh) ? 0 : -EINVAL; + + if ((sw >= SCALER_MAX_HRATIO * dw) || (sh >= SCALER_MAX_VRATIO * dh)) + return -EINVAL; + + return 0; +} + +static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) +{ + u32 sh = 6; + + if (src >= 64 * tar) + return -EINVAL; + + while (sh--) { + u32 tmp = 1 << sh; + if (src >= tar * tmp) { + *shift = sh, *ratio = tmp; + return 0; + } + } + *shift = 0, *ratio = 1; + return 0; +} + +int fimc_set_scaler_info(struct fimc_ctx *ctx) +{ + const struct fimc_variant *variant = ctx->fimc_dev->variant; + struct device *dev = &ctx->fimc_dev->pdev->dev; + struct fimc_scaler *sc = &ctx->scaler; + struct fimc_frame *s_frame = &ctx->s_frame; + struct fimc_frame *d_frame = &ctx->d_frame; + int tx, ty, sx, sy; + int ret; + + if (ctx->rotation == 90 || ctx->rotation == 270) { + ty = d_frame->width; + tx = d_frame->height; + } else { + tx = d_frame->width; + ty = d_frame->height; + } + if (tx <= 0 || ty <= 0) { + dev_err(dev, "Invalid target size: %dx%d\n", tx, ty); + return -EINVAL; + } + + sx = s_frame->width; + sy = s_frame->height; + if (sx <= 0 || sy <= 0) { + dev_err(dev, "Invalid source size: %dx%d\n", sx, sy); + return -EINVAL; + } + sc->real_width = sx; + sc->real_height = sy; + + ret = fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor); + if (ret) + return ret; + + ret = fimc_get_scaler_factor(sy, ty, &sc->pre_vratio, &sc->vfactor); + if (ret) + return ret; + + sc->pre_dst_width = sx / sc->pre_hratio; + sc->pre_dst_height = sy / sc->pre_vratio; + + if (variant->has_mainscaler_ext) { + sc->main_hratio = (sx << 14) / (tx << sc->hfactor); + sc->main_vratio = (sy << 14) / (ty << sc->vfactor); + } else { + sc->main_hratio = (sx << 8) / (tx << sc->hfactor); + sc->main_vratio = (sy << 8) / (ty << sc->vfactor); + + } + + sc->scaleup_h = (tx >= sx) ? 1 : 0; + sc->scaleup_v = (ty >= sy) ? 1 : 0; + + /* check to see if input and output size/format differ */ + if (s_frame->fmt->color == d_frame->fmt->color + && s_frame->width == d_frame->width + && s_frame->height == d_frame->height) + sc->copy_mode = 1; + else + sc->copy_mode = 0; + + return 0; +} + +static irqreturn_t fimc_irq_handler(int irq, void *priv) +{ + struct fimc_dev *fimc = priv; + struct fimc_ctx *ctx; + + fimc_hw_clear_irq(fimc); + + spin_lock(&fimc->slock); + + if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) { + if (test_and_clear_bit(ST_M2M_SUSPENDING, &fimc->state)) { + set_bit(ST_M2M_SUSPENDED, &fimc->state); + wake_up(&fimc->irq_queue); + goto out; + } + ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev); + if (ctx != NULL) { + spin_unlock(&fimc->slock); + fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE); + + if (ctx->state & FIMC_CTX_SHUT) { + ctx->state &= ~FIMC_CTX_SHUT; + wake_up(&fimc->irq_queue); + } + return IRQ_HANDLED; + } + } else if (test_bit(ST_CAPT_PEND, &fimc->state)) { + int last_buf = test_bit(ST_CAPT_JPEG, &fimc->state) && + fimc->vid_cap.reqbufs_count == 1; + fimc_capture_irq_handler(fimc, !last_buf); + } +out: + spin_unlock(&fimc->slock); + return IRQ_HANDLED; +} + +/* The color format (colplanes, memplanes) must be already configured. */ +int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, + struct fimc_frame *frame, struct fimc_addr *paddr) +{ + int ret = 0; + u32 pix_size; + + if (vb == NULL || frame == NULL) + return -EINVAL; + + pix_size = frame->width * frame->height; + + dbg("memplanes= %d, colplanes= %d, pix_size= %d", + frame->fmt->memplanes, frame->fmt->colplanes, pix_size); + + paddr->y = vb2_dma_contig_plane_dma_addr(vb, 0); + + if (frame->fmt->memplanes == 1) { + switch (frame->fmt->colplanes) { + case 1: + paddr->cb = 0; + paddr->cr = 0; + break; + case 2: + /* decompose Y into Y/Cb */ + paddr->cb = (u32)(paddr->y + pix_size); + paddr->cr = 0; + break; + case 3: + paddr->cb = (u32)(paddr->y + pix_size); + /* decompose Y into Y/Cb/Cr */ + if (FIMC_FMT_YCBCR420 == frame->fmt->color) + paddr->cr = (u32)(paddr->cb + + (pix_size >> 2)); + else /* 422 */ + paddr->cr = (u32)(paddr->cb + + (pix_size >> 1)); + break; + default: + return -EINVAL; + } + } else if (!frame->fmt->mdataplanes) { + if (frame->fmt->memplanes >= 2) + paddr->cb = vb2_dma_contig_plane_dma_addr(vb, 1); + + if (frame->fmt->memplanes == 3) + paddr->cr = vb2_dma_contig_plane_dma_addr(vb, 2); + } + + dbg("PHYS_ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d", + paddr->y, paddr->cb, paddr->cr, ret); + + return ret; +} + +/* Set order for 1 and 2 plane YCBCR 4:2:2 formats. */ +void fimc_set_yuv_order(struct fimc_ctx *ctx) +{ + /* The one only mode supported in SoC. */ + ctx->in_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB; + ctx->out_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB; + + /* Set order for 1 plane input formats. */ + switch (ctx->s_frame.fmt->color) { + case FIMC_FMT_YCRYCB422: + ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CBYCRY; + break; + case FIMC_FMT_CBYCRY422: + ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCRYCB; + break; + case FIMC_FMT_CRYCBY422: + ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCBYCR; + break; + case FIMC_FMT_YCBYCR422: + default: + ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CRYCBY; + break; + } + dbg("ctx->in_order_1p= %d", ctx->in_order_1p); + + switch (ctx->d_frame.fmt->color) { + case FIMC_FMT_YCRYCB422: + ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CBYCRY; + break; + case FIMC_FMT_CBYCRY422: + ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCRYCB; + break; + case FIMC_FMT_CRYCBY422: + ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCBYCR; + break; + case FIMC_FMT_YCBYCR422: + default: + ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CRYCBY; + break; + } + dbg("ctx->out_order_1p= %d", ctx->out_order_1p); +} + +void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f) +{ + bool pix_hoff = ctx->fimc_dev->drv_data->dma_pix_hoff; + u32 i, depth = 0; + + for (i = 0; i < f->fmt->colplanes; i++) + depth += f->fmt->depth[i]; + + f->dma_offset.y_h = f->offs_h; + if (!pix_hoff) + f->dma_offset.y_h *= (depth >> 3); + + f->dma_offset.y_v = f->offs_v; + + f->dma_offset.cb_h = f->offs_h; + f->dma_offset.cb_v = f->offs_v; + + f->dma_offset.cr_h = f->offs_h; + f->dma_offset.cr_v = f->offs_v; + + if (!pix_hoff) { + if (f->fmt->colplanes == 3) { + f->dma_offset.cb_h >>= 1; + f->dma_offset.cr_h >>= 1; + } + if (f->fmt->color == FIMC_FMT_YCBCR420) { + f->dma_offset.cb_v >>= 1; + f->dma_offset.cr_v >>= 1; + } + } + + dbg("in_offset: color= %d, y_h= %d, y_v= %d", + f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v); +} + +static int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx) +{ + struct fimc_effect *effect = &ctx->effect; + + switch (colorfx) { + case V4L2_COLORFX_NONE: + effect->type = FIMC_REG_CIIMGEFF_FIN_BYPASS; + break; + case V4L2_COLORFX_BW: + effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY; + effect->pat_cb = 128; + effect->pat_cr = 128; + break; + case V4L2_COLORFX_SEPIA: + effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY; + effect->pat_cb = 115; + effect->pat_cr = 145; + break; + case V4L2_COLORFX_NEGATIVE: + effect->type = FIMC_REG_CIIMGEFF_FIN_NEGATIVE; + break; + case V4L2_COLORFX_EMBOSS: + effect->type = FIMC_REG_CIIMGEFF_FIN_EMBOSSING; + break; + case V4L2_COLORFX_ART_FREEZE: + effect->type = FIMC_REG_CIIMGEFF_FIN_ARTFREEZE; + break; + case V4L2_COLORFX_SILHOUETTE: + effect->type = FIMC_REG_CIIMGEFF_FIN_SILHOUETTE; + break; + case V4L2_COLORFX_SET_CBCR: + effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY; + effect->pat_cb = ctx->ctrls.colorfx_cbcr->val >> 8; + effect->pat_cr = ctx->ctrls.colorfx_cbcr->val & 0xff; + break; + default: + return -EINVAL; + } + + return 0; +} + +/* + * V4L2 controls handling + */ +#define ctrl_to_ctx(__ctrl) \ + container_of((__ctrl)->handler, struct fimc_ctx, ctrls.handler) + +static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl) +{ + struct fimc_dev *fimc = ctx->fimc_dev; + const struct fimc_variant *variant = fimc->variant; + int ret = 0; + + if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) + return 0; + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + ctx->hflip = ctrl->val; + break; + + case V4L2_CID_VFLIP: + ctx->vflip = ctrl->val; + break; + + case V4L2_CID_ROTATE: + if (fimc_capture_pending(fimc)) { + ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, + ctx->s_frame.height, ctx->d_frame.width, + ctx->d_frame.height, ctrl->val); + if (ret) + return -EINVAL; + } + if ((ctrl->val == 90 || ctrl->val == 270) && + !variant->has_out_rot) + return -EINVAL; + + ctx->rotation = ctrl->val; + break; + + case V4L2_CID_ALPHA_COMPONENT: + ctx->d_frame.alpha = ctrl->val; + break; + + case V4L2_CID_COLORFX: + ret = fimc_set_color_effect(ctx, ctrl->val); + if (ret) + return ret; + break; + } + + ctx->state |= FIMC_PARAMS; + set_bit(ST_CAPT_APPLY_CFG, &fimc->state); + return 0; +} + +static int fimc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct fimc_ctx *ctx = ctrl_to_ctx(ctrl); + unsigned long flags; + int ret; + + spin_lock_irqsave(&ctx->fimc_dev->slock, flags); + ret = __fimc_s_ctrl(ctx, ctrl); + spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags); + + return ret; +} + +static const struct v4l2_ctrl_ops fimc_ctrl_ops = { + .s_ctrl = fimc_s_ctrl, +}; + +int fimc_ctrls_create(struct fimc_ctx *ctx) +{ + unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt); + struct fimc_ctrls *ctrls = &ctx->ctrls; + struct v4l2_ctrl_handler *handler = &ctrls->handler; + + if (ctx->ctrls.ready) + return 0; + + v4l2_ctrl_handler_init(handler, 6); + + ctrls->rotate = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops, + V4L2_CID_ROTATE, 0, 270, 90, 0); + ctrls->hflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + ctrls->vflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + if (ctx->fimc_dev->drv_data->alpha_color) + ctrls->alpha = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops, + V4L2_CID_ALPHA_COMPONENT, + 0, max_alpha, 1, 0); + else + ctrls->alpha = NULL; + + ctrls->colorfx = v4l2_ctrl_new_std_menu(handler, &fimc_ctrl_ops, + V4L2_CID_COLORFX, V4L2_COLORFX_SET_CBCR, + ~0x983f, V4L2_COLORFX_NONE); + + ctrls->colorfx_cbcr = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops, + V4L2_CID_COLORFX_CBCR, 0, 0xffff, 1, 0); + + ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS; + + if (!handler->error) { + v4l2_ctrl_cluster(2, &ctrls->colorfx); + ctrls->ready = true; + } + + return handler->error; +} + +void fimc_ctrls_delete(struct fimc_ctx *ctx) +{ + struct fimc_ctrls *ctrls = &ctx->ctrls; + + if (ctrls->ready) { + v4l2_ctrl_handler_free(&ctrls->handler); + ctrls->ready = false; + ctrls->alpha = NULL; + } +} + +void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active) +{ + unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA; + struct fimc_ctrls *ctrls = &ctx->ctrls; + + if (!ctrls->ready) + return; + + mutex_lock(ctrls->handler.lock); + v4l2_ctrl_activate(ctrls->rotate, active); + v4l2_ctrl_activate(ctrls->hflip, active); + v4l2_ctrl_activate(ctrls->vflip, active); + v4l2_ctrl_activate(ctrls->colorfx, active); + if (ctrls->alpha) + v4l2_ctrl_activate(ctrls->alpha, active && has_alpha); + + if (active) { + fimc_set_color_effect(ctx, ctrls->colorfx->cur.val); + ctx->rotation = ctrls->rotate->val; + ctx->hflip = ctrls->hflip->val; + ctx->vflip = ctrls->vflip->val; + } else { + ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS; + ctx->rotation = 0; + ctx->hflip = 0; + ctx->vflip = 0; + } + mutex_unlock(ctrls->handler.lock); +} + +/* Update maximum value of the alpha color control */ +void fimc_alpha_ctrl_update(struct fimc_ctx *ctx) +{ + struct fimc_dev *fimc = ctx->fimc_dev; + struct v4l2_ctrl *ctrl = ctx->ctrls.alpha; + + if (ctrl == NULL || !fimc->drv_data->alpha_color) + return; + + v4l2_ctrl_lock(ctrl); + ctrl->maximum = fimc_get_alpha_mask(ctx->d_frame.fmt); + + if (ctrl->cur.val > ctrl->maximum) + ctrl->cur.val = ctrl->maximum; + + v4l2_ctrl_unlock(ctrl); +} + +void __fimc_get_format(struct fimc_frame *frame, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; + int i; + + pixm->width = frame->o_width; + pixm->height = frame->o_height; + pixm->field = V4L2_FIELD_NONE; + pixm->pixelformat = frame->fmt->fourcc; + pixm->colorspace = V4L2_COLORSPACE_JPEG; + pixm->num_planes = frame->fmt->memplanes; + + for (i = 0; i < pixm->num_planes; ++i) { + pixm->plane_fmt[i].bytesperline = frame->bytesperline[i]; + pixm->plane_fmt[i].sizeimage = frame->payload[i]; + } +} + +/** + * fimc_adjust_mplane_format - adjust bytesperline/sizeimage for each plane + * @fmt: fimc pixel format description (input) + * @width: requested pixel width + * @height: requested pixel height + * @pix: multi-plane format to adjust + */ +void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, + struct v4l2_pix_format_mplane *pix) +{ + u32 bytesperline = 0; + int i; + + pix->colorspace = V4L2_COLORSPACE_JPEG; + pix->field = V4L2_FIELD_NONE; + pix->num_planes = fmt->memplanes; + pix->pixelformat = fmt->fourcc; + pix->height = height; + pix->width = width; + + for (i = 0; i < pix->num_planes; ++i) { + struct v4l2_plane_pix_format *plane_fmt = &pix->plane_fmt[i]; + u32 bpl = plane_fmt->bytesperline; + + if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width)) + bpl = pix->width; /* Planar */ + + if (fmt->colplanes == 1 && /* Packed */ + (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width)) + bpl = (pix->width * fmt->depth[0]) / 8; + /* + * Currently bytesperline for each plane is same, except + * V4L2_PIX_FMT_YUV420M format. This calculation may need + * to be changed when other multi-planar formats are added + * to the fimc_formats[] array. + */ + if (i == 0) + bytesperline = bpl; + else if (i == 1 && fmt->memplanes == 3) + bytesperline /= 2; + + plane_fmt->bytesperline = bytesperline; + plane_fmt->sizeimage = max((pix->width * pix->height * + fmt->depth[i]) / 8, plane_fmt->sizeimage); + } +} + +/** + * fimc_find_format - lookup fimc color format by fourcc or media bus format + * @pixelformat: fourcc to match, ignored if null + * @mbus_code: media bus code to match, ignored if null + * @mask: the color flags to match + * @index: offset in the fimc_formats array, ignored if negative + */ +struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code, + unsigned int mask, int index) +{ + struct fimc_fmt *fmt, *def_fmt = NULL; + unsigned int i; + int id = 0; + + if (index >= (int)ARRAY_SIZE(fimc_formats)) + return NULL; + + for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) { + fmt = &fimc_formats[i]; + if (!(fmt->flags & mask)) + continue; + if (pixelformat && fmt->fourcc == *pixelformat) + return fmt; + if (mbus_code && fmt->mbus_code == *mbus_code) + return fmt; + if (index == id) + def_fmt = fmt; + id++; + } + return def_fmt; +} + +static void fimc_clk_put(struct fimc_dev *fimc) +{ + int i; + for (i = 0; i < MAX_FIMC_CLOCKS; i++) { + if (IS_ERR(fimc->clock[i])) + continue; + clk_unprepare(fimc->clock[i]); + clk_put(fimc->clock[i]); + fimc->clock[i] = ERR_PTR(-EINVAL); + } +} + +static int fimc_clk_get(struct fimc_dev *fimc) +{ + int i, ret; + + for (i = 0; i < MAX_FIMC_CLOCKS; i++) + fimc->clock[i] = ERR_PTR(-EINVAL); + + for (i = 0; i < MAX_FIMC_CLOCKS; i++) { + fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]); + if (IS_ERR(fimc->clock[i])) { + ret = PTR_ERR(fimc->clock[i]); + goto err; + } + ret = clk_prepare(fimc->clock[i]); + if (ret < 0) { + clk_put(fimc->clock[i]); + fimc->clock[i] = ERR_PTR(-EINVAL); + goto err; + } + } + return 0; +err: + fimc_clk_put(fimc); + dev_err(&fimc->pdev->dev, "failed to get clock: %s\n", + fimc_clocks[i]); + return -ENXIO; +} + +static int fimc_m2m_suspend(struct fimc_dev *fimc) +{ + unsigned long flags; + int timeout; + + spin_lock_irqsave(&fimc->slock, flags); + if (!fimc_m2m_pending(fimc)) { + spin_unlock_irqrestore(&fimc->slock, flags); + return 0; + } + clear_bit(ST_M2M_SUSPENDED, &fimc->state); + set_bit(ST_M2M_SUSPENDING, &fimc->state); + spin_unlock_irqrestore(&fimc->slock, flags); + + timeout = wait_event_timeout(fimc->irq_queue, + test_bit(ST_M2M_SUSPENDED, &fimc->state), + FIMC_SHUTDOWN_TIMEOUT); + + clear_bit(ST_M2M_SUSPENDING, &fimc->state); + return timeout == 0 ? -EAGAIN : 0; +} + +static int fimc_m2m_resume(struct fimc_dev *fimc) +{ + unsigned long flags; + + spin_lock_irqsave(&fimc->slock, flags); + /* Clear for full H/W setup in first run after resume */ + fimc->m2m.ctx = NULL; + spin_unlock_irqrestore(&fimc->slock, flags); + + if (test_and_clear_bit(ST_M2M_SUSPENDED, &fimc->state)) + fimc_m2m_job_finish(fimc->m2m.ctx, + VB2_BUF_STATE_ERROR); + return 0; +} + +static const struct of_device_id fimc_of_match[]; + +static int fimc_parse_dt(struct fimc_dev *fimc, u32 *clk_freq) +{ + struct device *dev = &fimc->pdev->dev; + struct device_node *node = dev->of_node; + const struct of_device_id *of_id; + struct fimc_variant *v; + struct fimc_pix_limit *lim; + u32 args[FIMC_PIX_LIMITS_MAX]; + int ret; + + if (of_property_read_bool(node, "samsung,lcd-wb")) + return -ENODEV; + + v = devm_kzalloc(dev, sizeof(*v) + sizeof(*lim), GFP_KERNEL); + if (!v) + return -ENOMEM; + + of_id = of_match_node(fimc_of_match, node); + if (!of_id) + return -EINVAL; + fimc->drv_data = of_id->data; + ret = of_property_read_u32_array(node, "samsung,pix-limits", + args, FIMC_PIX_LIMITS_MAX); + if (ret < 0) + return ret; + + lim = (struct fimc_pix_limit *)&v[1]; + + lim->scaler_en_w = args[0]; + lim->scaler_dis_w = args[1]; + lim->out_rot_en_w = args[2]; + lim->out_rot_dis_w = args[3]; + v->pix_limit = lim; + + ret = of_property_read_u32_array(node, "samsung,min-pix-sizes", + args, 2); + v->min_inp_pixsize = ret ? FIMC_DEF_MIN_SIZE : args[0]; + v->min_out_pixsize = ret ? FIMC_DEF_MIN_SIZE : args[1]; + ret = of_property_read_u32_array(node, "samsung,min-pix-alignment", + args, 2); + v->min_vsize_align = ret ? FIMC_DEF_HEIGHT_ALIGN : args[0]; + v->hor_offs_align = ret ? FIMC_DEF_HOR_OFFS_ALIGN : args[1]; + + ret = of_property_read_u32(node, "samsung,rotators", &args[1]); + v->has_inp_rot = ret ? 1 : args[1] & 0x01; + v->has_out_rot = ret ? 1 : args[1] & 0x10; + v->has_mainscaler_ext = of_property_read_bool(node, + "samsung,mainscaler-ext"); + + v->has_isp_wb = of_property_read_bool(node, "samsung,isp-wb"); + v->has_cam_if = of_property_read_bool(node, "samsung,cam-if"); + of_property_read_u32(node, "clock-frequency", clk_freq); + fimc->id = of_alias_get_id(node, "fimc"); + + fimc->variant = v; + return 0; +} + +static int fimc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + u32 lclk_freq = 0; + struct fimc_dev *fimc; + struct resource *res; + int ret = 0; + + fimc = devm_kzalloc(dev, sizeof(*fimc), GFP_KERNEL); + if (!fimc) + return -ENOMEM; + + fimc->pdev = pdev; + + if (dev->of_node) { + ret = fimc_parse_dt(fimc, &lclk_freq); + if (ret < 0) + return ret; + } else { + fimc->drv_data = fimc_get_drvdata(pdev); + fimc->id = pdev->id; + } + if (!fimc->drv_data || fimc->id >= fimc->drv_data->num_entities || + fimc->id < 0) { + dev_err(dev, "Invalid driver data or device id (%d/%d)\n", + fimc->id, fimc->drv_data->num_entities); + return -EINVAL; + } + if (!dev->of_node) + fimc->variant = fimc->drv_data->variant[fimc->id]; + + init_waitqueue_head(&fimc->irq_queue); + spin_lock_init(&fimc->slock); + mutex_init(&fimc->lock); + + fimc->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, + "samsung,sysreg"); + if (IS_ERR(fimc->sysreg)) + return PTR_ERR(fimc->sysreg); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + fimc->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(fimc->regs)) + return PTR_ERR(fimc->regs); + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res == NULL) { + dev_err(dev, "Failed to get IRQ resource\n"); + return -ENXIO; + } + + ret = fimc_clk_get(fimc); + if (ret) + return ret; + + if (lclk_freq == 0) + lclk_freq = fimc->drv_data->lclk_frequency; + + ret = clk_set_rate(fimc->clock[CLK_BUS], lclk_freq); + if (ret < 0) + return ret; + + ret = clk_enable(fimc->clock[CLK_BUS]); + if (ret < 0) + return ret; + + ret = devm_request_irq(dev, res->start, fimc_irq_handler, + 0, dev_name(dev), fimc); + if (ret) { + dev_err(dev, "failed to install irq (%d)\n", ret); + goto err_clk; + } + + ret = fimc_initialize_capture_subdev(fimc); + if (ret) + goto err_clk; + + platform_set_drvdata(pdev, fimc); + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) + goto err_sd; + /* Initialize contiguous memory allocator */ + fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); + if (IS_ERR(fimc->alloc_ctx)) { + ret = PTR_ERR(fimc->alloc_ctx); + goto err_pm; + } + + dev_dbg(dev, "FIMC.%d registered successfully\n", fimc->id); + + pm_runtime_put(dev); + return 0; +err_pm: + pm_runtime_put(dev); +err_sd: + fimc_unregister_capture_subdev(fimc); +err_clk: + clk_disable(fimc->clock[CLK_BUS]); + fimc_clk_put(fimc); + return ret; +} + +static int fimc_runtime_resume(struct device *dev) +{ + struct fimc_dev *fimc = dev_get_drvdata(dev); + + dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state); + + /* Enable clocks and perform basic initalization */ + clk_enable(fimc->clock[CLK_GATE]); + fimc_hw_reset(fimc); + + /* Resume the capture or mem-to-mem device */ + if (fimc_capture_busy(fimc)) + return fimc_capture_resume(fimc); + + return fimc_m2m_resume(fimc); +} + +static int fimc_runtime_suspend(struct device *dev) +{ + struct fimc_dev *fimc = dev_get_drvdata(dev); + int ret = 0; + + if (fimc_capture_busy(fimc)) + ret = fimc_capture_suspend(fimc); + else + ret = fimc_m2m_suspend(fimc); + if (!ret) + clk_disable(fimc->clock[CLK_GATE]); + + dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state); + return ret; +} + +#ifdef CONFIG_PM_SLEEP +static int fimc_resume(struct device *dev) +{ + struct fimc_dev *fimc = dev_get_drvdata(dev); + unsigned long flags; + + dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state); + + /* Do not resume if the device was idle before system suspend */ + spin_lock_irqsave(&fimc->slock, flags); + if (!test_and_clear_bit(ST_LPM, &fimc->state) || + (!fimc_m2m_active(fimc) && !fimc_capture_busy(fimc))) { + spin_unlock_irqrestore(&fimc->slock, flags); + return 0; + } + fimc_hw_reset(fimc); + spin_unlock_irqrestore(&fimc->slock, flags); + + if (fimc_capture_busy(fimc)) + return fimc_capture_resume(fimc); + + return fimc_m2m_resume(fimc); +} + +static int fimc_suspend(struct device *dev) +{ + struct fimc_dev *fimc = dev_get_drvdata(dev); + + dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state); + + if (test_and_set_bit(ST_LPM, &fimc->state)) + return 0; + if (fimc_capture_busy(fimc)) + return fimc_capture_suspend(fimc); + + return fimc_m2m_suspend(fimc); +} +#endif /* CONFIG_PM_SLEEP */ + +static int fimc_remove(struct platform_device *pdev) +{ + struct fimc_dev *fimc = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + + fimc_unregister_capture_subdev(fimc); + vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); + + clk_disable(fimc->clock[CLK_BUS]); + fimc_clk_put(fimc); + + dev_info(&pdev->dev, "driver unloaded\n"); + return 0; +} + +/* Image pixel limits, similar across several FIMC HW revisions. */ +static const struct fimc_pix_limit s5p_pix_limit[4] = { + [0] = { + .scaler_en_w = 3264, + .scaler_dis_w = 8192, + .out_rot_en_w = 1920, + .out_rot_dis_w = 4224, + }, + [1] = { + .scaler_en_w = 4224, + .scaler_dis_w = 8192, + .out_rot_en_w = 1920, + .out_rot_dis_w = 4224, + }, + [2] = { + .scaler_en_w = 1920, + .scaler_dis_w = 8192, + .out_rot_en_w = 1280, + .out_rot_dis_w = 1920, + }, + [3] = { + .scaler_en_w = 1920, + .scaler_dis_w = 8192, + .in_rot_en_h = 1366, + .in_rot_dis_w = 8192, + .out_rot_en_w = 1366, + .out_rot_dis_w = 1920, + }, +}; + +static const struct fimc_variant fimc0_variant_s5p = { + .has_inp_rot = 1, + .has_out_rot = 1, + .has_cam_if = 1, + .min_inp_pixsize = 16, + .min_out_pixsize = 16, + .hor_offs_align = 8, + .min_vsize_align = 16, + .pix_limit = &s5p_pix_limit[0], +}; + +static const struct fimc_variant fimc2_variant_s5p = { + .has_cam_if = 1, + .min_inp_pixsize = 16, + .min_out_pixsize = 16, + .hor_offs_align = 8, + .min_vsize_align = 16, + .pix_limit = &s5p_pix_limit[1], +}; + +static const struct fimc_variant fimc0_variant_s5pv210 = { + .has_inp_rot = 1, + .has_out_rot = 1, + .has_cam_if = 1, + .min_inp_pixsize = 16, + .min_out_pixsize = 16, + .hor_offs_align = 8, + .min_vsize_align = 16, + .pix_limit = &s5p_pix_limit[1], +}; + +static const struct fimc_variant fimc1_variant_s5pv210 = { + .has_inp_rot = 1, + .has_out_rot = 1, + .has_cam_if = 1, + .has_mainscaler_ext = 1, + .min_inp_pixsize = 16, + .min_out_pixsize = 16, + .hor_offs_align = 1, + .min_vsize_align = 1, + .pix_limit = &s5p_pix_limit[2], +}; + +static const struct fimc_variant fimc2_variant_s5pv210 = { + .has_cam_if = 1, + .min_inp_pixsize = 16, + .min_out_pixsize = 16, + .hor_offs_align = 8, + .min_vsize_align = 16, + .pix_limit = &s5p_pix_limit[2], +}; + +static const struct fimc_variant fimc0_variant_exynos4210 = { + .has_inp_rot = 1, + .has_out_rot = 1, + .has_cam_if = 1, + .has_mainscaler_ext = 1, + .min_inp_pixsize = 16, + .min_out_pixsize = 16, + .hor_offs_align = 2, + .min_vsize_align = 1, + .pix_limit = &s5p_pix_limit[1], +}; + +static const struct fimc_variant fimc3_variant_exynos4210 = { + .has_mainscaler_ext = 1, + .min_inp_pixsize = 16, + .min_out_pixsize = 16, + .hor_offs_align = 2, + .min_vsize_align = 1, + .pix_limit = &s5p_pix_limit[3], +}; + +/* S5PC100 */ +static const struct fimc_drvdata fimc_drvdata_s5p = { + .variant = { + [0] = &fimc0_variant_s5p, + [1] = &fimc0_variant_s5p, + [2] = &fimc2_variant_s5p, + }, + .num_entities = 3, + .lclk_frequency = 133000000UL, + .out_buf_count = 4, +}; + +/* S5PV210, S5PC110 */ +static const struct fimc_drvdata fimc_drvdata_s5pv210 = { + .variant = { + [0] = &fimc0_variant_s5pv210, + [1] = &fimc1_variant_s5pv210, + [2] = &fimc2_variant_s5pv210, + }, + .num_entities = 3, + .lclk_frequency = 166000000UL, + .out_buf_count = 4, + .dma_pix_hoff = 1, +}; + +/* EXYNOS4210, S5PV310, S5PC210 */ +static const struct fimc_drvdata fimc_drvdata_exynos4210 = { + .variant = { + [0] = &fimc0_variant_exynos4210, + [1] = &fimc0_variant_exynos4210, + [2] = &fimc0_variant_exynos4210, + [3] = &fimc3_variant_exynos4210, + }, + .num_entities = 4, + .lclk_frequency = 166000000UL, + .dma_pix_hoff = 1, + .cistatus2 = 1, + .alpha_color = 1, + .out_buf_count = 32, +}; + +/* EXYNOS4212, EXYNOS4412 */ +static const struct fimc_drvdata fimc_drvdata_exynos4x12 = { + .num_entities = 4, + .lclk_frequency = 166000000UL, + .dma_pix_hoff = 1, + .cistatus2 = 1, + .alpha_color = 1, + .out_buf_count = 32, +}; + +static const struct platform_device_id fimc_driver_ids[] = { + { + .name = "s5p-fimc", + .driver_data = (unsigned long)&fimc_drvdata_s5p, + }, { + .name = "s5pv210-fimc", + .driver_data = (unsigned long)&fimc_drvdata_s5pv210, + }, { + .name = "exynos4-fimc", + .driver_data = (unsigned long)&fimc_drvdata_exynos4210, + }, { + .name = "exynos4x12-fimc", + .driver_data = (unsigned long)&fimc_drvdata_exynos4x12, + }, + { }, +}; + +static const struct of_device_id fimc_of_match[] = { + { + .compatible = "samsung,s5pv210-fimc", + .data = &fimc_drvdata_s5pv210, + }, { + .compatible = "samsung,exynos4210-fimc", + .data = &fimc_drvdata_exynos4210, + }, { + .compatible = "samsung,exynos4212-fimc", + .data = &fimc_drvdata_exynos4x12, + }, + { /* sentinel */ }, +}; + +static const struct dev_pm_ops fimc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume) + SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL) +}; + +static struct platform_driver fimc_driver = { + .probe = fimc_probe, + .remove = fimc_remove, + .id_table = fimc_driver_ids, + .driver = { + .of_match_table = fimc_of_match, + .name = FIMC_MODULE_NAME, + .owner = THIS_MODULE, + .pm = &fimc_pm_ops, + } +}; + +int __init fimc_register_driver(void) +{ + return platform_driver_register(&fimc_driver); +} + +void __exit fimc_unregister_driver(void) +{ + platform_driver_unregister(&fimc_driver); +} diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h new file mode 100644 index 000000000000..793333a33b24 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-core.h @@ -0,0 +1,718 @@ +/* + * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef FIMC_CORE_H_ +#define FIMC_CORE_H_ + +/*#define DEBUG*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define dbg(fmt, args...) \ + pr_debug("%s:%d: " fmt "\n", __func__, __LINE__, ##args) + +/* Time to wait for next frame VSYNC interrupt while stopping operation. */ +#define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000) +#define MAX_FIMC_CLOCKS 2 +#define FIMC_MODULE_NAME "s5p-fimc" +#define FIMC_MAX_DEVS 4 +#define FIMC_MAX_OUT_BUFS 4 +#define SCALER_MAX_HRATIO 64 +#define SCALER_MAX_VRATIO 64 +#define DMA_MIN_SIZE 8 +#define FIMC_CAMIF_MAX_HEIGHT 0x2000 +#define FIMC_MAX_JPEG_BUF_SIZE (10 * SZ_1M) +#define FIMC_MAX_PLANES 3 +#define FIMC_PIX_LIMITS_MAX 4 +#define FIMC_DEF_MIN_SIZE 16 +#define FIMC_DEF_HEIGHT_ALIGN 2 +#define FIMC_DEF_HOR_OFFS_ALIGN 1 + +/* indices to the clocks array */ +enum { + CLK_BUS, + CLK_GATE, +}; + +enum fimc_dev_flags { + ST_LPM, + /* m2m node */ + ST_M2M_RUN, + ST_M2M_PEND, + ST_M2M_SUSPENDING, + ST_M2M_SUSPENDED, + /* capture node */ + ST_CAPT_PEND, + ST_CAPT_RUN, + ST_CAPT_STREAM, + ST_CAPT_ISP_STREAM, + ST_CAPT_SUSPENDED, + ST_CAPT_SHUT, + ST_CAPT_BUSY, + ST_CAPT_APPLY_CFG, + ST_CAPT_JPEG, +}; + +#define fimc_m2m_active(dev) test_bit(ST_M2M_RUN, &(dev)->state) +#define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state) + +#define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state) +#define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state) +#define fimc_capture_busy(dev) test_bit(ST_CAPT_BUSY, &(dev)->state) + +enum fimc_datapath { + FIMC_IO_NONE, + FIMC_IO_CAMERA, + FIMC_IO_DMA, + FIMC_IO_LCDFIFO, + FIMC_IO_WRITEBACK, + FIMC_IO_ISP, +}; + +enum fimc_color_fmt { + FIMC_FMT_RGB444 = 0x10, + FIMC_FMT_RGB555, + FIMC_FMT_RGB565, + FIMC_FMT_RGB666, + FIMC_FMT_RGB888, + FIMC_FMT_RGB30_LOCAL, + FIMC_FMT_YCBCR420 = 0x20, + FIMC_FMT_YCBYCR422, + FIMC_FMT_YCRYCB422, + FIMC_FMT_CBYCRY422, + FIMC_FMT_CRYCBY422, + FIMC_FMT_YCBCR444_LOCAL, + FIMC_FMT_RAW8 = 0x40, + FIMC_FMT_RAW10, + FIMC_FMT_RAW12, + FIMC_FMT_JPEG = 0x80, + FIMC_FMT_YUYV_JPEG = 0x100, +}; + +#define fimc_fmt_is_user_defined(x) (!!((x) & 0x180)) +#define fimc_fmt_is_rgb(x) (!!((x) & 0x10)) + +#define IS_M2M(__strt) ((__strt) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || \ + __strt == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + +/* The hardware context state. */ +#define FIMC_PARAMS (1 << 0) +#define FIMC_COMPOSE (1 << 1) +#define FIMC_CTX_M2M (1 << 16) +#define FIMC_CTX_CAP (1 << 17) +#define FIMC_CTX_SHUT (1 << 18) + +/* Image conversion flags */ +#define FIMC_IN_DMA_ACCESS_TILED (1 << 0) +#define FIMC_IN_DMA_ACCESS_LINEAR (0 << 0) +#define FIMC_OUT_DMA_ACCESS_TILED (1 << 1) +#define FIMC_OUT_DMA_ACCESS_LINEAR (0 << 1) +#define FIMC_SCAN_MODE_PROGRESSIVE (0 << 2) +#define FIMC_SCAN_MODE_INTERLACED (1 << 2) +/* + * YCbCr data dynamic range for RGB-YUV color conversion. + * Y/Cb/Cr: (0 ~ 255) */ +#define FIMC_COLOR_RANGE_WIDE (0 << 3) +/* Y (16 ~ 235), Cb/Cr (16 ~ 240) */ +#define FIMC_COLOR_RANGE_NARROW (1 << 3) + +/** + * struct fimc_dma_offset - pixel offset information for DMA + * @y_h: y value horizontal offset + * @y_v: y value vertical offset + * @cb_h: cb value horizontal offset + * @cb_v: cb value vertical offset + * @cr_h: cr value horizontal offset + * @cr_v: cr value vertical offset + */ +struct fimc_dma_offset { + int y_h; + int y_v; + int cb_h; + int cb_v; + int cr_h; + int cr_v; +}; + +/** + * struct fimc_effect - color effect information + * @type: effect type + * @pat_cb: cr value when type is "arbitrary" + * @pat_cr: cr value when type is "arbitrary" + */ +struct fimc_effect { + u32 type; + u8 pat_cb; + u8 pat_cr; +}; + +/** + * struct fimc_scaler - the configuration data for FIMC inetrnal scaler + * @scaleup_h: flag indicating scaling up horizontally + * @scaleup_v: flag indicating scaling up vertically + * @copy_mode: flag indicating transparent DMA transfer (no scaling + * and color format conversion) + * @enabled: flag indicating if the scaler is used + * @hfactor: horizontal shift factor + * @vfactor: vertical shift factor + * @pre_hratio: horizontal ratio of the prescaler + * @pre_vratio: vertical ratio of the prescaler + * @pre_dst_width: the prescaler's destination width + * @pre_dst_height: the prescaler's destination height + * @main_hratio: the main scaler's horizontal ratio + * @main_vratio: the main scaler's vertical ratio + * @real_width: source pixel (width - offset) + * @real_height: source pixel (height - offset) + */ +struct fimc_scaler { + unsigned int scaleup_h:1; + unsigned int scaleup_v:1; + unsigned int copy_mode:1; + unsigned int enabled:1; + u32 hfactor; + u32 vfactor; + u32 pre_hratio; + u32 pre_vratio; + u32 pre_dst_width; + u32 pre_dst_height; + u32 main_hratio; + u32 main_vratio; + u32 real_width; + u32 real_height; +}; + +/** + * struct fimc_addr - the FIMC physical address set for DMA + * @y: luminance plane physical address + * @cb: Cb plane physical address + * @cr: Cr plane physical address + */ +struct fimc_addr { + u32 y; + u32 cb; + u32 cr; +}; + +/** + * struct fimc_vid_buffer - the driver's video buffer + * @vb: v4l videobuf buffer + * @list: linked list structure for buffer queue + * @paddr: precalculated physical address set + * @index: buffer index for the output DMA engine + */ +struct fimc_vid_buffer { + struct vb2_buffer vb; + struct list_head list; + struct fimc_addr paddr; + int index; +}; + +/** + * struct fimc_frame - source/target frame properties + * @f_width: image full width (virtual screen size) + * @f_height: image full height (virtual screen size) + * @o_width: original image width as set by S_FMT + * @o_height: original image height as set by S_FMT + * @offs_h: image horizontal pixel offset + * @offs_v: image vertical pixel offset + * @width: image pixel width + * @height: image pixel weight + * @payload: image size in bytes (w x h x bpp) + * @bytesperline: bytesperline value for each plane + * @paddr: image frame buffer physical addresses + * @dma_offset: DMA offset in bytes + * @fmt: fimc color format pointer + */ +struct fimc_frame { + u32 f_width; + u32 f_height; + u32 o_width; + u32 o_height; + u32 offs_h; + u32 offs_v; + u32 width; + u32 height; + unsigned int payload[VIDEO_MAX_PLANES]; + unsigned int bytesperline[VIDEO_MAX_PLANES]; + struct fimc_addr paddr; + struct fimc_dma_offset dma_offset; + struct fimc_fmt *fmt; + u8 alpha; +}; + +/** + * struct fimc_m2m_device - v4l2 memory-to-memory device data + * @vfd: the video device node for v4l2 m2m mode + * @m2m_dev: v4l2 memory-to-memory device data + * @ctx: hardware context data + * @refcnt: the reference counter + */ +struct fimc_m2m_device { + struct video_device vfd; + struct v4l2_m2m_dev *m2m_dev; + struct fimc_ctx *ctx; + int refcnt; +}; + +#define FIMC_SD_PAD_SINK_CAM 0 +#define FIMC_SD_PAD_SINK_FIFO 1 +#define FIMC_SD_PAD_SOURCE 2 +#define FIMC_SD_PADS_NUM 3 + +/** + * struct fimc_vid_cap - camera capture device information + * @ctx: hardware context data + * @vfd: video device node for camera capture mode + * @subdev: subdev exposing the FIMC processing block + * @vd_pad: fimc video capture node pad + * @sd_pads: fimc video processing block pads + * @ci_fmt: image format at the FIMC camera input (and the scaler output) + * @wb_fmt: image format at the FIMC ISP Writeback input + * @source_config: external image source related configuration structure + * @pending_buf_q: the pending buffer queue head + * @active_buf_q: the queue head of buffers scheduled in hardware + * @vbq: the capture am video buffer queue + * @active_buf_cnt: number of video buffers scheduled in hardware + * @buf_index: index for managing the output DMA buffers + * @frame_count: the frame counter for statistics + * @reqbufs_count: the number of buffers requested in REQBUFS ioctl + * @input_index: input (camera sensor) index + * @refcnt: driver's private reference counter + * @input: capture input type, grp_id of the attached subdev + * @user_subdev_api: true if subdevs are not configured by the host driver + */ +struct fimc_vid_cap { + struct fimc_ctx *ctx; + struct vb2_alloc_ctx *alloc_ctx; + struct video_device vfd; + struct v4l2_subdev subdev; + struct media_pad vd_pad; + struct media_pad sd_pads[FIMC_SD_PADS_NUM]; + struct v4l2_mbus_framefmt ci_fmt; + struct v4l2_mbus_framefmt wb_fmt; + struct fimc_source_info source_config; + struct list_head pending_buf_q; + struct list_head active_buf_q; + struct vb2_queue vbq; + int active_buf_cnt; + int buf_index; + unsigned int frame_count; + unsigned int reqbufs_count; + int input_index; + int refcnt; + u32 input; + bool user_subdev_api; +}; + +/** + * struct fimc_pix_limit - image pixel size limits in various IP configurations + * + * @scaler_en_w: max input pixel width when the scaler is enabled + * @scaler_dis_w: max input pixel width when the scaler is disabled + * @in_rot_en_h: max input width with the input rotator is on + * @in_rot_dis_w: max input width with the input rotator is off + * @out_rot_en_w: max output width with the output rotator on + * @out_rot_dis_w: max output width with the output rotator off + */ +struct fimc_pix_limit { + u16 scaler_en_w; + u16 scaler_dis_w; + u16 in_rot_en_h; + u16 in_rot_dis_w; + u16 out_rot_en_w; + u16 out_rot_dis_w; +}; + +/** + * struct fimc_variant - FIMC device variant information + * @has_inp_rot: set if has input rotator + * @has_out_rot: set if has output rotator + * @has_mainscaler_ext: 1 if extended mainscaler ratios in CIEXTEN register + * are present in this IP revision + * @has_cam_if: set if this instance has a camera input interface + * @has_isp_wb: set if this instance has ISP writeback input + * @pix_limit: pixel size constraints for the scaler + * @min_inp_pixsize: minimum input pixel size + * @min_out_pixsize: minimum output pixel size + * @hor_offs_align: horizontal pixel offset aligment + * @min_vsize_align: minimum vertical pixel size alignment + */ +struct fimc_variant { + unsigned int has_inp_rot:1; + unsigned int has_out_rot:1; + unsigned int has_mainscaler_ext:1; + unsigned int has_cam_if:1; + unsigned int has_isp_wb:1; + const struct fimc_pix_limit *pix_limit; + u16 min_inp_pixsize; + u16 min_out_pixsize; + u16 hor_offs_align; + u16 min_vsize_align; +}; + +/** + * struct fimc_drvdata - per device type driver data + * @variant: variant information for this device + * @num_entities: number of fimc instances available in a SoC + * @lclk_frequency: local bus clock frequency + * @cistatus2: 1 if the FIMC IPs have CISTATUS2 register + * @dma_pix_hoff: the horizontal DMA offset unit: 1 - pixels, 0 - bytes + * @alpha_color: 1 if alpha color component is supported + * @out_buf_count: maximum number of output DMA buffers supported + */ +struct fimc_drvdata { + const struct fimc_variant *variant[FIMC_MAX_DEVS]; + int num_entities; + unsigned long lclk_frequency; + /* Fields common to all FIMC IP instances */ + u8 cistatus2; + u8 dma_pix_hoff; + u8 alpha_color; + u8 out_buf_count; +}; + +#define fimc_get_drvdata(_pdev) \ + ((struct fimc_drvdata *) platform_get_device_id(_pdev)->driver_data) + +struct fimc_ctx; + +/** + * struct fimc_dev - abstraction for FIMC entity + * @slock: the spinlock protecting this data structure + * @lock: the mutex protecting this data structure + * @pdev: pointer to the FIMC platform device + * @pdata: pointer to the device platform data + * @sysreg: pointer to the SYSREG regmap + * @variant: the IP variant information + * @id: FIMC device index (0..FIMC_MAX_DEVS) + * @clock: clocks required for FIMC operation + * @regs: the mapped hardware registers + * @irq_queue: interrupt handler waitqueue + * @v4l2_dev: root v4l2_device + * @m2m: memory-to-memory V4L2 device information + * @vid_cap: camera capture device information + * @state: flags used to synchronize m2m and capture mode operation + * @alloc_ctx: videobuf2 memory allocator context + * @pipeline: fimc video capture pipeline data structure + */ +struct fimc_dev { + spinlock_t slock; + struct mutex lock; + struct platform_device *pdev; + struct s5p_platform_fimc *pdata; + struct regmap *sysreg; + const struct fimc_variant *variant; + const struct fimc_drvdata *drv_data; + u16 id; + struct clk *clock[MAX_FIMC_CLOCKS]; + void __iomem *regs; + wait_queue_head_t irq_queue; + struct v4l2_device *v4l2_dev; + struct fimc_m2m_device m2m; + struct fimc_vid_cap vid_cap; + unsigned long state; + struct vb2_alloc_ctx *alloc_ctx; + struct fimc_pipeline pipeline; + const struct fimc_pipeline_ops *pipeline_ops; +}; + +/** + * struct fimc_ctrls - v4l2 controls structure + * @handler: the control handler + * @colorfx: image effect control + * @colorfx_cbcr: Cb/Cr coefficients control + * @rotate: image rotation control + * @hflip: horizontal flip control + * @vflip: vertical flip control + * @alpha: RGB alpha control + * @ready: true if @handler is initialized + */ +struct fimc_ctrls { + struct v4l2_ctrl_handler handler; + struct { + struct v4l2_ctrl *colorfx; + struct v4l2_ctrl *colorfx_cbcr; + }; + struct v4l2_ctrl *rotate; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *alpha; + bool ready; +}; + +/** + * fimc_ctx - the device context data + * @s_frame: source frame properties + * @d_frame: destination frame properties + * @out_order_1p: output 1-plane YCBCR order + * @out_order_2p: output 2-plane YCBCR order + * @in_order_1p input 1-plane YCBCR order + * @in_order_2p: input 2-plane YCBCR order + * @in_path: input mode (DMA or camera) + * @out_path: output mode (DMA or FIFO) + * @scaler: image scaler properties + * @effect: image effect + * @rotation: image clockwise rotation in degrees + * @hflip: indicates image horizontal flip if set + * @vflip: indicates image vertical flip if set + * @flags: additional flags for image conversion + * @state: flags to keep track of user configuration + * @fimc_dev: the FIMC device this context applies to + * @m2m_ctx: memory-to-memory device context + * @fh: v4l2 file handle + * @ctrls: v4l2 controls structure + */ +struct fimc_ctx { + struct fimc_frame s_frame; + struct fimc_frame d_frame; + u32 out_order_1p; + u32 out_order_2p; + u32 in_order_1p; + u32 in_order_2p; + enum fimc_datapath in_path; + enum fimc_datapath out_path; + struct fimc_scaler scaler; + struct fimc_effect effect; + int rotation; + unsigned int hflip:1; + unsigned int vflip:1; + u32 flags; + u32 state; + struct fimc_dev *fimc_dev; + struct v4l2_m2m_ctx *m2m_ctx; + struct v4l2_fh fh; + struct fimc_ctrls ctrls; +}; + +#define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh) + +static inline void set_frame_bounds(struct fimc_frame *f, u32 width, u32 height) +{ + f->o_width = width; + f->o_height = height; + f->f_width = width; + f->f_height = height; +} + +static inline void set_frame_crop(struct fimc_frame *f, + u32 left, u32 top, u32 width, u32 height) +{ + f->offs_h = left; + f->offs_v = top; + f->width = width; + f->height = height; +} + +static inline u32 fimc_get_format_depth(struct fimc_fmt *ff) +{ + u32 i, depth = 0; + + if (ff != NULL) + for (i = 0; i < ff->colplanes; i++) + depth += ff->depth[i]; + return depth; +} + +static inline bool fimc_capture_active(struct fimc_dev *fimc) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&fimc->slock, flags); + ret = !!(fimc->state & (1 << ST_CAPT_RUN) || + fimc->state & (1 << ST_CAPT_PEND)); + spin_unlock_irqrestore(&fimc->slock, flags); + return ret; +} + +static inline void fimc_ctx_state_set(u32 state, struct fimc_ctx *ctx) +{ + unsigned long flags; + + spin_lock_irqsave(&ctx->fimc_dev->slock, flags); + ctx->state |= state; + spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags); +} + +static inline bool fimc_ctx_state_is_set(u32 mask, struct fimc_ctx *ctx) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&ctx->fimc_dev->slock, flags); + ret = (ctx->state & mask) == mask; + spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags); + return ret; +} + +static inline int tiled_fmt(struct fimc_fmt *fmt) +{ + return fmt->fourcc == V4L2_PIX_FMT_NV12MT; +} + +static inline bool fimc_jpeg_fourcc(u32 pixelformat) +{ + return (pixelformat == V4L2_PIX_FMT_JPEG || + pixelformat == V4L2_PIX_FMT_S5C_UYVY_JPG); +} + +static inline bool fimc_user_defined_mbus_fmt(u32 code) +{ + return (code == V4L2_MBUS_FMT_JPEG_1X8 || + code == V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8); +} + +/* Return the alpha component bit mask */ +static inline int fimc_get_alpha_mask(struct fimc_fmt *fmt) +{ + switch (fmt->color) { + case FIMC_FMT_RGB444: return 0x0f; + case FIMC_FMT_RGB555: return 0x01; + case FIMC_FMT_RGB888: return 0xff; + default: return 0; + }; +} + +static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx, + enum v4l2_buf_type type) +{ + struct fimc_frame *frame; + + if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) { + if (fimc_ctx_state_is_set(FIMC_CTX_M2M, ctx)) + frame = &ctx->s_frame; + else + return ERR_PTR(-EINVAL); + } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) { + frame = &ctx->d_frame; + } else { + v4l2_err(ctx->fimc_dev->v4l2_dev, + "Wrong buffer/video queue type (%d)\n", type); + return ERR_PTR(-EINVAL); + } + + return frame; +} + +/* -----------------------------------------------------*/ +/* fimc-core.c */ +int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f); +int fimc_ctrls_create(struct fimc_ctx *ctx); +void fimc_ctrls_delete(struct fimc_ctx *ctx); +void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active); +void fimc_alpha_ctrl_update(struct fimc_ctx *ctx); +void __fimc_get_format(struct fimc_frame *frame, struct v4l2_format *f); +void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, + struct v4l2_pix_format_mplane *pix); +struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code, + unsigned int mask, int index); +struct fimc_fmt *fimc_get_format(unsigned int index); + +int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh, + int dw, int dh, int rotation); +int fimc_set_scaler_info(struct fimc_ctx *ctx); +int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags); +int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, + struct fimc_frame *frame, struct fimc_addr *paddr); +void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f); +void fimc_set_yuv_order(struct fimc_ctx *ctx); +void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf); + +int fimc_register_m2m_device(struct fimc_dev *fimc, + struct v4l2_device *v4l2_dev); +void fimc_unregister_m2m_device(struct fimc_dev *fimc); +int fimc_register_driver(void); +void fimc_unregister_driver(void); + +/* -----------------------------------------------------*/ +/* fimc-m2m.c */ +void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state); + +/* -----------------------------------------------------*/ +/* fimc-capture.c */ +int fimc_initialize_capture_subdev(struct fimc_dev *fimc); +void fimc_unregister_capture_subdev(struct fimc_dev *fimc); +int fimc_capture_ctrls_create(struct fimc_dev *fimc); +void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification, + void *arg); +int fimc_capture_suspend(struct fimc_dev *fimc); +int fimc_capture_resume(struct fimc_dev *fimc); + +/* + * Buffer list manipulation functions. Must be called with fimc.slock held. + */ + +/** + * fimc_active_queue_add - add buffer to the capture active buffers queue + * @buf: buffer to add to the active buffers list + */ +static inline void fimc_active_queue_add(struct fimc_vid_cap *vid_cap, + struct fimc_vid_buffer *buf) +{ + list_add_tail(&buf->list, &vid_cap->active_buf_q); + vid_cap->active_buf_cnt++; +} + +/** + * fimc_active_queue_pop - pop buffer from the capture active buffers queue + * + * The caller must assure the active_buf_q list is not empty. + */ +static inline struct fimc_vid_buffer *fimc_active_queue_pop( + struct fimc_vid_cap *vid_cap) +{ + struct fimc_vid_buffer *buf; + buf = list_entry(vid_cap->active_buf_q.next, + struct fimc_vid_buffer, list); + list_del(&buf->list); + vid_cap->active_buf_cnt--; + return buf; +} + +/** + * fimc_pending_queue_add - add buffer to the capture pending buffers queue + * @buf: buffer to add to the pending buffers list + */ +static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap, + struct fimc_vid_buffer *buf) +{ + list_add_tail(&buf->list, &vid_cap->pending_buf_q); +} + +/** + * fimc_pending_queue_pop - pop buffer from the capture pending buffers queue + * + * The caller must assure the pending_buf_q list is not empty. + */ +static inline struct fimc_vid_buffer *fimc_pending_queue_pop( + struct fimc_vid_cap *vid_cap) +{ + struct fimc_vid_buffer *buf; + buf = list_entry(vid_cap->pending_buf_q.next, + struct fimc_vid_buffer, list); + list_del(&buf->list); + return buf; +} + +#endif /* FIMC_CORE_H_ */ diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c new file mode 100644 index 000000000000..f0af0754a7b4 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c @@ -0,0 +1,302 @@ +/* + * Register interface file for EXYNOS FIMC-LITE (camera interface) driver + * + * Copyright (C) 2012 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include + +#include "fimc-lite-reg.h" +#include "fimc-lite.h" +#include "fimc-core.h" + +#define FLITE_RESET_TIMEOUT 50 /* in ms */ + +void flite_hw_reset(struct fimc_lite *dev) +{ + unsigned long end = jiffies + msecs_to_jiffies(FLITE_RESET_TIMEOUT); + u32 cfg; + + cfg = readl(dev->regs + FLITE_REG_CIGCTRL); + cfg |= FLITE_REG_CIGCTRL_SWRST_REQ; + writel(cfg, dev->regs + FLITE_REG_CIGCTRL); + + while (time_is_after_jiffies(end)) { + cfg = readl(dev->regs + FLITE_REG_CIGCTRL); + if (cfg & FLITE_REG_CIGCTRL_SWRST_RDY) + break; + usleep_range(1000, 5000); + } + + cfg |= FLITE_REG_CIGCTRL_SWRST; + writel(cfg, dev->regs + FLITE_REG_CIGCTRL); +} + +void flite_hw_clear_pending_irq(struct fimc_lite *dev) +{ + u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS); + cfg &= ~FLITE_REG_CISTATUS_IRQ_CAM; + writel(cfg, dev->regs + FLITE_REG_CISTATUS); +} + +u32 flite_hw_get_interrupt_source(struct fimc_lite *dev) +{ + u32 intsrc = readl(dev->regs + FLITE_REG_CISTATUS); + return intsrc & FLITE_REG_CISTATUS_IRQ_MASK; +} + +void flite_hw_clear_last_capture_end(struct fimc_lite *dev) +{ + + u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS2); + cfg &= ~FLITE_REG_CISTATUS2_LASTCAPEND; + writel(cfg, dev->regs + FLITE_REG_CISTATUS2); +} + +void flite_hw_set_interrupt_mask(struct fimc_lite *dev) +{ + u32 cfg, intsrc; + + /* Select interrupts to be enabled for each output mode */ + if (atomic_read(&dev->out_path) == FIMC_IO_DMA) { + intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN | + FLITE_REG_CIGCTRL_IRQ_LASTEN | + FLITE_REG_CIGCTRL_IRQ_STARTEN; + } else { + /* An output to the FIMC-IS */ + intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN | + FLITE_REG_CIGCTRL_IRQ_LASTEN; + } + + cfg = readl(dev->regs + FLITE_REG_CIGCTRL); + cfg |= FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK; + cfg &= ~intsrc; + writel(cfg, dev->regs + FLITE_REG_CIGCTRL); +} + +void flite_hw_capture_start(struct fimc_lite *dev) +{ + u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT); + cfg |= FLITE_REG_CIIMGCPT_IMGCPTEN; + writel(cfg, dev->regs + FLITE_REG_CIIMGCPT); +} + +void flite_hw_capture_stop(struct fimc_lite *dev) +{ + u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT); + cfg &= ~FLITE_REG_CIIMGCPT_IMGCPTEN; + writel(cfg, dev->regs + FLITE_REG_CIIMGCPT); +} + +/* + * Test pattern (color bars) enable/disable. External sensor + * pixel clock must be active for the test pattern to work. + */ +void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on) +{ + u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL); + if (on) + cfg |= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR; + else + cfg &= ~FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR; + writel(cfg, dev->regs + FLITE_REG_CIGCTRL); +} + +static const u32 src_pixfmt_map[8][3] = { + { V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR, + FLITE_REG_CIGCTRL_YUV422_1P }, + { V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB, + FLITE_REG_CIGCTRL_YUV422_1P }, + { V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY, + FLITE_REG_CIGCTRL_YUV422_1P }, + { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY, + FLITE_REG_CIGCTRL_YUV422_1P }, + { V4L2_MBUS_FMT_SGRBG8_1X8, 0, FLITE_REG_CIGCTRL_RAW8 }, + { V4L2_MBUS_FMT_SGRBG10_1X10, 0, FLITE_REG_CIGCTRL_RAW10 }, + { V4L2_MBUS_FMT_SGRBG12_1X12, 0, FLITE_REG_CIGCTRL_RAW12 }, + { V4L2_MBUS_FMT_JPEG_1X8, 0, FLITE_REG_CIGCTRL_USER(1) }, +}; + +/* Set camera input pixel format and resolution */ +void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f) +{ + enum v4l2_mbus_pixelcode pixelcode = dev->fmt->mbus_code; + unsigned int i = ARRAY_SIZE(src_pixfmt_map); + u32 cfg; + + while (i-- >= 0) { + if (src_pixfmt_map[i][0] == pixelcode) + break; + } + + if (i == 0 && src_pixfmt_map[i][0] != pixelcode) { + v4l2_err(&dev->vfd, + "Unsupported pixel code, falling back to %#08x\n", + src_pixfmt_map[i][0]); + } + + cfg = readl(dev->regs + FLITE_REG_CIGCTRL); + cfg &= ~FLITE_REG_CIGCTRL_FMT_MASK; + cfg |= src_pixfmt_map[i][2]; + writel(cfg, dev->regs + FLITE_REG_CIGCTRL); + + cfg = readl(dev->regs + FLITE_REG_CISRCSIZE); + cfg &= ~(FLITE_REG_CISRCSIZE_ORDER422_MASK | + FLITE_REG_CISRCSIZE_SIZE_CAM_MASK); + cfg |= (f->f_width << 16) | f->f_height; + cfg |= src_pixfmt_map[i][1]; + writel(cfg, dev->regs + FLITE_REG_CISRCSIZE); +} + +/* Set the camera host input window offsets (cropping) */ +void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f) +{ + u32 hoff2, voff2; + u32 cfg; + + cfg = readl(dev->regs + FLITE_REG_CIWDOFST); + cfg &= ~FLITE_REG_CIWDOFST_OFST_MASK; + cfg |= (f->rect.left << 16) | f->rect.top; + cfg |= FLITE_REG_CIWDOFST_WINOFSEN; + writel(cfg, dev->regs + FLITE_REG_CIWDOFST); + + hoff2 = f->f_width - f->rect.width - f->rect.left; + voff2 = f->f_height - f->rect.height - f->rect.top; + + cfg = (hoff2 << 16) | voff2; + writel(cfg, dev->regs + FLITE_REG_CIWDOFST2); +} + +/* Select camera port (A, B) */ +static void flite_hw_set_camera_port(struct fimc_lite *dev, int id) +{ + u32 cfg = readl(dev->regs + FLITE_REG_CIGENERAL); + if (id == 0) + cfg &= ~FLITE_REG_CIGENERAL_CAM_B; + else + cfg |= FLITE_REG_CIGENERAL_CAM_B; + writel(cfg, dev->regs + FLITE_REG_CIGENERAL); +} + +/* Select serial or parallel bus, camera port (A,B) and set signals polarity */ +void flite_hw_set_camera_bus(struct fimc_lite *dev, + struct fimc_source_info *si) +{ + u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL); + unsigned int flags = si->flags; + + if (si->sensor_bus_type != FIMC_BUS_TYPE_MIPI_CSI2) { + cfg &= ~(FLITE_REG_CIGCTRL_SELCAM_MIPI | + FLITE_REG_CIGCTRL_INVPOLPCLK | + FLITE_REG_CIGCTRL_INVPOLVSYNC | + FLITE_REG_CIGCTRL_INVPOLHREF); + + if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + cfg |= FLITE_REG_CIGCTRL_INVPOLPCLK; + + if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + cfg |= FLITE_REG_CIGCTRL_INVPOLVSYNC; + + if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + cfg |= FLITE_REG_CIGCTRL_INVPOLHREF; + } else { + cfg |= FLITE_REG_CIGCTRL_SELCAM_MIPI; + } + + writel(cfg, dev->regs + FLITE_REG_CIGCTRL); + + flite_hw_set_camera_port(dev, si->mux_id); +} + +static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f) +{ + static const u32 pixcode[4][2] = { + { V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR }, + { V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CIODMAFMT_YCRYCB }, + { V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CIODMAFMT_CBYCRY }, + { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY }, + }; + u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT); + unsigned int i = ARRAY_SIZE(pixcode); + + while (i-- >= 0) + if (pixcode[i][0] == dev->fmt->mbus_code) + break; + cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK; + writel(cfg | pixcode[i][1], dev->regs + FLITE_REG_CIODMAFMT); +} + +void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f) +{ + u32 cfg; + + /* Maximum output pixel size */ + cfg = readl(dev->regs + FLITE_REG_CIOCAN); + cfg &= ~FLITE_REG_CIOCAN_MASK; + cfg = (f->f_height << 16) | f->f_width; + writel(cfg, dev->regs + FLITE_REG_CIOCAN); + + /* DMA offsets */ + cfg = readl(dev->regs + FLITE_REG_CIOOFF); + cfg &= ~FLITE_REG_CIOOFF_MASK; + cfg |= (f->rect.top << 16) | f->rect.left; + writel(cfg, dev->regs + FLITE_REG_CIOOFF); +} + +/* Enable/disable output DMA, set output pixel size and offsets (composition) */ +void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f, + bool enable) +{ + u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL); + + if (!enable) { + cfg |= FLITE_REG_CIGCTRL_ODMA_DISABLE; + writel(cfg, dev->regs + FLITE_REG_CIGCTRL); + return; + } + + cfg &= ~FLITE_REG_CIGCTRL_ODMA_DISABLE; + writel(cfg, dev->regs + FLITE_REG_CIGCTRL); + + flite_hw_set_out_order(dev, f); + flite_hw_set_dma_window(dev, f); +} + +void flite_hw_dump_regs(struct fimc_lite *dev, const char *label) +{ + struct { + u32 offset; + const char * const name; + } registers[] = { + { 0x00, "CISRCSIZE" }, + { 0x04, "CIGCTRL" }, + { 0x08, "CIIMGCPT" }, + { 0x0c, "CICPTSEQ" }, + { 0x10, "CIWDOFST" }, + { 0x14, "CIWDOFST2" }, + { 0x18, "CIODMAFMT" }, + { 0x20, "CIOCAN" }, + { 0x24, "CIOOFF" }, + { 0x30, "CIOSA" }, + { 0x40, "CISTATUS" }, + { 0x44, "CISTATUS2" }, + { 0xf0, "CITHOLD" }, + { 0xfc, "CIGENERAL" }, + }; + u32 i; + + v4l2_info(&dev->subdev, "--- %s ---\n", label); + + for (i = 0; i < ARRAY_SIZE(registers); i++) { + u32 cfg = readl(dev->regs + registers[i].offset); + v4l2_info(&dev->subdev, "%9s: 0x%08x\n", + registers[i].name, cfg); + } +} diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.h b/drivers/media/platform/exynos4-is/fimc-lite-reg.h new file mode 100644 index 000000000000..0e345844c13a --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2012 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef FIMC_LITE_REG_H_ +#define FIMC_LITE_REG_H_ + +#include "fimc-lite.h" + +/* Camera Source size */ +#define FLITE_REG_CISRCSIZE 0x00 +#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR (0 << 14) +#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB (1 << 14) +#define FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY (2 << 14) +#define FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY (3 << 14) +#define FLITE_REG_CISRCSIZE_ORDER422_MASK (0x3 << 14) +#define FLITE_REG_CISRCSIZE_SIZE_CAM_MASK (0x3fff << 16 | 0x3fff) + +/* Global control */ +#define FLITE_REG_CIGCTRL 0x04 +#define FLITE_REG_CIGCTRL_YUV422_1P (0x1e << 24) +#define FLITE_REG_CIGCTRL_RAW8 (0x2a << 24) +#define FLITE_REG_CIGCTRL_RAW10 (0x2b << 24) +#define FLITE_REG_CIGCTRL_RAW12 (0x2c << 24) +#define FLITE_REG_CIGCTRL_RAW14 (0x2d << 24) +/* User defined formats. x = 0...15 */ +#define FLITE_REG_CIGCTRL_USER(x) ((0x30 + x - 1) << 24) +#define FLITE_REG_CIGCTRL_FMT_MASK (0x3f << 24) +#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE (1 << 21) +#define FLITE_REG_CIGCTRL_ODMA_DISABLE (1 << 20) +#define FLITE_REG_CIGCTRL_SWRST_REQ (1 << 19) +#define FLITE_REG_CIGCTRL_SWRST_RDY (1 << 18) +#define FLITE_REG_CIGCTRL_SWRST (1 << 17) +#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR (1 << 15) +#define FLITE_REG_CIGCTRL_INVPOLPCLK (1 << 14) +#define FLITE_REG_CIGCTRL_INVPOLVSYNC (1 << 13) +#define FLITE_REG_CIGCTRL_INVPOLHREF (1 << 12) +/* Interrupts mask bits (1 disables an interrupt) */ +#define FLITE_REG_CIGCTRL_IRQ_LASTEN (1 << 8) +#define FLITE_REG_CIGCTRL_IRQ_ENDEN (1 << 7) +#define FLITE_REG_CIGCTRL_IRQ_STARTEN (1 << 6) +#define FLITE_REG_CIGCTRL_IRQ_OVFEN (1 << 5) +#define FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK (0xf << 5) +#define FLITE_REG_CIGCTRL_SELCAM_MIPI (1 << 3) + +/* Image Capture Enable */ +#define FLITE_REG_CIIMGCPT 0x08 +#define FLITE_REG_CIIMGCPT_IMGCPTEN (1 << 31) +#define FLITE_REG_CIIMGCPT_CPT_FREN (1 << 25) +#define FLITE_REG_CIIMGCPT_CPT_MOD_FRCNT (1 << 18) +#define FLITE_REG_CIIMGCPT_CPT_MOD_FREN (0 << 18) + +/* Capture Sequence */ +#define FLITE_REG_CICPTSEQ 0x0c + +/* Camera Window Offset */ +#define FLITE_REG_CIWDOFST 0x10 +#define FLITE_REG_CIWDOFST_WINOFSEN (1 << 31) +#define FLITE_REG_CIWDOFST_CLROVIY (1 << 31) +#define FLITE_REG_CIWDOFST_CLROVFICB (1 << 15) +#define FLITE_REG_CIWDOFST_CLROVFICR (1 << 14) +#define FLITE_REG_CIWDOFST_OFST_MASK ((0x1fff << 16) | 0x1fff) + +/* Camera Window Offset2 */ +#define FLITE_REG_CIWDOFST2 0x14 + +/* Camera Output DMA Format */ +#define FLITE_REG_CIODMAFMT 0x18 +#define FLITE_REG_CIODMAFMT_RAW_CON (1 << 15) +#define FLITE_REG_CIODMAFMT_PACK12 (1 << 14) +#define FLITE_REG_CIODMAFMT_CRYCBY (0 << 4) +#define FLITE_REG_CIODMAFMT_CBYCRY (1 << 4) +#define FLITE_REG_CIODMAFMT_YCRYCB (2 << 4) +#define FLITE_REG_CIODMAFMT_YCBYCR (3 << 4) +#define FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK (0x3 << 4) + +/* Camera Output Canvas */ +#define FLITE_REG_CIOCAN 0x20 +#define FLITE_REG_CIOCAN_MASK ((0x3fff << 16) | 0x3fff) + +/* Camera Output DMA Offset */ +#define FLITE_REG_CIOOFF 0x24 +#define FLITE_REG_CIOOFF_MASK ((0x3fff << 16) | 0x3fff) + +/* Camera Output DMA Start Address */ +#define FLITE_REG_CIOSA 0x30 + +/* Camera Status */ +#define FLITE_REG_CISTATUS 0x40 +#define FLITE_REG_CISTATUS_MIPI_VVALID (1 << 22) +#define FLITE_REG_CISTATUS_MIPI_HVALID (1 << 21) +#define FLITE_REG_CISTATUS_MIPI_DVALID (1 << 20) +#define FLITE_REG_CISTATUS_ITU_VSYNC (1 << 14) +#define FLITE_REG_CISTATUS_ITU_HREFF (1 << 13) +#define FLITE_REG_CISTATUS_OVFIY (1 << 10) +#define FLITE_REG_CISTATUS_OVFICB (1 << 9) +#define FLITE_REG_CISTATUS_OVFICR (1 << 8) +#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW (1 << 7) +#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND (1 << 6) +#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART (1 << 5) +#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND (1 << 4) +#define FLITE_REG_CISTATUS_IRQ_CAM (1 << 0) +#define FLITE_REG_CISTATUS_IRQ_MASK (0xf << 4) + +/* Camera Status2 */ +#define FLITE_REG_CISTATUS2 0x44 +#define FLITE_REG_CISTATUS2_LASTCAPEND (1 << 1) +#define FLITE_REG_CISTATUS2_FRMEND (1 << 0) + +/* Qos Threshold */ +#define FLITE_REG_CITHOLD 0xf0 +#define FLITE_REG_CITHOLD_W_QOS_EN (1 << 30) + +/* Camera General Purpose */ +#define FLITE_REG_CIGENERAL 0xfc +/* b0: 1 - camera B, 0 - camera A */ +#define FLITE_REG_CIGENERAL_CAM_B (1 << 0) + +/* ---------------------------------------------------------------------------- + * Function declarations + */ +void flite_hw_reset(struct fimc_lite *dev); +void flite_hw_clear_pending_irq(struct fimc_lite *dev); +u32 flite_hw_get_interrupt_source(struct fimc_lite *dev); +void flite_hw_clear_last_capture_end(struct fimc_lite *dev); +void flite_hw_set_interrupt_mask(struct fimc_lite *dev); +void flite_hw_capture_start(struct fimc_lite *dev); +void flite_hw_capture_stop(struct fimc_lite *dev); +void flite_hw_set_camera_bus(struct fimc_lite *dev, + struct fimc_source_info *s_info); +void flite_hw_set_camera_polarity(struct fimc_lite *dev, + struct fimc_source_info *cam); +void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f); +void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f); + +void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f, + bool enable); +void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f); +void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on); +void flite_hw_dump_regs(struct fimc_lite *dev, const char *label); + +static inline void flite_hw_set_output_addr(struct fimc_lite *dev, u32 paddr) +{ + writel(paddr, dev->regs + FLITE_REG_CIOSA); +} +#endif /* FIMC_LITE_REG_H */ diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c new file mode 100644 index 000000000000..bbcd74391560 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -0,0 +1,1626 @@ +/* + * Samsung EXYNOS FIMC-LITE (camera host interface) driver +* + * Copyright (C) 2012 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "media-dev.h" +#include "fimc-lite.h" +#include "fimc-lite-reg.h" + +static int debug; +module_param(debug, int, 0644); + +static const struct fimc_fmt fimc_lite_formats[] = { + { + .name = "YUV 4:2:2 packed, YCbYCr", + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = { 16 }, + .color = FIMC_FMT_YCBYCR422, + .memplanes = 1, + .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + }, { + .name = "YUV 4:2:2 packed, CbYCrY", + .fourcc = V4L2_PIX_FMT_UYVY, + .depth = { 16 }, + .color = FIMC_FMT_CBYCRY422, + .memplanes = 1, + .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, + }, { + .name = "YUV 4:2:2 packed, CrYCbY", + .fourcc = V4L2_PIX_FMT_VYUY, + .depth = { 16 }, + .color = FIMC_FMT_CRYCBY422, + .memplanes = 1, + .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8, + }, { + .name = "YUV 4:2:2 packed, YCrYCb", + .fourcc = V4L2_PIX_FMT_YVYU, + .depth = { 16 }, + .color = FIMC_FMT_YCRYCB422, + .memplanes = 1, + .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8, + }, { + .name = "RAW8 (GRBG)", + .fourcc = V4L2_PIX_FMT_SGRBG8, + .depth = { 8 }, + .color = FIMC_FMT_RAW8, + .memplanes = 1, + .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8, + }, { + .name = "RAW10 (GRBG)", + .fourcc = V4L2_PIX_FMT_SGRBG10, + .depth = { 10 }, + .color = FIMC_FMT_RAW10, + .memplanes = 1, + .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10, + }, { + .name = "RAW12 (GRBG)", + .fourcc = V4L2_PIX_FMT_SGRBG12, + .depth = { 12 }, + .color = FIMC_FMT_RAW12, + .memplanes = 1, + .mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12, + }, +}; + +/** + * fimc_lite_find_format - lookup fimc color format by fourcc or media bus code + * @pixelformat: fourcc to match, ignored if null + * @mbus_code: media bus code to match, ignored if null + * @index: index to the fimc_lite_formats array, ignored if negative + */ +static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat, + const u32 *mbus_code, int index) +{ + const struct fimc_fmt *fmt, *def_fmt = NULL; + unsigned int i; + int id = 0; + + if (index >= (int)ARRAY_SIZE(fimc_lite_formats)) + return NULL; + + for (i = 0; i < ARRAY_SIZE(fimc_lite_formats); ++i) { + fmt = &fimc_lite_formats[i]; + if (pixelformat && fmt->fourcc == *pixelformat) + return fmt; + if (mbus_code && fmt->mbus_code == *mbus_code) + return fmt; + if (index == id) + def_fmt = fmt; + id++; + } + return def_fmt; +} + +static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output) +{ + struct fimc_pipeline *pipeline = &fimc->pipeline; + struct v4l2_subdev *sensor; + struct fimc_sensor_info *si; + unsigned long flags; + + sensor = isp_output ? fimc->sensor : pipeline->subdevs[IDX_SENSOR]; + + if (sensor == NULL) + return -ENXIO; + + if (fimc->fmt == NULL) + return -EINVAL; + + /* Get sensor configuration data from the sensor subdev */ + si = v4l2_get_subdev_hostdata(sensor); + spin_lock_irqsave(&fimc->slock, flags); + + flite_hw_set_camera_bus(fimc, &si->pdata); + flite_hw_set_source_format(fimc, &fimc->inp_frame); + flite_hw_set_window_offset(fimc, &fimc->inp_frame); + flite_hw_set_output_dma(fimc, &fimc->out_frame, !isp_output); + flite_hw_set_interrupt_mask(fimc); + flite_hw_set_test_pattern(fimc, fimc->test_pattern->val); + + if (debug > 0) + flite_hw_dump_regs(fimc, __func__); + + spin_unlock_irqrestore(&fimc->slock, flags); + return 0; +} + +/* + * Reinitialize the driver so it is ready to start the streaming again. + * Set fimc->state to indicate stream off and the hardware shut down state. + * If not suspending (@suspend is false), return any buffers to videobuf2. + * Otherwise put any owned buffers onto the pending buffers queue, so they + * can be re-spun when the device is being resumed. Also perform FIMC + * software reset and disable streaming on the whole pipeline if required. + */ +static int fimc_lite_reinit(struct fimc_lite *fimc, bool suspend) +{ + struct flite_buffer *buf; + unsigned long flags; + bool streaming; + + spin_lock_irqsave(&fimc->slock, flags); + streaming = fimc->state & (1 << ST_SENSOR_STREAM); + + fimc->state &= ~(1 << ST_FLITE_RUN | 1 << ST_FLITE_OFF | + 1 << ST_FLITE_STREAM | 1 << ST_SENSOR_STREAM); + if (suspend) + fimc->state |= (1 << ST_FLITE_SUSPENDED); + else + fimc->state &= ~(1 << ST_FLITE_PENDING | + 1 << ST_FLITE_SUSPENDED); + + /* Release unused buffers */ + while (!suspend && !list_empty(&fimc->pending_buf_q)) { + buf = fimc_lite_pending_queue_pop(fimc); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + /* If suspending put unused buffers onto pending queue */ + while (!list_empty(&fimc->active_buf_q)) { + buf = fimc_lite_active_queue_pop(fimc); + if (suspend) + fimc_lite_pending_queue_add(fimc, buf); + else + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + + spin_unlock_irqrestore(&fimc->slock, flags); + + flite_hw_reset(fimc); + + if (!streaming) + return 0; + + return fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 0); +} + +static int fimc_lite_stop_capture(struct fimc_lite *fimc, bool suspend) +{ + unsigned long flags; + + if (!fimc_lite_active(fimc)) + return 0; + + spin_lock_irqsave(&fimc->slock, flags); + set_bit(ST_FLITE_OFF, &fimc->state); + flite_hw_capture_stop(fimc); + spin_unlock_irqrestore(&fimc->slock, flags); + + wait_event_timeout(fimc->irq_queue, + !test_bit(ST_FLITE_OFF, &fimc->state), + (2*HZ/10)); /* 200 ms */ + + return fimc_lite_reinit(fimc, suspend); +} + +/* Must be called with fimc.slock spinlock held. */ +static void fimc_lite_config_update(struct fimc_lite *fimc) +{ + flite_hw_set_window_offset(fimc, &fimc->inp_frame); + flite_hw_set_dma_window(fimc, &fimc->out_frame); + flite_hw_set_test_pattern(fimc, fimc->test_pattern->val); + clear_bit(ST_FLITE_CONFIG, &fimc->state); +} + +static irqreturn_t flite_irq_handler(int irq, void *priv) +{ + struct fimc_lite *fimc = priv; + struct flite_buffer *vbuf; + unsigned long flags; + struct timeval *tv; + struct timespec ts; + u32 intsrc; + + spin_lock_irqsave(&fimc->slock, flags); + + intsrc = flite_hw_get_interrupt_source(fimc); + flite_hw_clear_pending_irq(fimc); + + if (test_and_clear_bit(ST_FLITE_OFF, &fimc->state)) { + wake_up(&fimc->irq_queue); + goto done; + } + + if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW) { + clear_bit(ST_FLITE_RUN, &fimc->state); + fimc->events.data_overflow++; + } + + if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND) { + flite_hw_clear_last_capture_end(fimc); + clear_bit(ST_FLITE_STREAM, &fimc->state); + wake_up(&fimc->irq_queue); + } + + if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) + goto done; + + if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) && + test_bit(ST_FLITE_RUN, &fimc->state) && + !list_empty(&fimc->active_buf_q) && + !list_empty(&fimc->pending_buf_q)) { + vbuf = fimc_lite_active_queue_pop(fimc); + ktime_get_ts(&ts); + tv = &vbuf->vb.v4l2_buf.timestamp; + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; + vbuf->vb.v4l2_buf.sequence = fimc->frame_count++; + vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE); + + vbuf = fimc_lite_pending_queue_pop(fimc); + flite_hw_set_output_addr(fimc, vbuf->paddr); + fimc_lite_active_queue_add(fimc, vbuf); + } + + if (test_bit(ST_FLITE_CONFIG, &fimc->state)) + fimc_lite_config_update(fimc); + + if (list_empty(&fimc->pending_buf_q)) { + flite_hw_capture_stop(fimc); + clear_bit(ST_FLITE_STREAM, &fimc->state); + } +done: + set_bit(ST_FLITE_RUN, &fimc->state); + spin_unlock_irqrestore(&fimc->slock, flags); + return IRQ_HANDLED; +} + +static int start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct fimc_lite *fimc = q->drv_priv; + int ret; + + fimc->frame_count = 0; + + ret = fimc_lite_hw_init(fimc, false); + if (ret) { + fimc_lite_reinit(fimc, false); + return ret; + } + + set_bit(ST_FLITE_PENDING, &fimc->state); + + if (!list_empty(&fimc->active_buf_q) && + !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) { + flite_hw_capture_start(fimc); + + if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state)) + fimc_pipeline_call(fimc, set_stream, + &fimc->pipeline, 1); + } + if (debug > 0) + flite_hw_dump_regs(fimc, __func__); + + return 0; +} + +static int stop_streaming(struct vb2_queue *q) +{ + struct fimc_lite *fimc = q->drv_priv; + + if (!fimc_lite_active(fimc)) + return -EINVAL; + + return fimc_lite_stop_capture(fimc, false); +} + +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *allocators[]) +{ + const struct v4l2_pix_format_mplane *pixm = NULL; + struct fimc_lite *fimc = vq->drv_priv; + struct flite_frame *frame = &fimc->out_frame; + const struct fimc_fmt *fmt = fimc->fmt; + unsigned long wh; + int i; + + if (pfmt) { + pixm = &pfmt->fmt.pix_mp; + fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, -1); + wh = pixm->width * pixm->height; + } else { + wh = frame->f_width * frame->f_height; + } + + if (fmt == NULL) + return -EINVAL; + + *num_planes = fmt->memplanes; + + for (i = 0; i < fmt->memplanes; i++) { + unsigned int size = (wh * fmt->depth[i]) / 8; + if (pixm) + sizes[i] = max(size, pixm->plane_fmt[i].sizeimage); + else + sizes[i] = size; + allocators[i] = fimc->alloc_ctx; + } + + return 0; +} + +static int buffer_prepare(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct fimc_lite *fimc = vq->drv_priv; + int i; + + if (fimc->fmt == NULL) + return -EINVAL; + + for (i = 0; i < fimc->fmt->memplanes; i++) { + unsigned long size = fimc->payload[i]; + + if (vb2_plane_size(vb, i) < size) { + v4l2_err(&fimc->vfd, + "User buffer too small (%ld < %ld)\n", + vb2_plane_size(vb, i), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, i, size); + } + + return 0; +} + +static void buffer_queue(struct vb2_buffer *vb) +{ + struct flite_buffer *buf + = container_of(vb, struct flite_buffer, vb); + struct fimc_lite *fimc = vb2_get_drv_priv(vb->vb2_queue); + unsigned long flags; + + spin_lock_irqsave(&fimc->slock, flags); + buf->paddr = vb2_dma_contig_plane_dma_addr(vb, 0); + + if (!test_bit(ST_FLITE_SUSPENDED, &fimc->state) && + !test_bit(ST_FLITE_STREAM, &fimc->state) && + list_empty(&fimc->active_buf_q)) { + flite_hw_set_output_addr(fimc, buf->paddr); + fimc_lite_active_queue_add(fimc, buf); + } else { + fimc_lite_pending_queue_add(fimc, buf); + } + + if (vb2_is_streaming(&fimc->vb_queue) && + !list_empty(&fimc->pending_buf_q) && + !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) { + flite_hw_capture_start(fimc); + spin_unlock_irqrestore(&fimc->slock, flags); + + if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state)) + fimc_pipeline_call(fimc, set_stream, + &fimc->pipeline, 1); + return; + } + spin_unlock_irqrestore(&fimc->slock, flags); +} + +static const struct vb2_ops fimc_lite_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, +}; + +static void fimc_lite_clear_event_counters(struct fimc_lite *fimc) +{ + unsigned long flags; + + spin_lock_irqsave(&fimc->slock, flags); + memset(&fimc->events, 0, sizeof(fimc->events)); + spin_unlock_irqrestore(&fimc->slock, flags); +} + +static int fimc_lite_open(struct file *file) +{ + struct fimc_lite *fimc = video_drvdata(file); + struct media_entity *me = &fimc->vfd.entity; + int ret; + + mutex_lock(&me->parent->graph_mutex); + + mutex_lock(&fimc->lock); + if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) { + ret = -EBUSY; + goto unlock; + } + + set_bit(ST_FLITE_IN_USE, &fimc->state); + ret = pm_runtime_get_sync(&fimc->pdev->dev); + if (ret < 0) + goto unlock; + + ret = v4l2_fh_open(file); + if (ret < 0) + goto err_pm; + + if (!v4l2_fh_is_singular_file(file) || + atomic_read(&fimc->out_path) != FIMC_IO_DMA) + goto unlock; + + ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, + me, true); + if (!ret) { + fimc_lite_clear_event_counters(fimc); + fimc->ref_count++; + goto unlock; + } + + v4l2_fh_release(file); +err_pm: + pm_runtime_put_sync(&fimc->pdev->dev); + clear_bit(ST_FLITE_IN_USE, &fimc->state); +unlock: + mutex_unlock(&fimc->lock); + mutex_unlock(&me->parent->graph_mutex); + return ret; +} + +static int fimc_lite_release(struct file *file) +{ + struct fimc_lite *fimc = video_drvdata(file); + + mutex_lock(&fimc->lock); + + if (v4l2_fh_is_singular_file(file) && + atomic_read(&fimc->out_path) == FIMC_IO_DMA) { + clear_bit(ST_FLITE_IN_USE, &fimc->state); + fimc_lite_stop_capture(fimc, false); + fimc_pipeline_call(fimc, close, &fimc->pipeline); + fimc->ref_count--; + } + + vb2_fop_release(file); + pm_runtime_put(&fimc->pdev->dev); + clear_bit(ST_FLITE_SUSPENDED, &fimc->state); + + mutex_unlock(&fimc->lock); + return 0; +} + +static const struct v4l2_file_operations fimc_lite_fops = { + .owner = THIS_MODULE, + .open = fimc_lite_open, + .release = fimc_lite_release, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +/* + * Format and crop negotiation helpers + */ + +static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc, + u32 *width, u32 *height, + u32 *code, u32 *fourcc, int pad) +{ + struct flite_variant *variant = fimc->variant; + const struct fimc_fmt *fmt; + + fmt = fimc_lite_find_format(fourcc, code, 0); + if (WARN_ON(!fmt)) + return NULL; + + if (code) + *code = fmt->mbus_code; + if (fourcc) + *fourcc = fmt->fourcc; + + if (pad == FLITE_SD_PAD_SINK) { + v4l_bound_align_image(width, 8, variant->max_width, + ffs(variant->out_width_align) - 1, + height, 0, variant->max_height, 0, 0); + } else { + v4l_bound_align_image(width, 8, fimc->inp_frame.rect.width, + ffs(variant->out_width_align) - 1, + height, 0, fimc->inp_frame.rect.height, + 0, 0); + } + + v4l2_dbg(1, debug, &fimc->subdev, "code: 0x%x, %dx%d\n", + code ? *code : 0, *width, *height); + + return fmt; +} + +static void fimc_lite_try_crop(struct fimc_lite *fimc, struct v4l2_rect *r) +{ + struct flite_frame *frame = &fimc->inp_frame; + + v4l_bound_align_image(&r->width, 0, frame->f_width, 0, + &r->height, 0, frame->f_height, 0, 0); + + /* Adjust left/top if cropping rectangle got out of bounds */ + r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width); + r->left = round_down(r->left, fimc->variant->win_hor_offs_align); + r->top = clamp_t(u32, r->top, 0, frame->f_height - r->height); + + v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, sink fmt: %dx%d\n", + r->left, r->top, r->width, r->height, + frame->f_width, frame->f_height); +} + +static void fimc_lite_try_compose(struct fimc_lite *fimc, struct v4l2_rect *r) +{ + struct flite_frame *frame = &fimc->out_frame; + struct v4l2_rect *crop_rect = &fimc->inp_frame.rect; + + /* Scaling is not supported so we enforce compose rectangle size + same as size of the sink crop rectangle. */ + r->width = crop_rect->width; + r->height = crop_rect->height; + + /* Adjust left/top if the composing rectangle got out of bounds */ + r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width); + r->left = round_down(r->left, fimc->variant->out_hor_offs_align); + r->top = clamp_t(u32, r->top, 0, fimc->out_frame.f_height - r->height); + + v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, source fmt: %dx%d\n", + r->left, r->top, r->width, r->height, + frame->f_width, frame->f_height); +} + +/* + * Video node ioctl operations + */ +static int fimc_vidioc_querycap_capture(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strlcpy(cap->driver, FIMC_LITE_DRV_NAME, sizeof(cap->driver)); + cap->bus_info[0] = 0; + cap->card[0] = 0; + cap->capabilities = V4L2_CAP_STREAMING; + return 0; +} + +static int fimc_lite_enum_fmt_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + const struct fimc_fmt *fmt; + + if (f->index >= ARRAY_SIZE(fimc_lite_formats)) + return -EINVAL; + + fmt = &fimc_lite_formats[f->index]; + strlcpy(f->description, fmt->name, sizeof(f->description)); + f->pixelformat = fmt->fourcc; + + return 0; +} + +static int fimc_lite_g_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct fimc_lite *fimc = video_drvdata(file); + struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; + struct v4l2_plane_pix_format *plane_fmt = &pixm->plane_fmt[0]; + struct flite_frame *frame = &fimc->out_frame; + const struct fimc_fmt *fmt = fimc->fmt; + + plane_fmt->bytesperline = (frame->f_width * fmt->depth[0]) / 8; + plane_fmt->sizeimage = plane_fmt->bytesperline * frame->f_height; + + pixm->num_planes = fmt->memplanes; + pixm->pixelformat = fmt->fourcc; + pixm->width = frame->f_width; + pixm->height = frame->f_height; + pixm->field = V4L2_FIELD_NONE; + pixm->colorspace = V4L2_COLORSPACE_JPEG; + return 0; +} + +static int fimc_lite_try_fmt(struct fimc_lite *fimc, + struct v4l2_pix_format_mplane *pixm, + const struct fimc_fmt **ffmt) +{ + struct flite_variant *variant = fimc->variant; + u32 bpl = pixm->plane_fmt[0].bytesperline; + const struct fimc_fmt *fmt; + + fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0); + if (WARN_ON(fmt == NULL)) + return -EINVAL; + if (ffmt) + *ffmt = fmt; + v4l_bound_align_image(&pixm->width, 8, variant->max_width, + ffs(variant->out_width_align) - 1, + &pixm->height, 0, variant->max_height, 0, 0); + + if ((bpl == 0 || ((bpl * 8) / fmt->depth[0]) < pixm->width)) + pixm->plane_fmt[0].bytesperline = (pixm->width * + fmt->depth[0]) / 8; + + if (pixm->plane_fmt[0].sizeimage == 0) + pixm->plane_fmt[0].sizeimage = (pixm->width * pixm->height * + fmt->depth[0]) / 8; + pixm->num_planes = fmt->memplanes; + pixm->pixelformat = fmt->fourcc; + pixm->colorspace = V4L2_COLORSPACE_JPEG; + pixm->field = V4L2_FIELD_NONE; + return 0; +} + +static int fimc_lite_try_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct fimc_lite *fimc = video_drvdata(file); + return fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, NULL); +} + +static int fimc_lite_s_fmt_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; + struct fimc_lite *fimc = video_drvdata(file); + struct flite_frame *frame = &fimc->out_frame; + const struct fimc_fmt *fmt = NULL; + int ret; + + if (vb2_is_busy(&fimc->vb_queue)) + return -EBUSY; + + ret = fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, &fmt); + if (ret < 0) + return ret; + + fimc->fmt = fmt; + fimc->payload[0] = max((pixm->width * pixm->height * fmt->depth[0]) / 8, + pixm->plane_fmt[0].sizeimage); + frame->f_width = pixm->width; + frame->f_height = pixm->height; + + return 0; +} + +static int fimc_pipeline_validate(struct fimc_lite *fimc) +{ + struct v4l2_subdev *sd = &fimc->subdev; + struct v4l2_subdev_format sink_fmt, src_fmt; + struct media_pad *pad; + int ret; + + while (1) { + /* Retrieve format at the sink pad */ + pad = &sd->entity.pads[0]; + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + break; + /* Don't call FIMC subdev operation to avoid nested locking */ + if (sd == &fimc->subdev) { + struct flite_frame *ff = &fimc->out_frame; + sink_fmt.format.width = ff->f_width; + sink_fmt.format.height = ff->f_height; + sink_fmt.format.code = fimc->fmt->mbus_code; + } else { + sink_fmt.pad = pad->index; + sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, + &sink_fmt); + if (ret < 0 && ret != -ENOIOCTLCMD) + return -EPIPE; + } + /* Retrieve format at the source pad */ + pad = media_entity_remote_source(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + sd = media_entity_to_v4l2_subdev(pad->entity); + src_fmt.pad = pad->index; + src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt); + if (ret < 0 && ret != -ENOIOCTLCMD) + return -EPIPE; + + if (src_fmt.format.width != sink_fmt.format.width || + src_fmt.format.height != sink_fmt.format.height || + src_fmt.format.code != sink_fmt.format.code) + return -EPIPE; + } + return 0; +} + +static int fimc_lite_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct fimc_lite *fimc = video_drvdata(file); + struct media_entity *entity = &fimc->vfd.entity; + struct fimc_pipeline *p = &fimc->pipeline; + int ret; + + if (fimc_lite_active(fimc)) + return -EBUSY; + + ret = media_entity_pipeline_start(entity, p->m_pipeline); + if (ret < 0) + return ret; + + ret = fimc_pipeline_validate(fimc); + if (ret < 0) + goto err_p_stop; + + ret = vb2_ioctl_streamon(file, priv, type); + if (!ret) + return ret; +err_p_stop: + media_entity_pipeline_stop(entity); + return 0; +} + +static int fimc_lite_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct fimc_lite *fimc = video_drvdata(file); + int ret; + + ret = vb2_ioctl_streamoff(file, priv, type); + if (ret == 0) + media_entity_pipeline_stop(&fimc->vfd.entity); + return ret; +} + +static int fimc_lite_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) +{ + struct fimc_lite *fimc = video_drvdata(file); + int ret; + + reqbufs->count = max_t(u32, FLITE_REQ_BUFS_MIN, reqbufs->count); + ret = vb2_ioctl_reqbufs(file, priv, reqbufs); + if (!ret) + fimc->reqbufs_count = reqbufs->count; + + return ret; +} + +/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ +static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) +{ + if (a->left < b->left || a->top < b->top) + return 0; + if (a->left + a->width > b->left + b->width) + return 0; + if (a->top + a->height > b->top + b->height) + return 0; + + return 1; +} + +static int fimc_lite_g_selection(struct file *file, void *fh, + struct v4l2_selection *sel) +{ + struct fimc_lite *fimc = video_drvdata(file); + struct flite_frame *f = &fimc->out_frame; + + if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = f->f_width; + sel->r.height = f->f_height; + return 0; + + case V4L2_SEL_TGT_COMPOSE: + sel->r = f->rect; + return 0; + } + + return -EINVAL; +} + +static int fimc_lite_s_selection(struct file *file, void *fh, + struct v4l2_selection *sel) +{ + struct fimc_lite *fimc = video_drvdata(file); + struct flite_frame *f = &fimc->out_frame; + struct v4l2_rect rect = sel->r; + unsigned long flags; + + if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE || + sel->target != V4L2_SEL_TGT_COMPOSE) + return -EINVAL; + + fimc_lite_try_compose(fimc, &rect); + + if ((sel->flags & V4L2_SEL_FLAG_LE) && + !enclosed_rectangle(&rect, &sel->r)) + return -ERANGE; + + if ((sel->flags & V4L2_SEL_FLAG_GE) && + !enclosed_rectangle(&sel->r, &rect)) + return -ERANGE; + + sel->r = rect; + spin_lock_irqsave(&fimc->slock, flags); + f->rect = rect; + set_bit(ST_FLITE_CONFIG, &fimc->state); + spin_unlock_irqrestore(&fimc->slock, flags); + + return 0; +} + +static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = { + .vidioc_querycap = fimc_vidioc_querycap_capture, + .vidioc_enum_fmt_vid_cap_mplane = fimc_lite_enum_fmt_mplane, + .vidioc_try_fmt_vid_cap_mplane = fimc_lite_try_fmt_mplane, + .vidioc_s_fmt_vid_cap_mplane = fimc_lite_s_fmt_mplane, + .vidioc_g_fmt_vid_cap_mplane = fimc_lite_g_fmt_mplane, + .vidioc_g_selection = fimc_lite_g_selection, + .vidioc_s_selection = fimc_lite_s_selection, + .vidioc_reqbufs = fimc_lite_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = fimc_lite_streamon, + .vidioc_streamoff = fimc_lite_streamoff, +}; + +/* Called with the media graph mutex held */ +static struct v4l2_subdev *__find_remote_sensor(struct media_entity *me) +{ + struct media_pad *pad = &me->pads[0]; + struct v4l2_subdev *sd; + + while (pad->flags & MEDIA_PAD_FL_SINK) { + /* source pad */ + pad = media_entity_remote_source(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + sd = media_entity_to_v4l2_subdev(pad->entity); + + if (sd->grp_id == GRP_ID_FIMC_IS_SENSOR) + return sd; + /* sink pad */ + pad = &sd->entity.pads[0]; + } + return NULL; +} + +/* Capture subdev media entity operations */ +static int fimc_lite_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct fimc_lite *fimc = v4l2_get_subdevdata(sd); + unsigned int remote_ent_type = media_entity_type(remote->entity); + int ret = 0; + + if (WARN_ON(fimc == NULL)) + return 0; + + v4l2_dbg(1, debug, sd, "%s: %s --> %s, flags: 0x%x. source_id: 0x%x\n", + __func__, remote->entity->name, local->entity->name, + flags, fimc->source_subdev_grp_id); + + mutex_lock(&fimc->lock); + + switch (local->index) { + case FLITE_SD_PAD_SINK: + if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV) { + ret = -EINVAL; + break; + } + if (flags & MEDIA_LNK_FL_ENABLED) { + if (fimc->source_subdev_grp_id == 0) + fimc->source_subdev_grp_id = sd->grp_id; + else + ret = -EBUSY; + } else { + fimc->source_subdev_grp_id = 0; + fimc->sensor = NULL; + } + break; + + case FLITE_SD_PAD_SOURCE_DMA: + if (!(flags & MEDIA_LNK_FL_ENABLED)) + atomic_set(&fimc->out_path, FIMC_IO_NONE); + else if (remote_ent_type == MEDIA_ENT_T_DEVNODE) + atomic_set(&fimc->out_path, FIMC_IO_DMA); + else + ret = -EINVAL; + break; + + case FLITE_SD_PAD_SOURCE_ISP: + if (!(flags & MEDIA_LNK_FL_ENABLED)) + atomic_set(&fimc->out_path, FIMC_IO_NONE); + else if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV) + atomic_set(&fimc->out_path, FIMC_IO_ISP); + else + ret = -EINVAL; + break; + + default: + v4l2_err(sd, "Invalid pad index\n"); + ret = -EINVAL; + } + mb(); + + mutex_unlock(&fimc->lock); + return ret; +} + +static const struct media_entity_operations fimc_lite_subdev_media_ops = { + .link_setup = fimc_lite_link_setup, +}; + +static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + const struct fimc_fmt *fmt; + + fmt = fimc_lite_find_format(NULL, NULL, code->index); + if (!fmt) + return -EINVAL; + code->code = fmt->mbus_code; + return 0; +} + +static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct fimc_lite *fimc = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf = &fmt->format; + struct flite_frame *f = &fimc->out_frame; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(fh, fmt->pad); + fmt->format = *mf; + return 0; + } + mf->colorspace = V4L2_COLORSPACE_JPEG; + + mutex_lock(&fimc->lock); + mf->code = fimc->fmt->mbus_code; + + if (fmt->pad == FLITE_SD_PAD_SINK) { + /* full camera input frame size */ + mf->width = f->f_width; + mf->height = f->f_height; + } else { + /* crop size */ + mf->width = f->rect.width; + mf->height = f->rect.height; + } + mutex_unlock(&fimc->lock); + return 0; +} + +static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct fimc_lite *fimc = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf = &fmt->format; + struct flite_frame *sink = &fimc->inp_frame; + struct flite_frame *source = &fimc->out_frame; + const struct fimc_fmt *ffmt; + + v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %dx%d\n", + fmt->pad, mf->code, mf->width, mf->height); + + mf->colorspace = V4L2_COLORSPACE_JPEG; + mutex_lock(&fimc->lock); + + if ((atomic_read(&fimc->out_path) == FIMC_IO_ISP && + sd->entity.stream_count > 0) || + (atomic_read(&fimc->out_path) == FIMC_IO_DMA && + vb2_is_busy(&fimc->vb_queue))) { + mutex_unlock(&fimc->lock); + return -EBUSY; + } + + ffmt = fimc_lite_try_format(fimc, &mf->width, &mf->height, + &mf->code, NULL, fmt->pad); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(fh, fmt->pad); + *mf = fmt->format; + mutex_unlock(&fimc->lock); + return 0; + } + + if (fmt->pad == FLITE_SD_PAD_SINK) { + sink->f_width = mf->width; + sink->f_height = mf->height; + fimc->fmt = ffmt; + /* Set sink crop rectangle */ + sink->rect.width = mf->width; + sink->rect.height = mf->height; + sink->rect.left = 0; + sink->rect.top = 0; + /* Reset source format and crop rectangle */ + source->rect = sink->rect; + source->f_width = mf->width; + source->f_height = mf->height; + } else { + /* Allow changing format only on sink pad */ + mf->code = fimc->fmt->mbus_code; + mf->width = sink->rect.width; + mf->height = sink->rect.height; + } + + mutex_unlock(&fimc->lock); + return 0; +} + +static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) +{ + struct fimc_lite *fimc = v4l2_get_subdevdata(sd); + struct flite_frame *f = &fimc->inp_frame; + + if ((sel->target != V4L2_SEL_TGT_CROP && + sel->target != V4L2_SEL_TGT_CROP_BOUNDS) || + sel->pad != FLITE_SD_PAD_SINK) + return -EINVAL; + + if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { + sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad); + return 0; + } + + mutex_lock(&fimc->lock); + if (sel->target == V4L2_SEL_TGT_CROP) { + sel->r = f->rect; + } else { + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = f->f_width; + sel->r.height = f->f_height; + } + mutex_unlock(&fimc->lock); + + v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d\n", + __func__, f->rect.left, f->rect.top, f->rect.width, + f->rect.height, f->f_width, f->f_height); + + return 0; +} + +static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) +{ + struct fimc_lite *fimc = v4l2_get_subdevdata(sd); + struct flite_frame *f = &fimc->inp_frame; + int ret = 0; + + if (sel->target != V4L2_SEL_TGT_CROP || sel->pad != FLITE_SD_PAD_SINK) + return -EINVAL; + + mutex_lock(&fimc->lock); + fimc_lite_try_crop(fimc, &sel->r); + + if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { + *v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r; + } else { + unsigned long flags; + spin_lock_irqsave(&fimc->slock, flags); + f->rect = sel->r; + /* Same crop rectangle on the source pad */ + fimc->out_frame.rect = sel->r; + set_bit(ST_FLITE_CONFIG, &fimc->state); + spin_unlock_irqrestore(&fimc->slock, flags); + } + mutex_unlock(&fimc->lock); + + v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d\n", + __func__, f->rect.left, f->rect.top, f->rect.width, + f->rect.height, f->f_width, f->f_height); + + return ret; +} + +static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on) +{ + struct fimc_lite *fimc = v4l2_get_subdevdata(sd); + unsigned long flags; + int ret; + + /* + * Find sensor subdev linked to FIMC-LITE directly or through + * MIPI-CSIS. This is required for configuration where FIMC-LITE + * is used as a subdev only and feeds data internally to FIMC-IS. + * The pipeline links are protected through entity.stream_count + * so there is no need to take the media graph mutex here. + */ + fimc->sensor = __find_remote_sensor(&sd->entity); + + if (atomic_read(&fimc->out_path) != FIMC_IO_ISP) + return -ENOIOCTLCMD; + + mutex_lock(&fimc->lock); + if (on) { + flite_hw_reset(fimc); + ret = fimc_lite_hw_init(fimc, true); + if (!ret) { + spin_lock_irqsave(&fimc->slock, flags); + flite_hw_capture_start(fimc); + spin_unlock_irqrestore(&fimc->slock, flags); + } + } else { + set_bit(ST_FLITE_OFF, &fimc->state); + + spin_lock_irqsave(&fimc->slock, flags); + flite_hw_capture_stop(fimc); + spin_unlock_irqrestore(&fimc->slock, flags); + + ret = wait_event_timeout(fimc->irq_queue, + !test_bit(ST_FLITE_OFF, &fimc->state), + msecs_to_jiffies(200)); + if (ret == 0) + v4l2_err(sd, "s_stream(0) timeout\n"); + clear_bit(ST_FLITE_RUN, &fimc->state); + } + + mutex_unlock(&fimc->lock); + return ret; +} + +static int fimc_lite_log_status(struct v4l2_subdev *sd) +{ + struct fimc_lite *fimc = v4l2_get_subdevdata(sd); + + flite_hw_dump_regs(fimc, __func__); + return 0; +} + +static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) +{ + struct fimc_lite *fimc = v4l2_get_subdevdata(sd); + struct vb2_queue *q = &fimc->vb_queue; + struct video_device *vfd = &fimc->vfd; + int ret; + + memset(vfd, 0, sizeof(*vfd)); + + fimc->fmt = &fimc_lite_formats[0]; + atomic_set(&fimc->out_path, FIMC_IO_DMA); + + snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture", + fimc->index); + + vfd->fops = &fimc_lite_fops; + vfd->ioctl_ops = &fimc_lite_ioctl_ops; + vfd->v4l2_dev = sd->v4l2_dev; + vfd->minor = -1; + vfd->release = video_device_release_empty; + vfd->queue = q; + fimc->reqbufs_count = 0; + + INIT_LIST_HEAD(&fimc->pending_buf_q); + INIT_LIST_HEAD(&fimc->active_buf_q); + + memset(q, 0, sizeof(*q)); + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->ops = &fimc_lite_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct flite_buffer); + q->drv_priv = fimc; + q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &fimc->lock; + + ret = vb2_queue_init(q); + if (ret < 0) + return ret; + + fimc->vd_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_init(&vfd->entity, 1, &fimc->vd_pad, 0); + if (ret < 0) + return ret; + + video_set_drvdata(vfd, fimc); + fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd); + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + media_entity_cleanup(&vfd->entity); + fimc->pipeline_ops = NULL; + return ret; + } + + v4l2_info(sd->v4l2_dev, "Registered %s as /dev/%s\n", + vfd->name, video_device_node_name(vfd)); + return 0; +} + +static void fimc_lite_subdev_unregistered(struct v4l2_subdev *sd) +{ + struct fimc_lite *fimc = v4l2_get_subdevdata(sd); + + if (fimc == NULL) + return; + + if (video_is_registered(&fimc->vfd)) { + video_unregister_device(&fimc->vfd); + media_entity_cleanup(&fimc->vfd.entity); + fimc->pipeline_ops = NULL; + } +} + +static const struct v4l2_subdev_internal_ops fimc_lite_subdev_internal_ops = { + .registered = fimc_lite_subdev_registered, + .unregistered = fimc_lite_subdev_unregistered, +}; + +static const struct v4l2_subdev_pad_ops fimc_lite_subdev_pad_ops = { + .enum_mbus_code = fimc_lite_subdev_enum_mbus_code, + .get_selection = fimc_lite_subdev_get_selection, + .set_selection = fimc_lite_subdev_set_selection, + .get_fmt = fimc_lite_subdev_get_fmt, + .set_fmt = fimc_lite_subdev_set_fmt, +}; + +static const struct v4l2_subdev_video_ops fimc_lite_subdev_video_ops = { + .s_stream = fimc_lite_subdev_s_stream, +}; + +static const struct v4l2_subdev_core_ops fimc_lite_core_ops = { + .log_status = fimc_lite_log_status, +}; + +static struct v4l2_subdev_ops fimc_lite_subdev_ops = { + .core = &fimc_lite_core_ops, + .video = &fimc_lite_subdev_video_ops, + .pad = &fimc_lite_subdev_pad_ops, +}; + +static int fimc_lite_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct fimc_lite *fimc = container_of(ctrl->handler, struct fimc_lite, + ctrl_handler); + set_bit(ST_FLITE_CONFIG, &fimc->state); + return 0; +} + +static const struct v4l2_ctrl_ops fimc_lite_ctrl_ops = { + .s_ctrl = fimc_lite_s_ctrl, +}; + +static const struct v4l2_ctrl_config fimc_lite_ctrl = { + .ops = &fimc_lite_ctrl_ops, + .id = V4L2_CTRL_CLASS_USER | 0x1001, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Test Pattern 640x480", +}; + +static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc) +{ + struct v4l2_ctrl_handler *handler = &fimc->ctrl_handler; + struct v4l2_subdev *sd = &fimc->subdev; + int ret; + + v4l2_subdev_init(sd, &fimc_lite_subdev_ops); + sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(sd->name, sizeof(sd->name), "FIMC-LITE.%d", fimc->index); + + fimc->subdev_pads[FLITE_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + fimc->subdev_pads[FLITE_SD_PAD_SOURCE_DMA].flags = MEDIA_PAD_FL_SOURCE; + fimc->subdev_pads[FLITE_SD_PAD_SOURCE_ISP].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_init(&sd->entity, FLITE_SD_PADS_NUM, + fimc->subdev_pads, 0); + if (ret) + return ret; + + v4l2_ctrl_handler_init(handler, 1); + fimc->test_pattern = v4l2_ctrl_new_custom(handler, &fimc_lite_ctrl, + NULL); + if (handler->error) { + media_entity_cleanup(&sd->entity); + return handler->error; + } + + sd->ctrl_handler = handler; + sd->internal_ops = &fimc_lite_subdev_internal_ops; + sd->entity.ops = &fimc_lite_subdev_media_ops; + v4l2_set_subdevdata(sd, fimc); + + return 0; +} + +static void fimc_lite_unregister_capture_subdev(struct fimc_lite *fimc) +{ + struct v4l2_subdev *sd = &fimc->subdev; + + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(&fimc->ctrl_handler); + v4l2_set_subdevdata(sd, NULL); +} + +static void fimc_lite_clk_put(struct fimc_lite *fimc) +{ + if (IS_ERR_OR_NULL(fimc->clock)) + return; + + clk_unprepare(fimc->clock); + clk_put(fimc->clock); + fimc->clock = NULL; +} + +static int fimc_lite_clk_get(struct fimc_lite *fimc) +{ + int ret; + + fimc->clock = clk_get(&fimc->pdev->dev, FLITE_CLK_NAME); + if (IS_ERR(fimc->clock)) + return PTR_ERR(fimc->clock); + + ret = clk_prepare(fimc->clock); + if (ret < 0) { + clk_put(fimc->clock); + fimc->clock = NULL; + } + return ret; +} + +static const struct of_device_id flite_of_match[]; + +static int fimc_lite_probe(struct platform_device *pdev) +{ + struct flite_drvdata *drv_data = NULL; + struct device *dev = &pdev->dev; + const struct of_device_id *of_id; + struct fimc_lite *fimc; + struct resource *res; + int ret; + + fimc = devm_kzalloc(dev, sizeof(*fimc), GFP_KERNEL); + if (!fimc) + return -ENOMEM; + + if (dev->of_node) { + of_id = of_match_node(flite_of_match, dev->of_node); + if (of_id) + drv_data = (struct flite_drvdata *)of_id->data; + fimc->index = of_alias_get_id(dev->of_node, "fimc-lite"); + } else { + drv_data = fimc_lite_get_drvdata(pdev); + fimc->index = pdev->id; + } + + if (!drv_data || fimc->index < 0 || fimc->index >= FIMC_LITE_MAX_DEVS) + return -EINVAL; + + fimc->variant = drv_data->variant[fimc->index]; + fimc->pdev = pdev; + + init_waitqueue_head(&fimc->irq_queue); + spin_lock_init(&fimc->slock); + mutex_init(&fimc->lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + fimc->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(fimc->regs)) + return PTR_ERR(fimc->regs); + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res == NULL) { + dev_err(dev, "Failed to get IRQ resource\n"); + return -ENXIO; + } + + ret = fimc_lite_clk_get(fimc); + if (ret) + return ret; + + ret = devm_request_irq(dev, res->start, flite_irq_handler, + 0, dev_name(dev), fimc); + if (ret) { + dev_err(dev, "Failed to install irq (%d)\n", ret); + goto err_clk; + } + + /* The video node will be created within the subdev's registered() op */ + ret = fimc_lite_create_capture_subdev(fimc); + if (ret) + goto err_clk; + + platform_set_drvdata(pdev, fimc); + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) + goto err_sd; + + fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); + if (IS_ERR(fimc->alloc_ctx)) { + ret = PTR_ERR(fimc->alloc_ctx); + goto err_pm; + } + pm_runtime_put(dev); + + dev_dbg(dev, "FIMC-LITE.%d registered successfully\n", + fimc->index); + return 0; +err_pm: + pm_runtime_put(dev); +err_sd: + fimc_lite_unregister_capture_subdev(fimc); +err_clk: + fimc_lite_clk_put(fimc); + return ret; +} + +static int fimc_lite_runtime_resume(struct device *dev) +{ + struct fimc_lite *fimc = dev_get_drvdata(dev); + + clk_enable(fimc->clock); + return 0; +} + +static int fimc_lite_runtime_suspend(struct device *dev) +{ + struct fimc_lite *fimc = dev_get_drvdata(dev); + + clk_disable(fimc->clock); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int fimc_lite_resume(struct device *dev) +{ + struct fimc_lite *fimc = dev_get_drvdata(dev); + struct flite_buffer *buf; + unsigned long flags; + int i; + + spin_lock_irqsave(&fimc->slock, flags); + if (!test_and_clear_bit(ST_LPM, &fimc->state) || + !test_bit(ST_FLITE_IN_USE, &fimc->state)) { + spin_unlock_irqrestore(&fimc->slock, flags); + return 0; + } + flite_hw_reset(fimc); + spin_unlock_irqrestore(&fimc->slock, flags); + + if (!test_and_clear_bit(ST_FLITE_SUSPENDED, &fimc->state)) + return 0; + + INIT_LIST_HEAD(&fimc->active_buf_q); + fimc_pipeline_call(fimc, open, &fimc->pipeline, + &fimc->vfd.entity, false); + fimc_lite_hw_init(fimc, atomic_read(&fimc->out_path) == FIMC_IO_ISP); + clear_bit(ST_FLITE_SUSPENDED, &fimc->state); + + for (i = 0; i < fimc->reqbufs_count; i++) { + if (list_empty(&fimc->pending_buf_q)) + break; + buf = fimc_lite_pending_queue_pop(fimc); + buffer_queue(&buf->vb); + } + return 0; +} + +static int fimc_lite_suspend(struct device *dev) +{ + struct fimc_lite *fimc = dev_get_drvdata(dev); + bool suspend = test_bit(ST_FLITE_IN_USE, &fimc->state); + int ret; + + if (test_and_set_bit(ST_LPM, &fimc->state)) + return 0; + + ret = fimc_lite_stop_capture(fimc, suspend); + if (ret < 0 || !fimc_lite_active(fimc)) + return ret; + + return fimc_pipeline_call(fimc, close, &fimc->pipeline); +} +#endif /* CONFIG_PM_SLEEP */ + +static int fimc_lite_remove(struct platform_device *pdev) +{ + struct fimc_lite *fimc = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + fimc_lite_unregister_capture_subdev(fimc); + vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); + fimc_lite_clk_put(fimc); + + dev_info(dev, "Driver unloaded\n"); + return 0; +} + +static const struct dev_pm_ops fimc_lite_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(fimc_lite_suspend, fimc_lite_resume) + SET_RUNTIME_PM_OPS(fimc_lite_runtime_suspend, fimc_lite_runtime_resume, + NULL) +}; + +static struct flite_variant fimc_lite0_variant_exynos4 = { + .max_width = 8192, + .max_height = 8192, + .out_width_align = 8, + .win_hor_offs_align = 2, + .out_hor_offs_align = 8, +}; + +/* EXYNOS4212, EXYNOS4412 */ +static struct flite_drvdata fimc_lite_drvdata_exynos4 = { + .variant = { + [0] = &fimc_lite0_variant_exynos4, + [1] = &fimc_lite0_variant_exynos4, + }, +}; + +static struct platform_device_id fimc_lite_driver_ids[] = { + { + .name = "exynos-fimc-lite", + .driver_data = (unsigned long)&fimc_lite_drvdata_exynos4, + }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(platform, fimc_lite_driver_ids); + +static const struct of_device_id flite_of_match[] = { + { + .compatible = "samsung,exynos4212-fimc-lite", + .data = &fimc_lite_drvdata_exynos4, + }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, flite_of_match); + +static struct platform_driver fimc_lite_driver = { + .probe = fimc_lite_probe, + .remove = fimc_lite_remove, + .id_table = fimc_lite_driver_ids, + .driver = { + .of_match_table = flite_of_match, + .name = FIMC_LITE_DRV_NAME, + .owner = THIS_MODULE, + .pm = &fimc_lite_pm_ops, + } +}; +module_platform_driver(fimc_lite_driver); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" FIMC_LITE_DRV_NAME); diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h new file mode 100644 index 000000000000..4c2345086366 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2012 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef FIMC_LITE_H_ +#define FIMC_LITE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define FIMC_LITE_DRV_NAME "exynos-fimc-lite" +#define FLITE_CLK_NAME "flite" +#define FIMC_LITE_MAX_DEVS 2 +#define FLITE_REQ_BUFS_MIN 2 + +/* Bit index definitions for struct fimc_lite::state */ +enum { + ST_FLITE_LPM, + ST_FLITE_PENDING, + ST_FLITE_RUN, + ST_FLITE_STREAM, + ST_FLITE_SUSPENDED, + ST_FLITE_OFF, + ST_FLITE_IN_USE, + ST_FLITE_CONFIG, + ST_SENSOR_STREAM, +}; + +#define FLITE_SD_PAD_SINK 0 +#define FLITE_SD_PAD_SOURCE_DMA 1 +#define FLITE_SD_PAD_SOURCE_ISP 2 +#define FLITE_SD_PADS_NUM 3 + +struct flite_variant { + unsigned short max_width; + unsigned short max_height; + unsigned short out_width_align; + unsigned short win_hor_offs_align; + unsigned short out_hor_offs_align; +}; + +struct flite_drvdata { + struct flite_variant *variant[FIMC_LITE_MAX_DEVS]; +}; + +#define fimc_lite_get_drvdata(_pdev) \ + ((struct flite_drvdata *) platform_get_device_id(_pdev)->driver_data) + +struct fimc_lite_events { + unsigned int data_overflow; +}; + +#define FLITE_MAX_PLANES 1 + +/** + * struct flite_frame - source/target frame properties + * @f_width: full pixel width + * @f_height: full pixel height + * @rect: crop/composition rectangle + */ +struct flite_frame { + u16 f_width; + u16 f_height; + struct v4l2_rect rect; +}; + +/** + * struct flite_buffer - video buffer structure + * @vb: vb2 buffer + * @list: list head for the buffers queue + * @paddr: precalculated physical address + */ +struct flite_buffer { + struct vb2_buffer vb; + struct list_head list; + dma_addr_t paddr; +}; + +/** + * struct fimc_lite - fimc lite structure + * @pdev: pointer to FIMC-LITE platform device + * @variant: variant information for this IP + * @v4l2_dev: pointer to top the level v4l2_device + * @vfd: video device node + * @fh: v4l2 file handle + * @alloc_ctx: videobuf2 memory allocator context + * @subdev: FIMC-LITE subdev + * @vd_pad: media (sink) pad for the capture video node + * @subdev_pads: the subdev media pads + * @sensor: sensor subdev attached to FIMC-LITE directly or through MIPI-CSIS + * @ctrl_handler: v4l2 control handler + * @test_pattern: test pattern controls + * @index: FIMC-LITE platform device index + * @pipeline: video capture pipeline data structure + * @pipeline_ops: media pipeline ops for the video node driver + * @slock: spinlock protecting this data structure and the hw registers + * @lock: mutex serializing video device and the subdev operations + * @clock: FIMC-LITE gate clock + * @regs: memory mapped io registers + * @irq_queue: interrupt handler waitqueue + * @fmt: pointer to color format description structure + * @payload: image size in bytes (w x h x bpp) + * @inp_frame: camera input frame structure + * @out_frame: DMA output frame structure + * @out_path: output data path (DMA or FIFO) + * @source_subdev_grp_id: source subdev group id + * @state: driver state flags + * @pending_buf_q: pending buffers queue head + * @active_buf_q: the queue head of buffers scheduled in hardware + * @vb_queue: vb2 buffers queue + * @active_buf_count: number of video buffers scheduled in hardware + * @frame_count: the captured frames counter + * @reqbufs_count: the number of buffers requested with REQBUFS ioctl + * @ref_count: driver's private reference counter + */ +struct fimc_lite { + struct platform_device *pdev; + struct flite_variant *variant; + struct v4l2_device *v4l2_dev; + struct video_device vfd; + struct v4l2_fh fh; + struct vb2_alloc_ctx *alloc_ctx; + struct v4l2_subdev subdev; + struct media_pad vd_pad; + struct media_pad subdev_pads[FLITE_SD_PADS_NUM]; + struct v4l2_subdev *sensor; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *test_pattern; + u32 index; + struct fimc_pipeline pipeline; + const struct fimc_pipeline_ops *pipeline_ops; + + struct mutex lock; + spinlock_t slock; + + struct clk *clock; + void __iomem *regs; + wait_queue_head_t irq_queue; + + const struct fimc_fmt *fmt; + unsigned long payload[FLITE_MAX_PLANES]; + struct flite_frame inp_frame; + struct flite_frame out_frame; + atomic_t out_path; + unsigned int source_subdev_grp_id; + + unsigned long state; + struct list_head pending_buf_q; + struct list_head active_buf_q; + struct vb2_queue vb_queue; + unsigned int frame_count; + unsigned int reqbufs_count; + int ref_count; + + struct fimc_lite_events events; +}; + +static inline bool fimc_lite_active(struct fimc_lite *fimc) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&fimc->slock, flags); + ret = fimc->state & (1 << ST_FLITE_RUN) || + fimc->state & (1 << ST_FLITE_PENDING); + spin_unlock_irqrestore(&fimc->slock, flags); + return ret; +} + +static inline void fimc_lite_active_queue_add(struct fimc_lite *dev, + struct flite_buffer *buf) +{ + list_add_tail(&buf->list, &dev->active_buf_q); +} + +static inline struct flite_buffer *fimc_lite_active_queue_pop( + struct fimc_lite *dev) +{ + struct flite_buffer *buf = list_entry(dev->active_buf_q.next, + struct flite_buffer, list); + list_del(&buf->list); + return buf; +} + +static inline void fimc_lite_pending_queue_add(struct fimc_lite *dev, + struct flite_buffer *buf) +{ + list_add_tail(&buf->list, &dev->pending_buf_q); +} + +static inline struct flite_buffer *fimc_lite_pending_queue_pop( + struct fimc_lite *dev) +{ + struct flite_buffer *buf = list_entry(dev->pending_buf_q.next, + struct flite_buffer, list); + list_del(&buf->list); + return buf; +} + +#endif /* FIMC_LITE_H_ */ diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c new file mode 100644 index 000000000000..8449c0705e60 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -0,0 +1,863 @@ +/* + * Samsung S5P/EXYNOS4 SoC series FIMC (video postprocessor) driver + * + * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 2 of the License, + * or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fimc-core.h" +#include "fimc-reg.h" +#include "media-dev.h" + +static unsigned int get_m2m_fmt_flags(unsigned int stream_type) +{ + if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return FMT_FLAGS_M2M_IN; + else + return FMT_FLAGS_M2M_OUT; +} + +void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state) +{ + struct vb2_buffer *src_vb, *dst_vb; + + if (!ctx || !ctx->m2m_ctx) + return; + + src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + + if (src_vb && dst_vb) { + v4l2_m2m_buf_done(src_vb, vb_state); + v4l2_m2m_buf_done(dst_vb, vb_state); + v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev, + ctx->m2m_ctx); + } +} + +/* Complete the transaction which has been scheduled for execution. */ +static int fimc_m2m_shutdown(struct fimc_ctx *ctx) +{ + struct fimc_dev *fimc = ctx->fimc_dev; + int ret; + + if (!fimc_m2m_pending(fimc)) + return 0; + + fimc_ctx_state_set(FIMC_CTX_SHUT, ctx); + + ret = wait_event_timeout(fimc->irq_queue, + !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx), + FIMC_SHUTDOWN_TIMEOUT); + + return ret == 0 ? -ETIMEDOUT : ret; +} + +static int start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct fimc_ctx *ctx = q->drv_priv; + int ret; + + ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev); + return ret > 0 ? 0 : ret; +} + +static int stop_streaming(struct vb2_queue *q) +{ + struct fimc_ctx *ctx = q->drv_priv; + int ret; + + ret = fimc_m2m_shutdown(ctx); + if (ret == -ETIMEDOUT) + fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); + + pm_runtime_put(&ctx->fimc_dev->pdev->dev); + return 0; +} + +static void fimc_device_run(void *priv) +{ + struct vb2_buffer *vb = NULL; + struct fimc_ctx *ctx = priv; + struct fimc_frame *sf, *df; + struct fimc_dev *fimc; + unsigned long flags; + int ret; + + if (WARN(!ctx, "Null context\n")) + return; + + fimc = ctx->fimc_dev; + spin_lock_irqsave(&fimc->slock, flags); + + set_bit(ST_M2M_PEND, &fimc->state); + sf = &ctx->s_frame; + df = &ctx->d_frame; + + if (ctx->state & FIMC_PARAMS) { + /* Prepare the DMA offsets for scaler */ + fimc_prepare_dma_offset(ctx, sf); + fimc_prepare_dma_offset(ctx, df); + } + + vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + ret = fimc_prepare_addr(ctx, vb, sf, &sf->paddr); + if (ret) + goto dma_unlock; + + vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + ret = fimc_prepare_addr(ctx, vb, df, &df->paddr); + if (ret) + goto dma_unlock; + + /* Reconfigure hardware if the context has changed. */ + if (fimc->m2m.ctx != ctx) { + ctx->state |= FIMC_PARAMS; + fimc->m2m.ctx = ctx; + } + + if (ctx->state & FIMC_PARAMS) { + fimc_set_yuv_order(ctx); + fimc_hw_set_input_path(ctx); + fimc_hw_set_in_dma(ctx); + ret = fimc_set_scaler_info(ctx); + if (ret) + goto dma_unlock; + fimc_hw_set_prescaler(ctx); + fimc_hw_set_mainscaler(ctx); + fimc_hw_set_target_format(ctx); + fimc_hw_set_rotation(ctx); + fimc_hw_set_effect(ctx); + fimc_hw_set_out_dma(ctx); + if (fimc->drv_data->alpha_color) + fimc_hw_set_rgb_alpha(ctx); + fimc_hw_set_output_path(ctx); + } + fimc_hw_set_input_addr(fimc, &sf->paddr); + fimc_hw_set_output_addr(fimc, &df->paddr, -1); + + fimc_activate_capture(ctx); + ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP); + fimc_hw_activate_input_dma(fimc, true); + +dma_unlock: + spin_unlock_irqrestore(&fimc->slock, flags); +} + +static void fimc_job_abort(void *priv) +{ + fimc_m2m_shutdown(priv); +} + +static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *allocators[]) +{ + struct fimc_ctx *ctx = vb2_get_drv_priv(vq); + struct fimc_frame *f; + int i; + + f = ctx_get_frame(ctx, vq->type); + if (IS_ERR(f)) + return PTR_ERR(f); + /* + * Return number of non-contigous planes (plane buffers) + * depending on the configured color format. + */ + if (!f->fmt) + return -EINVAL; + + *num_planes = f->fmt->memplanes; + for (i = 0; i < f->fmt->memplanes; i++) { + sizes[i] = (f->f_width * f->f_height * f->fmt->depth[i]) / 8; + allocators[i] = ctx->fimc_dev->alloc_ctx; + } + return 0; +} + +static int fimc_buf_prepare(struct vb2_buffer *vb) +{ + struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct fimc_frame *frame; + int i; + + frame = ctx_get_frame(ctx, vb->vb2_queue->type); + if (IS_ERR(frame)) + return PTR_ERR(frame); + + for (i = 0; i < frame->fmt->memplanes; i++) + vb2_set_plane_payload(vb, i, frame->payload[i]); + + return 0; +} + +static void fimc_buf_queue(struct vb2_buffer *vb) +{ + struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state); + + if (ctx->m2m_ctx) + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); +} + +static void fimc_lock(struct vb2_queue *vq) +{ + struct fimc_ctx *ctx = vb2_get_drv_priv(vq); + mutex_lock(&ctx->fimc_dev->lock); +} + +static void fimc_unlock(struct vb2_queue *vq) +{ + struct fimc_ctx *ctx = vb2_get_drv_priv(vq); + mutex_unlock(&ctx->fimc_dev->lock); +} + +static struct vb2_ops fimc_qops = { + .queue_setup = fimc_queue_setup, + .buf_prepare = fimc_buf_prepare, + .buf_queue = fimc_buf_queue, + .wait_prepare = fimc_unlock, + .wait_finish = fimc_lock, + .stop_streaming = stop_streaming, + .start_streaming = start_streaming, +}; + +/* + * V4L2 ioctl handlers + */ +static int fimc_m2m_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_dev *fimc = ctx->fimc_dev; + + strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1); + strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1); + cap->bus_info[0] = 0; + /* + * This is only a mem-to-mem video device. The capture and output + * device capability flags are left only for backward compatibility + * and are scheduled for removal. + */ + cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE | + V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; + + return 0; +} + +static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct fimc_fmt *fmt; + + fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type), + f->index); + if (!fmt) + return -EINVAL; + + strncpy(f->description, fmt->name, sizeof(f->description) - 1); + f->pixelformat = fmt->fourcc; + return 0; +} + +static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_frame *frame = ctx_get_frame(ctx, f->type); + + if (IS_ERR(frame)) + return PTR_ERR(frame); + + __fimc_get_format(frame, f); + return 0; +} + +static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) +{ + struct fimc_dev *fimc = ctx->fimc_dev; + const struct fimc_variant *variant = fimc->variant; + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; + struct fimc_fmt *fmt; + u32 max_w, mod_x, mod_y; + + if (!IS_M2M(f->type)) + return -EINVAL; + + fmt = fimc_find_format(&pix->pixelformat, NULL, + get_m2m_fmt_flags(f->type), 0); + if (WARN(fmt == NULL, "Pixel format lookup failed")) + return -EINVAL; + + if (pix->field == V4L2_FIELD_ANY) + pix->field = V4L2_FIELD_NONE; + else if (pix->field != V4L2_FIELD_NONE) + return -EINVAL; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + max_w = variant->pix_limit->scaler_dis_w; + mod_x = ffs(variant->min_inp_pixsize) - 1; + } else { + max_w = variant->pix_limit->out_rot_dis_w; + mod_x = ffs(variant->min_out_pixsize) - 1; + } + + if (tiled_fmt(fmt)) { + mod_x = 6; /* 64 x 32 pixels tile */ + mod_y = 5; + } else { + if (variant->min_vsize_align == 1) + mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1; + else + mod_y = ffs(variant->min_vsize_align) - 1; + } + + v4l_bound_align_image(&pix->width, 16, max_w, mod_x, + &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0); + + fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp); + return 0; +} + +static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + return fimc_try_fmt_mplane(ctx, f); +} + +static void __set_frame_format(struct fimc_frame *frame, struct fimc_fmt *fmt, + struct v4l2_pix_format_mplane *pixm) +{ + int i; + + for (i = 0; i < fmt->colplanes; i++) { + frame->bytesperline[i] = pixm->plane_fmt[i].bytesperline; + frame->payload[i] = pixm->plane_fmt[i].sizeimage; + } + + frame->f_width = pixm->width; + frame->f_height = pixm->height; + frame->o_width = pixm->width; + frame->o_height = pixm->height; + frame->width = pixm->width; + frame->height = pixm->height; + frame->offs_h = 0; + frame->offs_v = 0; + frame->fmt = fmt; +} + +static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_dev *fimc = ctx->fimc_dev; + struct fimc_fmt *fmt; + struct vb2_queue *vq; + struct fimc_frame *frame; + int ret; + + ret = fimc_try_fmt_mplane(ctx, f); + if (ret) + return ret; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + + if (vb2_is_busy(vq)) { + v4l2_err(&fimc->m2m.vfd, "queue (%d) busy\n", f->type); + return -EBUSY; + } + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + frame = &ctx->s_frame; + else + frame = &ctx->d_frame; + + fmt = fimc_find_format(&f->fmt.pix_mp.pixelformat, NULL, + get_m2m_fmt_flags(f->type), 0); + if (!fmt) + return -EINVAL; + + __set_frame_format(frame, fmt, &f->fmt.pix_mp); + + /* Update RGB Alpha control state and value range */ + fimc_alpha_ctrl_update(ctx); + + return 0; +} + +static int fimc_m2m_reqbufs(struct file *file, void *fh, + struct v4l2_requestbuffers *reqbufs) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); +} + +static int fimc_m2m_querybuf(struct file *file, void *fh, + struct v4l2_buffer *buf) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); +} + +static int fimc_m2m_qbuf(struct file *file, void *fh, + struct v4l2_buffer *buf) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); +} + +static int fimc_m2m_dqbuf(struct file *file, void *fh, + struct v4l2_buffer *buf) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); +} + +static int fimc_m2m_expbuf(struct file *file, void *fh, + struct v4l2_exportbuffer *eb) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb); +} + + +static int fimc_m2m_streamon(struct file *file, void *fh, + enum v4l2_buf_type type) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); +} + +static int fimc_m2m_streamoff(struct file *file, void *fh, + enum v4l2_buf_type type) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); +} + +static int fimc_m2m_cropcap(struct file *file, void *fh, + struct v4l2_cropcap *cr) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_frame *frame; + + frame = ctx_get_frame(ctx, cr->type); + if (IS_ERR(frame)) + return PTR_ERR(frame); + + cr->bounds.left = 0; + cr->bounds.top = 0; + cr->bounds.width = frame->o_width; + cr->bounds.height = frame->o_height; + cr->defrect = cr->bounds; + + return 0; +} + +static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_frame *frame; + + frame = ctx_get_frame(ctx, cr->type); + if (IS_ERR(frame)) + return PTR_ERR(frame); + + cr->c.left = frame->offs_h; + cr->c.top = frame->offs_v; + cr->c.width = frame->width; + cr->c.height = frame->height; + + return 0; +} + +static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) +{ + struct fimc_dev *fimc = ctx->fimc_dev; + struct fimc_frame *f; + u32 min_size, halign, depth = 0; + int i; + + if (cr->c.top < 0 || cr->c.left < 0) { + v4l2_err(&fimc->m2m.vfd, + "doesn't support negative values for top & left\n"); + return -EINVAL; + } + if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + f = &ctx->d_frame; + else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + f = &ctx->s_frame; + else + return -EINVAL; + + min_size = (f == &ctx->s_frame) ? + fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; + + /* Get pixel alignment constraints. */ + if (fimc->variant->min_vsize_align == 1) + halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1; + else + halign = ffs(fimc->variant->min_vsize_align) - 1; + + for (i = 0; i < f->fmt->colplanes; i++) + depth += f->fmt->depth[i]; + + v4l_bound_align_image(&cr->c.width, min_size, f->o_width, + ffs(min_size) - 1, + &cr->c.height, min_size, f->o_height, + halign, 64/(ALIGN(depth, 8))); + + /* adjust left/top if cropping rectangle is out of bounds */ + if (cr->c.left + cr->c.width > f->o_width) + cr->c.left = f->o_width - cr->c.width; + if (cr->c.top + cr->c.height > f->o_height) + cr->c.top = f->o_height - cr->c.height; + + cr->c.left = round_down(cr->c.left, min_size); + cr->c.top = round_down(cr->c.top, fimc->variant->hor_offs_align); + + dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", + cr->c.left, cr->c.top, cr->c.width, cr->c.height, + f->f_width, f->f_height); + + return 0; +} + +static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_dev *fimc = ctx->fimc_dev; + struct v4l2_crop cr = *crop; + struct fimc_frame *f; + int ret; + + ret = fimc_m2m_try_crop(ctx, &cr); + if (ret) + return ret; + + f = (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? + &ctx->s_frame : &ctx->d_frame; + + /* Check to see if scaling ratio is within supported range */ + if (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret = fimc_check_scaler_ratio(ctx, cr.c.width, + cr.c.height, ctx->d_frame.width, + ctx->d_frame.height, ctx->rotation); + } else { + ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, + ctx->s_frame.height, cr.c.width, + cr.c.height, ctx->rotation); + } + if (ret) { + v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n"); + return -EINVAL; + } + + f->offs_h = cr.c.left; + f->offs_v = cr.c.top; + f->width = cr.c.width; + f->height = cr.c.height; + + fimc_ctx_state_set(FIMC_PARAMS, ctx); + + return 0; +} + +static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { + .vidioc_querycap = fimc_m2m_querycap, + .vidioc_enum_fmt_vid_cap_mplane = fimc_m2m_enum_fmt_mplane, + .vidioc_enum_fmt_vid_out_mplane = fimc_m2m_enum_fmt_mplane, + .vidioc_g_fmt_vid_cap_mplane = fimc_m2m_g_fmt_mplane, + .vidioc_g_fmt_vid_out_mplane = fimc_m2m_g_fmt_mplane, + .vidioc_try_fmt_vid_cap_mplane = fimc_m2m_try_fmt_mplane, + .vidioc_try_fmt_vid_out_mplane = fimc_m2m_try_fmt_mplane, + .vidioc_s_fmt_vid_cap_mplane = fimc_m2m_s_fmt_mplane, + .vidioc_s_fmt_vid_out_mplane = fimc_m2m_s_fmt_mplane, + .vidioc_reqbufs = fimc_m2m_reqbufs, + .vidioc_querybuf = fimc_m2m_querybuf, + .vidioc_qbuf = fimc_m2m_qbuf, + .vidioc_dqbuf = fimc_m2m_dqbuf, + .vidioc_expbuf = fimc_m2m_expbuf, + .vidioc_streamon = fimc_m2m_streamon, + .vidioc_streamoff = fimc_m2m_streamoff, + .vidioc_g_crop = fimc_m2m_g_crop, + .vidioc_s_crop = fimc_m2m_s_crop, + .vidioc_cropcap = fimc_m2m_cropcap + +}; + +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct fimc_ctx *ctx = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->ops = &fimc_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->ops = &fimc_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + + return vb2_queue_init(dst_vq); +} + +static int fimc_m2m_set_default_format(struct fimc_ctx *ctx) +{ + struct v4l2_pix_format_mplane pixm = { + .pixelformat = V4L2_PIX_FMT_RGB32, + .width = 800, + .height = 600, + .plane_fmt[0] = { + .bytesperline = 800 * 4, + .sizeimage = 800 * 4 * 600, + }, + }; + struct fimc_fmt *fmt; + + fmt = fimc_find_format(&pixm.pixelformat, NULL, FMT_FLAGS_M2M, 0); + if (!fmt) + return -EINVAL; + + __set_frame_format(&ctx->s_frame, fmt, &pixm); + __set_frame_format(&ctx->d_frame, fmt, &pixm); + + return 0; +} + +static int fimc_m2m_open(struct file *file) +{ + struct fimc_dev *fimc = video_drvdata(file); + struct fimc_ctx *ctx; + int ret = -EBUSY; + + pr_debug("pid: %d, state: %#lx\n", task_pid_nr(current), fimc->state); + + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; + /* + * Don't allow simultaneous open() of the mem-to-mem and the + * capture video node that belong to same FIMC IP instance. + */ + if (test_bit(ST_CAPT_BUSY, &fimc->state)) + goto unlock; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + ret = -ENOMEM; + goto unlock; + } + v4l2_fh_init(&ctx->fh, &fimc->m2m.vfd); + ctx->fimc_dev = fimc; + + /* Default color format */ + ctx->s_frame.fmt = fimc_get_format(0); + ctx->d_frame.fmt = fimc_get_format(0); + + ret = fimc_ctrls_create(ctx); + if (ret) + goto error_fh; + + /* Use separate control handler per file handle */ + ctx->fh.ctrl_handler = &ctx->ctrls.handler; + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + /* Setup the device context for memory-to-memory mode */ + ctx->state = FIMC_CTX_M2M; + ctx->flags = 0; + ctx->in_path = FIMC_IO_DMA; + ctx->out_path = FIMC_IO_DMA; + ctx->scaler.enabled = 1; + + ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); + if (IS_ERR(ctx->m2m_ctx)) { + ret = PTR_ERR(ctx->m2m_ctx); + goto error_c; + } + + if (fimc->m2m.refcnt++ == 0) + set_bit(ST_M2M_RUN, &fimc->state); + + ret = fimc_m2m_set_default_format(ctx); + if (ret < 0) + goto error_m2m_ctx; + + mutex_unlock(&fimc->lock); + return 0; + +error_m2m_ctx: + v4l2_m2m_ctx_release(ctx->m2m_ctx); +error_c: + fimc_ctrls_delete(ctx); +error_fh: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); +unlock: + mutex_unlock(&fimc->lock); + return ret; +} + +static int fimc_m2m_release(struct file *file) +{ + struct fimc_ctx *ctx = fh_to_ctx(file->private_data); + struct fimc_dev *fimc = ctx->fimc_dev; + + dbg("pid: %d, state: 0x%lx, refcnt= %d", + task_pid_nr(current), fimc->state, fimc->m2m.refcnt); + + mutex_lock(&fimc->lock); + + v4l2_m2m_ctx_release(ctx->m2m_ctx); + fimc_ctrls_delete(ctx); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + + if (--fimc->m2m.refcnt <= 0) + clear_bit(ST_M2M_RUN, &fimc->state); + kfree(ctx); + + mutex_unlock(&fimc->lock); + return 0; +} + +static unsigned int fimc_m2m_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct fimc_ctx *ctx = fh_to_ctx(file->private_data); + struct fimc_dev *fimc = ctx->fimc_dev; + int ret; + + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; + + ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); + mutex_unlock(&fimc->lock); + + return ret; +} + + +static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct fimc_ctx *ctx = fh_to_ctx(file->private_data); + struct fimc_dev *fimc = ctx->fimc_dev; + int ret; + + if (mutex_lock_interruptible(&fimc->lock)) + return -ERESTARTSYS; + + ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); + mutex_unlock(&fimc->lock); + + return ret; +} + +static const struct v4l2_file_operations fimc_m2m_fops = { + .owner = THIS_MODULE, + .open = fimc_m2m_open, + .release = fimc_m2m_release, + .poll = fimc_m2m_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = fimc_m2m_mmap, +}; + +static struct v4l2_m2m_ops m2m_ops = { + .device_run = fimc_device_run, + .job_abort = fimc_job_abort, +}; + +int fimc_register_m2m_device(struct fimc_dev *fimc, + struct v4l2_device *v4l2_dev) +{ + struct video_device *vfd = &fimc->m2m.vfd; + int ret; + + fimc->v4l2_dev = v4l2_dev; + + memset(vfd, 0, sizeof(*vfd)); + vfd->fops = &fimc_m2m_fops; + vfd->ioctl_ops = &fimc_m2m_ioctl_ops; + vfd->v4l2_dev = v4l2_dev; + vfd->minor = -1; + vfd->release = video_device_release_empty; + vfd->lock = &fimc->lock; + vfd->vfl_dir = VFL_DIR_M2M; + + snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id); + video_set_drvdata(vfd, fimc); + + fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops); + if (IS_ERR(fimc->m2m.m2m_dev)) { + v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n"); + return PTR_ERR(fimc->m2m.m2m_dev); + } + + ret = media_entity_init(&vfd->entity, 0, NULL, 0); + if (ret) + goto err_me; + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); + if (ret) + goto err_vd; + + v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n", + vfd->name, video_device_node_name(vfd)); + return 0; + +err_vd: + media_entity_cleanup(&vfd->entity); +err_me: + v4l2_m2m_release(fimc->m2m.m2m_dev); + return ret; +} + +void fimc_unregister_m2m_device(struct fimc_dev *fimc) +{ + if (!fimc) + return; + + if (fimc->m2m.m2m_dev) + v4l2_m2m_release(fimc->m2m.m2m_dev); + + if (video_is_registered(&fimc->m2m.vfd)) { + video_unregister_device(&fimc->m2m.vfd); + media_entity_cleanup(&fimc->m2m.vfd.entity); + } +} diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c new file mode 100644 index 000000000000..c276eb8e9711 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-reg.c @@ -0,0 +1,837 @@ +/* + * Register interface file for Samsung Camera Interface (FIMC) driver + * + * Copyright (C) 2010 - 2013 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include +#include + +#include +#include "media-dev.h" + +#include "fimc-reg.h" +#include "fimc-core.h" + +void fimc_hw_reset(struct fimc_dev *dev) +{ + u32 cfg; + + cfg = readl(dev->regs + FIMC_REG_CISRCFMT); + cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; + writel(cfg, dev->regs + FIMC_REG_CISRCFMT); + + /* Software reset. */ + cfg = readl(dev->regs + FIMC_REG_CIGCTRL); + cfg |= (FIMC_REG_CIGCTRL_SWRST | FIMC_REG_CIGCTRL_IRQ_LEVEL); + writel(cfg, dev->regs + FIMC_REG_CIGCTRL); + udelay(10); + + cfg = readl(dev->regs + FIMC_REG_CIGCTRL); + cfg &= ~FIMC_REG_CIGCTRL_SWRST; + writel(cfg, dev->regs + FIMC_REG_CIGCTRL); + + if (dev->drv_data->out_buf_count > 4) + fimc_hw_set_dma_seq(dev, 0xF); +} + +static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx) +{ + u32 flip = FIMC_REG_MSCTRL_FLIP_NORMAL; + + if (ctx->hflip) + flip = FIMC_REG_MSCTRL_FLIP_Y_MIRROR; + if (ctx->vflip) + flip = FIMC_REG_MSCTRL_FLIP_X_MIRROR; + + if (ctx->rotation <= 90) + return flip; + + return (flip ^ FIMC_REG_MSCTRL_FLIP_180) & FIMC_REG_MSCTRL_FLIP_180; +} + +static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx) +{ + u32 flip = FIMC_REG_CITRGFMT_FLIP_NORMAL; + + if (ctx->hflip) + flip |= FIMC_REG_CITRGFMT_FLIP_Y_MIRROR; + if (ctx->vflip) + flip |= FIMC_REG_CITRGFMT_FLIP_X_MIRROR; + + if (ctx->rotation <= 90) + return flip; + + return (flip ^ FIMC_REG_CITRGFMT_FLIP_180) & FIMC_REG_CITRGFMT_FLIP_180; +} + +void fimc_hw_set_rotation(struct fimc_ctx *ctx) +{ + u32 cfg, flip; + struct fimc_dev *dev = ctx->fimc_dev; + + cfg = readl(dev->regs + FIMC_REG_CITRGFMT); + cfg &= ~(FIMC_REG_CITRGFMT_INROT90 | FIMC_REG_CITRGFMT_OUTROT90 | + FIMC_REG_CITRGFMT_FLIP_180); + + /* + * The input and output rotator cannot work simultaneously. + * Use the output rotator in output DMA mode or the input rotator + * in direct fifo output mode. + */ + if (ctx->rotation == 90 || ctx->rotation == 270) { + if (ctx->out_path == FIMC_IO_LCDFIFO) + cfg |= FIMC_REG_CITRGFMT_INROT90; + else + cfg |= FIMC_REG_CITRGFMT_OUTROT90; + } + + if (ctx->out_path == FIMC_IO_DMA) { + cfg |= fimc_hw_get_target_flip(ctx); + writel(cfg, dev->regs + FIMC_REG_CITRGFMT); + } else { + /* LCD FIFO path */ + flip = readl(dev->regs + FIMC_REG_MSCTRL); + flip &= ~FIMC_REG_MSCTRL_FLIP_MASK; + flip |= fimc_hw_get_in_flip(ctx); + writel(flip, dev->regs + FIMC_REG_MSCTRL); + } +} + +void fimc_hw_set_target_format(struct fimc_ctx *ctx) +{ + u32 cfg; + struct fimc_dev *dev = ctx->fimc_dev; + struct fimc_frame *frame = &ctx->d_frame; + + dbg("w= %d, h= %d color: %d", frame->width, + frame->height, frame->fmt->color); + + cfg = readl(dev->regs + FIMC_REG_CITRGFMT); + cfg &= ~(FIMC_REG_CITRGFMT_FMT_MASK | FIMC_REG_CITRGFMT_HSIZE_MASK | + FIMC_REG_CITRGFMT_VSIZE_MASK); + + switch (frame->fmt->color) { + case FIMC_FMT_RGB444...FIMC_FMT_RGB888: + cfg |= FIMC_REG_CITRGFMT_RGB; + break; + case FIMC_FMT_YCBCR420: + cfg |= FIMC_REG_CITRGFMT_YCBCR420; + break; + case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422: + if (frame->fmt->colplanes == 1) + cfg |= FIMC_REG_CITRGFMT_YCBCR422_1P; + else + cfg |= FIMC_REG_CITRGFMT_YCBCR422; + break; + default: + break; + } + + if (ctx->rotation == 90 || ctx->rotation == 270) + cfg |= (frame->height << 16) | frame->width; + else + cfg |= (frame->width << 16) | frame->height; + + writel(cfg, dev->regs + FIMC_REG_CITRGFMT); + + cfg = readl(dev->regs + FIMC_REG_CITAREA); + cfg &= ~FIMC_REG_CITAREA_MASK; + cfg |= (frame->width * frame->height); + writel(cfg, dev->regs + FIMC_REG_CITAREA); +} + +static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + struct fimc_frame *frame = &ctx->d_frame; + u32 cfg; + + cfg = (frame->f_height << 16) | frame->f_width; + writel(cfg, dev->regs + FIMC_REG_ORGOSIZE); + + /* Select color space conversion equation (HD/SD size).*/ + cfg = readl(dev->regs + FIMC_REG_CIGCTRL); + if (frame->f_width >= 1280) /* HD */ + cfg |= FIMC_REG_CIGCTRL_CSC_ITU601_709; + else /* SD */ + cfg &= ~FIMC_REG_CIGCTRL_CSC_ITU601_709; + writel(cfg, dev->regs + FIMC_REG_CIGCTRL); + +} + +void fimc_hw_set_out_dma(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + struct fimc_frame *frame = &ctx->d_frame; + struct fimc_dma_offset *offset = &frame->dma_offset; + struct fimc_fmt *fmt = frame->fmt; + u32 cfg; + + /* Set the input dma offsets. */ + cfg = (offset->y_v << 16) | offset->y_h; + writel(cfg, dev->regs + FIMC_REG_CIOYOFF); + + cfg = (offset->cb_v << 16) | offset->cb_h; + writel(cfg, dev->regs + FIMC_REG_CIOCBOFF); + + cfg = (offset->cr_v << 16) | offset->cr_h; + writel(cfg, dev->regs + FIMC_REG_CIOCROFF); + + fimc_hw_set_out_dma_size(ctx); + + /* Configure chroma components order. */ + cfg = readl(dev->regs + FIMC_REG_CIOCTRL); + + cfg &= ~(FIMC_REG_CIOCTRL_ORDER2P_MASK | + FIMC_REG_CIOCTRL_ORDER422_MASK | + FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK | + FIMC_REG_CIOCTRL_RGB16FMT_MASK); + + if (fmt->colplanes == 1) + cfg |= ctx->out_order_1p; + else if (fmt->colplanes == 2) + cfg |= ctx->out_order_2p | FIMC_REG_CIOCTRL_YCBCR_2PLANE; + else if (fmt->colplanes == 3) + cfg |= FIMC_REG_CIOCTRL_YCBCR_3PLANE; + + if (fmt->color == FIMC_FMT_RGB565) + cfg |= FIMC_REG_CIOCTRL_RGB565; + else if (fmt->color == FIMC_FMT_RGB555) + cfg |= FIMC_REG_CIOCTRL_ARGB1555; + else if (fmt->color == FIMC_FMT_RGB444) + cfg |= FIMC_REG_CIOCTRL_ARGB4444; + + writel(cfg, dev->regs + FIMC_REG_CIOCTRL); +} + +static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable) +{ + u32 cfg = readl(dev->regs + FIMC_REG_ORGISIZE); + if (enable) + cfg |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN; + else + cfg &= ~FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN; + writel(cfg, dev->regs + FIMC_REG_ORGISIZE); +} + +void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable) +{ + u32 cfg = readl(dev->regs + FIMC_REG_CIOCTRL); + if (enable) + cfg |= FIMC_REG_CIOCTRL_LASTIRQ_ENABLE; + else + cfg &= ~FIMC_REG_CIOCTRL_LASTIRQ_ENABLE; + writel(cfg, dev->regs + FIMC_REG_CIOCTRL); +} + +void fimc_hw_set_prescaler(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + struct fimc_scaler *sc = &ctx->scaler; + u32 cfg, shfactor; + + shfactor = 10 - (sc->hfactor + sc->vfactor); + cfg = shfactor << 28; + + cfg |= (sc->pre_hratio << 16) | sc->pre_vratio; + writel(cfg, dev->regs + FIMC_REG_CISCPRERATIO); + + cfg = (sc->pre_dst_width << 16) | sc->pre_dst_height; + writel(cfg, dev->regs + FIMC_REG_CISCPREDST); +} + +static void fimc_hw_set_scaler(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + struct fimc_scaler *sc = &ctx->scaler; + struct fimc_frame *src_frame = &ctx->s_frame; + struct fimc_frame *dst_frame = &ctx->d_frame; + + u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); + + cfg &= ~(FIMC_REG_CISCCTRL_CSCR2Y_WIDE | FIMC_REG_CISCCTRL_CSCY2R_WIDE | + FIMC_REG_CISCCTRL_SCALEUP_H | FIMC_REG_CISCCTRL_SCALEUP_V | + FIMC_REG_CISCCTRL_SCALERBYPASS | FIMC_REG_CISCCTRL_ONE2ONE | + FIMC_REG_CISCCTRL_INRGB_FMT_MASK | FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK | + FIMC_REG_CISCCTRL_INTERLACE | FIMC_REG_CISCCTRL_RGB_EXT); + + if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW)) + cfg |= (FIMC_REG_CISCCTRL_CSCR2Y_WIDE | + FIMC_REG_CISCCTRL_CSCY2R_WIDE); + + if (!sc->enabled) + cfg |= FIMC_REG_CISCCTRL_SCALERBYPASS; + + if (sc->scaleup_h) + cfg |= FIMC_REG_CISCCTRL_SCALEUP_H; + + if (sc->scaleup_v) + cfg |= FIMC_REG_CISCCTRL_SCALEUP_V; + + if (sc->copy_mode) + cfg |= FIMC_REG_CISCCTRL_ONE2ONE; + + if (ctx->in_path == FIMC_IO_DMA) { + switch (src_frame->fmt->color) { + case FIMC_FMT_RGB565: + cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB565; + break; + case FIMC_FMT_RGB666: + cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB666; + break; + case FIMC_FMT_RGB888: + cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB888; + break; + } + } + + if (ctx->out_path == FIMC_IO_DMA) { + u32 color = dst_frame->fmt->color; + + if (color >= FIMC_FMT_RGB444 && color <= FIMC_FMT_RGB565) + cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB565; + else if (color == FIMC_FMT_RGB666) + cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666; + else if (color == FIMC_FMT_RGB888) + cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888; + } else { + cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888; + + if (ctx->flags & FIMC_SCAN_MODE_INTERLACED) + cfg |= FIMC_REG_CISCCTRL_INTERLACE; + } + + writel(cfg, dev->regs + FIMC_REG_CISCCTRL); +} + +void fimc_hw_set_mainscaler(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + const struct fimc_variant *variant = dev->variant; + struct fimc_scaler *sc = &ctx->scaler; + u32 cfg; + + dbg("main_hratio= 0x%X main_vratio= 0x%X", + sc->main_hratio, sc->main_vratio); + + fimc_hw_set_scaler(ctx); + + cfg = readl(dev->regs + FIMC_REG_CISCCTRL); + cfg &= ~(FIMC_REG_CISCCTRL_MHRATIO_MASK | + FIMC_REG_CISCCTRL_MVRATIO_MASK); + + if (variant->has_mainscaler_ext) { + cfg |= FIMC_REG_CISCCTRL_MHRATIO_EXT(sc->main_hratio); + cfg |= FIMC_REG_CISCCTRL_MVRATIO_EXT(sc->main_vratio); + writel(cfg, dev->regs + FIMC_REG_CISCCTRL); + + cfg = readl(dev->regs + FIMC_REG_CIEXTEN); + + cfg &= ~(FIMC_REG_CIEXTEN_MVRATIO_EXT_MASK | + FIMC_REG_CIEXTEN_MHRATIO_EXT_MASK); + cfg |= FIMC_REG_CIEXTEN_MHRATIO_EXT(sc->main_hratio); + cfg |= FIMC_REG_CIEXTEN_MVRATIO_EXT(sc->main_vratio); + writel(cfg, dev->regs + FIMC_REG_CIEXTEN); + } else { + cfg |= FIMC_REG_CISCCTRL_MHRATIO(sc->main_hratio); + cfg |= FIMC_REG_CISCCTRL_MVRATIO(sc->main_vratio); + writel(cfg, dev->regs + FIMC_REG_CISCCTRL); + } +} + +void fimc_hw_enable_capture(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + u32 cfg; + + cfg = readl(dev->regs + FIMC_REG_CIIMGCPT); + cfg |= FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE; + + if (ctx->scaler.enabled) + cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN_SC; + else + cfg &= FIMC_REG_CIIMGCPT_IMGCPTEN_SC; + + cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN; + writel(cfg, dev->regs + FIMC_REG_CIIMGCPT); +} + +void fimc_hw_disable_capture(struct fimc_dev *dev) +{ + u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT); + cfg &= ~(FIMC_REG_CIIMGCPT_IMGCPTEN | + FIMC_REG_CIIMGCPT_IMGCPTEN_SC); + writel(cfg, dev->regs + FIMC_REG_CIIMGCPT); +} + +void fimc_hw_set_effect(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + struct fimc_effect *effect = &ctx->effect; + u32 cfg = 0; + + if (effect->type != FIMC_REG_CIIMGEFF_FIN_BYPASS) { + cfg |= FIMC_REG_CIIMGEFF_IE_SC_AFTER | + FIMC_REG_CIIMGEFF_IE_ENABLE; + cfg |= effect->type; + if (effect->type == FIMC_REG_CIIMGEFF_FIN_ARBITRARY) + cfg |= (effect->pat_cb << 13) | effect->pat_cr; + } + + writel(cfg, dev->regs + FIMC_REG_CIIMGEFF); +} + +void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + struct fimc_frame *frame = &ctx->d_frame; + u32 cfg; + + if (!(frame->fmt->flags & FMT_HAS_ALPHA)) + return; + + cfg = readl(dev->regs + FIMC_REG_CIOCTRL); + cfg &= ~FIMC_REG_CIOCTRL_ALPHA_OUT_MASK; + cfg |= (frame->alpha << 4); + writel(cfg, dev->regs + FIMC_REG_CIOCTRL); +} + +static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + struct fimc_frame *frame = &ctx->s_frame; + u32 cfg_o = 0; + u32 cfg_r = 0; + + if (FIMC_IO_LCDFIFO == ctx->out_path) + cfg_r |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN; + + cfg_o |= (frame->f_height << 16) | frame->f_width; + cfg_r |= (frame->height << 16) | frame->width; + + writel(cfg_o, dev->regs + FIMC_REG_ORGISIZE); + writel(cfg_r, dev->regs + FIMC_REG_CIREAL_ISIZE); +} + +void fimc_hw_set_in_dma(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + struct fimc_frame *frame = &ctx->s_frame; + struct fimc_dma_offset *offset = &frame->dma_offset; + u32 cfg; + + /* Set the pixel offsets. */ + cfg = (offset->y_v << 16) | offset->y_h; + writel(cfg, dev->regs + FIMC_REG_CIIYOFF); + + cfg = (offset->cb_v << 16) | offset->cb_h; + writel(cfg, dev->regs + FIMC_REG_CIICBOFF); + + cfg = (offset->cr_v << 16) | offset->cr_h; + writel(cfg, dev->regs + FIMC_REG_CIICROFF); + + /* Input original and real size. */ + fimc_hw_set_in_dma_size(ctx); + + /* Use DMA autoload only in FIFO mode. */ + fimc_hw_en_autoload(dev, ctx->out_path == FIMC_IO_LCDFIFO); + + /* Set the input DMA to process single frame only. */ + cfg = readl(dev->regs + FIMC_REG_MSCTRL); + cfg &= ~(FIMC_REG_MSCTRL_INFORMAT_MASK + | FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK + | FIMC_REG_MSCTRL_INPUT_MASK + | FIMC_REG_MSCTRL_C_INT_IN_MASK + | FIMC_REG_MSCTRL_2P_IN_ORDER_MASK); + + cfg |= (FIMC_REG_MSCTRL_IN_BURST_COUNT(4) + | FIMC_REG_MSCTRL_INPUT_MEMORY + | FIMC_REG_MSCTRL_FIFO_CTRL_FULL); + + switch (frame->fmt->color) { + case FIMC_FMT_RGB565...FIMC_FMT_RGB888: + cfg |= FIMC_REG_MSCTRL_INFORMAT_RGB; + break; + case FIMC_FMT_YCBCR420: + cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR420; + + if (frame->fmt->colplanes == 2) + cfg |= ctx->in_order_2p | FIMC_REG_MSCTRL_C_INT_IN_2PLANE; + else + cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE; + + break; + case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422: + if (frame->fmt->colplanes == 1) { + cfg |= ctx->in_order_1p + | FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P; + } else { + cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR422; + + if (frame->fmt->colplanes == 2) + cfg |= ctx->in_order_2p + | FIMC_REG_MSCTRL_C_INT_IN_2PLANE; + else + cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE; + } + break; + default: + break; + } + + writel(cfg, dev->regs + FIMC_REG_MSCTRL); + + /* Input/output DMA linear/tiled mode. */ + cfg = readl(dev->regs + FIMC_REG_CIDMAPARAM); + cfg &= ~FIMC_REG_CIDMAPARAM_TILE_MASK; + + if (tiled_fmt(ctx->s_frame.fmt)) + cfg |= FIMC_REG_CIDMAPARAM_R_64X32; + + if (tiled_fmt(ctx->d_frame.fmt)) + cfg |= FIMC_REG_CIDMAPARAM_W_64X32; + + writel(cfg, dev->regs + FIMC_REG_CIDMAPARAM); +} + + +void fimc_hw_set_input_path(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + + u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL); + cfg &= ~FIMC_REG_MSCTRL_INPUT_MASK; + + if (ctx->in_path == FIMC_IO_DMA) + cfg |= FIMC_REG_MSCTRL_INPUT_MEMORY; + else + cfg |= FIMC_REG_MSCTRL_INPUT_EXTCAM; + + writel(cfg, dev->regs + FIMC_REG_MSCTRL); +} + +void fimc_hw_set_output_path(struct fimc_ctx *ctx) +{ + struct fimc_dev *dev = ctx->fimc_dev; + + u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); + cfg &= ~FIMC_REG_CISCCTRL_LCDPATHEN_FIFO; + if (ctx->out_path == FIMC_IO_LCDFIFO) + cfg |= FIMC_REG_CISCCTRL_LCDPATHEN_FIFO; + writel(cfg, dev->regs + FIMC_REG_CISCCTRL); +} + +void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr) +{ + u32 cfg = readl(dev->regs + FIMC_REG_CIREAL_ISIZE); + cfg |= FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS; + writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE); + + writel(paddr->y, dev->regs + FIMC_REG_CIIYSA(0)); + writel(paddr->cb, dev->regs + FIMC_REG_CIICBSA(0)); + writel(paddr->cr, dev->regs + FIMC_REG_CIICRSA(0)); + + cfg &= ~FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS; + writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE); +} + +void fimc_hw_set_output_addr(struct fimc_dev *dev, + struct fimc_addr *paddr, int index) +{ + int i = (index == -1) ? 0 : index; + do { + writel(paddr->y, dev->regs + FIMC_REG_CIOYSA(i)); + writel(paddr->cb, dev->regs + FIMC_REG_CIOCBSA(i)); + writel(paddr->cr, dev->regs + FIMC_REG_CIOCRSA(i)); + dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", + i, paddr->y, paddr->cb, paddr->cr); + } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS); +} + +int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, + struct fimc_source_info *cam) +{ + u32 cfg = readl(fimc->regs + FIMC_REG_CIGCTRL); + + cfg &= ~(FIMC_REG_CIGCTRL_INVPOLPCLK | FIMC_REG_CIGCTRL_INVPOLVSYNC | + FIMC_REG_CIGCTRL_INVPOLHREF | FIMC_REG_CIGCTRL_INVPOLHSYNC | + FIMC_REG_CIGCTRL_INVPOLFIELD); + + if (cam->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + cfg |= FIMC_REG_CIGCTRL_INVPOLPCLK; + + if (cam->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + cfg |= FIMC_REG_CIGCTRL_INVPOLVSYNC; + + if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + cfg |= FIMC_REG_CIGCTRL_INVPOLHREF; + + if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + cfg |= FIMC_REG_CIGCTRL_INVPOLHSYNC; + + if (cam->flags & V4L2_MBUS_FIELD_EVEN_LOW) + cfg |= FIMC_REG_CIGCTRL_INVPOLFIELD; + + writel(cfg, fimc->regs + FIMC_REG_CIGCTRL); + + return 0; +} + +struct mbus_pixfmt_desc { + u32 pixelcode; + u32 cisrcfmt; + u16 bus_width; +}; + +static const struct mbus_pixfmt_desc pix_desc[] = { + { V4L2_MBUS_FMT_YUYV8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCBYCR, 8 }, + { V4L2_MBUS_FMT_YVYU8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCRYCB, 8 }, + { V4L2_MBUS_FMT_VYUY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CRYCBY, 8 }, + { V4L2_MBUS_FMT_UYVY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CBYCRY, 8 }, +}; + +int fimc_hw_set_camera_source(struct fimc_dev *fimc, + struct fimc_source_info *source) +{ + struct fimc_vid_cap *vc = &fimc->vid_cap; + struct fimc_frame *f = &vc->ctx->s_frame; + u32 bus_width, cfg = 0; + int i; + + switch (source->fimc_bus_type) { + case FIMC_BUS_TYPE_ITU_601: + case FIMC_BUS_TYPE_ITU_656: + for (i = 0; i < ARRAY_SIZE(pix_desc); i++) { + if (vc->ci_fmt.code == pix_desc[i].pixelcode) { + cfg = pix_desc[i].cisrcfmt; + bus_width = pix_desc[i].bus_width; + break; + } + } + + if (i == ARRAY_SIZE(pix_desc)) { + v4l2_err(&vc->vfd, + "Camera color format not supported: %d\n", + vc->ci_fmt.code); + return -EINVAL; + } + + if (source->fimc_bus_type == FIMC_BUS_TYPE_ITU_601) { + if (bus_width == 8) + cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; + else if (bus_width == 16) + cfg |= FIMC_REG_CISRCFMT_ITU601_16BIT; + } /* else defaults to ITU-R BT.656 8-bit */ + break; + case FIMC_BUS_TYPE_MIPI_CSI2: + if (fimc_fmt_is_user_defined(f->fmt->color)) + cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; + break; + default: + case FIMC_BUS_TYPE_ISP_WRITEBACK: + /* Anything to do here ? */ + break; + } + + cfg |= (f->o_width << 16) | f->o_height; + writel(cfg, fimc->regs + FIMC_REG_CISRCFMT); + return 0; +} + +void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f) +{ + u32 hoff2, voff2; + + u32 cfg = readl(fimc->regs + FIMC_REG_CIWDOFST); + + cfg &= ~(FIMC_REG_CIWDOFST_HOROFF_MASK | FIMC_REG_CIWDOFST_VEROFF_MASK); + cfg |= FIMC_REG_CIWDOFST_OFF_EN | + (f->offs_h << 16) | f->offs_v; + + writel(cfg, fimc->regs + FIMC_REG_CIWDOFST); + + /* See CIWDOFSTn register description in the datasheet for details. */ + hoff2 = f->o_width - f->width - f->offs_h; + voff2 = f->o_height - f->height - f->offs_v; + cfg = (hoff2 << 16) | voff2; + writel(cfg, fimc->regs + FIMC_REG_CIWDOFST2); +} + +int fimc_hw_set_camera_type(struct fimc_dev *fimc, + struct fimc_source_info *source) +{ + struct fimc_vid_cap *vid_cap = &fimc->vid_cap; + u32 csis_data_alignment = 32; + u32 cfg, tmp; + + cfg = readl(fimc->regs + FIMC_REG_CIGCTRL); + + /* Select ITU B interface, disable Writeback path and test pattern. */ + cfg &= ~(FIMC_REG_CIGCTRL_TESTPAT_MASK | FIMC_REG_CIGCTRL_SELCAM_ITU_A | + FIMC_REG_CIGCTRL_SELCAM_MIPI | FIMC_REG_CIGCTRL_CAMIF_SELWB | + FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG | + FIMC_REG_CIGCTRL_SELWB_A); + + switch (source->fimc_bus_type) { + case FIMC_BUS_TYPE_MIPI_CSI2: + cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI; + + if (source->mux_id == 0) + cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI_A; + + /* TODO: add remaining supported formats. */ + switch (vid_cap->ci_fmt.code) { + case V4L2_MBUS_FMT_VYUY8_2X8: + tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT; + break; + case V4L2_MBUS_FMT_JPEG_1X8: + case V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8: + tmp = FIMC_REG_CSIIMGFMT_USER(1); + cfg |= FIMC_REG_CIGCTRL_CAM_JPEG; + break; + default: + v4l2_err(&vid_cap->vfd, + "Not supported camera pixel format: %#x\n", + vid_cap->ci_fmt.code); + return -EINVAL; + } + tmp |= (csis_data_alignment == 32) << 8; + + writel(tmp, fimc->regs + FIMC_REG_CSIIMGFMT); + break; + case FIMC_BUS_TYPE_ITU_601...FIMC_BUS_TYPE_ITU_656: + if (source->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */ + cfg |= FIMC_REG_CIGCTRL_SELCAM_ITU_A; + break; + case FIMC_BUS_TYPE_LCD_WRITEBACK_A: + cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; + /* fall through */ + case FIMC_BUS_TYPE_ISP_WRITEBACK: + if (fimc->variant->has_isp_wb) + cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; + else + WARN_ONCE(1, "ISP Writeback input is not supported\n"); + break; + default: + v4l2_err(&vid_cap->vfd, "Invalid FIMC bus type selected: %d\n", + source->fimc_bus_type); + return -EINVAL; + } + writel(cfg, fimc->regs + FIMC_REG_CIGCTRL); + + return 0; +} + +void fimc_hw_clear_irq(struct fimc_dev *dev) +{ + u32 cfg = readl(dev->regs + FIMC_REG_CIGCTRL); + cfg |= FIMC_REG_CIGCTRL_IRQ_CLR; + writel(cfg, dev->regs + FIMC_REG_CIGCTRL); +} + +void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on) +{ + u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); + if (on) + cfg |= FIMC_REG_CISCCTRL_SCALERSTART; + else + cfg &= ~FIMC_REG_CISCCTRL_SCALERSTART; + writel(cfg, dev->regs + FIMC_REG_CISCCTRL); +} + +void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on) +{ + u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL); + if (on) + cfg |= FIMC_REG_MSCTRL_ENVID; + else + cfg &= ~FIMC_REG_MSCTRL_ENVID; + writel(cfg, dev->regs + FIMC_REG_MSCTRL); +} + +/* Return an index to the buffer actually being written. */ +s32 fimc_hw_get_frame_index(struct fimc_dev *dev) +{ + s32 reg; + + if (dev->drv_data->cistatus2) { + reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3f; + return reg - 1; + } + + reg = readl(dev->regs + FIMC_REG_CISTATUS); + + return (reg & FIMC_REG_CISTATUS_FRAMECNT_MASK) >> + FIMC_REG_CISTATUS_FRAMECNT_SHIFT; +} + +/* Return an index to the buffer being written previously. */ +s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev) +{ + s32 reg; + + if (!dev->drv_data->cistatus2) + return -1; + + reg = readl(dev->regs + FIMC_REG_CISTATUS2); + return ((reg >> 7) & 0x3f) - 1; +} + +/* Locking: the caller holds fimc->slock */ +void fimc_activate_capture(struct fimc_ctx *ctx) +{ + fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled); + fimc_hw_enable_capture(ctx); +} + +void fimc_deactivate_capture(struct fimc_dev *fimc) +{ + fimc_hw_en_lastirq(fimc, true); + fimc_hw_disable_capture(fimc); + fimc_hw_enable_scaler(fimc, false); + fimc_hw_en_lastirq(fimc, false); +} + +int fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc) +{ + struct regmap *map = fimc->sysreg; + unsigned int mask, val, camblk_cfg; + int ret; + + ret = regmap_read(map, SYSREG_CAMBLK, &camblk_cfg); + if (ret < 0 || ((camblk_cfg & 0x00700000) >> 20 != 0x3)) + return ret; + + if (!WARN(fimc->id >= 3, "not supported id: %d\n", fimc->id)) + val = 0x1 << (fimc->id + 20); + else + val = 0; + + mask = SYSREG_CAMBLK_FIFORST_ISP | SYSREG_CAMBLK_ISPWB_FULL_EN; + ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val); + if (ret < 0) + return ret; + + usleep_range(1000, 2000); + + val |= SYSREG_CAMBLK_FIFORST_ISP; + ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val); + if (ret < 0) + return ret; + + mask = SYSREG_ISPBLK_FIFORST_CAM_BLK; + ret = regmap_update_bits(map, SYSREG_ISPBLK, mask, ~mask); + if (ret < 0) + return ret; + + usleep_range(1000, 2000); + + return regmap_update_bits(map, SYSREG_ISPBLK, mask, mask); +} diff --git a/drivers/media/platform/exynos4-is/fimc-reg.h b/drivers/media/platform/exynos4-is/fimc-reg.h new file mode 100644 index 000000000000..01da7f3622bf --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-reg.h @@ -0,0 +1,338 @@ +/* + * Samsung camera host interface (FIMC) registers definition + * + * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef FIMC_REG_H_ +#define FIMC_REG_H_ + +#include "fimc-core.h" + +/* Input source format */ +#define FIMC_REG_CISRCFMT 0x00 +#define FIMC_REG_CISRCFMT_ITU601_8BIT (1 << 31) +#define FIMC_REG_CISRCFMT_ITU601_16BIT (1 << 29) +#define FIMC_REG_CISRCFMT_ORDER422_YCBYCR (0 << 14) +#define FIMC_REG_CISRCFMT_ORDER422_YCRYCB (1 << 14) +#define FIMC_REG_CISRCFMT_ORDER422_CBYCRY (2 << 14) +#define FIMC_REG_CISRCFMT_ORDER422_CRYCBY (3 << 14) + +/* Window offset */ +#define FIMC_REG_CIWDOFST 0x04 +#define FIMC_REG_CIWDOFST_OFF_EN (1 << 31) +#define FIMC_REG_CIWDOFST_CLROVFIY (1 << 30) +#define FIMC_REG_CIWDOFST_CLROVRLB (1 << 29) +#define FIMC_REG_CIWDOFST_HOROFF_MASK (0x7ff << 16) +#define FIMC_REG_CIWDOFST_CLROVFICB (1 << 15) +#define FIMC_REG_CIWDOFST_CLROVFICR (1 << 14) +#define FIMC_REG_CIWDOFST_VEROFF_MASK (0xfff << 0) + +/* Global control */ +#define FIMC_REG_CIGCTRL 0x08 +#define FIMC_REG_CIGCTRL_SWRST (1 << 31) +#define FIMC_REG_CIGCTRL_CAMRST_A (1 << 30) +#define FIMC_REG_CIGCTRL_SELCAM_ITU_A (1 << 29) +#define FIMC_REG_CIGCTRL_TESTPAT_NORMAL (0 << 27) +#define FIMC_REG_CIGCTRL_TESTPAT_COLOR_BAR (1 << 27) +#define FIMC_REG_CIGCTRL_TESTPAT_HOR_INC (2 << 27) +#define FIMC_REG_CIGCTRL_TESTPAT_VER_INC (3 << 27) +#define FIMC_REG_CIGCTRL_TESTPAT_MASK (3 << 27) +#define FIMC_REG_CIGCTRL_TESTPAT_SHIFT 27 +#define FIMC_REG_CIGCTRL_INVPOLPCLK (1 << 26) +#define FIMC_REG_CIGCTRL_INVPOLVSYNC (1 << 25) +#define FIMC_REG_CIGCTRL_INVPOLHREF (1 << 24) +#define FIMC_REG_CIGCTRL_IRQ_OVFEN (1 << 22) +#define FIMC_REG_CIGCTRL_HREF_MASK (1 << 21) +#define FIMC_REG_CIGCTRL_IRQ_LEVEL (1 << 20) +#define FIMC_REG_CIGCTRL_IRQ_CLR (1 << 19) +#define FIMC_REG_CIGCTRL_IRQ_ENABLE (1 << 16) +#define FIMC_REG_CIGCTRL_SHDW_DISABLE (1 << 12) +/* 0 - selects Writeback A (LCD), 1 - selects Writeback B (LCD/ISP) */ +#define FIMC_REG_CIGCTRL_SELWB_A (1 << 10) +#define FIMC_REG_CIGCTRL_CAM_JPEG (1 << 8) +#define FIMC_REG_CIGCTRL_SELCAM_MIPI_A (1 << 7) +#define FIMC_REG_CIGCTRL_CAMIF_SELWB (1 << 6) +/* 0 - ITU601; 1 - ITU709 */ +#define FIMC_REG_CIGCTRL_CSC_ITU601_709 (1 << 5) +#define FIMC_REG_CIGCTRL_INVPOLHSYNC (1 << 4) +#define FIMC_REG_CIGCTRL_SELCAM_MIPI (1 << 3) +#define FIMC_REG_CIGCTRL_INVPOLFIELD (1 << 1) +#define FIMC_REG_CIGCTRL_INTERLACE (1 << 0) + +/* Window offset 2 */ +#define FIMC_REG_CIWDOFST2 0x14 +#define FIMC_REG_CIWDOFST2_HOROFF_MASK (0xfff << 16) +#define FIMC_REG_CIWDOFST2_VEROFF_MASK (0xfff << 0) + +/* Output DMA Y/Cb/Cr plane start addresses */ +#define FIMC_REG_CIOYSA(n) (0x18 + (n) * 4) +#define FIMC_REG_CIOCBSA(n) (0x28 + (n) * 4) +#define FIMC_REG_CIOCRSA(n) (0x38 + (n) * 4) + +/* Target image format */ +#define FIMC_REG_CITRGFMT 0x48 +#define FIMC_REG_CITRGFMT_INROT90 (1 << 31) +#define FIMC_REG_CITRGFMT_YCBCR420 (0 << 29) +#define FIMC_REG_CITRGFMT_YCBCR422 (1 << 29) +#define FIMC_REG_CITRGFMT_YCBCR422_1P (2 << 29) +#define FIMC_REG_CITRGFMT_RGB (3 << 29) +#define FIMC_REG_CITRGFMT_FMT_MASK (3 << 29) +#define FIMC_REG_CITRGFMT_HSIZE_MASK (0xfff << 16) +#define FIMC_REG_CITRGFMT_FLIP_SHIFT 14 +#define FIMC_REG_CITRGFMT_FLIP_NORMAL (0 << 14) +#define FIMC_REG_CITRGFMT_FLIP_X_MIRROR (1 << 14) +#define FIMC_REG_CITRGFMT_FLIP_Y_MIRROR (2 << 14) +#define FIMC_REG_CITRGFMT_FLIP_180 (3 << 14) +#define FIMC_REG_CITRGFMT_FLIP_MASK (3 << 14) +#define FIMC_REG_CITRGFMT_OUTROT90 (1 << 13) +#define FIMC_REG_CITRGFMT_VSIZE_MASK (0xfff << 0) + +/* Output DMA control */ +#define FIMC_REG_CIOCTRL 0x4c +#define FIMC_REG_CIOCTRL_ORDER422_MASK (3 << 0) +#define FIMC_REG_CIOCTRL_ORDER422_CRYCBY (0 << 0) +#define FIMC_REG_CIOCTRL_ORDER422_CBYCRY (1 << 0) +#define FIMC_REG_CIOCTRL_ORDER422_YCRYCB (2 << 0) +#define FIMC_REG_CIOCTRL_ORDER422_YCBYCR (3 << 0) +#define FIMC_REG_CIOCTRL_LASTIRQ_ENABLE (1 << 2) +#define FIMC_REG_CIOCTRL_YCBCR_3PLANE (0 << 3) +#define FIMC_REG_CIOCTRL_YCBCR_2PLANE (1 << 3) +#define FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK (1 << 3) +#define FIMC_REG_CIOCTRL_ALPHA_OUT_MASK (0xff << 4) +#define FIMC_REG_CIOCTRL_RGB16FMT_MASK (3 << 16) +#define FIMC_REG_CIOCTRL_RGB565 (0 << 16) +#define FIMC_REG_CIOCTRL_ARGB1555 (1 << 16) +#define FIMC_REG_CIOCTRL_ARGB4444 (2 << 16) +#define FIMC_REG_CIOCTRL_ORDER2P_SHIFT 24 +#define FIMC_REG_CIOCTRL_ORDER2P_MASK (3 << 24) +#define FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB (0 << 24) + +/* Pre-scaler control 1 */ +#define FIMC_REG_CISCPRERATIO 0x50 + +#define FIMC_REG_CISCPREDST 0x54 + +/* Main scaler control */ +#define FIMC_REG_CISCCTRL 0x58 +#define FIMC_REG_CISCCTRL_SCALERBYPASS (1 << 31) +#define FIMC_REG_CISCCTRL_SCALEUP_H (1 << 30) +#define FIMC_REG_CISCCTRL_SCALEUP_V (1 << 29) +#define FIMC_REG_CISCCTRL_CSCR2Y_WIDE (1 << 28) +#define FIMC_REG_CISCCTRL_CSCY2R_WIDE (1 << 27) +#define FIMC_REG_CISCCTRL_LCDPATHEN_FIFO (1 << 26) +#define FIMC_REG_CISCCTRL_INTERLACE (1 << 25) +#define FIMC_REG_CISCCTRL_SCALERSTART (1 << 15) +#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB565 (0 << 13) +#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB666 (1 << 13) +#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB888 (2 << 13) +#define FIMC_REG_CISCCTRL_INRGB_FMT_MASK (3 << 13) +#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB565 (0 << 11) +#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666 (1 << 11) +#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888 (2 << 11) +#define FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK (3 << 11) +#define FIMC_REG_CISCCTRL_RGB_EXT (1 << 10) +#define FIMC_REG_CISCCTRL_ONE2ONE (1 << 9) +#define FIMC_REG_CISCCTRL_MHRATIO(x) ((x) << 16) +#define FIMC_REG_CISCCTRL_MVRATIO(x) ((x) << 0) +#define FIMC_REG_CISCCTRL_MHRATIO_MASK (0x1ff << 16) +#define FIMC_REG_CISCCTRL_MVRATIO_MASK (0x1ff << 0) +#define FIMC_REG_CISCCTRL_MHRATIO_EXT(x) (((x) >> 6) << 16) +#define FIMC_REG_CISCCTRL_MVRATIO_EXT(x) (((x) >> 6) << 0) + +/* Target area */ +#define FIMC_REG_CITAREA 0x5c +#define FIMC_REG_CITAREA_MASK 0x0fffffff + +/* General status */ +#define FIMC_REG_CISTATUS 0x64 +#define FIMC_REG_CISTATUS_OVFIY (1 << 31) +#define FIMC_REG_CISTATUS_OVFICB (1 << 30) +#define FIMC_REG_CISTATUS_OVFICR (1 << 29) +#define FIMC_REG_CISTATUS_VSYNC (1 << 28) +#define FIMC_REG_CISTATUS_FRAMECNT_MASK (3 << 26) +#define FIMC_REG_CISTATUS_FRAMECNT_SHIFT 26 +#define FIMC_REG_CISTATUS_WINOFF_EN (1 << 25) +#define FIMC_REG_CISTATUS_IMGCPT_EN (1 << 22) +#define FIMC_REG_CISTATUS_IMGCPT_SCEN (1 << 21) +#define FIMC_REG_CISTATUS_VSYNC_A (1 << 20) +#define FIMC_REG_CISTATUS_VSYNC_B (1 << 19) +#define FIMC_REG_CISTATUS_OVRLB (1 << 18) +#define FIMC_REG_CISTATUS_FRAME_END (1 << 17) +#define FIMC_REG_CISTATUS_LASTCAPT_END (1 << 16) +#define FIMC_REG_CISTATUS_VVALID_A (1 << 15) +#define FIMC_REG_CISTATUS_VVALID_B (1 << 14) + +/* Indexes to the last and the currently processed buffer. */ +#define FIMC_REG_CISTATUS2 0x68 + +/* Image capture control */ +#define FIMC_REG_CIIMGCPT 0xc0 +#define FIMC_REG_CIIMGCPT_IMGCPTEN (1 << 31) +#define FIMC_REG_CIIMGCPT_IMGCPTEN_SC (1 << 30) +#define FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE (1 << 25) +#define FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT (1 << 18) + +/* Frame capture sequence */ +#define FIMC_REG_CICPTSEQ 0xc4 + +/* Image effect */ +#define FIMC_REG_CIIMGEFF 0xd0 +#define FIMC_REG_CIIMGEFF_IE_ENABLE (1 << 30) +#define FIMC_REG_CIIMGEFF_IE_SC_BEFORE (0 << 29) +#define FIMC_REG_CIIMGEFF_IE_SC_AFTER (1 << 29) +#define FIMC_REG_CIIMGEFF_FIN_BYPASS (0 << 26) +#define FIMC_REG_CIIMGEFF_FIN_ARBITRARY (1 << 26) +#define FIMC_REG_CIIMGEFF_FIN_NEGATIVE (2 << 26) +#define FIMC_REG_CIIMGEFF_FIN_ARTFREEZE (3 << 26) +#define FIMC_REG_CIIMGEFF_FIN_EMBOSSING (4 << 26) +#define FIMC_REG_CIIMGEFF_FIN_SILHOUETTE (5 << 26) +#define FIMC_REG_CIIMGEFF_FIN_MASK (7 << 26) +#define FIMC_REG_CIIMGEFF_PAT_CBCR_MASK ((0xff << 13) | 0xff) + +/* Input DMA Y/Cb/Cr plane start address 0/1 */ +#define FIMC_REG_CIIYSA(n) (0xd4 + (n) * 0x70) +#define FIMC_REG_CIICBSA(n) (0xd8 + (n) * 0x70) +#define FIMC_REG_CIICRSA(n) (0xdc + (n) * 0x70) + +/* Real input DMA image size */ +#define FIMC_REG_CIREAL_ISIZE 0xf8 +#define FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN (1 << 31) +#define FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS (1 << 30) + +/* Input DMA control */ +#define FIMC_REG_MSCTRL 0xfc +#define FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK (0xf << 24) +#define FIMC_REG_MSCTRL_2P_IN_ORDER_MASK (3 << 16) +#define FIMC_REG_MSCTRL_2P_IN_ORDER_SHIFT 16 +#define FIMC_REG_MSCTRL_C_INT_IN_3PLANE (0 << 15) +#define FIMC_REG_MSCTRL_C_INT_IN_2PLANE (1 << 15) +#define FIMC_REG_MSCTRL_C_INT_IN_MASK (1 << 15) +#define FIMC_REG_MSCTRL_FLIP_SHIFT 13 +#define FIMC_REG_MSCTRL_FLIP_MASK (3 << 13) +#define FIMC_REG_MSCTRL_FLIP_NORMAL (0 << 13) +#define FIMC_REG_MSCTRL_FLIP_X_MIRROR (1 << 13) +#define FIMC_REG_MSCTRL_FLIP_Y_MIRROR (2 << 13) +#define FIMC_REG_MSCTRL_FLIP_180 (3 << 13) +#define FIMC_REG_MSCTRL_FIFO_CTRL_FULL (1 << 12) +#define FIMC_REG_MSCTRL_ORDER422_SHIFT 4 +#define FIMC_REG_MSCTRL_ORDER422_YCBYCR (0 << 4) +#define FIMC_REG_MSCTRL_ORDER422_CBYCRY (1 << 4) +#define FIMC_REG_MSCTRL_ORDER422_YCRYCB (2 << 4) +#define FIMC_REG_MSCTRL_ORDER422_CRYCBY (3 << 4) +#define FIMC_REG_MSCTRL_ORDER422_MASK (3 << 4) +#define FIMC_REG_MSCTRL_INPUT_EXTCAM (0 << 3) +#define FIMC_REG_MSCTRL_INPUT_MEMORY (1 << 3) +#define FIMC_REG_MSCTRL_INPUT_MASK (1 << 3) +#define FIMC_REG_MSCTRL_INFORMAT_YCBCR420 (0 << 1) +#define FIMC_REG_MSCTRL_INFORMAT_YCBCR422 (1 << 1) +#define FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P (2 << 1) +#define FIMC_REG_MSCTRL_INFORMAT_RGB (3 << 1) +#define FIMC_REG_MSCTRL_INFORMAT_MASK (3 << 1) +#define FIMC_REG_MSCTRL_ENVID (1 << 0) +#define FIMC_REG_MSCTRL_IN_BURST_COUNT(x) ((x) << 24) + +/* Output DMA Y/Cb/Cr offset */ +#define FIMC_REG_CIOYOFF 0x168 +#define FIMC_REG_CIOCBOFF 0x16c +#define FIMC_REG_CIOCROFF 0x170 + +/* Input DMA Y/Cb/Cr offset */ +#define FIMC_REG_CIIYOFF 0x174 +#define FIMC_REG_CIICBOFF 0x178 +#define FIMC_REG_CIICROFF 0x17c + +/* Input DMA original image size */ +#define FIMC_REG_ORGISIZE 0x180 + +/* Output DMA original image size */ +#define FIMC_REG_ORGOSIZE 0x184 + +/* Real output DMA image size (extension register) */ +#define FIMC_REG_CIEXTEN 0x188 +#define FIMC_REG_CIEXTEN_MHRATIO_EXT(x) (((x) & 0x3f) << 10) +#define FIMC_REG_CIEXTEN_MVRATIO_EXT(x) ((x) & 0x3f) +#define FIMC_REG_CIEXTEN_MHRATIO_EXT_MASK (0x3f << 10) +#define FIMC_REG_CIEXTEN_MVRATIO_EXT_MASK 0x3f + +#define FIMC_REG_CIDMAPARAM 0x18c +#define FIMC_REG_CIDMAPARAM_R_LINEAR (0 << 29) +#define FIMC_REG_CIDMAPARAM_R_64X32 (3 << 29) +#define FIMC_REG_CIDMAPARAM_W_LINEAR (0 << 13) +#define FIMC_REG_CIDMAPARAM_W_64X32 (3 << 13) +#define FIMC_REG_CIDMAPARAM_TILE_MASK ((3 << 29) | (3 << 13)) + +/* MIPI CSI image format */ +#define FIMC_REG_CSIIMGFMT 0x194 +#define FIMC_REG_CSIIMGFMT_YCBCR422_8BIT 0x1e +#define FIMC_REG_CSIIMGFMT_RAW8 0x2a +#define FIMC_REG_CSIIMGFMT_RAW10 0x2b +#define FIMC_REG_CSIIMGFMT_RAW12 0x2c +/* User defined formats. x = 0...16. */ +#define FIMC_REG_CSIIMGFMT_USER(x) (0x30 + x - 1) + +/* Output frame buffer sequence mask */ +#define FIMC_REG_CIFCNTSEQ 0x1fc + +/* SYSREG ISP Writeback register address offsets */ +#define SYSREG_ISPBLK 0x020c +#define SYSREG_ISPBLK_FIFORST_CAM_BLK (1 << 7) + +#define SYSREG_CAMBLK 0x0218 +#define SYSREG_CAMBLK_FIFORST_ISP (1 << 15) +#define SYSREG_CAMBLK_ISPWB_FULL_EN (7 << 20) + +/* + * Function declarations + */ +void fimc_hw_reset(struct fimc_dev *fimc); +void fimc_hw_set_rotation(struct fimc_ctx *ctx); +void fimc_hw_set_target_format(struct fimc_ctx *ctx); +void fimc_hw_set_out_dma(struct fimc_ctx *ctx); +void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable); +void fimc_hw_en_irq(struct fimc_dev *fimc, int enable); +void fimc_hw_set_prescaler(struct fimc_ctx *ctx); +void fimc_hw_set_mainscaler(struct fimc_ctx *ctx); +void fimc_hw_enable_capture(struct fimc_ctx *ctx); +void fimc_hw_set_effect(struct fimc_ctx *ctx); +void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx); +void fimc_hw_set_in_dma(struct fimc_ctx *ctx); +void fimc_hw_set_input_path(struct fimc_ctx *ctx); +void fimc_hw_set_output_path(struct fimc_ctx *ctx); +void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr); +void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr, + int index); +int fimc_hw_set_camera_source(struct fimc_dev *fimc, + struct fimc_source_info *cam); +void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f); +int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, + struct fimc_source_info *cam); +int fimc_hw_set_camera_type(struct fimc_dev *fimc, + struct fimc_source_info *cam); +void fimc_hw_clear_irq(struct fimc_dev *dev); +void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on); +void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on); +void fimc_hw_disable_capture(struct fimc_dev *dev); +s32 fimc_hw_get_frame_index(struct fimc_dev *dev); +s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev); +int fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc); +void fimc_activate_capture(struct fimc_ctx *ctx); +void fimc_deactivate_capture(struct fimc_dev *fimc); + +/** + * fimc_hw_set_dma_seq - configure output DMA buffer sequence + * @mask: bitmask for the DMA output buffer registers, set to 0 to skip buffer + * This function masks output DMA ring buffers, it allows to select which of + * the 32 available output buffer address registers will be used by the DMA + * engine. + */ +static inline void fimc_hw_set_dma_seq(struct fimc_dev *dev, u32 mask) +{ + writel(mask, dev->regs + FIMC_REG_CIFCNTSEQ); +} + +#endif /* FIMC_REG_H_ */ diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c new file mode 100644 index 000000000000..4a0057708aaf --- /dev/null +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -0,0 +1,1437 @@ +/* + * S5P/EXYNOS4 SoC series camera host interface media device driver + * + * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 2 of the License, + * or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "media-dev.h" +#include "fimc-core.h" +#include "fimc-lite.h" +#include "mipi-csis.h" + +static int __fimc_md_set_camclk(struct fimc_md *fmd, + struct fimc_sensor_info *s_info, + bool on); +/** + * fimc_pipeline_prepare - update pipeline information with subdevice pointers + * @me: media entity terminating the pipeline + * + * Caller holds the graph mutex. + */ +static void fimc_pipeline_prepare(struct fimc_pipeline *p, + struct media_entity *me) +{ + struct v4l2_subdev *sd; + int i; + + for (i = 0; i < IDX_MAX; i++) + p->subdevs[i] = NULL; + + while (1) { + struct media_pad *pad = NULL; + + /* Find remote source pad */ + for (i = 0; i < me->num_pads; i++) { + struct media_pad *spad = &me->pads[i]; + if (!(spad->flags & MEDIA_PAD_FL_SINK)) + continue; + pad = media_entity_remote_source(spad); + if (pad) + break; + } + + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + sd = media_entity_to_v4l2_subdev(pad->entity); + + switch (sd->grp_id) { + case GRP_ID_FIMC_IS_SENSOR: + case GRP_ID_SENSOR: + p->subdevs[IDX_SENSOR] = sd; + break; + case GRP_ID_CSIS: + p->subdevs[IDX_CSIS] = sd; + break; + case GRP_ID_FLITE: + p->subdevs[IDX_FLITE] = sd; + break; + case GRP_ID_FIMC: + /* No need to control FIMC subdev through subdev ops */ + break; + default: + pr_warn("%s: Unknown subdev grp_id: %#x\n", + __func__, sd->grp_id); + } + me = &sd->entity; + if (me->num_pads == 1) + break; + } +} + +/** + * __subdev_set_power - change power state of a single subdev + * @sd: subdevice to change power state for + * @on: 1 to enable power or 0 to disable + * + * Return result of s_power subdev operation or -ENXIO if sd argument + * is NULL. Return 0 if the subdevice does not implement s_power. + */ +static int __subdev_set_power(struct v4l2_subdev *sd, int on) +{ + int *use_count; + int ret; + + if (sd == NULL) + return -ENXIO; + + use_count = &sd->entity.use_count; + if (on && (*use_count)++ > 0) + return 0; + else if (!on && (*use_count == 0 || --(*use_count) > 0)) + return 0; + ret = v4l2_subdev_call(sd, core, s_power, on); + + return ret != -ENOIOCTLCMD ? ret : 0; +} + +/** + * fimc_pipeline_s_power - change power state of all pipeline subdevs + * @fimc: fimc device terminating the pipeline + * @state: true to power on, false to power off + * + * Needs to be called with the graph mutex held. + */ +static int fimc_pipeline_s_power(struct fimc_pipeline *p, bool on) +{ + static const u8 seq[2][IDX_MAX - 1] = { + { IDX_IS_ISP, IDX_SENSOR, IDX_CSIS, IDX_FLITE }, + { IDX_CSIS, IDX_FLITE, IDX_SENSOR, IDX_IS_ISP }, + }; + int i, ret = 0; + + if (p->subdevs[IDX_SENSOR] == NULL) + return -ENXIO; + + for (i = 0; i < IDX_MAX - 1; i++) { + unsigned int idx = seq[on][i]; + + ret = __subdev_set_power(p->subdevs[idx], on); + + + if (ret < 0 && ret != -ENXIO) + goto error; + } + return 0; +error: + for (; i >= 0; i--) { + unsigned int idx = seq[on][i]; + __subdev_set_power(p->subdevs[idx], !on); + } + return ret; +} + +/** + * __fimc_pipeline_open - update the pipeline information, enable power + * of all pipeline subdevs and the sensor clock + * @me: media entity to start graph walk with + * @prepare: true to walk the current pipeline and acquire all subdevs + * + * Called with the graph mutex held. + */ +static int __fimc_pipeline_open(struct fimc_pipeline *p, + struct media_entity *me, bool prepare) +{ + struct fimc_md *fmd = entity_to_fimc_mdev(me); + struct v4l2_subdev *sd; + int ret; + + if (WARN_ON(p == NULL || me == NULL)) + return -EINVAL; + + if (prepare) + fimc_pipeline_prepare(p, me); + + sd = p->subdevs[IDX_SENSOR]; + if (sd == NULL) + return -EINVAL; + + /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */ + if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) { + ret = clk_prepare_enable(fmd->wbclk[CLK_IDX_WB_B]); + if (ret < 0) + return ret; + } + ret = fimc_md_set_camclk(sd, true); + if (ret < 0) + goto err_wbclk; + + ret = fimc_pipeline_s_power(p, 1); + if (!ret) + return 0; + + fimc_md_set_camclk(sd, false); + +err_wbclk: + if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) + clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); + + return ret; +} + +/** + * __fimc_pipeline_close - disable the sensor clock and pipeline power + * @fimc: fimc device terminating the pipeline + * + * Disable power of all subdevs and turn the external sensor clock off. + */ +static int __fimc_pipeline_close(struct fimc_pipeline *p) +{ + struct v4l2_subdev *sd = p ? p->subdevs[IDX_SENSOR] : NULL; + struct fimc_md *fmd; + int ret = 0; + + if (WARN_ON(sd == NULL)) + return -EINVAL; + + if (p->subdevs[IDX_SENSOR]) { + ret = fimc_pipeline_s_power(p, 0); + fimc_md_set_camclk(sd, false); + } + + fmd = entity_to_fimc_mdev(&sd->entity); + + /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */ + if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) + clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); + + return ret == -ENXIO ? 0 : ret; +} + +/** + * __fimc_pipeline_s_stream - call s_stream() on pipeline subdevs + * @pipeline: video pipeline structure + * @on: passed as the s_stream() callback argument + */ +static int __fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on) +{ + static const u8 seq[2][IDX_MAX] = { + { IDX_FIMC, IDX_SENSOR, IDX_IS_ISP, IDX_CSIS, IDX_FLITE }, + { IDX_CSIS, IDX_FLITE, IDX_FIMC, IDX_SENSOR, IDX_IS_ISP }, + }; + int i, ret = 0; + + if (p->subdevs[IDX_SENSOR] == NULL) + return -ENODEV; + + for (i = 0; i < IDX_MAX; i++) { + unsigned int idx = seq[on][i]; + + ret = v4l2_subdev_call(p->subdevs[idx], video, s_stream, on); + + if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) + goto error; + } + return 0; +error: + for (; i >= 0; i--) { + unsigned int idx = seq[on][i]; + v4l2_subdev_call(p->subdevs[idx], video, s_stream, !on); + } + return ret; +} + +/* Media pipeline operations for the FIMC/FIMC-LITE video device driver */ +static const struct fimc_pipeline_ops fimc_pipeline_ops = { + .open = __fimc_pipeline_open, + .close = __fimc_pipeline_close, + .set_stream = __fimc_pipeline_s_stream, +}; + +/* + * Sensor subdevice helper functions + */ +static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd, + struct fimc_sensor_info *s_info) +{ + struct i2c_adapter *adapter; + struct v4l2_subdev *sd = NULL; + + if (!s_info || !fmd) + return NULL; + /* + * If FIMC bus type is not Writeback FIFO assume it is same + * as sensor_bus_type. + */ + s_info->pdata.fimc_bus_type = s_info->pdata.sensor_bus_type; + + adapter = i2c_get_adapter(s_info->pdata.i2c_bus_num); + if (!adapter) { + v4l2_warn(&fmd->v4l2_dev, + "Failed to get I2C adapter %d, deferring probe\n", + s_info->pdata.i2c_bus_num); + return ERR_PTR(-EPROBE_DEFER); + } + sd = v4l2_i2c_new_subdev_board(&fmd->v4l2_dev, adapter, + s_info->pdata.board_info, NULL); + if (IS_ERR_OR_NULL(sd)) { + i2c_put_adapter(adapter); + v4l2_warn(&fmd->v4l2_dev, + "Failed to acquire subdev %s, deferring probe\n", + s_info->pdata.board_info->type); + return ERR_PTR(-EPROBE_DEFER); + } + v4l2_set_subdev_hostdata(sd, s_info); + sd->grp_id = GRP_ID_SENSOR; + + v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice %s\n", + sd->name); + return sd; +} + +static void fimc_md_unregister_sensor(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct i2c_adapter *adapter; + + if (!client) + return; + v4l2_device_unregister_subdev(sd); + + if (!client->dev.of_node) { + adapter = client->adapter; + i2c_unregister_device(client); + if (adapter) + i2c_put_adapter(adapter); + } +} + +#ifdef CONFIG_OF +/* Register I2C client subdev associated with @node. */ +static int fimc_md_of_add_sensor(struct fimc_md *fmd, + struct device_node *node, int index) +{ + struct fimc_sensor_info *si; + struct i2c_client *client; + struct v4l2_subdev *sd; + int ret; + + if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor))) + return -EINVAL; + si = &fmd->sensor[index]; + + client = of_find_i2c_device_by_node(node); + if (!client) + return -EPROBE_DEFER; + + device_lock(&client->dev); + + if (!client->driver || + !try_module_get(client->driver->driver.owner)) { + ret = -EPROBE_DEFER; + v4l2_info(&fmd->v4l2_dev, "No driver found for %s\n", + node->full_name); + goto dev_put; + } + + /* Enable sensor's master clock */ + ret = __fimc_md_set_camclk(fmd, si, true); + if (ret < 0) + goto mod_put; + sd = i2c_get_clientdata(client); + + ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); + __fimc_md_set_camclk(fmd, si, false); + if (ret < 0) + goto mod_put; + + v4l2_set_subdev_hostdata(sd, si); + sd->grp_id = GRP_ID_SENSOR; + si->subdev = sd; + v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice: %s (%d)\n", + sd->name, fmd->num_sensors); + fmd->num_sensors++; + +mod_put: + module_put(client->driver->driver.owner); +dev_put: + device_unlock(&client->dev); + put_device(&client->dev); + return ret; +} + +/* Parse port node and register as a sub-device any sensor specified there. */ +static int fimc_md_parse_port_node(struct fimc_md *fmd, + struct device_node *port, + unsigned int index) +{ + struct device_node *rem, *ep, *np; + struct fimc_source_info *pd; + struct v4l2_of_endpoint endpoint; + int ret; + u32 val; + + pd = &fmd->sensor[index].pdata; + + /* Assume here a port node can have only one endpoint node. */ + ep = of_get_next_child(port, NULL); + if (!ep) + return 0; + + v4l2_of_parse_endpoint(ep, &endpoint); + if (WARN_ON(endpoint.port == 0) || index >= FIMC_MAX_SENSORS) + return -EINVAL; + + pd->mux_id = (endpoint.port - 1) & 0x1; + + rem = v4l2_of_get_remote_port_parent(ep); + of_node_put(ep); + if (rem == NULL) { + v4l2_info(&fmd->v4l2_dev, "Remote device at %s not found\n", + ep->full_name); + return 0; + } + if (!of_property_read_u32(rem, "samsung,camclk-out", &val)) + pd->clk_id = val; + + if (!of_property_read_u32(rem, "clock-frequency", &val)) + pd->clk_frequency = val; + + if (pd->clk_frequency == 0) { + v4l2_err(&fmd->v4l2_dev, "Wrong clock frequency at node %s\n", + rem->full_name); + of_node_put(rem); + return -EINVAL; + } + + if (fimc_input_is_parallel(endpoint.port)) { + if (endpoint.bus_type == V4L2_MBUS_PARALLEL) + pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_601; + else + pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_656; + pd->flags = endpoint.bus.parallel.flags; + } else if (fimc_input_is_mipi_csi(endpoint.port)) { + /* + * MIPI CSI-2: only input mux selection and + * the sensor's clock frequency is needed. + */ + pd->sensor_bus_type = FIMC_BUS_TYPE_MIPI_CSI2; + } else { + v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %s\n", + endpoint.port, rem->full_name); + } + /* + * For FIMC-IS handled sensors, that are placed under i2c-isp device + * node, FIMC is connected to the FIMC-IS through its ISP Writeback + * input. Sensors are attached to the FIMC-LITE hostdata interface + * directly or through MIPI-CSIS, depending on the external media bus + * used. This needs to be handled in a more reliable way, not by just + * checking parent's node name. + */ + np = of_get_parent(rem); + + if (np && !of_node_cmp(np->name, "i2c-isp")) + pd->fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK; + else + pd->fimc_bus_type = pd->sensor_bus_type; + + ret = fimc_md_of_add_sensor(fmd, rem, index); + of_node_put(rem); + + return ret; +} + +/* Register all SoC external sub-devices */ +static int fimc_md_of_sensors_register(struct fimc_md *fmd, + struct device_node *np) +{ + struct device_node *parent = fmd->pdev->dev.of_node; + struct device_node *node, *ports; + int index = 0; + int ret; + + /* Attach sensors linked to MIPI CSI-2 receivers */ + for_each_available_child_of_node(parent, node) { + struct device_node *port; + + if (of_node_cmp(node->name, "csis")) + continue; + /* The csis node can have only port subnode. */ + port = of_get_next_child(node, NULL); + if (!port) + continue; + + ret = fimc_md_parse_port_node(fmd, port, index); + if (ret < 0) + return ret; + index++; + } + + /* Attach sensors listed in the parallel-ports node */ + ports = of_get_child_by_name(parent, "parallel-ports"); + if (!ports) + return 0; + + for_each_child_of_node(ports, node) { + ret = fimc_md_parse_port_node(fmd, node, index); + if (ret < 0) + break; + index++; + } + + return 0; +} + +static int __of_get_csis_id(struct device_node *np) +{ + u32 reg = 0; + + np = of_get_child_by_name(np, "port"); + if (!np) + return -EINVAL; + of_property_read_u32(np, "reg", ®); + return reg - FIMC_INPUT_MIPI_CSI2_0; +} +#else +#define fimc_md_of_sensors_register(fmd, np) (-ENOSYS) +#define __of_get_csis_id(np) (-ENOSYS) +#endif + +static int fimc_md_register_sensor_entities(struct fimc_md *fmd) +{ + struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data; + struct device_node *of_node = fmd->pdev->dev.of_node; + int num_clients = 0; + int ret, i; + + /* + * Runtime resume one of the FIMC entities to make sure + * the sclk_cam clocks are not globally disabled. + */ + if (!fmd->pmf) + return -ENXIO; + + ret = pm_runtime_get_sync(fmd->pmf); + if (ret < 0) + return ret; + + if (of_node) { + fmd->num_sensors = 0; + ret = fimc_md_of_sensors_register(fmd, of_node); + } else if (pdata) { + WARN_ON(pdata->num_clients > ARRAY_SIZE(fmd->sensor)); + num_clients = min_t(u32, pdata->num_clients, + ARRAY_SIZE(fmd->sensor)); + fmd->num_sensors = num_clients; + + for (i = 0; i < num_clients; i++) { + struct v4l2_subdev *sd; + + fmd->sensor[i].pdata = pdata->source_info[i]; + ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], true); + if (ret) + break; + sd = fimc_md_register_sensor(fmd, &fmd->sensor[i]); + ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], false); + + if (IS_ERR(sd)) { + fmd->sensor[i].subdev = NULL; + ret = PTR_ERR(sd); + break; + } + fmd->sensor[i].subdev = sd; + if (ret) + break; + } + } + + pm_runtime_put(fmd->pmf); + return ret; +} + +/* + * MIPI-CSIS, FIMC and FIMC-LITE platform devices registration. + */ + +static int register_fimc_lite_entity(struct fimc_md *fmd, + struct fimc_lite *fimc_lite) +{ + struct v4l2_subdev *sd; + int ret; + + if (WARN_ON(fimc_lite->index >= FIMC_LITE_MAX_DEVS || + fmd->fimc_lite[fimc_lite->index])) + return -EBUSY; + + sd = &fimc_lite->subdev; + sd->grp_id = GRP_ID_FLITE; + v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops); + + ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); + if (!ret) + fmd->fimc_lite[fimc_lite->index] = fimc_lite; + else + v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.LITE%d\n", + fimc_lite->index); + return ret; +} + +static int register_fimc_entity(struct fimc_md *fmd, struct fimc_dev *fimc) +{ + struct v4l2_subdev *sd; + int ret; + + if (WARN_ON(fimc->id >= FIMC_MAX_DEVS || fmd->fimc[fimc->id])) + return -EBUSY; + + sd = &fimc->vid_cap.subdev; + sd->grp_id = GRP_ID_FIMC; + v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops); + + ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); + if (!ret) { + if (!fmd->pmf && fimc->pdev) + fmd->pmf = &fimc->pdev->dev; + fmd->fimc[fimc->id] = fimc; + fimc->vid_cap.user_subdev_api = fmd->user_subdev_api; + } else { + v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.%d (%d)\n", + fimc->id, ret); + } + return ret; +} + +static int register_csis_entity(struct fimc_md *fmd, + struct platform_device *pdev, + struct v4l2_subdev *sd) +{ + struct device_node *node = pdev->dev.of_node; + int id, ret; + + id = node ? __of_get_csis_id(node) : max(0, pdev->id); + + if (WARN_ON(id < 0 || id >= CSIS_MAX_ENTITIES)) + return -ENOENT; + + if (WARN_ON(fmd->csis[id].sd)) + return -EBUSY; + + sd->grp_id = GRP_ID_CSIS; + ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); + if (!ret) + fmd->csis[id].sd = sd; + else + v4l2_err(&fmd->v4l2_dev, + "Failed to register MIPI-CSIS.%d (%d)\n", id, ret); + return ret; +} + +static int fimc_md_register_platform_entity(struct fimc_md *fmd, + struct platform_device *pdev, + int plat_entity) +{ + struct device *dev = &pdev->dev; + int ret = -EPROBE_DEFER; + void *drvdata; + + /* Lock to ensure dev->driver won't change. */ + device_lock(dev); + + if (!dev->driver || !try_module_get(dev->driver->owner)) + goto dev_unlock; + + drvdata = dev_get_drvdata(dev); + /* Some subdev didn't probe succesfully id drvdata is NULL */ + if (drvdata) { + switch (plat_entity) { + case IDX_FIMC: + ret = register_fimc_entity(fmd, drvdata); + break; + case IDX_FLITE: + ret = register_fimc_lite_entity(fmd, drvdata); + break; + case IDX_CSIS: + ret = register_csis_entity(fmd, pdev, drvdata); + break; + default: + ret = -ENODEV; + } + } + + module_put(dev->driver->owner); +dev_unlock: + device_unlock(dev); + if (ret == -EPROBE_DEFER) + dev_info(&fmd->pdev->dev, "deferring %s device registration\n", + dev_name(dev)); + else if (ret < 0) + dev_err(&fmd->pdev->dev, "%s device registration failed (%d)\n", + dev_name(dev), ret); + return ret; +} + +static int fimc_md_pdev_match(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + int plat_entity = -1; + int ret; + char *p; + + if (!get_device(dev)) + return -ENODEV; + + if (!strcmp(pdev->name, CSIS_DRIVER_NAME)) { + plat_entity = IDX_CSIS; + } else if (!strcmp(pdev->name, FIMC_LITE_DRV_NAME)) { + plat_entity = IDX_FLITE; + } else { + p = strstr(pdev->name, "fimc"); + if (p && *(p + 4) == 0) + plat_entity = IDX_FIMC; + } + + if (plat_entity >= 0) + ret = fimc_md_register_platform_entity(data, pdev, + plat_entity); + put_device(dev); + return 0; +} + +/* Register FIMC, FIMC-LITE and CSIS media entities */ +#ifdef CONFIG_OF +static int fimc_md_register_of_platform_entities(struct fimc_md *fmd, + struct device_node *parent) +{ + struct device_node *node; + int ret = 0; + + for_each_available_child_of_node(parent, node) { + struct platform_device *pdev; + int plat_entity = -1; + + pdev = of_find_device_by_node(node); + if (!pdev) + continue; + + /* If driver of any entity isn't ready try all again later. */ + if (!strcmp(node->name, CSIS_OF_NODE_NAME)) + plat_entity = IDX_CSIS; + else if (!strcmp(node->name, FIMC_LITE_OF_NODE_NAME)) + plat_entity = IDX_FLITE; + else if (!strcmp(node->name, FIMC_OF_NODE_NAME) && + !of_property_read_bool(node, "samsung,lcd-wb")) + plat_entity = IDX_FIMC; + + if (plat_entity >= 0) + ret = fimc_md_register_platform_entity(fmd, pdev, + plat_entity); + put_device(&pdev->dev); + if (ret < 0) + break; + } + + return ret; +} +#else +#define fimc_md_register_of_platform_entities(fmd, node) (-ENOSYS) +#endif + +static void fimc_md_unregister_entities(struct fimc_md *fmd) +{ + int i; + + for (i = 0; i < FIMC_MAX_DEVS; i++) { + if (fmd->fimc[i] == NULL) + continue; + v4l2_device_unregister_subdev(&fmd->fimc[i]->vid_cap.subdev); + fmd->fimc[i]->pipeline_ops = NULL; + fmd->fimc[i] = NULL; + } + for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) { + if (fmd->fimc_lite[i] == NULL) + continue; + v4l2_device_unregister_subdev(&fmd->fimc_lite[i]->subdev); + fmd->fimc_lite[i]->pipeline_ops = NULL; + fmd->fimc_lite[i] = NULL; + } + for (i = 0; i < CSIS_MAX_ENTITIES; i++) { + if (fmd->csis[i].sd == NULL) + continue; + v4l2_device_unregister_subdev(fmd->csis[i].sd); + module_put(fmd->csis[i].sd->owner); + fmd->csis[i].sd = NULL; + } + for (i = 0; i < fmd->num_sensors; i++) { + if (fmd->sensor[i].subdev == NULL) + continue; + fimc_md_unregister_sensor(fmd->sensor[i].subdev); + fmd->sensor[i].subdev = NULL; + } + v4l2_info(&fmd->v4l2_dev, "Unregistered all entities\n"); +} + +/** + * __fimc_md_create_fimc_links - create links to all FIMC entities + * @fmd: fimc media device + * @source: the source entity to create links to all fimc entities from + * @sensor: sensor subdev linked to FIMC[fimc_id] entity, may be null + * @pad: the source entity pad index + * @link_mask: bitmask of the fimc devices for which link should be enabled + */ +static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, + struct media_entity *source, + struct v4l2_subdev *sensor, + int pad, int link_mask) +{ + struct fimc_sensor_info *s_info = NULL; + struct media_entity *sink; + unsigned int flags = 0; + int ret, i; + + for (i = 0; i < FIMC_MAX_DEVS; i++) { + if (!fmd->fimc[i]) + continue; + /* + * Some FIMC variants are not fitted with camera capture + * interface. Skip creating a link from sensor for those. + */ + if (!fmd->fimc[i]->variant->has_cam_if) + continue; + + flags = ((1 << i) & link_mask) ? MEDIA_LNK_FL_ENABLED : 0; + + sink = &fmd->fimc[i]->vid_cap.subdev.entity; + ret = media_entity_create_link(source, pad, sink, + FIMC_SD_PAD_SINK_CAM, flags); + if (ret) + return ret; + + /* Notify FIMC capture subdev entity */ + ret = media_entity_call(sink, link_setup, &sink->pads[0], + &source->pads[pad], flags); + if (ret) + break; + + v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]\n", + source->name, flags ? '=' : '-', sink->name); + + if (flags == 0 || sensor == NULL) + continue; + s_info = v4l2_get_subdev_hostdata(sensor); + if (!WARN_ON(s_info == NULL)) { + unsigned long irq_flags; + spin_lock_irqsave(&fmd->slock, irq_flags); + s_info->host = fmd->fimc[i]; + spin_unlock_irqrestore(&fmd->slock, irq_flags); + } + } + + for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) { + if (!fmd->fimc_lite[i]) + continue; + + if (link_mask & (1 << (i + FIMC_MAX_DEVS))) + flags = MEDIA_LNK_FL_ENABLED; + else + flags = 0; + + sink = &fmd->fimc_lite[i]->subdev.entity; + ret = media_entity_create_link(source, pad, sink, + FLITE_SD_PAD_SINK, flags); + if (ret) + return ret; + + /* Notify FIMC-LITE subdev entity */ + ret = media_entity_call(sink, link_setup, &sink->pads[0], + &source->pads[pad], flags); + if (ret) + break; + + v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]\n", + source->name, flags ? '=' : '-', sink->name); + } + return 0; +} + +/* Create links from FIMC-LITE source pads to other entities */ +static int __fimc_md_create_flite_source_links(struct fimc_md *fmd) +{ + struct media_entity *source, *sink; + unsigned int flags = MEDIA_LNK_FL_ENABLED; + int i, ret = 0; + + for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) { + struct fimc_lite *fimc = fmd->fimc_lite[i]; + if (fimc == NULL) + continue; + source = &fimc->subdev.entity; + sink = &fimc->vfd.entity; + /* FIMC-LITE's subdev and video node */ + ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_DMA, + sink, 0, flags); + if (ret) + break; + /* TODO: create links to other entities */ + } + + return ret; +} + +/** + * fimc_md_create_links - create default links between registered entities + * + * Parallel interface sensor entities are connected directly to FIMC capture + * entities. The sensors using MIPI CSIS bus are connected through immutable + * link with CSI receiver entity specified by mux_id. Any registered CSIS + * entity has a link to each registered FIMC capture entity. Enabled links + * are created by default between each subsequent registered sensor and + * subsequent FIMC capture entity. The number of default active links is + * determined by the number of available sensors or FIMC entities, + * whichever is less. + */ +static int fimc_md_create_links(struct fimc_md *fmd) +{ + struct v4l2_subdev *csi_sensors[CSIS_MAX_ENTITIES] = { NULL }; + struct v4l2_subdev *sensor, *csis; + struct fimc_source_info *pdata; + struct fimc_sensor_info *s_info; + struct media_entity *source, *sink; + int i, pad, fimc_id = 0, ret = 0; + u32 flags, link_mask = 0; + + for (i = 0; i < fmd->num_sensors; i++) { + if (fmd->sensor[i].subdev == NULL) + continue; + + sensor = fmd->sensor[i].subdev; + s_info = v4l2_get_subdev_hostdata(sensor); + if (!s_info) + continue; + + source = NULL; + pdata = &s_info->pdata; + + switch (pdata->sensor_bus_type) { + case FIMC_BUS_TYPE_MIPI_CSI2: + if (WARN(pdata->mux_id >= CSIS_MAX_ENTITIES, + "Wrong CSI channel id: %d\n", pdata->mux_id)) + return -EINVAL; + + csis = fmd->csis[pdata->mux_id].sd; + if (WARN(csis == NULL, + "MIPI-CSI interface specified " + "but s5p-csis module is not loaded!\n")) + return -EINVAL; + + pad = sensor->entity.num_pads - 1; + ret = media_entity_create_link(&sensor->entity, pad, + &csis->entity, CSIS_PAD_SINK, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + + v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]\n", + sensor->entity.name, csis->entity.name); + + source = NULL; + csi_sensors[pdata->mux_id] = sensor; + break; + + case FIMC_BUS_TYPE_ITU_601...FIMC_BUS_TYPE_ITU_656: + source = &sensor->entity; + pad = 0; + break; + + default: + v4l2_err(&fmd->v4l2_dev, "Wrong bus_type: %x\n", + pdata->sensor_bus_type); + return -EINVAL; + } + if (source == NULL) + continue; + + link_mask = 1 << fimc_id++; + ret = __fimc_md_create_fimc_sink_links(fmd, source, sensor, + pad, link_mask); + } + + for (i = 0; i < CSIS_MAX_ENTITIES; i++) { + if (fmd->csis[i].sd == NULL) + continue; + source = &fmd->csis[i].sd->entity; + pad = CSIS_PAD_SOURCE; + sensor = csi_sensors[i]; + + link_mask = 1 << fimc_id++; + ret = __fimc_md_create_fimc_sink_links(fmd, source, sensor, + pad, link_mask); + } + + /* Create immutable links between each FIMC's subdev and video node */ + flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED; + for (i = 0; i < FIMC_MAX_DEVS; i++) { + if (!fmd->fimc[i]) + continue; + source = &fmd->fimc[i]->vid_cap.subdev.entity; + sink = &fmd->fimc[i]->vid_cap.vfd.entity; + ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE, + sink, 0, flags); + if (ret) + break; + } + + return __fimc_md_create_flite_source_links(fmd); +} + +/* + * The peripheral sensor and CAM_BLK (PIXELASYNCMx) clocks management. + */ +static void fimc_md_put_clocks(struct fimc_md *fmd) +{ + int i = FIMC_MAX_CAMCLKS; + + while (--i >= 0) { + if (IS_ERR(fmd->camclk[i].clock)) + continue; + clk_unprepare(fmd->camclk[i].clock); + clk_put(fmd->camclk[i].clock); + fmd->camclk[i].clock = ERR_PTR(-EINVAL); + } + + /* Writeback (PIXELASYNCMx) clocks */ + for (i = 0; i < FIMC_MAX_WBCLKS; i++) { + if (IS_ERR(fmd->wbclk[i])) + continue; + clk_put(fmd->wbclk[i]); + fmd->wbclk[i] = ERR_PTR(-EINVAL); + } +} + +static int fimc_md_get_clocks(struct fimc_md *fmd) +{ + struct device *dev = NULL; + char clk_name[32]; + struct clk *clock; + int ret, i; + + for (i = 0; i < FIMC_MAX_CAMCLKS; i++) + fmd->camclk[i].clock = ERR_PTR(-EINVAL); + + if (fmd->pdev->dev.of_node) + dev = &fmd->pdev->dev; + + for (i = 0; i < FIMC_MAX_CAMCLKS; i++) { + snprintf(clk_name, sizeof(clk_name), "sclk_cam%u", i); + clock = clk_get(dev, clk_name); + + if (IS_ERR(clock)) { + dev_err(&fmd->pdev->dev, "Failed to get clock: %s\n", + clk_name); + ret = PTR_ERR(clock); + break; + } + ret = clk_prepare(clock); + if (ret < 0) { + clk_put(clock); + fmd->camclk[i].clock = ERR_PTR(-EINVAL); + break; + } + fmd->camclk[i].clock = clock; + } + if (ret) + fimc_md_put_clocks(fmd); + + if (!fmd->use_isp) + return 0; + /* + * For now get only PIXELASYNCM1 clock (Writeback B/ISP), + * leave PIXELASYNCM0 out for the LCD Writeback driver. + */ + fmd->wbclk[CLK_IDX_WB_A] = ERR_PTR(-EINVAL); + + for (i = CLK_IDX_WB_B; i < FIMC_MAX_WBCLKS; i++) { + snprintf(clk_name, sizeof(clk_name), "pxl_async%u", i); + clock = clk_get(dev, clk_name); + if (IS_ERR(clock)) { + v4l2_err(&fmd->v4l2_dev, "Failed to get clock: %s\n", + clk_name); + ret = PTR_ERR(clock); + break; + } + fmd->wbclk[i] = clock; + } + if (ret) + fimc_md_put_clocks(fmd); + + return ret; +} + +static int __fimc_md_set_camclk(struct fimc_md *fmd, + struct fimc_sensor_info *s_info, + bool on) +{ + struct fimc_source_info *pdata = &s_info->pdata; + struct fimc_camclk_info *camclk; + int ret = 0; + + if (WARN_ON(pdata->clk_id >= FIMC_MAX_CAMCLKS) || !fmd || !fmd->pmf) + return -EINVAL; + + camclk = &fmd->camclk[pdata->clk_id]; + + dbg("camclk %d, f: %lu, use_count: %d, on: %d", + pdata->clk_id, pdata->clk_frequency, camclk->use_count, on); + + if (on) { + if (camclk->use_count > 0 && + camclk->frequency != pdata->clk_frequency) + return -EINVAL; + + if (camclk->use_count++ == 0) { + clk_set_rate(camclk->clock, pdata->clk_frequency); + camclk->frequency = pdata->clk_frequency; + ret = pm_runtime_get_sync(fmd->pmf); + if (ret < 0) + return ret; + ret = clk_enable(camclk->clock); + dbg("Enabled camclk %d: f: %lu", pdata->clk_id, + clk_get_rate(camclk->clock)); + } + return ret; + } + + if (WARN_ON(camclk->use_count == 0)) + return 0; + + if (--camclk->use_count == 0) { + clk_disable(camclk->clock); + pm_runtime_put(fmd->pmf); + dbg("Disabled camclk %d", pdata->clk_id); + } + return ret; +} + +/** + * fimc_md_set_camclk - peripheral sensor clock setup + * @sd: sensor subdev to configure sclk_cam clock for + * @on: 1 to enable or 0 to disable the clock + * + * There are 2 separate clock outputs available in the SoC for external + * image processors. These clocks are shared between all registered FIMC + * devices to which sensors can be attached, either directly or through + * the MIPI CSI receiver. The clock is allowed here to be used by + * multiple sensors concurrently if they use same frequency. + * This function should only be called when the graph mutex is held. + */ +int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on) +{ + struct fimc_sensor_info *s_info = v4l2_get_subdev_hostdata(sd); + struct fimc_md *fmd = entity_to_fimc_mdev(&sd->entity); + + return __fimc_md_set_camclk(fmd, s_info, on); +} + +static int fimc_md_link_notify(struct media_pad *source, + struct media_pad *sink, u32 flags) +{ + struct fimc_lite *fimc_lite = NULL; + struct fimc_dev *fimc = NULL; + struct fimc_pipeline *pipeline; + struct v4l2_subdev *sd; + struct mutex *lock; + int ret = 0; + int ref_count; + + if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + return 0; + + sd = media_entity_to_v4l2_subdev(sink->entity); + + switch (sd->grp_id) { + case GRP_ID_FLITE: + fimc_lite = v4l2_get_subdevdata(sd); + if (WARN_ON(fimc_lite == NULL)) + return 0; + pipeline = &fimc_lite->pipeline; + lock = &fimc_lite->lock; + break; + case GRP_ID_FIMC: + fimc = v4l2_get_subdevdata(sd); + if (WARN_ON(fimc == NULL)) + return 0; + pipeline = &fimc->pipeline; + lock = &fimc->lock; + break; + default: + return 0; + } + + if (!(flags & MEDIA_LNK_FL_ENABLED)) { + int i; + mutex_lock(lock); + ret = __fimc_pipeline_close(pipeline); + for (i = 0; i < IDX_MAX; i++) + pipeline->subdevs[i] = NULL; + if (fimc) + fimc_ctrls_delete(fimc->vid_cap.ctx); + mutex_unlock(lock); + return ret; + } + /* + * Link activation. Enable power of pipeline elements only if the + * pipeline is already in use, i.e. its video node is opened. + * Recreate the controls destroyed during the link deactivation. + */ + mutex_lock(lock); + + ref_count = fimc ? fimc->vid_cap.refcnt : fimc_lite->ref_count; + if (ref_count > 0) + ret = __fimc_pipeline_open(pipeline, source->entity, true); + if (!ret && fimc) + ret = fimc_capture_ctrls_create(fimc); + + mutex_unlock(lock); + return ret ? -EPIPE : ret; +} + +static ssize_t fimc_md_sysfs_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fimc_md *fmd = platform_get_drvdata(pdev); + + if (fmd->user_subdev_api) + return strlcpy(buf, "Sub-device API (sub-dev)\n", PAGE_SIZE); + + return strlcpy(buf, "V4L2 video node only API (vid-dev)\n", PAGE_SIZE); +} + +static ssize_t fimc_md_sysfs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct platform_device *pdev = to_platform_device(dev); + struct fimc_md *fmd = platform_get_drvdata(pdev); + bool subdev_api; + int i; + + if (!strcmp(buf, "vid-dev\n")) + subdev_api = false; + else if (!strcmp(buf, "sub-dev\n")) + subdev_api = true; + else + return count; + + fmd->user_subdev_api = subdev_api; + for (i = 0; i < FIMC_MAX_DEVS; i++) + if (fmd->fimc[i]) + fmd->fimc[i]->vid_cap.user_subdev_api = subdev_api; + return count; +} +/* + * This device attribute is to select video pipeline configuration method. + * There are following valid values: + * vid-dev - for V4L2 video node API only, subdevice will be configured + * by the host driver. + * sub-dev - for media controller API, subdevs must be configured in user + * space before starting streaming. + */ +static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO, + fimc_md_sysfs_show, fimc_md_sysfs_store); + +static int fimc_md_get_pinctrl(struct fimc_md *fmd) +{ + struct device *dev = &fmd->pdev->dev; + struct fimc_pinctrl *pctl = &fmd->pinctl; + + pctl->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(pctl->pinctrl)) + return PTR_ERR(pctl->pinctrl); + + pctl->state_default = pinctrl_lookup_state(pctl->pinctrl, + PINCTRL_STATE_DEFAULT); + if (IS_ERR(pctl->state_default)) + return PTR_ERR(pctl->state_default); + + pctl->state_idle = pinctrl_lookup_state(pctl->pinctrl, + PINCTRL_STATE_IDLE); + return 0; +} + +static int fimc_md_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct v4l2_device *v4l2_dev; + struct fimc_md *fmd; + int ret; + + fmd = devm_kzalloc(dev, sizeof(*fmd), GFP_KERNEL); + if (!fmd) + return -ENOMEM; + + spin_lock_init(&fmd->slock); + fmd->pdev = pdev; + + strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC", + sizeof(fmd->media_dev.model)); + fmd->media_dev.link_notify = fimc_md_link_notify; + fmd->media_dev.dev = dev; + + v4l2_dev = &fmd->v4l2_dev; + v4l2_dev->mdev = &fmd->media_dev; + v4l2_dev->notify = fimc_sensor_notify; + strlcpy(v4l2_dev->name, "s5p-fimc-md", sizeof(v4l2_dev->name)); + + ret = v4l2_device_register(dev, &fmd->v4l2_dev); + if (ret < 0) { + v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); + return ret; + } + ret = media_device_register(&fmd->media_dev); + if (ret < 0) { + v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret); + goto err_md; + } + ret = fimc_md_get_clocks(fmd); + if (ret) + goto err_clk; + + fmd->user_subdev_api = (dev->of_node != NULL); + + /* Protect the media graph while we're registering entities */ + mutex_lock(&fmd->media_dev.graph_mutex); + + ret = fimc_md_get_pinctrl(fmd); + if (ret < 0) { + if (ret != EPROBE_DEFER) + dev_err(dev, "Failed to get pinctrl: %d\n", ret); + goto err_unlock; + } + + if (dev->of_node) + ret = fimc_md_register_of_platform_entities(fmd, dev->of_node); + else + ret = bus_for_each_dev(&platform_bus_type, NULL, fmd, + fimc_md_pdev_match); + if (ret) + goto err_unlock; + + if (dev->platform_data || dev->of_node) { + ret = fimc_md_register_sensor_entities(fmd); + if (ret) + goto err_unlock; + } + + ret = fimc_md_create_links(fmd); + if (ret) + goto err_unlock; + ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev); + if (ret) + goto err_unlock; + + ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode); + if (ret) + goto err_unlock; + + platform_set_drvdata(pdev, fmd); + mutex_unlock(&fmd->media_dev.graph_mutex); + return 0; + +err_unlock: + mutex_unlock(&fmd->media_dev.graph_mutex); +err_clk: + media_device_unregister(&fmd->media_dev); + fimc_md_put_clocks(fmd); + fimc_md_unregister_entities(fmd); +err_md: + v4l2_device_unregister(&fmd->v4l2_dev); + return ret; +} + +static int fimc_md_remove(struct platform_device *pdev) +{ + struct fimc_md *fmd = platform_get_drvdata(pdev); + + if (!fmd) + return 0; + device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode); + fimc_md_unregister_entities(fmd); + media_device_unregister(&fmd->media_dev); + fimc_md_put_clocks(fmd); + return 0; +} + +static struct platform_device_id fimc_driver_ids[] __always_unused = { + { .name = "s5p-fimc-md" }, + { }, +}; +MODULE_DEVICE_TABLE(platform, fimc_driver_ids); + +static const struct of_device_id fimc_md_of_match[] = { + { .compatible = "samsung,fimc" }, + { }, +}; +MODULE_DEVICE_TABLE(of, fimc_md_of_match); + +static struct platform_driver fimc_md_driver = { + .probe = fimc_md_probe, + .remove = fimc_md_remove, + .driver = { + .of_match_table = of_match_ptr(fimc_md_of_match), + .name = "s5p-fimc-md", + .owner = THIS_MODULE, + } +}; + +static int __init fimc_md_init(void) +{ + int ret; + + request_module("s5p-csis"); + ret = fimc_register_driver(); + if (ret) + return ret; + + return platform_driver_register(&fimc_md_driver); +} + +static void __exit fimc_md_exit(void) +{ + platform_driver_unregister(&fimc_md_driver); + fimc_unregister_driver(); +} + +module_init(fimc_md_init); +module_exit(fimc_md_exit); + +MODULE_AUTHOR("Sylwester Nawrocki "); +MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("2.0.1"); diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h new file mode 100644 index 000000000000..1d5cea5a6bbe --- /dev/null +++ b/drivers/media/platform/exynos4-is/media-dev.h @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef FIMC_MDEVICE_H_ +#define FIMC_MDEVICE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fimc-core.h" +#include "fimc-lite.h" +#include "mipi-csis.h" + +#define FIMC_OF_NODE_NAME "fimc" +#define FIMC_LITE_OF_NODE_NAME "fimc-lite" +#define FIMC_IS_OF_NODE_NAME "fimc-is" +#define CSIS_OF_NODE_NAME "csis" + +#define PINCTRL_STATE_IDLE "idle" + +/* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */ +#define GRP_ID_SENSOR (1 << 8) +#define GRP_ID_FIMC_IS_SENSOR (1 << 9) +#define GRP_ID_WRITEBACK (1 << 10) +#define GRP_ID_CSIS (1 << 11) +#define GRP_ID_FIMC (1 << 12) +#define GRP_ID_FLITE (1 << 13) +#define GRP_ID_FIMC_IS (1 << 14) + +#define FIMC_MAX_SENSORS 8 +#define FIMC_MAX_CAMCLKS 2 + +/* LCD/ISP Writeback clocks (PIXELASYNCMx) */ +enum { + CLK_IDX_WB_A, + CLK_IDX_WB_B, + FIMC_MAX_WBCLKS +}; + +struct fimc_csis_info { + struct v4l2_subdev *sd; + int id; +}; + +struct fimc_camclk_info { + struct clk *clock; + int use_count; + unsigned long frequency; +}; + +/** + * struct fimc_sensor_info - image data source subdev information + * @pdata: sensor's atrributes passed as media device's platform data + * @subdev: image sensor v4l2 subdev + * @host: fimc device the sensor is currently linked to + * + * This data structure applies to image sensor and the writeback subdevs. + */ +struct fimc_sensor_info { + struct fimc_source_info pdata; + struct v4l2_subdev *subdev; + struct fimc_dev *host; +}; + +/** + * struct fimc_md - fimc media device information + * @csis: MIPI CSIS subdevs data + * @sensor: array of registered sensor subdevs + * @num_sensors: actual number of registered sensors + * @camclk: external sensor clock information + * @fimc: array of registered fimc devices + * @use_isp: set to true when FIMC-IS subsystem is used + * @pmf: handle to the CAMCLK clock control FIMC helper device + * @media_dev: top level media device + * @v4l2_dev: top level v4l2_device holding up the subdevs + * @pdev: platform device this media device is hooked up into + * @pinctrl: camera port pinctrl handle + * @state_default: pinctrl default state handle + * @state_idle: pinctrl idle state handle + * @user_subdev_api: true if subdevs are not configured by the host driver + * @slock: spinlock protecting @sensor array + */ +struct fimc_md { + struct fimc_csis_info csis[CSIS_MAX_ENTITIES]; + struct fimc_sensor_info sensor[FIMC_MAX_SENSORS]; + int num_sensors; + struct fimc_camclk_info camclk[FIMC_MAX_CAMCLKS]; + struct clk *wbclk[FIMC_MAX_WBCLKS]; + struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS]; + struct fimc_dev *fimc[FIMC_MAX_DEVS]; + bool use_isp; + struct device *pmf; + struct media_device media_dev; + struct v4l2_device v4l2_dev; + struct platform_device *pdev; + struct fimc_pinctrl { + struct pinctrl *pinctrl; + struct pinctrl_state *state_default; + struct pinctrl_state *state_idle; + } pinctl; + bool user_subdev_api; + spinlock_t slock; +}; + +#define is_subdev_pad(pad) (pad == NULL || \ + media_entity_type(pad->entity) == MEDIA_ENT_T_V4L2_SUBDEV) + +#define me_subtype(me) \ + ((me->type) & (MEDIA_ENT_TYPE_MASK | MEDIA_ENT_SUBTYPE_MASK)) + +#define subdev_has_devnode(__sd) (__sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE) + +static inline struct fimc_md *entity_to_fimc_mdev(struct media_entity *me) +{ + return me->parent == NULL ? NULL : + container_of(me->parent, struct fimc_md, media_dev); +} + +static inline void fimc_md_graph_lock(struct fimc_dev *fimc) +{ + mutex_lock(&fimc->vid_cap.vfd.entity.parent->graph_mutex); +} + +static inline void fimc_md_graph_unlock(struct fimc_dev *fimc) +{ + mutex_unlock(&fimc->vid_cap.vfd.entity.parent->graph_mutex); +} + +int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on); + +#endif diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c new file mode 100644 index 000000000000..8636bcddde1b --- /dev/null +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -0,0 +1,1025 @@ +/* + * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver + * + * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mipi-csis.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-2)"); + +/* Register map definition */ + +/* CSIS global control */ +#define S5PCSIS_CTRL 0x00 +#define S5PCSIS_CTRL_DPDN_DEFAULT (0 << 31) +#define S5PCSIS_CTRL_DPDN_SWAP (1 << 31) +#define S5PCSIS_CTRL_ALIGN_32BIT (1 << 20) +#define S5PCSIS_CTRL_UPDATE_SHADOW (1 << 16) +#define S5PCSIS_CTRL_WCLK_EXTCLK (1 << 8) +#define S5PCSIS_CTRL_RESET (1 << 4) +#define S5PCSIS_CTRL_ENABLE (1 << 0) + +/* D-PHY control */ +#define S5PCSIS_DPHYCTRL 0x04 +#define S5PCSIS_DPHYCTRL_HSS_MASK (0x1f << 27) +#define S5PCSIS_DPHYCTRL_ENABLE (0x1f << 0) + +#define S5PCSIS_CONFIG 0x08 +#define S5PCSIS_CFG_FMT_YCBCR422_8BIT (0x1e << 2) +#define S5PCSIS_CFG_FMT_RAW8 (0x2a << 2) +#define S5PCSIS_CFG_FMT_RAW10 (0x2b << 2) +#define S5PCSIS_CFG_FMT_RAW12 (0x2c << 2) +/* User defined formats, x = 1...4 */ +#define S5PCSIS_CFG_FMT_USER(x) ((0x30 + x - 1) << 2) +#define S5PCSIS_CFG_FMT_MASK (0x3f << 2) +#define S5PCSIS_CFG_NR_LANE_MASK 3 + +/* Interrupt mask */ +#define S5PCSIS_INTMSK 0x10 +#define S5PCSIS_INTMSK_EN_ALL 0xf000103f +#define S5PCSIS_INTMSK_EVEN_BEFORE (1 << 31) +#define S5PCSIS_INTMSK_EVEN_AFTER (1 << 30) +#define S5PCSIS_INTMSK_ODD_BEFORE (1 << 29) +#define S5PCSIS_INTMSK_ODD_AFTER (1 << 28) +#define S5PCSIS_INTMSK_ERR_SOT_HS (1 << 12) +#define S5PCSIS_INTMSK_ERR_LOST_FS (1 << 5) +#define S5PCSIS_INTMSK_ERR_LOST_FE (1 << 4) +#define S5PCSIS_INTMSK_ERR_OVER (1 << 3) +#define S5PCSIS_INTMSK_ERR_ECC (1 << 2) +#define S5PCSIS_INTMSK_ERR_CRC (1 << 1) +#define S5PCSIS_INTMSK_ERR_UNKNOWN (1 << 0) + +/* Interrupt source */ +#define S5PCSIS_INTSRC 0x14 +#define S5PCSIS_INTSRC_EVEN_BEFORE (1 << 31) +#define S5PCSIS_INTSRC_EVEN_AFTER (1 << 30) +#define S5PCSIS_INTSRC_EVEN (0x3 << 30) +#define S5PCSIS_INTSRC_ODD_BEFORE (1 << 29) +#define S5PCSIS_INTSRC_ODD_AFTER (1 << 28) +#define S5PCSIS_INTSRC_ODD (0x3 << 28) +#define S5PCSIS_INTSRC_NON_IMAGE_DATA (0xff << 28) +#define S5PCSIS_INTSRC_ERR_SOT_HS (0xf << 12) +#define S5PCSIS_INTSRC_ERR_LOST_FS (1 << 5) +#define S5PCSIS_INTSRC_ERR_LOST_FE (1 << 4) +#define S5PCSIS_INTSRC_ERR_OVER (1 << 3) +#define S5PCSIS_INTSRC_ERR_ECC (1 << 2) +#define S5PCSIS_INTSRC_ERR_CRC (1 << 1) +#define S5PCSIS_INTSRC_ERR_UNKNOWN (1 << 0) +#define S5PCSIS_INTSRC_ERRORS 0xf03f + +/* Pixel resolution */ +#define S5PCSIS_RESOL 0x2c +#define CSIS_MAX_PIX_WIDTH 0xffff +#define CSIS_MAX_PIX_HEIGHT 0xffff + +/* Non-image packet data buffers */ +#define S5PCSIS_PKTDATA_ODD 0x2000 +#define S5PCSIS_PKTDATA_EVEN 0x3000 +#define S5PCSIS_PKTDATA_SIZE SZ_4K + +enum { + CSIS_CLK_MUX, + CSIS_CLK_GATE, +}; + +static char *csi_clock_name[] = { + [CSIS_CLK_MUX] = "sclk_csis", + [CSIS_CLK_GATE] = "csis", +}; +#define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name) +#define DEFAULT_SCLK_CSIS_FREQ 166000000UL + +static const char * const csis_supply_name[] = { + "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */ + "vddio", /* CSIS I/O and PLL (1.8V) supply */ +}; +#define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name) + +enum { + ST_POWERED = 1, + ST_STREAMING = 2, + ST_SUSPENDED = 4, +}; + +struct s5pcsis_event { + u32 mask; + const char * const name; + unsigned int counter; +}; + +static const struct s5pcsis_event s5pcsis_events[] = { + /* Errors */ + { S5PCSIS_INTSRC_ERR_SOT_HS, "SOT Error" }, + { S5PCSIS_INTSRC_ERR_LOST_FS, "Lost Frame Start Error" }, + { S5PCSIS_INTSRC_ERR_LOST_FE, "Lost Frame End Error" }, + { S5PCSIS_INTSRC_ERR_OVER, "FIFO Overflow Error" }, + { S5PCSIS_INTSRC_ERR_ECC, "ECC Error" }, + { S5PCSIS_INTSRC_ERR_CRC, "CRC Error" }, + { S5PCSIS_INTSRC_ERR_UNKNOWN, "Unknown Error" }, + /* Non-image data receive events */ + { S5PCSIS_INTSRC_EVEN_BEFORE, "Non-image data before even frame" }, + { S5PCSIS_INTSRC_EVEN_AFTER, "Non-image data after even frame" }, + { S5PCSIS_INTSRC_ODD_BEFORE, "Non-image data before odd frame" }, + { S5PCSIS_INTSRC_ODD_AFTER, "Non-image data after odd frame" }, +}; +#define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events) + +struct csis_pktbuf { + u32 *data; + unsigned int len; +}; + +/** + * struct csis_state - the driver's internal state data structure + * @lock: mutex serializing the subdev and power management operations, + * protecting @format and @flags members + * @pads: CSIS pads array + * @sd: v4l2_subdev associated with CSIS device instance + * @index: the hardware instance index + * @pdev: CSIS platform device + * @regs: mmaped I/O registers memory + * @supplies: CSIS regulator supplies + * @clock: CSIS clocks + * @irq: requested s5p-mipi-csis irq number + * @flags: the state variable for power and streaming control + * @clock_frequency: device bus clock frequency + * @hs_settle: HS-RX settle time + * @num_lanes: number of MIPI-CSI data lanes used + * @max_num_lanes: maximum number of MIPI-CSI data lanes supported + * @wclk_ext: CSI wrapper clock: 0 - bus clock, 1 - external SCLK_CAM + * @csis_fmt: current CSIS pixel format + * @format: common media bus format for the source and sink pad + * @slock: spinlock protecting structure members below + * @pkt_buf: the frame embedded (non-image) data buffer + * @events: MIPI-CSIS event (error) counters + */ +struct csis_state { + struct mutex lock; + struct media_pad pads[CSIS_PADS_NUM]; + struct v4l2_subdev sd; + u8 index; + struct platform_device *pdev; + void __iomem *regs; + struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; + struct clk *clock[NUM_CSIS_CLOCKS]; + int irq; + u32 flags; + + u32 clk_frequency; + u32 hs_settle; + u32 num_lanes; + u32 max_num_lanes; + u8 wclk_ext; + + const struct csis_pix_format *csis_fmt; + struct v4l2_mbus_framefmt format; + + spinlock_t slock; + struct csis_pktbuf pkt_buf; + struct s5pcsis_event events[S5PCSIS_NUM_EVENTS]; +}; + +/** + * struct csis_pix_format - CSIS pixel format description + * @pix_width_alignment: horizontal pixel alignment, width will be + * multiple of 2^pix_width_alignment + * @code: corresponding media bus code + * @fmt_reg: S5PCSIS_CONFIG register value + * @data_alignment: MIPI-CSI data alignment in bits + */ +struct csis_pix_format { + unsigned int pix_width_alignment; + enum v4l2_mbus_pixelcode code; + u32 fmt_reg; + u8 data_alignment; +}; + +static const struct csis_pix_format s5pcsis_formats[] = { + { + .code = V4L2_MBUS_FMT_VYUY8_2X8, + .fmt_reg = S5PCSIS_CFG_FMT_YCBCR422_8BIT, + .data_alignment = 32, + }, { + .code = V4L2_MBUS_FMT_JPEG_1X8, + .fmt_reg = S5PCSIS_CFG_FMT_USER(1), + .data_alignment = 32, + }, { + .code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8, + .fmt_reg = S5PCSIS_CFG_FMT_USER(1), + .data_alignment = 32, + }, { + .code = V4L2_MBUS_FMT_SGRBG8_1X8, + .fmt_reg = S5PCSIS_CFG_FMT_RAW8, + .data_alignment = 24, + }, { + .code = V4L2_MBUS_FMT_SGRBG10_1X10, + .fmt_reg = S5PCSIS_CFG_FMT_RAW10, + .data_alignment = 24, + }, { + .code = V4L2_MBUS_FMT_SGRBG12_1X12, + .fmt_reg = S5PCSIS_CFG_FMT_RAW12, + .data_alignment = 24, + } +}; + +#define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r) +#define s5pcsis_read(__csis, __r) readl(__csis->regs + __r) + +static struct csis_state *sd_to_csis_state(struct v4l2_subdev *sdev) +{ + return container_of(sdev, struct csis_state, sd); +} + +static const struct csis_pix_format *find_csis_format( + struct v4l2_mbus_framefmt *mf) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(s5pcsis_formats); i++) + if (mf->code == s5pcsis_formats[i].code) + return &s5pcsis_formats[i]; + return NULL; +} + +static void s5pcsis_enable_interrupts(struct csis_state *state, bool on) +{ + u32 val = s5pcsis_read(state, S5PCSIS_INTMSK); + + val = on ? val | S5PCSIS_INTMSK_EN_ALL : + val & ~S5PCSIS_INTMSK_EN_ALL; + s5pcsis_write(state, S5PCSIS_INTMSK, val); +} + +static void s5pcsis_reset(struct csis_state *state) +{ + u32 val = s5pcsis_read(state, S5PCSIS_CTRL); + + s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_RESET); + udelay(10); +} + +static void s5pcsis_system_enable(struct csis_state *state, int on) +{ + u32 val, mask; + + val = s5pcsis_read(state, S5PCSIS_CTRL); + if (on) + val |= S5PCSIS_CTRL_ENABLE; + else + val &= ~S5PCSIS_CTRL_ENABLE; + s5pcsis_write(state, S5PCSIS_CTRL, val); + + val = s5pcsis_read(state, S5PCSIS_DPHYCTRL); + val &= ~S5PCSIS_DPHYCTRL_ENABLE; + if (on) { + mask = (1 << (state->num_lanes + 1)) - 1; + val |= (mask & S5PCSIS_DPHYCTRL_ENABLE); + } + s5pcsis_write(state, S5PCSIS_DPHYCTRL, val); +} + +/* Called with the state.lock mutex held */ +static void __s5pcsis_set_format(struct csis_state *state) +{ + struct v4l2_mbus_framefmt *mf = &state->format; + u32 val; + + v4l2_dbg(1, debug, &state->sd, "fmt: %#x, %d x %d\n", + mf->code, mf->width, mf->height); + + /* Color format */ + val = s5pcsis_read(state, S5PCSIS_CONFIG); + val = (val & ~S5PCSIS_CFG_FMT_MASK) | state->csis_fmt->fmt_reg; + s5pcsis_write(state, S5PCSIS_CONFIG, val); + + /* Pixel resolution */ + val = (mf->width << 16) | mf->height; + s5pcsis_write(state, S5PCSIS_RESOL, val); +} + +static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle) +{ + u32 val = s5pcsis_read(state, S5PCSIS_DPHYCTRL); + + val = (val & ~S5PCSIS_DPHYCTRL_HSS_MASK) | (settle << 27); + s5pcsis_write(state, S5PCSIS_DPHYCTRL, val); +} + +static void s5pcsis_set_params(struct csis_state *state) +{ + u32 val; + + val = s5pcsis_read(state, S5PCSIS_CONFIG); + val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (state->num_lanes - 1); + s5pcsis_write(state, S5PCSIS_CONFIG, val); + + __s5pcsis_set_format(state); + s5pcsis_set_hsync_settle(state, state->hs_settle); + + val = s5pcsis_read(state, S5PCSIS_CTRL); + if (state->csis_fmt->data_alignment == 32) + val |= S5PCSIS_CTRL_ALIGN_32BIT; + else /* 24-bits */ + val &= ~S5PCSIS_CTRL_ALIGN_32BIT; + + val &= ~S5PCSIS_CTRL_WCLK_EXTCLK; + if (state->wclk_ext) + val |= S5PCSIS_CTRL_WCLK_EXTCLK; + s5pcsis_write(state, S5PCSIS_CTRL, val); + + /* Update the shadow register. */ + val = s5pcsis_read(state, S5PCSIS_CTRL); + s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_UPDATE_SHADOW); +} + +static void s5pcsis_clk_put(struct csis_state *state) +{ + int i; + + for (i = 0; i < NUM_CSIS_CLOCKS; i++) { + if (IS_ERR(state->clock[i])) + continue; + clk_unprepare(state->clock[i]); + clk_put(state->clock[i]); + state->clock[i] = ERR_PTR(-EINVAL); + } +} + +static int s5pcsis_clk_get(struct csis_state *state) +{ + struct device *dev = &state->pdev->dev; + int i, ret; + + for (i = 0; i < NUM_CSIS_CLOCKS; i++) + state->clock[i] = ERR_PTR(-EINVAL); + + for (i = 0; i < NUM_CSIS_CLOCKS; i++) { + state->clock[i] = clk_get(dev, csi_clock_name[i]); + if (IS_ERR(state->clock[i])) { + ret = PTR_ERR(state->clock[i]); + goto err; + } + ret = clk_prepare(state->clock[i]); + if (ret < 0) { + clk_put(state->clock[i]); + state->clock[i] = ERR_PTR(-EINVAL); + goto err; + } + } + return 0; +err: + s5pcsis_clk_put(state); + dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]); + return ret; +} + +static void dump_regs(struct csis_state *state, const char *label) +{ + struct { + u32 offset; + const char * const name; + } registers[] = { + { 0x00, "CTRL" }, + { 0x04, "DPHYCTRL" }, + { 0x08, "CONFIG" }, + { 0x0c, "DPHYSTS" }, + { 0x10, "INTMSK" }, + { 0x2c, "RESOL" }, + { 0x38, "SDW_CONFIG" }, + }; + u32 i; + + v4l2_info(&state->sd, "--- %s ---\n", label); + + for (i = 0; i < ARRAY_SIZE(registers); i++) { + u32 cfg = s5pcsis_read(state, registers[i].offset); + v4l2_info(&state->sd, "%10s: 0x%08x\n", registers[i].name, cfg); + } +} + +static void s5pcsis_start_stream(struct csis_state *state) +{ + s5pcsis_reset(state); + s5pcsis_set_params(state); + s5pcsis_system_enable(state, true); + s5pcsis_enable_interrupts(state, true); +} + +static void s5pcsis_stop_stream(struct csis_state *state) +{ + s5pcsis_enable_interrupts(state, false); + s5pcsis_system_enable(state, false); +} + +static void s5pcsis_clear_counters(struct csis_state *state) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&state->slock, flags); + for (i = 0; i < S5PCSIS_NUM_EVENTS; i++) + state->events[i].counter = 0; + spin_unlock_irqrestore(&state->slock, flags); +} + +static void s5pcsis_log_counters(struct csis_state *state, bool non_errors) +{ + int i = non_errors ? S5PCSIS_NUM_EVENTS : S5PCSIS_NUM_EVENTS - 4; + unsigned long flags; + + spin_lock_irqsave(&state->slock, flags); + + for (i--; i >= 0; i--) { + if (state->events[i].counter > 0 || debug) + v4l2_info(&state->sd, "%s events: %d\n", + state->events[i].name, + state->events[i].counter); + } + spin_unlock_irqrestore(&state->slock, flags); +} + +/* + * V4L2 subdev operations + */ +static int s5pcsis_s_power(struct v4l2_subdev *sd, int on) +{ + struct csis_state *state = sd_to_csis_state(sd); + struct device *dev = &state->pdev->dev; + + if (on) + return pm_runtime_get_sync(dev); + + return pm_runtime_put_sync(dev); +} + +static int s5pcsis_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct csis_state *state = sd_to_csis_state(sd); + int ret = 0; + + v4l2_dbg(1, debug, sd, "%s: %d, state: 0x%x\n", + __func__, enable, state->flags); + + if (enable) { + s5pcsis_clear_counters(state); + ret = pm_runtime_get_sync(&state->pdev->dev); + if (ret && ret != 1) + return ret; + } + + mutex_lock(&state->lock); + if (enable) { + if (state->flags & ST_SUSPENDED) { + ret = -EBUSY; + goto unlock; + } + s5pcsis_start_stream(state); + state->flags |= ST_STREAMING; + } else { + s5pcsis_stop_stream(state); + state->flags &= ~ST_STREAMING; + if (debug > 0) + s5pcsis_log_counters(state, true); + } +unlock: + mutex_unlock(&state->lock); + if (!enable) + pm_runtime_put(&state->pdev->dev); + + return ret == 1 ? 0 : ret; +} + +static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(s5pcsis_formats)) + return -EINVAL; + + code->code = s5pcsis_formats[code->index].code; + return 0; +} + +static struct csis_pix_format const *s5pcsis_try_format( + struct v4l2_mbus_framefmt *mf) +{ + struct csis_pix_format const *csis_fmt; + + csis_fmt = find_csis_format(mf); + if (csis_fmt == NULL) + csis_fmt = &s5pcsis_formats[0]; + + mf->code = csis_fmt->code; + v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH, + csis_fmt->pix_width_alignment, + &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1, + 0); + return csis_fmt; +} + +static struct v4l2_mbus_framefmt *__s5pcsis_get_format( + struct csis_state *state, struct v4l2_subdev_fh *fh, + u32 pad, enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL; + + return &state->format; +} + +static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct csis_state *state = sd_to_csis_state(sd); + struct csis_pix_format const *csis_fmt; + struct v4l2_mbus_framefmt *mf; + + if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK) + return -EINVAL; + + mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which); + + if (fmt->pad == CSIS_PAD_SOURCE) { + if (mf) { + mutex_lock(&state->lock); + fmt->format = *mf; + mutex_unlock(&state->lock); + } + return 0; + } + csis_fmt = s5pcsis_try_format(&fmt->format); + if (mf) { + mutex_lock(&state->lock); + *mf = fmt->format; + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) + state->csis_fmt = csis_fmt; + mutex_unlock(&state->lock); + } + return 0; +} + +static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct csis_state *state = sd_to_csis_state(sd); + struct v4l2_mbus_framefmt *mf; + + if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK) + return -EINVAL; + + mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which); + if (!mf) + return -EINVAL; + + mutex_lock(&state->lock); + fmt->format = *mf; + mutex_unlock(&state->lock); + return 0; +} + +static int s5pcsis_s_rx_buffer(struct v4l2_subdev *sd, void *buf, + unsigned int *size) +{ + struct csis_state *state = sd_to_csis_state(sd); + unsigned long flags; + + *size = min_t(unsigned int, *size, S5PCSIS_PKTDATA_SIZE); + + spin_lock_irqsave(&state->slock, flags); + state->pkt_buf.data = buf; + state->pkt_buf.len = *size; + spin_unlock_irqrestore(&state->slock, flags); + + return 0; +} + +static int s5pcsis_log_status(struct v4l2_subdev *sd) +{ + struct csis_state *state = sd_to_csis_state(sd); + + mutex_lock(&state->lock); + s5pcsis_log_counters(state, true); + if (debug && (state->flags & ST_POWERED)) + dump_regs(state, __func__); + mutex_unlock(&state->lock); + return 0; +} + +static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + + format->colorspace = V4L2_COLORSPACE_JPEG; + format->code = s5pcsis_formats[0].code; + format->width = S5PCSIS_DEF_PIX_WIDTH; + format->height = S5PCSIS_DEF_PIX_HEIGHT; + format->field = V4L2_FIELD_NONE; + + return 0; +} + +static const struct v4l2_subdev_internal_ops s5pcsis_sd_internal_ops = { + .open = s5pcsis_open, +}; + +static struct v4l2_subdev_core_ops s5pcsis_core_ops = { + .s_power = s5pcsis_s_power, + .log_status = s5pcsis_log_status, +}; + +static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = { + .enum_mbus_code = s5pcsis_enum_mbus_code, + .get_fmt = s5pcsis_get_fmt, + .set_fmt = s5pcsis_set_fmt, +}; + +static struct v4l2_subdev_video_ops s5pcsis_video_ops = { + .s_rx_buffer = s5pcsis_s_rx_buffer, + .s_stream = s5pcsis_s_stream, +}; + +static struct v4l2_subdev_ops s5pcsis_subdev_ops = { + .core = &s5pcsis_core_ops, + .pad = &s5pcsis_pad_ops, + .video = &s5pcsis_video_ops, +}; + +static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id) +{ + struct csis_state *state = dev_id; + struct csis_pktbuf *pktbuf = &state->pkt_buf; + unsigned long flags; + u32 status; + + status = s5pcsis_read(state, S5PCSIS_INTSRC); + spin_lock_irqsave(&state->slock, flags); + + if ((status & S5PCSIS_INTSRC_NON_IMAGE_DATA) && pktbuf->data) { + u32 offset; + + if (status & S5PCSIS_INTSRC_EVEN) + offset = S5PCSIS_PKTDATA_EVEN; + else + offset = S5PCSIS_PKTDATA_ODD; + + memcpy(pktbuf->data, state->regs + offset, pktbuf->len); + pktbuf->data = NULL; + rmb(); + } + + /* Update the event/error counters */ + if ((status & S5PCSIS_INTSRC_ERRORS) || debug) { + int i; + for (i = 0; i < S5PCSIS_NUM_EVENTS; i++) { + if (!(status & state->events[i].mask)) + continue; + state->events[i].counter++; + v4l2_dbg(2, debug, &state->sd, "%s: %d\n", + state->events[i].name, + state->events[i].counter); + } + v4l2_dbg(2, debug, &state->sd, "status: %08x\n", status); + } + spin_unlock_irqrestore(&state->slock, flags); + + s5pcsis_write(state, S5PCSIS_INTSRC, status); + return IRQ_HANDLED; +} + +static int s5pcsis_get_platform_data(struct platform_device *pdev, + struct csis_state *state) +{ + struct s5p_platform_mipi_csis *pdata = pdev->dev.platform_data; + + if (pdata == NULL) { + dev_err(&pdev->dev, "Platform data not specified\n"); + return -EINVAL; + } + + state->clk_frequency = pdata->clk_rate; + state->num_lanes = pdata->lanes; + state->hs_settle = pdata->hs_settle; + state->index = max(0, pdev->id); + state->max_num_lanes = state->index ? CSIS1_MAX_LANES : + CSIS0_MAX_LANES; + return 0; +} + +#ifdef CONFIG_OF +static int s5pcsis_parse_dt(struct platform_device *pdev, + struct csis_state *state) +{ + struct device_node *node = pdev->dev.of_node; + struct v4l2_of_endpoint endpoint; + + if (of_property_read_u32(node, "clock-frequency", + &state->clk_frequency)) + state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; + if (of_property_read_u32(node, "bus-width", + &state->max_num_lanes)) + return -EINVAL; + + node = v4l2_of_get_next_endpoint(node, NULL); + if (!node) { + dev_err(&pdev->dev, "No port node at %s\n", + node->full_name); + return -EINVAL; + } + /* Get port node and validate MIPI-CSI channel id. */ + v4l2_of_parse_endpoint(node, &endpoint); + + state->index = endpoint.port - FIMC_INPUT_MIPI_CSI2_0; + if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES) + return -ENXIO; + + /* Get MIPI CSI-2 bus configration from the endpoint node. */ + of_property_read_u32(node, "samsung,csis-hs-settle", + &state->hs_settle); + state->wclk_ext = of_property_read_bool(node, + "samsung,csis-wclk"); + + state->num_lanes = endpoint.bus.mipi_csi2.num_data_lanes; + + of_node_put(node); + return 0; +} +#else +#define s5pcsis_parse_dt(pdev, state) (-ENOSYS) +#endif + +static int s5pcsis_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *mem_res; + struct csis_state *state; + int ret = -ENOMEM; + int i; + + state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + mutex_init(&state->lock); + spin_lock_init(&state->slock); + state->pdev = pdev; + + if (dev->of_node) + ret = s5pcsis_parse_dt(pdev, state); + else + ret = s5pcsis_get_platform_data(pdev, state); + if (ret < 0) + return ret; + + if (state->num_lanes == 0 || state->num_lanes > state->max_num_lanes) { + dev_err(dev, "Unsupported number of data lanes: %d (max. %d)\n", + state->num_lanes, state->max_num_lanes); + return -EINVAL; + } + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + state->regs = devm_ioremap_resource(dev, mem_res); + if (IS_ERR(state->regs)) + return PTR_ERR(state->regs); + + state->irq = platform_get_irq(pdev, 0); + if (state->irq < 0) { + dev_err(dev, "Failed to get irq\n"); + return state->irq; + } + + for (i = 0; i < CSIS_NUM_SUPPLIES; i++) + state->supplies[i].supply = csis_supply_name[i]; + + ret = devm_regulator_bulk_get(dev, CSIS_NUM_SUPPLIES, + state->supplies); + if (ret) + return ret; + + ret = s5pcsis_clk_get(state); + if (ret < 0) + return ret; + + if (state->clk_frequency) + ret = clk_set_rate(state->clock[CSIS_CLK_MUX], + state->clk_frequency); + else + dev_WARN(dev, "No clock frequency specified!\n"); + if (ret < 0) + goto e_clkput; + + ret = clk_enable(state->clock[CSIS_CLK_MUX]); + if (ret < 0) + goto e_clkput; + + ret = devm_request_irq(dev, state->irq, s5pcsis_irq_handler, + 0, dev_name(dev), state); + if (ret) { + dev_err(dev, "Interrupt request failed\n"); + goto e_clkdis; + } + + v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops); + state->sd.owner = THIS_MODULE; + snprintf(state->sd.name, sizeof(state->sd.name), "%s.%d", + CSIS_SUBDEV_NAME, state->index); + state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + state->csis_fmt = &s5pcsis_formats[0]; + + state->format.code = s5pcsis_formats[0].code; + state->format.width = S5PCSIS_DEF_PIX_WIDTH; + state->format.height = S5PCSIS_DEF_PIX_HEIGHT; + + state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_init(&state->sd.entity, + CSIS_PADS_NUM, state->pads, 0); + if (ret < 0) + goto e_clkdis; + + /* This allows to retrieve the platform device id by the host driver */ + v4l2_set_subdevdata(&state->sd, pdev); + + /* .. and a pointer to the subdev. */ + platform_set_drvdata(pdev, &state->sd); + memcpy(state->events, s5pcsis_events, sizeof(state->events)); + pm_runtime_enable(dev); + + dev_info(&pdev->dev, "lanes: %d, hs_settle: %d, wclk: %d, freq: %u\n", + state->num_lanes, state->hs_settle, state->wclk_ext, + state->clk_frequency); + return 0; + +e_clkdis: + clk_disable(state->clock[CSIS_CLK_MUX]); +e_clkput: + s5pcsis_clk_put(state); + return ret; +} + +static int s5pcsis_pm_suspend(struct device *dev, bool runtime) +{ + struct platform_device *pdev = to_platform_device(dev); + struct v4l2_subdev *sd = platform_get_drvdata(pdev); + struct csis_state *state = sd_to_csis_state(sd); + int ret = 0; + + v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n", + __func__, state->flags); + + mutex_lock(&state->lock); + if (state->flags & ST_POWERED) { + s5pcsis_stop_stream(state); + ret = s5p_csis_phy_enable(state->index, false); + if (ret) + goto unlock; + ret = regulator_bulk_disable(CSIS_NUM_SUPPLIES, + state->supplies); + if (ret) + goto unlock; + clk_disable(state->clock[CSIS_CLK_GATE]); + state->flags &= ~ST_POWERED; + if (!runtime) + state->flags |= ST_SUSPENDED; + } + unlock: + mutex_unlock(&state->lock); + return ret ? -EAGAIN : 0; +} + +static int s5pcsis_pm_resume(struct device *dev, bool runtime) +{ + struct platform_device *pdev = to_platform_device(dev); + struct v4l2_subdev *sd = platform_get_drvdata(pdev); + struct csis_state *state = sd_to_csis_state(sd); + int ret = 0; + + v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n", + __func__, state->flags); + + mutex_lock(&state->lock); + if (!runtime && !(state->flags & ST_SUSPENDED)) + goto unlock; + + if (!(state->flags & ST_POWERED)) { + ret = regulator_bulk_enable(CSIS_NUM_SUPPLIES, + state->supplies); + if (ret) + goto unlock; + ret = s5p_csis_phy_enable(state->index, true); + if (!ret) { + state->flags |= ST_POWERED; + } else { + regulator_bulk_disable(CSIS_NUM_SUPPLIES, + state->supplies); + goto unlock; + } + clk_enable(state->clock[CSIS_CLK_GATE]); + } + if (state->flags & ST_STREAMING) + s5pcsis_start_stream(state); + + state->flags &= ~ST_SUSPENDED; + unlock: + mutex_unlock(&state->lock); + return ret ? -EAGAIN : 0; +} + +#ifdef CONFIG_PM_SLEEP +static int s5pcsis_suspend(struct device *dev) +{ + return s5pcsis_pm_suspend(dev, false); +} + +static int s5pcsis_resume(struct device *dev) +{ + return s5pcsis_pm_resume(dev, false); +} +#endif + +#ifdef CONFIG_PM_RUNTIME +static int s5pcsis_runtime_suspend(struct device *dev) +{ + return s5pcsis_pm_suspend(dev, true); +} + +static int s5pcsis_runtime_resume(struct device *dev) +{ + return s5pcsis_pm_resume(dev, true); +} +#endif + +static int s5pcsis_remove(struct platform_device *pdev) +{ + struct v4l2_subdev *sd = platform_get_drvdata(pdev); + struct csis_state *state = sd_to_csis_state(sd); + + pm_runtime_disable(&pdev->dev); + s5pcsis_pm_suspend(&pdev->dev, false); + clk_disable(state->clock[CSIS_CLK_MUX]); + pm_runtime_set_suspended(&pdev->dev); + s5pcsis_clk_put(state); + + media_entity_cleanup(&state->sd.entity); + + return 0; +} + +static const struct dev_pm_ops s5pcsis_pm_ops = { + SET_RUNTIME_PM_OPS(s5pcsis_runtime_suspend, s5pcsis_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume) +}; + +static const struct of_device_id s5pcsis_of_match[] = { + { .compatible = "samsung,s5pv210-csis" }, + { .compatible = "samsung,exynos4210-csis" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, s5pcsis_of_match); + +static struct platform_driver s5pcsis_driver = { + .probe = s5pcsis_probe, + .remove = s5pcsis_remove, + .driver = { + .of_match_table = s5pcsis_of_match, + .name = CSIS_DRIVER_NAME, + .owner = THIS_MODULE, + .pm = &s5pcsis_pm_ops, + }, +}; + +module_platform_driver(s5pcsis_driver); + +MODULE_AUTHOR("Sylwester Nawrocki "); +MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC MIPI-CSI2 receiver driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/exynos4-is/mipi-csis.h b/drivers/media/platform/exynos4-is/mipi-csis.h new file mode 100644 index 000000000000..28c11c4085d8 --- /dev/null +++ b/drivers/media/platform/exynos4-is/mipi-csis.h @@ -0,0 +1,26 @@ +/* + * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef S5P_MIPI_CSIS_H_ +#define S5P_MIPI_CSIS_H_ + +#define CSIS_DRIVER_NAME "s5p-mipi-csis" +#define CSIS_SUBDEV_NAME CSIS_DRIVER_NAME +#define CSIS_MAX_ENTITIES 2 +#define CSIS0_MAX_LANES 4 +#define CSIS1_MAX_LANES 2 + +#define CSIS_PAD_SINK 0 +#define CSIS_PAD_SOURCE 1 +#define CSIS_PADS_NUM 2 + +#define S5PCSIS_DEF_PIX_WIDTH 640 +#define S5PCSIS_DEF_PIX_HEIGHT 480 + +#endif diff --git a/drivers/media/platform/s5p-fimc/Kconfig b/drivers/media/platform/s5p-fimc/Kconfig deleted file mode 100644 index c5caf08ed3c4..000000000000 --- a/drivers/media/platform/s5p-fimc/Kconfig +++ /dev/null @@ -1,49 +0,0 @@ - -config VIDEO_SAMSUNG_S5P_FIMC - bool "Samsung S5P/EXYNOS SoC camera interface driver (experimental)" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && PLAT_S5P && PM_RUNTIME - depends on MFD_SYSCON - help - Say Y here to enable camera host interface devices for - Samsung S5P and EXYNOS SoC series. - -if VIDEO_SAMSUNG_S5P_FIMC - -config VIDEO_S5P_FIMC - tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver" - depends on I2C - select VIDEOBUF2_DMA_CONTIG - select V4L2_MEM2MEM_DEV - help - This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC camera host - interface and video postprocessor (FIMC and FIMC-LITE) devices. - - To compile this driver as a module, choose M here: the - module will be called s5p-fimc. - -config VIDEO_S5P_MIPI_CSIS - tristate "S5P/EXYNOS MIPI-CSI2 receiver (MIPI-CSIS) driver" - depends on REGULATOR - select S5P_SETUP_MIPIPHY - help - This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC MIPI-CSI2 - receiver (MIPI-CSIS) devices. - - To compile this driver as a module, choose M here: the - module will be called s5p-csis. - -if SOC_EXYNOS4212 || SOC_EXYNOS4412 || SOC_EXYNOS5250 - -config VIDEO_EXYNOS_FIMC_LITE - tristate "EXYNOS FIMC-LITE camera interface driver" - depends on I2C - select VIDEOBUF2_DMA_CONTIG - help - This is a V4L2 driver for Samsung EXYNOS4/5 SoC FIMC-LITE camera - host interface. - - To compile this driver as a module, choose M here: the - module will be called exynos-fimc-lite. -endif - -endif # VIDEO_SAMSUNG_S5P_FIMC diff --git a/drivers/media/platform/s5p-fimc/Makefile b/drivers/media/platform/s5p-fimc/Makefile deleted file mode 100644 index 46485143e1ca..000000000000 --- a/drivers/media/platform/s5p-fimc/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-m2m.o fimc-capture.o fimc-mdevice.o -exynos-fimc-lite-objs += fimc-lite-reg.o fimc-lite.o -s5p-csis-objs := mipi-csis.o - -obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS) += s5p-csis.o -obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE) += exynos-fimc-lite.o -obj-$(CONFIG_VIDEO_S5P_FIMC) += s5p-fimc.o diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c deleted file mode 100644 index 1675d385d900..000000000000 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ /dev/null @@ -1,1887 +0,0 @@ -/* - * Samsung S5P/EXYNOS4 SoC series camera interface (camera capture) driver - * - * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "fimc-mdevice.h" -#include "fimc-core.h" -#include "fimc-reg.h" - -static int fimc_capture_hw_init(struct fimc_dev *fimc) -{ - struct fimc_source_info *si = &fimc->vid_cap.source_config; - struct fimc_ctx *ctx = fimc->vid_cap.ctx; - int ret; - unsigned long flags; - - if (ctx == NULL || ctx->s_frame.fmt == NULL) - return -EINVAL; - - if (si->fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) { - ret = fimc_hw_camblk_cfg_writeback(fimc); - if (ret < 0) - return ret; - } - - spin_lock_irqsave(&fimc->slock, flags); - fimc_prepare_dma_offset(ctx, &ctx->d_frame); - fimc_set_yuv_order(ctx); - - fimc_hw_set_camera_polarity(fimc, si); - fimc_hw_set_camera_type(fimc, si); - fimc_hw_set_camera_source(fimc, si); - fimc_hw_set_camera_offset(fimc, &ctx->s_frame); - - ret = fimc_set_scaler_info(ctx); - if (!ret) { - fimc_hw_set_input_path(ctx); - fimc_hw_set_prescaler(ctx); - fimc_hw_set_mainscaler(ctx); - fimc_hw_set_target_format(ctx); - fimc_hw_set_rotation(ctx); - fimc_hw_set_effect(ctx); - fimc_hw_set_output_path(ctx); - fimc_hw_set_out_dma(ctx); - if (fimc->drv_data->alpha_color) - fimc_hw_set_rgb_alpha(ctx); - clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); - } - spin_unlock_irqrestore(&fimc->slock, flags); - return ret; -} - -/* - * Reinitialize the driver so it is ready to start the streaming again. - * Set fimc->state to indicate stream off and the hardware shut down state. - * If not suspending (@suspend is false), return any buffers to videobuf2. - * Otherwise put any owned buffers onto the pending buffers queue, so they - * can be re-spun when the device is being resumed. Also perform FIMC - * software reset and disable streaming on the whole pipeline if required. - */ -static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend) -{ - struct fimc_vid_cap *cap = &fimc->vid_cap; - struct fimc_vid_buffer *buf; - unsigned long flags; - bool streaming; - - spin_lock_irqsave(&fimc->slock, flags); - streaming = fimc->state & (1 << ST_CAPT_ISP_STREAM); - - fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_SHUT | - 1 << ST_CAPT_STREAM | 1 << ST_CAPT_ISP_STREAM); - if (suspend) - fimc->state |= (1 << ST_CAPT_SUSPENDED); - else - fimc->state &= ~(1 << ST_CAPT_PEND | 1 << ST_CAPT_SUSPENDED); - - /* Release unused buffers */ - while (!suspend && !list_empty(&cap->pending_buf_q)) { - buf = fimc_pending_queue_pop(cap); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); - } - /* If suspending put unused buffers onto pending queue */ - while (!list_empty(&cap->active_buf_q)) { - buf = fimc_active_queue_pop(cap); - if (suspend) - fimc_pending_queue_add(cap, buf); - else - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); - } - - fimc_hw_reset(fimc); - cap->buf_index = 0; - - spin_unlock_irqrestore(&fimc->slock, flags); - - if (streaming) - return fimc_pipeline_call(fimc, set_stream, - &fimc->pipeline, 0); - else - return 0; -} - -static int fimc_stop_capture(struct fimc_dev *fimc, bool suspend) -{ - unsigned long flags; - - if (!fimc_capture_active(fimc)) - return 0; - - spin_lock_irqsave(&fimc->slock, flags); - set_bit(ST_CAPT_SHUT, &fimc->state); - fimc_deactivate_capture(fimc); - spin_unlock_irqrestore(&fimc->slock, flags); - - wait_event_timeout(fimc->irq_queue, - !test_bit(ST_CAPT_SHUT, &fimc->state), - (2*HZ/10)); /* 200 ms */ - - return fimc_capture_state_cleanup(fimc, suspend); -} - -/** - * fimc_capture_config_update - apply the camera interface configuration - * - * To be called from within the interrupt handler with fimc.slock - * spinlock held. It updates the camera pixel crop, rotation and - * image flip in H/W. - */ -static int fimc_capture_config_update(struct fimc_ctx *ctx) -{ - struct fimc_dev *fimc = ctx->fimc_dev; - int ret; - - fimc_hw_set_camera_offset(fimc, &ctx->s_frame); - - ret = fimc_set_scaler_info(ctx); - if (ret) - return ret; - - fimc_hw_set_prescaler(ctx); - fimc_hw_set_mainscaler(ctx); - fimc_hw_set_target_format(ctx); - fimc_hw_set_rotation(ctx); - fimc_hw_set_effect(ctx); - fimc_prepare_dma_offset(ctx, &ctx->d_frame); - fimc_hw_set_out_dma(ctx); - if (fimc->drv_data->alpha_color) - fimc_hw_set_rgb_alpha(ctx); - - clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); - return ret; -} - -void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) -{ - struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS]; - struct fimc_vid_cap *cap = &fimc->vid_cap; - struct fimc_frame *f = &cap->ctx->d_frame; - struct fimc_vid_buffer *v_buf; - struct timeval *tv; - struct timespec ts; - - if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) { - wake_up(&fimc->irq_queue); - goto done; - } - - if (!list_empty(&cap->active_buf_q) && - test_bit(ST_CAPT_RUN, &fimc->state) && deq_buf) { - ktime_get_real_ts(&ts); - - v_buf = fimc_active_queue_pop(cap); - - tv = &v_buf->vb.v4l2_buf.timestamp; - tv->tv_sec = ts.tv_sec; - tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; - v_buf->vb.v4l2_buf.sequence = cap->frame_count++; - - vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE); - } - - if (!list_empty(&cap->pending_buf_q)) { - - v_buf = fimc_pending_queue_pop(cap); - fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index); - v_buf->index = cap->buf_index; - - /* Move the buffer to the capture active queue */ - fimc_active_queue_add(cap, v_buf); - - dbg("next frame: %d, done frame: %d", - fimc_hw_get_frame_index(fimc), v_buf->index); - - if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) - cap->buf_index = 0; - } - /* - * Set up a buffer at MIPI-CSIS if current image format - * requires the frame embedded data capture. - */ - if (f->fmt->mdataplanes && !list_empty(&cap->active_buf_q)) { - unsigned int plane = ffs(f->fmt->mdataplanes) - 1; - unsigned int size = f->payload[plane]; - s32 index = fimc_hw_get_frame_index(fimc); - void *vaddr; - - list_for_each_entry(v_buf, &cap->active_buf_q, list) { - if (v_buf->index != index) - continue; - vaddr = vb2_plane_vaddr(&v_buf->vb, plane); - v4l2_subdev_call(csis, video, s_rx_buffer, - vaddr, &size); - break; - } - } - - if (cap->active_buf_cnt == 0) { - if (deq_buf) - clear_bit(ST_CAPT_RUN, &fimc->state); - - if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) - cap->buf_index = 0; - } else { - set_bit(ST_CAPT_RUN, &fimc->state); - } - - if (test_bit(ST_CAPT_APPLY_CFG, &fimc->state)) - fimc_capture_config_update(cap->ctx); -done: - if (cap->active_buf_cnt == 1) { - fimc_deactivate_capture(fimc); - clear_bit(ST_CAPT_STREAM, &fimc->state); - } - - dbg("frame: %d, active_buf_cnt: %d", - fimc_hw_get_frame_index(fimc), cap->active_buf_cnt); -} - - -static int start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct fimc_ctx *ctx = q->drv_priv; - struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - int min_bufs; - int ret; - - vid_cap->frame_count = 0; - - ret = fimc_capture_hw_init(fimc); - if (ret) { - fimc_capture_state_cleanup(fimc, false); - return ret; - } - - set_bit(ST_CAPT_PEND, &fimc->state); - - min_bufs = fimc->vid_cap.reqbufs_count > 1 ? 2 : 1; - - if (vid_cap->active_buf_cnt >= min_bufs && - !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) { - fimc_activate_capture(ctx); - - if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) - return fimc_pipeline_call(fimc, set_stream, - &fimc->pipeline, 1); - } - - return 0; -} - -static int stop_streaming(struct vb2_queue *q) -{ - struct fimc_ctx *ctx = q->drv_priv; - struct fimc_dev *fimc = ctx->fimc_dev; - - if (!fimc_capture_active(fimc)) - return -EINVAL; - - return fimc_stop_capture(fimc, false); -} - -int fimc_capture_suspend(struct fimc_dev *fimc) -{ - bool suspend = fimc_capture_busy(fimc); - - int ret = fimc_stop_capture(fimc, suspend); - if (ret) - return ret; - return fimc_pipeline_call(fimc, close, &fimc->pipeline); -} - -static void buffer_queue(struct vb2_buffer *vb); - -int fimc_capture_resume(struct fimc_dev *fimc) -{ - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - struct fimc_vid_buffer *buf; - int i; - - if (!test_and_clear_bit(ST_CAPT_SUSPENDED, &fimc->state)) - return 0; - - INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); - vid_cap->buf_index = 0; - fimc_pipeline_call(fimc, open, &fimc->pipeline, - &vid_cap->vfd.entity, false); - fimc_capture_hw_init(fimc); - - clear_bit(ST_CAPT_SUSPENDED, &fimc->state); - - for (i = 0; i < vid_cap->reqbufs_count; i++) { - if (list_empty(&vid_cap->pending_buf_q)) - break; - buf = fimc_pending_queue_pop(vid_cap); - buffer_queue(&buf->vb); - } - return 0; - -} - -static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, - unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *allocators[]) -{ - const struct v4l2_pix_format_mplane *pixm = NULL; - struct fimc_ctx *ctx = vq->drv_priv; - struct fimc_frame *frame = &ctx->d_frame; - struct fimc_fmt *fmt = frame->fmt; - unsigned long wh; - int i; - - if (pfmt) { - pixm = &pfmt->fmt.pix_mp; - fmt = fimc_find_format(&pixm->pixelformat, NULL, - FMT_FLAGS_CAM | FMT_FLAGS_M2M, -1); - wh = pixm->width * pixm->height; - } else { - wh = frame->f_width * frame->f_height; - } - - if (fmt == NULL) - return -EINVAL; - - *num_planes = fmt->memplanes; - - for (i = 0; i < fmt->memplanes; i++) { - unsigned int size = (wh * fmt->depth[i]) / 8; - if (pixm) - sizes[i] = max(size, pixm->plane_fmt[i].sizeimage); - else if (fimc_fmt_is_user_defined(fmt->color)) - sizes[i] = frame->payload[i]; - else - sizes[i] = max_t(u32, size, frame->payload[i]); - - allocators[i] = ctx->fimc_dev->alloc_ctx; - } - - return 0; -} - -static int buffer_prepare(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct fimc_ctx *ctx = vq->drv_priv; - int i; - - if (ctx->d_frame.fmt == NULL) - return -EINVAL; - - for (i = 0; i < ctx->d_frame.fmt->memplanes; i++) { - unsigned long size = ctx->d_frame.payload[i]; - - if (vb2_plane_size(vb, i) < size) { - v4l2_err(&ctx->fimc_dev->vid_cap.vfd, - "User buffer too small (%ld < %ld)\n", - vb2_plane_size(vb, i), size); - return -EINVAL; - } - vb2_set_plane_payload(vb, i, size); - } - - return 0; -} - -static void buffer_queue(struct vb2_buffer *vb) -{ - struct fimc_vid_buffer *buf - = container_of(vb, struct fimc_vid_buffer, vb); - struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - unsigned long flags; - int min_bufs; - - spin_lock_irqsave(&fimc->slock, flags); - fimc_prepare_addr(ctx, &buf->vb, &ctx->d_frame, &buf->paddr); - - if (!test_bit(ST_CAPT_SUSPENDED, &fimc->state) && - !test_bit(ST_CAPT_STREAM, &fimc->state) && - vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) { - /* Setup the buffer directly for processing. */ - int buf_id = (vid_cap->reqbufs_count == 1) ? -1 : - vid_cap->buf_index; - - fimc_hw_set_output_addr(fimc, &buf->paddr, buf_id); - buf->index = vid_cap->buf_index; - fimc_active_queue_add(vid_cap, buf); - - if (++vid_cap->buf_index >= FIMC_MAX_OUT_BUFS) - vid_cap->buf_index = 0; - } else { - fimc_pending_queue_add(vid_cap, buf); - } - - min_bufs = vid_cap->reqbufs_count > 1 ? 2 : 1; - - - if (vb2_is_streaming(&vid_cap->vbq) && - vid_cap->active_buf_cnt >= min_bufs && - !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) { - int ret; - - fimc_activate_capture(ctx); - spin_unlock_irqrestore(&fimc->slock, flags); - - if (test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) - return; - - ret = fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 1); - if (ret < 0) - v4l2_err(&vid_cap->vfd, "stream on failed: %d\n", ret); - return; - } - spin_unlock_irqrestore(&fimc->slock, flags); -} - -static struct vb2_ops fimc_capture_qops = { - .queue_setup = queue_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .start_streaming = start_streaming, - .stop_streaming = stop_streaming, -}; - -/** - * fimc_capture_ctrls_create - initialize the control handler - * Initialize the capture video node control handler and fill it - * with the FIMC controls. Inherit any sensor's controls if the - * 'user_subdev_api' flag is false (default behaviour). - * This function need to be called with the graph mutex held. - */ -int fimc_capture_ctrls_create(struct fimc_dev *fimc) -{ - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - struct v4l2_subdev *sensor = fimc->pipeline.subdevs[IDX_SENSOR]; - int ret; - - if (WARN_ON(vid_cap->ctx == NULL)) - return -ENXIO; - if (vid_cap->ctx->ctrls.ready) - return 0; - - ret = fimc_ctrls_create(vid_cap->ctx); - - if (ret || vid_cap->user_subdev_api || !sensor || - !vid_cap->ctx->ctrls.ready) - return ret; - - return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrls.handler, - sensor->ctrl_handler, NULL); -} - -static int fimc_capture_set_default_format(struct fimc_dev *fimc); - -static int fimc_capture_open(struct file *file) -{ - struct fimc_dev *fimc = video_drvdata(file); - int ret = -EBUSY; - - dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); - - fimc_md_graph_lock(fimc); - mutex_lock(&fimc->lock); - - if (fimc_m2m_active(fimc)) - goto unlock; - - set_bit(ST_CAPT_BUSY, &fimc->state); - ret = pm_runtime_get_sync(&fimc->pdev->dev); - if (ret < 0) - goto unlock; - - ret = v4l2_fh_open(file); - if (ret) { - pm_runtime_put(&fimc->pdev->dev); - goto unlock; - } - - if (v4l2_fh_is_singular_file(file)) { - ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, - &fimc->vid_cap.vfd.entity, true); - - if (!ret && !fimc->vid_cap.user_subdev_api) - ret = fimc_capture_set_default_format(fimc); - - if (!ret) - ret = fimc_capture_ctrls_create(fimc); - - if (ret < 0) { - clear_bit(ST_CAPT_BUSY, &fimc->state); - pm_runtime_put_sync(&fimc->pdev->dev); - v4l2_fh_release(file); - } else { - fimc->vid_cap.refcnt++; - } - } -unlock: - mutex_unlock(&fimc->lock); - fimc_md_graph_unlock(fimc); - return ret; -} - -static int fimc_capture_release(struct file *file) -{ - struct fimc_dev *fimc = video_drvdata(file); - int ret; - - dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); - - mutex_lock(&fimc->lock); - - if (v4l2_fh_is_singular_file(file)) { - clear_bit(ST_CAPT_BUSY, &fimc->state); - fimc_stop_capture(fimc, false); - fimc_pipeline_call(fimc, close, &fimc->pipeline); - clear_bit(ST_CAPT_SUSPENDED, &fimc->state); - fimc->vid_cap.refcnt--; - } - - pm_runtime_put(&fimc->pdev->dev); - - if (v4l2_fh_is_singular_file(file)) - fimc_ctrls_delete(fimc->vid_cap.ctx); - - ret = vb2_fop_release(file); - mutex_unlock(&fimc->lock); - - return ret; -} - -static const struct v4l2_file_operations fimc_capture_fops = { - .owner = THIS_MODULE, - .open = fimc_capture_open, - .release = fimc_capture_release, - .poll = vb2_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = vb2_fop_mmap, -}; - -/* - * Format and crop negotiation helpers - */ - -static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, - u32 *width, u32 *height, - u32 *code, u32 *fourcc, int pad) -{ - bool rotation = ctx->rotation == 90 || ctx->rotation == 270; - struct fimc_dev *fimc = ctx->fimc_dev; - const struct fimc_variant *var = fimc->variant; - const struct fimc_pix_limit *pl = var->pix_limit; - struct fimc_frame *dst = &ctx->d_frame; - u32 depth, min_w, max_w, min_h, align_h = 3; - u32 mask = FMT_FLAGS_CAM; - struct fimc_fmt *ffmt; - - /* Conversion from/to JPEG or User Defined format is not supported */ - if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE && - fimc_fmt_is_user_defined(ctx->s_frame.fmt->color)) - *code = ctx->s_frame.fmt->mbus_code; - - if (fourcc && *fourcc != V4L2_PIX_FMT_JPEG && pad == FIMC_SD_PAD_SOURCE) - mask |= FMT_FLAGS_M2M; - - if (pad == FIMC_SD_PAD_SINK_FIFO) - mask = FMT_FLAGS_WRITEBACK; - - ffmt = fimc_find_format(fourcc, code, mask, 0); - if (WARN_ON(!ffmt)) - return NULL; - - if (code) - *code = ffmt->mbus_code; - if (fourcc) - *fourcc = ffmt->fourcc; - - if (pad != FIMC_SD_PAD_SOURCE) { - max_w = fimc_fmt_is_user_defined(ffmt->color) ? - pl->scaler_dis_w : pl->scaler_en_w; - /* Apply the camera input interface pixel constraints */ - v4l_bound_align_image(width, max_t(u32, *width, 32), max_w, 4, - height, max_t(u32, *height, 32), - FIMC_CAMIF_MAX_HEIGHT, - fimc_fmt_is_user_defined(ffmt->color) ? - 3 : 1, - 0); - return ffmt; - } - /* Can't scale or crop in transparent (JPEG) transfer mode */ - if (fimc_fmt_is_user_defined(ffmt->color)) { - *width = ctx->s_frame.f_width; - *height = ctx->s_frame.f_height; - return ffmt; - } - /* Apply the scaler and the output DMA constraints */ - max_w = rotation ? pl->out_rot_en_w : pl->out_rot_dis_w; - if (ctx->state & FIMC_COMPOSE) { - min_w = dst->offs_h + dst->width; - min_h = dst->offs_v + dst->height; - } else { - min_w = var->min_out_pixsize; - min_h = var->min_out_pixsize; - } - if (var->min_vsize_align == 1 && !rotation) - align_h = fimc_fmt_is_rgb(ffmt->color) ? 0 : 1; - - depth = fimc_get_format_depth(ffmt); - v4l_bound_align_image(width, min_w, max_w, - ffs(var->min_out_pixsize) - 1, - height, min_h, FIMC_CAMIF_MAX_HEIGHT, - align_h, - 64/(ALIGN(depth, 8))); - - dbg("pad%d: code: 0x%x, %dx%d. dst fmt: %dx%d", - pad, code ? *code : 0, *width, *height, - dst->f_width, dst->f_height); - - return ffmt; -} - -static void fimc_capture_try_selection(struct fimc_ctx *ctx, - struct v4l2_rect *r, - int target) -{ - bool rotate = ctx->rotation == 90 || ctx->rotation == 270; - struct fimc_dev *fimc = ctx->fimc_dev; - const struct fimc_variant *var = fimc->variant; - const struct fimc_pix_limit *pl = var->pix_limit; - struct fimc_frame *sink = &ctx->s_frame; - u32 max_w, max_h, min_w = 0, min_h = 0, min_sz; - u32 align_sz = 0, align_h = 4; - u32 max_sc_h, max_sc_v; - - /* In JPEG transparent transfer mode cropping is not supported */ - if (fimc_fmt_is_user_defined(ctx->d_frame.fmt->color)) { - r->width = sink->f_width; - r->height = sink->f_height; - r->left = r->top = 0; - return; - } - if (target == V4L2_SEL_TGT_COMPOSE) { - if (ctx->rotation != 90 && ctx->rotation != 270) - align_h = 1; - max_sc_h = min(SCALER_MAX_HRATIO, 1 << (ffs(sink->width) - 3)); - max_sc_v = min(SCALER_MAX_VRATIO, 1 << (ffs(sink->height) - 1)); - min_sz = var->min_out_pixsize; - } else { - u32 depth = fimc_get_format_depth(sink->fmt); - align_sz = 64/ALIGN(depth, 8); - min_sz = var->min_inp_pixsize; - min_w = min_h = min_sz; - max_sc_h = max_sc_v = 1; - } - /* - * For the compose rectangle the following constraints must be met: - * - it must fit in the sink pad format rectangle (f_width/f_height); - * - maximum downscaling ratio is 64; - * - maximum crop size depends if the rotator is used or not; - * - the sink pad format width/height must be 4 multiple of the - * prescaler ratios determined by sink pad size and source pad crop, - * the prescaler ratio is returned by fimc_get_scaler_factor(). - */ - max_w = min_t(u32, - rotate ? pl->out_rot_en_w : pl->out_rot_dis_w, - rotate ? sink->f_height : sink->f_width); - max_h = min_t(u32, FIMC_CAMIF_MAX_HEIGHT, sink->f_height); - - if (target == V4L2_SEL_TGT_COMPOSE) { - min_w = min_t(u32, max_w, sink->f_width / max_sc_h); - min_h = min_t(u32, max_h, sink->f_height / max_sc_v); - if (rotate) { - swap(max_sc_h, max_sc_v); - swap(min_w, min_h); - } - } - v4l_bound_align_image(&r->width, min_w, max_w, ffs(min_sz) - 1, - &r->height, min_h, max_h, align_h, - align_sz); - /* Adjust left/top if crop/compose rectangle is out of bounds */ - r->left = clamp_t(u32, r->left, 0, sink->f_width - r->width); - r->top = clamp_t(u32, r->top, 0, sink->f_height - r->height); - r->left = round_down(r->left, var->hor_offs_align); - - dbg("target %#x: (%d,%d)/%dx%d, sink fmt: %dx%d", - target, r->left, r->top, r->width, r->height, - sink->f_width, sink->f_height); -} - -/* - * The video node ioctl operations - */ -static int fimc_vidioc_querycap_capture(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct fimc_dev *fimc = video_drvdata(file); - - strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1); - strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1); - cap->bus_info[0] = 0; - cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE; - - return 0; -} - -static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct fimc_fmt *fmt; - - fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM | FMT_FLAGS_M2M, - f->index); - if (!fmt) - return -EINVAL; - strncpy(f->description, fmt->name, sizeof(f->description) - 1); - f->pixelformat = fmt->fourcc; - if (fmt->fourcc == V4L2_MBUS_FMT_JPEG_1X8) - f->flags |= V4L2_FMT_FLAG_COMPRESSED; - return 0; -} - -static struct media_entity *fimc_pipeline_get_head(struct media_entity *me) -{ - struct media_pad *pad = &me->pads[0]; - - while (!(pad->flags & MEDIA_PAD_FL_SOURCE)) { - pad = media_entity_remote_source(pad); - if (!pad) - break; - me = pad->entity; - pad = &me->pads[0]; - } - - return me; -} - -/** - * fimc_pipeline_try_format - negotiate and/or set formats at pipeline - * elements - * @ctx: FIMC capture context - * @tfmt: media bus format to try/set on subdevs - * @fmt_id: fimc pixel format id corresponding to returned @tfmt (output) - * @set: true to set format on subdevs, false to try only - */ -static int fimc_pipeline_try_format(struct fimc_ctx *ctx, - struct v4l2_mbus_framefmt *tfmt, - struct fimc_fmt **fmt_id, - bool set) -{ - struct fimc_dev *fimc = ctx->fimc_dev; - struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR]; - struct v4l2_subdev_format sfmt; - struct v4l2_mbus_framefmt *mf = &sfmt.format; - struct media_entity *me; - struct fimc_fmt *ffmt; - struct media_pad *pad; - int ret, i = 1; - u32 fcc; - - if (WARN_ON(!sd || !tfmt)) - return -EINVAL; - - memset(&sfmt, 0, sizeof(sfmt)); - sfmt.format = *tfmt; - sfmt.which = set ? V4L2_SUBDEV_FORMAT_ACTIVE : V4L2_SUBDEV_FORMAT_TRY; - - me = fimc_pipeline_get_head(&sd->entity); - - while (1) { - ffmt = fimc_find_format(NULL, mf->code != 0 ? &mf->code : NULL, - FMT_FLAGS_CAM, i++); - if (ffmt == NULL) { - /* - * Notify user-space if common pixel code for - * host and sensor does not exist. - */ - return -EINVAL; - } - mf->code = tfmt->code = ffmt->mbus_code; - - /* set format on all pipeline subdevs */ - while (me != &fimc->vid_cap.subdev.entity) { - sd = media_entity_to_v4l2_subdev(me); - - sfmt.pad = 0; - ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sfmt); - if (ret) - return ret; - - if (me->pads[0].flags & MEDIA_PAD_FL_SINK) { - sfmt.pad = me->num_pads - 1; - mf->code = tfmt->code; - ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, - &sfmt); - if (ret) - return ret; - } - - pad = media_entity_remote_source(&me->pads[sfmt.pad]); - if (!pad) - return -EINVAL; - me = pad->entity; - } - - if (mf->code != tfmt->code) - continue; - - fcc = ffmt->fourcc; - tfmt->width = mf->width; - tfmt->height = mf->height; - ffmt = fimc_capture_try_format(ctx, &tfmt->width, &tfmt->height, - NULL, &fcc, FIMC_SD_PAD_SINK_CAM); - ffmt = fimc_capture_try_format(ctx, &tfmt->width, &tfmt->height, - NULL, &fcc, FIMC_SD_PAD_SOURCE); - if (ffmt && ffmt->mbus_code) - mf->code = ffmt->mbus_code; - if (mf->width != tfmt->width || mf->height != tfmt->height) - continue; - tfmt->code = mf->code; - break; - } - - if (fmt_id && ffmt) - *fmt_id = ffmt; - *tfmt = *mf; - - return 0; -} - -/** - * fimc_get_sensor_frame_desc - query the sensor for media bus frame parameters - * @sensor: pointer to the sensor subdev - * @plane_fmt: provides plane sizes corresponding to the frame layout entries - * @try: true to set the frame parameters, false to query only - * - * This function is used by this driver only for compressed/blob data formats. - */ -static int fimc_get_sensor_frame_desc(struct v4l2_subdev *sensor, - struct v4l2_plane_pix_format *plane_fmt, - unsigned int num_planes, bool try) -{ - struct v4l2_mbus_frame_desc fd; - int i, ret; - int pad; - - for (i = 0; i < num_planes; i++) - fd.entry[i].length = plane_fmt[i].sizeimage; - - pad = sensor->entity.num_pads - 1; - if (try) - ret = v4l2_subdev_call(sensor, pad, set_frame_desc, pad, &fd); - else - ret = v4l2_subdev_call(sensor, pad, get_frame_desc, pad, &fd); - - if (ret < 0) - return ret; - - if (num_planes != fd.num_entries) - return -EINVAL; - - for (i = 0; i < num_planes; i++) - plane_fmt[i].sizeimage = fd.entry[i].length; - - if (fd.entry[0].length > FIMC_MAX_JPEG_BUF_SIZE) { - v4l2_err(sensor->v4l2_dev, "Unsupported buffer size: %u\n", - fd.entry[0].length); - - return -EINVAL; - } - - return 0; -} - -static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct fimc_dev *fimc = video_drvdata(file); - - __fimc_get_format(&fimc->vid_cap.ctx->d_frame, f); - return 0; -} - -static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct fimc_dev *fimc = video_drvdata(file); - struct fimc_ctx *ctx = fimc->vid_cap.ctx; - struct v4l2_mbus_framefmt mf; - struct fimc_fmt *ffmt = NULL; - int ret = 0; - - fimc_md_graph_lock(fimc); - mutex_lock(&fimc->lock); - - if (fimc_jpeg_fourcc(pix->pixelformat)) { - fimc_capture_try_format(ctx, &pix->width, &pix->height, - NULL, &pix->pixelformat, - FIMC_SD_PAD_SINK_CAM); - ctx->s_frame.f_width = pix->width; - ctx->s_frame.f_height = pix->height; - } - ffmt = fimc_capture_try_format(ctx, &pix->width, &pix->height, - NULL, &pix->pixelformat, - FIMC_SD_PAD_SOURCE); - if (!ffmt) { - ret = -EINVAL; - goto unlock; - } - - if (!fimc->vid_cap.user_subdev_api) { - mf.width = pix->width; - mf.height = pix->height; - mf.code = ffmt->mbus_code; - fimc_pipeline_try_format(ctx, &mf, &ffmt, false); - pix->width = mf.width; - pix->height = mf.height; - if (ffmt) - pix->pixelformat = ffmt->fourcc; - } - - fimc_adjust_mplane_format(ffmt, pix->width, pix->height, pix); - - if (ffmt->flags & FMT_FLAGS_COMPRESSED) - fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], - pix->plane_fmt, ffmt->memplanes, true); -unlock: - mutex_unlock(&fimc->lock); - fimc_md_graph_unlock(fimc); - - return ret; -} - -static void fimc_capture_mark_jpeg_xfer(struct fimc_ctx *ctx, - enum fimc_color_fmt color) -{ - bool jpeg = fimc_fmt_is_user_defined(color); - - ctx->scaler.enabled = !jpeg; - fimc_ctrls_activate(ctx, !jpeg); - - if (jpeg) - set_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state); - else - clear_bit(ST_CAPT_JPEG, &ctx->fimc_dev->state); -} - -static int __fimc_capture_set_format(struct fimc_dev *fimc, - struct v4l2_format *f) -{ - struct fimc_ctx *ctx = fimc->vid_cap.ctx; - struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct v4l2_mbus_framefmt *mf = &fimc->vid_cap.ci_fmt; - struct fimc_frame *ff = &ctx->d_frame; - struct fimc_fmt *s_fmt = NULL; - int ret, i; - - if (vb2_is_busy(&fimc->vid_cap.vbq)) - return -EBUSY; - - /* Pre-configure format at camera interface input, for JPEG only */ - if (fimc_jpeg_fourcc(pix->pixelformat)) { - fimc_capture_try_format(ctx, &pix->width, &pix->height, - NULL, &pix->pixelformat, - FIMC_SD_PAD_SINK_CAM); - ctx->s_frame.f_width = pix->width; - ctx->s_frame.f_height = pix->height; - } - /* Try the format at the scaler and the DMA output */ - ff->fmt = fimc_capture_try_format(ctx, &pix->width, &pix->height, - NULL, &pix->pixelformat, - FIMC_SD_PAD_SOURCE); - if (!ff->fmt) - return -EINVAL; - - /* Update RGB Alpha control state and value range */ - fimc_alpha_ctrl_update(ctx); - - /* Try to match format at the host and the sensor */ - if (!fimc->vid_cap.user_subdev_api) { - mf->code = ff->fmt->mbus_code; - mf->width = pix->width; - mf->height = pix->height; - ret = fimc_pipeline_try_format(ctx, mf, &s_fmt, true); - if (ret) - return ret; - - pix->width = mf->width; - pix->height = mf->height; - } - - fimc_adjust_mplane_format(ff->fmt, pix->width, pix->height, pix); - - if (ff->fmt->flags & FMT_FLAGS_COMPRESSED) { - ret = fimc_get_sensor_frame_desc(fimc->pipeline.subdevs[IDX_SENSOR], - pix->plane_fmt, ff->fmt->memplanes, - true); - if (ret < 0) - return ret; - } - - for (i = 0; i < ff->fmt->memplanes; i++) { - ff->bytesperline[i] = pix->plane_fmt[i].bytesperline; - ff->payload[i] = pix->plane_fmt[i].sizeimage; - } - - set_frame_bounds(ff, pix->width, pix->height); - /* Reset the composition rectangle if not yet configured */ - if (!(ctx->state & FIMC_COMPOSE)) - set_frame_crop(ff, 0, 0, pix->width, pix->height); - - fimc_capture_mark_jpeg_xfer(ctx, ff->fmt->color); - - /* Reset cropping and set format at the camera interface input */ - if (!fimc->vid_cap.user_subdev_api) { - ctx->s_frame.fmt = s_fmt; - set_frame_bounds(&ctx->s_frame, pix->width, pix->height); - set_frame_crop(&ctx->s_frame, 0, 0, pix->width, pix->height); - } - - return ret; -} - -static int fimc_cap_s_fmt_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct fimc_dev *fimc = video_drvdata(file); - int ret; - - fimc_md_graph_lock(fimc); - mutex_lock(&fimc->lock); - /* - * The graph is walked within __fimc_capture_set_format() to set - * the format at subdevs thus the graph mutex needs to be held at - * this point and acquired before the video mutex, to avoid AB-BA - * deadlock when fimc_md_link_notify() is called by other thread. - * Ideally the graph walking and setting format at the whole pipeline - * should be removed from this driver and handled in userspace only. - */ - ret = __fimc_capture_set_format(fimc, f); - - mutex_unlock(&fimc->lock); - fimc_md_graph_unlock(fimc); - return ret; -} - -static int fimc_cap_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct fimc_dev *fimc = video_drvdata(file); - struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR]; - - if (i->index != 0) - return -EINVAL; - - i->type = V4L2_INPUT_TYPE_CAMERA; - if (sd) - strlcpy(i->name, sd->name, sizeof(i->name)); - return 0; -} - -static int fimc_cap_s_input(struct file *file, void *priv, unsigned int i) -{ - return i == 0 ? i : -EINVAL; -} - -static int fimc_cap_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -/** - * fimc_pipeline_validate - check for formats inconsistencies - * between source and sink pad of each link - * - * Return 0 if all formats match or -EPIPE otherwise. - */ -static int fimc_pipeline_validate(struct fimc_dev *fimc) -{ - struct v4l2_subdev_format sink_fmt, src_fmt; - struct fimc_vid_cap *vc = &fimc->vid_cap; - struct v4l2_subdev *sd = &vc->subdev; - struct media_pad *sink_pad, *src_pad; - int i, ret; - - while (1) { - /* - * Find current entity sink pad and any remote sink pad linked - * to it. We stop if there is no sink pad in current entity or - * it is not linked to any other remote entity. - */ - src_pad = NULL; - - for (i = 0; i < sd->entity.num_pads; i++) { - struct media_pad *p = &sd->entity.pads[i]; - - if (p->flags & MEDIA_PAD_FL_SINK) { - sink_pad = p; - src_pad = media_entity_remote_source(sink_pad); - if (src_pad) - break; - } - } - - if (src_pad == NULL || - media_entity_type(src_pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - break; - - /* Don't call FIMC subdev operation to avoid nested locking */ - if (sd == &vc->subdev) { - struct fimc_frame *ff = &vc->ctx->s_frame; - sink_fmt.format.width = ff->f_width; - sink_fmt.format.height = ff->f_height; - sink_fmt.format.code = ff->fmt ? ff->fmt->mbus_code : 0; - } else { - sink_fmt.pad = sink_pad->index; - sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sink_fmt); - if (ret < 0 && ret != -ENOIOCTLCMD) - return -EPIPE; - } - - /* Retrieve format at the source pad */ - sd = media_entity_to_v4l2_subdev(src_pad->entity); - src_fmt.pad = src_pad->index; - src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt); - if (ret < 0 && ret != -ENOIOCTLCMD) - return -EPIPE; - - if (src_fmt.format.width != sink_fmt.format.width || - src_fmt.format.height != sink_fmt.format.height || - src_fmt.format.code != sink_fmt.format.code) - return -EPIPE; - - if (sd == fimc->pipeline.subdevs[IDX_SENSOR] && - fimc_user_defined_mbus_fmt(src_fmt.format.code)) { - struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES]; - struct fimc_frame *frame = &vc->ctx->d_frame; - unsigned int i; - - ret = fimc_get_sensor_frame_desc(sd, plane_fmt, - frame->fmt->memplanes, - false); - if (ret < 0) - return -EPIPE; - - for (i = 0; i < frame->fmt->memplanes; i++) - if (frame->payload[i] < plane_fmt[i].sizeimage) - return -EPIPE; - } - } - return 0; -} - -static int fimc_cap_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct fimc_dev *fimc = video_drvdata(file); - struct fimc_pipeline *p = &fimc->pipeline; - struct fimc_vid_cap *vc = &fimc->vid_cap; - struct media_entity *entity = &vc->vfd.entity; - struct fimc_source_info *si = NULL; - struct v4l2_subdev *sd; - int ret; - - if (fimc_capture_active(fimc)) - return -EBUSY; - - ret = media_entity_pipeline_start(entity, p->m_pipeline); - if (ret < 0) - return ret; - - sd = p->subdevs[IDX_SENSOR]; - if (sd) - si = v4l2_get_subdev_hostdata(sd); - - if (si == NULL) { - ret = -EPIPE; - goto err_p_stop; - } - /* - * Save configuration data related to currently attached image - * sensor or other data source, e.g. FIMC-IS. - */ - vc->source_config = *si; - - if (vc->input == GRP_ID_FIMC_IS) - vc->source_config.fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK; - - if (vc->user_subdev_api) { - ret = fimc_pipeline_validate(fimc); - if (ret < 0) - goto err_p_stop; - } - - ret = vb2_ioctl_streamon(file, priv, type); - if (!ret) - return ret; - -err_p_stop: - media_entity_pipeline_stop(entity); - return ret; -} - -static int fimc_cap_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct fimc_dev *fimc = video_drvdata(file); - int ret; - - ret = vb2_ioctl_streamoff(file, priv, type); - - if (ret == 0) - media_entity_pipeline_stop(&fimc->vid_cap.vfd.entity); - - return ret; -} - -static int fimc_cap_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) -{ - struct fimc_dev *fimc = video_drvdata(file); - int ret; - - ret = vb2_ioctl_reqbufs(file, priv, reqbufs); - - if (!ret) - fimc->vid_cap.reqbufs_count = reqbufs->count; - - return ret; -} - -static int fimc_cap_g_selection(struct file *file, void *fh, - struct v4l2_selection *s) -{ - struct fimc_dev *fimc = video_drvdata(file); - struct fimc_ctx *ctx = fimc->vid_cap.ctx; - struct fimc_frame *f = &ctx->s_frame; - - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return -EINVAL; - - switch (s->target) { - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - f = &ctx->d_frame; - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: - s->r.left = 0; - s->r.top = 0; - s->r.width = f->o_width; - s->r.height = f->o_height; - return 0; - - case V4L2_SEL_TGT_COMPOSE: - f = &ctx->d_frame; - case V4L2_SEL_TGT_CROP: - s->r.left = f->offs_h; - s->r.top = f->offs_v; - s->r.width = f->width; - s->r.height = f->height; - return 0; - } - - return -EINVAL; -} - -/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ -static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) -{ - if (a->left < b->left || a->top < b->top) - return 0; - if (a->left + a->width > b->left + b->width) - return 0; - if (a->top + a->height > b->top + b->height) - return 0; - - return 1; -} - -static int fimc_cap_s_selection(struct file *file, void *fh, - struct v4l2_selection *s) -{ - struct fimc_dev *fimc = video_drvdata(file); - struct fimc_ctx *ctx = fimc->vid_cap.ctx; - struct v4l2_rect rect = s->r; - struct fimc_frame *f; - unsigned long flags; - - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return -EINVAL; - - if (s->target == V4L2_SEL_TGT_COMPOSE) - f = &ctx->d_frame; - else if (s->target == V4L2_SEL_TGT_CROP) - f = &ctx->s_frame; - else - return -EINVAL; - - fimc_capture_try_selection(ctx, &rect, s->target); - - if (s->flags & V4L2_SEL_FLAG_LE && - !enclosed_rectangle(&rect, &s->r)) - return -ERANGE; - - if (s->flags & V4L2_SEL_FLAG_GE && - !enclosed_rectangle(&s->r, &rect)) - return -ERANGE; - - s->r = rect; - spin_lock_irqsave(&fimc->slock, flags); - set_frame_crop(f, s->r.left, s->r.top, s->r.width, - s->r.height); - spin_unlock_irqrestore(&fimc->slock, flags); - - set_bit(ST_CAPT_APPLY_CFG, &fimc->state); - return 0; -} - -static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { - .vidioc_querycap = fimc_vidioc_querycap_capture, - - .vidioc_enum_fmt_vid_cap_mplane = fimc_cap_enum_fmt_mplane, - .vidioc_try_fmt_vid_cap_mplane = fimc_cap_try_fmt_mplane, - .vidioc_s_fmt_vid_cap_mplane = fimc_cap_s_fmt_mplane, - .vidioc_g_fmt_vid_cap_mplane = fimc_cap_g_fmt_mplane, - - .vidioc_reqbufs = fimc_cap_reqbufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - - .vidioc_streamon = fimc_cap_streamon, - .vidioc_streamoff = fimc_cap_streamoff, - - .vidioc_g_selection = fimc_cap_g_selection, - .vidioc_s_selection = fimc_cap_s_selection, - - .vidioc_enum_input = fimc_cap_enum_input, - .vidioc_s_input = fimc_cap_s_input, - .vidioc_g_input = fimc_cap_g_input, -}; - -/* Capture subdev media entity operations */ -static int fimc_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct fimc_dev *fimc = v4l2_get_subdevdata(sd); - - if (media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - return -EINVAL; - - if (WARN_ON(fimc == NULL)) - return 0; - - dbg("%s --> %s, flags: 0x%x. input: 0x%x", - local->entity->name, remote->entity->name, flags, - fimc->vid_cap.input); - - if (flags & MEDIA_LNK_FL_ENABLED) { - if (fimc->vid_cap.input != 0) - return -EBUSY; - fimc->vid_cap.input = sd->grp_id; - return 0; - } - - fimc->vid_cap.input = 0; - return 0; -} - -static const struct media_entity_operations fimc_sd_media_ops = { - .link_setup = fimc_link_setup, -}; - -/** - * fimc_sensor_notify - v4l2_device notification from a sensor subdev - * @sd: pointer to a subdev generating the notification - * @notification: the notification type, must be S5P_FIMC_TX_END_NOTIFY - * @arg: pointer to an u32 type integer that stores the frame payload value - * - * The End Of Frame notification sent by sensor subdev in its still capture - * mode. If there is only a single VSYNC generated by the sensor at the - * beginning of a frame transmission, FIMC does not issue the LastIrq - * (end of frame) interrupt. And this notification is used to complete the - * frame capture and returning a buffer to user-space. Subdev drivers should - * call this notification from their last 'End of frame capture' interrupt. - */ -void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification, - void *arg) -{ - struct fimc_sensor_info *sensor; - struct fimc_vid_buffer *buf; - struct fimc_md *fmd; - struct fimc_dev *fimc; - unsigned long flags; - - if (sd == NULL) - return; - - sensor = v4l2_get_subdev_hostdata(sd); - fmd = entity_to_fimc_mdev(&sd->entity); - - spin_lock_irqsave(&fmd->slock, flags); - fimc = sensor ? sensor->host : NULL; - - if (fimc && arg && notification == S5P_FIMC_TX_END_NOTIFY && - test_bit(ST_CAPT_PEND, &fimc->state)) { - unsigned long irq_flags; - spin_lock_irqsave(&fimc->slock, irq_flags); - if (!list_empty(&fimc->vid_cap.active_buf_q)) { - buf = list_entry(fimc->vid_cap.active_buf_q.next, - struct fimc_vid_buffer, list); - vb2_set_plane_payload(&buf->vb, 0, *((u32 *)arg)); - } - fimc_capture_irq_handler(fimc, 1); - fimc_deactivate_capture(fimc); - spin_unlock_irqrestore(&fimc->slock, irq_flags); - } - spin_unlock_irqrestore(&fmd->slock, flags); -} - -static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct fimc_fmt *fmt; - - fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, code->index); - if (!fmt) - return -EINVAL; - code->code = fmt->mbus_code; - return 0; -} - -static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct fimc_dev *fimc = v4l2_get_subdevdata(sd); - struct fimc_ctx *ctx = fimc->vid_cap.ctx; - struct fimc_frame *ff = &ctx->s_frame; - struct v4l2_mbus_framefmt *mf; - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); - fmt->format = *mf; - return 0; - } - - mf = &fmt->format; - mutex_lock(&fimc->lock); - - switch (fmt->pad) { - case FIMC_SD_PAD_SOURCE: - if (!WARN_ON(ff->fmt == NULL)) - mf->code = ff->fmt->mbus_code; - /* Sink pads crop rectangle size */ - mf->width = ff->width; - mf->height = ff->height; - break; - case FIMC_SD_PAD_SINK_FIFO: - *mf = fimc->vid_cap.wb_fmt; - break; - case FIMC_SD_PAD_SINK_CAM: - default: - *mf = fimc->vid_cap.ci_fmt; - break; - } - - mutex_unlock(&fimc->lock); - mf->colorspace = V4L2_COLORSPACE_JPEG; - - return 0; -} - -static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct fimc_dev *fimc = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *mf = &fmt->format; - struct fimc_vid_cap *vc = &fimc->vid_cap; - struct fimc_ctx *ctx = vc->ctx; - struct fimc_frame *ff; - struct fimc_fmt *ffmt; - - dbg("pad%d: code: 0x%x, %dx%d", - fmt->pad, mf->code, mf->width, mf->height); - - if (fmt->pad == FIMC_SD_PAD_SOURCE && vb2_is_busy(&vc->vbq)) - return -EBUSY; - - mutex_lock(&fimc->lock); - ffmt = fimc_capture_try_format(ctx, &mf->width, &mf->height, - &mf->code, NULL, fmt->pad); - mutex_unlock(&fimc->lock); - mf->colorspace = V4L2_COLORSPACE_JPEG; - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); - *mf = fmt->format; - return 0; - } - /* There must be a bug in the driver if this happens */ - if (WARN_ON(ffmt == NULL)) - return -EINVAL; - - /* Update RGB Alpha control state and value range */ - fimc_alpha_ctrl_update(ctx); - - fimc_capture_mark_jpeg_xfer(ctx, ffmt->color); - if (fmt->pad == FIMC_SD_PAD_SOURCE) { - ff = &ctx->d_frame; - /* Sink pads crop rectangle size */ - mf->width = ctx->s_frame.width; - mf->height = ctx->s_frame.height; - } else { - ff = &ctx->s_frame; - } - - mutex_lock(&fimc->lock); - set_frame_bounds(ff, mf->width, mf->height); - - if (fmt->pad == FIMC_SD_PAD_SINK_FIFO) - vc->wb_fmt = *mf; - else if (fmt->pad == FIMC_SD_PAD_SINK_CAM) - vc->ci_fmt = *mf; - - ff->fmt = ffmt; - - /* Reset the crop rectangle if required. */ - if (!(fmt->pad == FIMC_SD_PAD_SOURCE && (ctx->state & FIMC_COMPOSE))) - set_frame_crop(ff, 0, 0, mf->width, mf->height); - - if (fmt->pad != FIMC_SD_PAD_SOURCE) - ctx->state &= ~FIMC_COMPOSE; - - mutex_unlock(&fimc->lock); - return 0; -} - -static int fimc_subdev_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_selection *sel) -{ - struct fimc_dev *fimc = v4l2_get_subdevdata(sd); - struct fimc_ctx *ctx = fimc->vid_cap.ctx; - struct fimc_frame *f = &ctx->s_frame; - struct v4l2_rect *r = &sel->r; - struct v4l2_rect *try_sel; - - if (sel->pad == FIMC_SD_PAD_SOURCE) - return -EINVAL; - - mutex_lock(&fimc->lock); - - switch (sel->target) { - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - f = &ctx->d_frame; - case V4L2_SEL_TGT_CROP_BOUNDS: - r->width = f->o_width; - r->height = f->o_height; - r->left = 0; - r->top = 0; - mutex_unlock(&fimc->lock); - return 0; - - case V4L2_SEL_TGT_CROP: - try_sel = v4l2_subdev_get_try_crop(fh, sel->pad); - break; - case V4L2_SEL_TGT_COMPOSE: - try_sel = v4l2_subdev_get_try_compose(fh, sel->pad); - f = &ctx->d_frame; - break; - default: - mutex_unlock(&fimc->lock); - return -EINVAL; - } - - if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - sel->r = *try_sel; - } else { - r->left = f->offs_h; - r->top = f->offs_v; - r->width = f->width; - r->height = f->height; - } - - dbg("target %#x: l:%d, t:%d, %dx%d, f_w: %d, f_h: %d", - sel->pad, r->left, r->top, r->width, r->height, - f->f_width, f->f_height); - - mutex_unlock(&fimc->lock); - return 0; -} - -static int fimc_subdev_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_selection *sel) -{ - struct fimc_dev *fimc = v4l2_get_subdevdata(sd); - struct fimc_ctx *ctx = fimc->vid_cap.ctx; - struct fimc_frame *f = &ctx->s_frame; - struct v4l2_rect *r = &sel->r; - struct v4l2_rect *try_sel; - unsigned long flags; - - if (sel->pad == FIMC_SD_PAD_SOURCE) - return -EINVAL; - - mutex_lock(&fimc->lock); - fimc_capture_try_selection(ctx, r, V4L2_SEL_TGT_CROP); - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - try_sel = v4l2_subdev_get_try_crop(fh, sel->pad); - break; - case V4L2_SEL_TGT_COMPOSE: - try_sel = v4l2_subdev_get_try_compose(fh, sel->pad); - f = &ctx->d_frame; - break; - default: - mutex_unlock(&fimc->lock); - return -EINVAL; - } - - if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - *try_sel = sel->r; - } else { - spin_lock_irqsave(&fimc->slock, flags); - set_frame_crop(f, r->left, r->top, r->width, r->height); - set_bit(ST_CAPT_APPLY_CFG, &fimc->state); - if (sel->target == V4L2_SEL_TGT_COMPOSE) - ctx->state |= FIMC_COMPOSE; - spin_unlock_irqrestore(&fimc->slock, flags); - } - - dbg("target %#x: (%d,%d)/%dx%d", sel->target, r->left, r->top, - r->width, r->height); - - mutex_unlock(&fimc->lock); - return 0; -} - -static struct v4l2_subdev_pad_ops fimc_subdev_pad_ops = { - .enum_mbus_code = fimc_subdev_enum_mbus_code, - .get_selection = fimc_subdev_get_selection, - .set_selection = fimc_subdev_set_selection, - .get_fmt = fimc_subdev_get_fmt, - .set_fmt = fimc_subdev_set_fmt, -}; - -static struct v4l2_subdev_ops fimc_subdev_ops = { - .pad = &fimc_subdev_pad_ops, -}; - -/* Set default format at the sensor and host interface */ -static int fimc_capture_set_default_format(struct fimc_dev *fimc) -{ - struct v4l2_format fmt = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, - .fmt.pix_mp = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_YUYV, - .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_JPEG, - }, - }; - - return __fimc_capture_set_format(fimc, &fmt); -} - -/* fimc->lock must be already initialized */ -static int fimc_register_capture_device(struct fimc_dev *fimc, - struct v4l2_device *v4l2_dev) -{ - struct video_device *vfd = &fimc->vid_cap.vfd; - struct vb2_queue *q = &fimc->vid_cap.vbq; - struct fimc_ctx *ctx; - struct fimc_vid_cap *vid_cap; - int ret = -ENOMEM; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->fimc_dev = fimc; - ctx->in_path = FIMC_IO_CAMERA; - ctx->out_path = FIMC_IO_DMA; - ctx->state = FIMC_CTX_CAP; - ctx->s_frame.fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0); - ctx->d_frame.fmt = ctx->s_frame.fmt; - - memset(vfd, 0, sizeof(*vfd)); - snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.capture", fimc->id); - - vfd->fops = &fimc_capture_fops; - vfd->ioctl_ops = &fimc_capture_ioctl_ops; - vfd->v4l2_dev = v4l2_dev; - vfd->minor = -1; - vfd->release = video_device_release_empty; - vfd->queue = q; - vfd->lock = &fimc->lock; - - video_set_drvdata(vfd, fimc); - vid_cap = &fimc->vid_cap; - vid_cap->active_buf_cnt = 0; - vid_cap->reqbufs_count = 0; - vid_cap->ctx = ctx; - - INIT_LIST_HEAD(&vid_cap->pending_buf_q); - INIT_LIST_HEAD(&vid_cap->active_buf_q); - - memset(q, 0, sizeof(*q)); - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - q->drv_priv = ctx; - q->ops = &fimc_capture_qops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct fimc_vid_buffer); - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->lock = &fimc->lock; - - ret = vb2_queue_init(q); - if (ret) - goto err_ent; - - vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0); - if (ret) - goto err_ent; - /* - * For proper order of acquiring/releasing the video - * and the graph mutex. - */ - v4l2_disable_ioctl_locking(vfd, VIDIOC_TRY_FMT); - v4l2_disable_ioctl_locking(vfd, VIDIOC_S_FMT); - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); - if (ret) - goto err_vd; - - v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n", - vfd->name, video_device_node_name(vfd)); - - vfd->ctrl_handler = &ctx->ctrls.handler; - return 0; - -err_vd: - media_entity_cleanup(&vfd->entity); -err_ent: - kfree(ctx); - return ret; -} - -static int fimc_capture_subdev_registered(struct v4l2_subdev *sd) -{ - struct fimc_dev *fimc = v4l2_get_subdevdata(sd); - int ret; - - if (fimc == NULL) - return -ENXIO; - - ret = fimc_register_m2m_device(fimc, sd->v4l2_dev); - if (ret) - return ret; - - fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd); - - ret = fimc_register_capture_device(fimc, sd->v4l2_dev); - if (ret) { - fimc_unregister_m2m_device(fimc); - fimc->pipeline_ops = NULL; - } - - return ret; -} - -static void fimc_capture_subdev_unregistered(struct v4l2_subdev *sd) -{ - struct fimc_dev *fimc = v4l2_get_subdevdata(sd); - - if (fimc == NULL) - return; - - fimc_unregister_m2m_device(fimc); - - if (video_is_registered(&fimc->vid_cap.vfd)) { - video_unregister_device(&fimc->vid_cap.vfd); - media_entity_cleanup(&fimc->vid_cap.vfd.entity); - fimc->pipeline_ops = NULL; - } - kfree(fimc->vid_cap.ctx); - fimc->vid_cap.ctx = NULL; -} - -static const struct v4l2_subdev_internal_ops fimc_capture_sd_internal_ops = { - .registered = fimc_capture_subdev_registered, - .unregistered = fimc_capture_subdev_unregistered, -}; - -int fimc_initialize_capture_subdev(struct fimc_dev *fimc) -{ - struct v4l2_subdev *sd = &fimc->vid_cap.subdev; - int ret; - - v4l2_subdev_init(sd, &fimc_subdev_ops); - sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->id); - - fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_CAM].flags = MEDIA_PAD_FL_SINK; - fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_FIFO].flags = MEDIA_PAD_FL_SINK; - fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM, - fimc->vid_cap.sd_pads, 0); - if (ret) - return ret; - - sd->entity.ops = &fimc_sd_media_ops; - sd->internal_ops = &fimc_capture_sd_internal_ops; - v4l2_set_subdevdata(sd, fimc); - return 0; -} - -void fimc_unregister_capture_subdev(struct fimc_dev *fimc) -{ - struct v4l2_subdev *sd = &fimc->vid_cap.subdev; - - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&sd->entity); - v4l2_set_subdevdata(sd, NULL); -} diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c deleted file mode 100644 index 1edd3aa8f3f3..000000000000 --- a/drivers/media/platform/s5p-fimc/fimc-core.c +++ /dev/null @@ -1,1334 +0,0 @@ -/* - * Samsung S5P/EXYNOS4 SoC series FIMC (CAMIF) driver - * - * Copyright (C) 2010-2012 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation, either version 2 of the License, - * or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "fimc-core.h" -#include "fimc-reg.h" -#include "fimc-mdevice.h" - -static char *fimc_clocks[MAX_FIMC_CLOCKS] = { - "sclk_fimc", "fimc" -}; - -static struct fimc_fmt fimc_formats[] = { - { - .name = "RGB565", - .fourcc = V4L2_PIX_FMT_RGB565, - .depth = { 16 }, - .color = FIMC_FMT_RGB565, - .memplanes = 1, - .colplanes = 1, - .flags = FMT_FLAGS_M2M, - }, { - .name = "BGR666", - .fourcc = V4L2_PIX_FMT_BGR666, - .depth = { 32 }, - .color = FIMC_FMT_RGB666, - .memplanes = 1, - .colplanes = 1, - .flags = FMT_FLAGS_M2M, - }, { - .name = "ARGB8888, 32 bpp", - .fourcc = V4L2_PIX_FMT_RGB32, - .depth = { 32 }, - .color = FIMC_FMT_RGB888, - .memplanes = 1, - .colplanes = 1, - .flags = FMT_FLAGS_M2M | FMT_HAS_ALPHA, - }, { - .name = "ARGB1555", - .fourcc = V4L2_PIX_FMT_RGB555, - .depth = { 16 }, - .color = FIMC_FMT_RGB555, - .memplanes = 1, - .colplanes = 1, - .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA, - }, { - .name = "ARGB4444", - .fourcc = V4L2_PIX_FMT_RGB444, - .depth = { 16 }, - .color = FIMC_FMT_RGB444, - .memplanes = 1, - .colplanes = 1, - .flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA, - }, { - .name = "YUV 4:4:4", - .mbus_code = V4L2_MBUS_FMT_YUV10_1X30, - .flags = FMT_FLAGS_WRITEBACK, - }, { - .name = "YUV 4:2:2 packed, YCbYCr", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = { 16 }, - .color = FIMC_FMT_YCBYCR422, - .memplanes = 1, - .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, - .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, - }, { - .name = "YUV 4:2:2 packed, CbYCrY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = { 16 }, - .color = FIMC_FMT_CBYCRY422, - .memplanes = 1, - .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, - .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, - }, { - .name = "YUV 4:2:2 packed, CrYCbY", - .fourcc = V4L2_PIX_FMT_VYUY, - .depth = { 16 }, - .color = FIMC_FMT_CRYCBY422, - .memplanes = 1, - .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8, - .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, - }, { - .name = "YUV 4:2:2 packed, YCrYCb", - .fourcc = V4L2_PIX_FMT_YVYU, - .depth = { 16 }, - .color = FIMC_FMT_YCRYCB422, - .memplanes = 1, - .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8, - .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM, - }, { - .name = "YUV 4:2:2 planar, Y/Cb/Cr", - .fourcc = V4L2_PIX_FMT_YUV422P, - .depth = { 12 }, - .color = FIMC_FMT_YCBYCR422, - .memplanes = 1, - .colplanes = 3, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:2 planar, Y/CbCr", - .fourcc = V4L2_PIX_FMT_NV16, - .depth = { 16 }, - .color = FIMC_FMT_YCBYCR422, - .memplanes = 1, - .colplanes = 2, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:2 planar, Y/CrCb", - .fourcc = V4L2_PIX_FMT_NV61, - .depth = { 16 }, - .color = FIMC_FMT_YCRYCB422, - .memplanes = 1, - .colplanes = 2, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:0 planar, YCbCr", - .fourcc = V4L2_PIX_FMT_YUV420, - .depth = { 12 }, - .color = FIMC_FMT_YCBCR420, - .memplanes = 1, - .colplanes = 3, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:0 planar, Y/CbCr", - .fourcc = V4L2_PIX_FMT_NV12, - .depth = { 12 }, - .color = FIMC_FMT_YCBCR420, - .memplanes = 1, - .colplanes = 2, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:0 non-contig. 2p, Y/CbCr", - .fourcc = V4L2_PIX_FMT_NV12M, - .color = FIMC_FMT_YCBCR420, - .depth = { 8, 4 }, - .memplanes = 2, - .colplanes = 2, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr", - .fourcc = V4L2_PIX_FMT_YUV420M, - .color = FIMC_FMT_YCBCR420, - .depth = { 8, 2, 2 }, - .memplanes = 3, - .colplanes = 3, - .flags = FMT_FLAGS_M2M, - }, { - .name = "YUV 4:2:0 non-contig. 2p, tiled", - .fourcc = V4L2_PIX_FMT_NV12MT, - .color = FIMC_FMT_YCBCR420, - .depth = { 8, 4 }, - .memplanes = 2, - .colplanes = 2, - .flags = FMT_FLAGS_M2M, - }, { - .name = "JPEG encoded data", - .fourcc = V4L2_PIX_FMT_JPEG, - .color = FIMC_FMT_JPEG, - .depth = { 8 }, - .memplanes = 1, - .colplanes = 1, - .mbus_code = V4L2_MBUS_FMT_JPEG_1X8, - .flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED, - }, { - .name = "S5C73MX interleaved UYVY/JPEG", - .fourcc = V4L2_PIX_FMT_S5C_UYVY_JPG, - .color = FIMC_FMT_YUYV_JPEG, - .depth = { 8 }, - .memplanes = 2, - .colplanes = 1, - .mdataplanes = 0x2, /* plane 1 holds frame meta data */ - .mbus_code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8, - .flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED, - }, -}; - -struct fimc_fmt *fimc_get_format(unsigned int index) -{ - if (index >= ARRAY_SIZE(fimc_formats)) - return NULL; - - return &fimc_formats[index]; -} - -int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh, - int dw, int dh, int rotation) -{ - if (rotation == 90 || rotation == 270) - swap(dw, dh); - - if (!ctx->scaler.enabled) - return (sw == dw && sh == dh) ? 0 : -EINVAL; - - if ((sw >= SCALER_MAX_HRATIO * dw) || (sh >= SCALER_MAX_VRATIO * dh)) - return -EINVAL; - - return 0; -} - -static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) -{ - u32 sh = 6; - - if (src >= 64 * tar) - return -EINVAL; - - while (sh--) { - u32 tmp = 1 << sh; - if (src >= tar * tmp) { - *shift = sh, *ratio = tmp; - return 0; - } - } - *shift = 0, *ratio = 1; - return 0; -} - -int fimc_set_scaler_info(struct fimc_ctx *ctx) -{ - const struct fimc_variant *variant = ctx->fimc_dev->variant; - struct device *dev = &ctx->fimc_dev->pdev->dev; - struct fimc_scaler *sc = &ctx->scaler; - struct fimc_frame *s_frame = &ctx->s_frame; - struct fimc_frame *d_frame = &ctx->d_frame; - int tx, ty, sx, sy; - int ret; - - if (ctx->rotation == 90 || ctx->rotation == 270) { - ty = d_frame->width; - tx = d_frame->height; - } else { - tx = d_frame->width; - ty = d_frame->height; - } - if (tx <= 0 || ty <= 0) { - dev_err(dev, "Invalid target size: %dx%d\n", tx, ty); - return -EINVAL; - } - - sx = s_frame->width; - sy = s_frame->height; - if (sx <= 0 || sy <= 0) { - dev_err(dev, "Invalid source size: %dx%d\n", sx, sy); - return -EINVAL; - } - sc->real_width = sx; - sc->real_height = sy; - - ret = fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor); - if (ret) - return ret; - - ret = fimc_get_scaler_factor(sy, ty, &sc->pre_vratio, &sc->vfactor); - if (ret) - return ret; - - sc->pre_dst_width = sx / sc->pre_hratio; - sc->pre_dst_height = sy / sc->pre_vratio; - - if (variant->has_mainscaler_ext) { - sc->main_hratio = (sx << 14) / (tx << sc->hfactor); - sc->main_vratio = (sy << 14) / (ty << sc->vfactor); - } else { - sc->main_hratio = (sx << 8) / (tx << sc->hfactor); - sc->main_vratio = (sy << 8) / (ty << sc->vfactor); - - } - - sc->scaleup_h = (tx >= sx) ? 1 : 0; - sc->scaleup_v = (ty >= sy) ? 1 : 0; - - /* check to see if input and output size/format differ */ - if (s_frame->fmt->color == d_frame->fmt->color - && s_frame->width == d_frame->width - && s_frame->height == d_frame->height) - sc->copy_mode = 1; - else - sc->copy_mode = 0; - - return 0; -} - -static irqreturn_t fimc_irq_handler(int irq, void *priv) -{ - struct fimc_dev *fimc = priv; - struct fimc_ctx *ctx; - - fimc_hw_clear_irq(fimc); - - spin_lock(&fimc->slock); - - if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) { - if (test_and_clear_bit(ST_M2M_SUSPENDING, &fimc->state)) { - set_bit(ST_M2M_SUSPENDED, &fimc->state); - wake_up(&fimc->irq_queue); - goto out; - } - ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev); - if (ctx != NULL) { - spin_unlock(&fimc->slock); - fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE); - - if (ctx->state & FIMC_CTX_SHUT) { - ctx->state &= ~FIMC_CTX_SHUT; - wake_up(&fimc->irq_queue); - } - return IRQ_HANDLED; - } - } else if (test_bit(ST_CAPT_PEND, &fimc->state)) { - int last_buf = test_bit(ST_CAPT_JPEG, &fimc->state) && - fimc->vid_cap.reqbufs_count == 1; - fimc_capture_irq_handler(fimc, !last_buf); - } -out: - spin_unlock(&fimc->slock); - return IRQ_HANDLED; -} - -/* The color format (colplanes, memplanes) must be already configured. */ -int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, - struct fimc_frame *frame, struct fimc_addr *paddr) -{ - int ret = 0; - u32 pix_size; - - if (vb == NULL || frame == NULL) - return -EINVAL; - - pix_size = frame->width * frame->height; - - dbg("memplanes= %d, colplanes= %d, pix_size= %d", - frame->fmt->memplanes, frame->fmt->colplanes, pix_size); - - paddr->y = vb2_dma_contig_plane_dma_addr(vb, 0); - - if (frame->fmt->memplanes == 1) { - switch (frame->fmt->colplanes) { - case 1: - paddr->cb = 0; - paddr->cr = 0; - break; - case 2: - /* decompose Y into Y/Cb */ - paddr->cb = (u32)(paddr->y + pix_size); - paddr->cr = 0; - break; - case 3: - paddr->cb = (u32)(paddr->y + pix_size); - /* decompose Y into Y/Cb/Cr */ - if (FIMC_FMT_YCBCR420 == frame->fmt->color) - paddr->cr = (u32)(paddr->cb - + (pix_size >> 2)); - else /* 422 */ - paddr->cr = (u32)(paddr->cb - + (pix_size >> 1)); - break; - default: - return -EINVAL; - } - } else if (!frame->fmt->mdataplanes) { - if (frame->fmt->memplanes >= 2) - paddr->cb = vb2_dma_contig_plane_dma_addr(vb, 1); - - if (frame->fmt->memplanes == 3) - paddr->cr = vb2_dma_contig_plane_dma_addr(vb, 2); - } - - dbg("PHYS_ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d", - paddr->y, paddr->cb, paddr->cr, ret); - - return ret; -} - -/* Set order for 1 and 2 plane YCBCR 4:2:2 formats. */ -void fimc_set_yuv_order(struct fimc_ctx *ctx) -{ - /* The one only mode supported in SoC. */ - ctx->in_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB; - ctx->out_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB; - - /* Set order for 1 plane input formats. */ - switch (ctx->s_frame.fmt->color) { - case FIMC_FMT_YCRYCB422: - ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CBYCRY; - break; - case FIMC_FMT_CBYCRY422: - ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCRYCB; - break; - case FIMC_FMT_CRYCBY422: - ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCBYCR; - break; - case FIMC_FMT_YCBYCR422: - default: - ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CRYCBY; - break; - } - dbg("ctx->in_order_1p= %d", ctx->in_order_1p); - - switch (ctx->d_frame.fmt->color) { - case FIMC_FMT_YCRYCB422: - ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CBYCRY; - break; - case FIMC_FMT_CBYCRY422: - ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCRYCB; - break; - case FIMC_FMT_CRYCBY422: - ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCBYCR; - break; - case FIMC_FMT_YCBYCR422: - default: - ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CRYCBY; - break; - } - dbg("ctx->out_order_1p= %d", ctx->out_order_1p); -} - -void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f) -{ - bool pix_hoff = ctx->fimc_dev->drv_data->dma_pix_hoff; - u32 i, depth = 0; - - for (i = 0; i < f->fmt->colplanes; i++) - depth += f->fmt->depth[i]; - - f->dma_offset.y_h = f->offs_h; - if (!pix_hoff) - f->dma_offset.y_h *= (depth >> 3); - - f->dma_offset.y_v = f->offs_v; - - f->dma_offset.cb_h = f->offs_h; - f->dma_offset.cb_v = f->offs_v; - - f->dma_offset.cr_h = f->offs_h; - f->dma_offset.cr_v = f->offs_v; - - if (!pix_hoff) { - if (f->fmt->colplanes == 3) { - f->dma_offset.cb_h >>= 1; - f->dma_offset.cr_h >>= 1; - } - if (f->fmt->color == FIMC_FMT_YCBCR420) { - f->dma_offset.cb_v >>= 1; - f->dma_offset.cr_v >>= 1; - } - } - - dbg("in_offset: color= %d, y_h= %d, y_v= %d", - f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v); -} - -static int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx) -{ - struct fimc_effect *effect = &ctx->effect; - - switch (colorfx) { - case V4L2_COLORFX_NONE: - effect->type = FIMC_REG_CIIMGEFF_FIN_BYPASS; - break; - case V4L2_COLORFX_BW: - effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY; - effect->pat_cb = 128; - effect->pat_cr = 128; - break; - case V4L2_COLORFX_SEPIA: - effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY; - effect->pat_cb = 115; - effect->pat_cr = 145; - break; - case V4L2_COLORFX_NEGATIVE: - effect->type = FIMC_REG_CIIMGEFF_FIN_NEGATIVE; - break; - case V4L2_COLORFX_EMBOSS: - effect->type = FIMC_REG_CIIMGEFF_FIN_EMBOSSING; - break; - case V4L2_COLORFX_ART_FREEZE: - effect->type = FIMC_REG_CIIMGEFF_FIN_ARTFREEZE; - break; - case V4L2_COLORFX_SILHOUETTE: - effect->type = FIMC_REG_CIIMGEFF_FIN_SILHOUETTE; - break; - case V4L2_COLORFX_SET_CBCR: - effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY; - effect->pat_cb = ctx->ctrls.colorfx_cbcr->val >> 8; - effect->pat_cr = ctx->ctrls.colorfx_cbcr->val & 0xff; - break; - default: - return -EINVAL; - } - - return 0; -} - -/* - * V4L2 controls handling - */ -#define ctrl_to_ctx(__ctrl) \ - container_of((__ctrl)->handler, struct fimc_ctx, ctrls.handler) - -static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl) -{ - struct fimc_dev *fimc = ctx->fimc_dev; - const struct fimc_variant *variant = fimc->variant; - int ret = 0; - - if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) - return 0; - - switch (ctrl->id) { - case V4L2_CID_HFLIP: - ctx->hflip = ctrl->val; - break; - - case V4L2_CID_VFLIP: - ctx->vflip = ctrl->val; - break; - - case V4L2_CID_ROTATE: - if (fimc_capture_pending(fimc)) { - ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, - ctx->s_frame.height, ctx->d_frame.width, - ctx->d_frame.height, ctrl->val); - if (ret) - return -EINVAL; - } - if ((ctrl->val == 90 || ctrl->val == 270) && - !variant->has_out_rot) - return -EINVAL; - - ctx->rotation = ctrl->val; - break; - - case V4L2_CID_ALPHA_COMPONENT: - ctx->d_frame.alpha = ctrl->val; - break; - - case V4L2_CID_COLORFX: - ret = fimc_set_color_effect(ctx, ctrl->val); - if (ret) - return ret; - break; - } - - ctx->state |= FIMC_PARAMS; - set_bit(ST_CAPT_APPLY_CFG, &fimc->state); - return 0; -} - -static int fimc_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct fimc_ctx *ctx = ctrl_to_ctx(ctrl); - unsigned long flags; - int ret; - - spin_lock_irqsave(&ctx->fimc_dev->slock, flags); - ret = __fimc_s_ctrl(ctx, ctrl); - spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags); - - return ret; -} - -static const struct v4l2_ctrl_ops fimc_ctrl_ops = { - .s_ctrl = fimc_s_ctrl, -}; - -int fimc_ctrls_create(struct fimc_ctx *ctx) -{ - unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt); - struct fimc_ctrls *ctrls = &ctx->ctrls; - struct v4l2_ctrl_handler *handler = &ctrls->handler; - - if (ctx->ctrls.ready) - return 0; - - v4l2_ctrl_handler_init(handler, 6); - - ctrls->rotate = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops, - V4L2_CID_ROTATE, 0, 270, 90, 0); - ctrls->hflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - ctrls->vflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - - if (ctx->fimc_dev->drv_data->alpha_color) - ctrls->alpha = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops, - V4L2_CID_ALPHA_COMPONENT, - 0, max_alpha, 1, 0); - else - ctrls->alpha = NULL; - - ctrls->colorfx = v4l2_ctrl_new_std_menu(handler, &fimc_ctrl_ops, - V4L2_CID_COLORFX, V4L2_COLORFX_SET_CBCR, - ~0x983f, V4L2_COLORFX_NONE); - - ctrls->colorfx_cbcr = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops, - V4L2_CID_COLORFX_CBCR, 0, 0xffff, 1, 0); - - ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS; - - if (!handler->error) { - v4l2_ctrl_cluster(2, &ctrls->colorfx); - ctrls->ready = true; - } - - return handler->error; -} - -void fimc_ctrls_delete(struct fimc_ctx *ctx) -{ - struct fimc_ctrls *ctrls = &ctx->ctrls; - - if (ctrls->ready) { - v4l2_ctrl_handler_free(&ctrls->handler); - ctrls->ready = false; - ctrls->alpha = NULL; - } -} - -void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active) -{ - unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA; - struct fimc_ctrls *ctrls = &ctx->ctrls; - - if (!ctrls->ready) - return; - - mutex_lock(ctrls->handler.lock); - v4l2_ctrl_activate(ctrls->rotate, active); - v4l2_ctrl_activate(ctrls->hflip, active); - v4l2_ctrl_activate(ctrls->vflip, active); - v4l2_ctrl_activate(ctrls->colorfx, active); - if (ctrls->alpha) - v4l2_ctrl_activate(ctrls->alpha, active && has_alpha); - - if (active) { - fimc_set_color_effect(ctx, ctrls->colorfx->cur.val); - ctx->rotation = ctrls->rotate->val; - ctx->hflip = ctrls->hflip->val; - ctx->vflip = ctrls->vflip->val; - } else { - ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS; - ctx->rotation = 0; - ctx->hflip = 0; - ctx->vflip = 0; - } - mutex_unlock(ctrls->handler.lock); -} - -/* Update maximum value of the alpha color control */ -void fimc_alpha_ctrl_update(struct fimc_ctx *ctx) -{ - struct fimc_dev *fimc = ctx->fimc_dev; - struct v4l2_ctrl *ctrl = ctx->ctrls.alpha; - - if (ctrl == NULL || !fimc->drv_data->alpha_color) - return; - - v4l2_ctrl_lock(ctrl); - ctrl->maximum = fimc_get_alpha_mask(ctx->d_frame.fmt); - - if (ctrl->cur.val > ctrl->maximum) - ctrl->cur.val = ctrl->maximum; - - v4l2_ctrl_unlock(ctrl); -} - -void __fimc_get_format(struct fimc_frame *frame, struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; - int i; - - pixm->width = frame->o_width; - pixm->height = frame->o_height; - pixm->field = V4L2_FIELD_NONE; - pixm->pixelformat = frame->fmt->fourcc; - pixm->colorspace = V4L2_COLORSPACE_JPEG; - pixm->num_planes = frame->fmt->memplanes; - - for (i = 0; i < pixm->num_planes; ++i) { - pixm->plane_fmt[i].bytesperline = frame->bytesperline[i]; - pixm->plane_fmt[i].sizeimage = frame->payload[i]; - } -} - -/** - * fimc_adjust_mplane_format - adjust bytesperline/sizeimage for each plane - * @fmt: fimc pixel format description (input) - * @width: requested pixel width - * @height: requested pixel height - * @pix: multi-plane format to adjust - */ -void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, - struct v4l2_pix_format_mplane *pix) -{ - u32 bytesperline = 0; - int i; - - pix->colorspace = V4L2_COLORSPACE_JPEG; - pix->field = V4L2_FIELD_NONE; - pix->num_planes = fmt->memplanes; - pix->pixelformat = fmt->fourcc; - pix->height = height; - pix->width = width; - - for (i = 0; i < pix->num_planes; ++i) { - struct v4l2_plane_pix_format *plane_fmt = &pix->plane_fmt[i]; - u32 bpl = plane_fmt->bytesperline; - - if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width)) - bpl = pix->width; /* Planar */ - - if (fmt->colplanes == 1 && /* Packed */ - (bpl == 0 || ((bpl * 8) / fmt->depth[i]) < pix->width)) - bpl = (pix->width * fmt->depth[0]) / 8; - /* - * Currently bytesperline for each plane is same, except - * V4L2_PIX_FMT_YUV420M format. This calculation may need - * to be changed when other multi-planar formats are added - * to the fimc_formats[] array. - */ - if (i == 0) - bytesperline = bpl; - else if (i == 1 && fmt->memplanes == 3) - bytesperline /= 2; - - plane_fmt->bytesperline = bytesperline; - plane_fmt->sizeimage = max((pix->width * pix->height * - fmt->depth[i]) / 8, plane_fmt->sizeimage); - } -} - -/** - * fimc_find_format - lookup fimc color format by fourcc or media bus format - * @pixelformat: fourcc to match, ignored if null - * @mbus_code: media bus code to match, ignored if null - * @mask: the color flags to match - * @index: offset in the fimc_formats array, ignored if negative - */ -struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code, - unsigned int mask, int index) -{ - struct fimc_fmt *fmt, *def_fmt = NULL; - unsigned int i; - int id = 0; - - if (index >= (int)ARRAY_SIZE(fimc_formats)) - return NULL; - - for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) { - fmt = &fimc_formats[i]; - if (!(fmt->flags & mask)) - continue; - if (pixelformat && fmt->fourcc == *pixelformat) - return fmt; - if (mbus_code && fmt->mbus_code == *mbus_code) - return fmt; - if (index == id) - def_fmt = fmt; - id++; - } - return def_fmt; -} - -static void fimc_clk_put(struct fimc_dev *fimc) -{ - int i; - for (i = 0; i < MAX_FIMC_CLOCKS; i++) { - if (IS_ERR(fimc->clock[i])) - continue; - clk_unprepare(fimc->clock[i]); - clk_put(fimc->clock[i]); - fimc->clock[i] = ERR_PTR(-EINVAL); - } -} - -static int fimc_clk_get(struct fimc_dev *fimc) -{ - int i, ret; - - for (i = 0; i < MAX_FIMC_CLOCKS; i++) - fimc->clock[i] = ERR_PTR(-EINVAL); - - for (i = 0; i < MAX_FIMC_CLOCKS; i++) { - fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]); - if (IS_ERR(fimc->clock[i])) { - ret = PTR_ERR(fimc->clock[i]); - goto err; - } - ret = clk_prepare(fimc->clock[i]); - if (ret < 0) { - clk_put(fimc->clock[i]); - fimc->clock[i] = ERR_PTR(-EINVAL); - goto err; - } - } - return 0; -err: - fimc_clk_put(fimc); - dev_err(&fimc->pdev->dev, "failed to get clock: %s\n", - fimc_clocks[i]); - return -ENXIO; -} - -static int fimc_m2m_suspend(struct fimc_dev *fimc) -{ - unsigned long flags; - int timeout; - - spin_lock_irqsave(&fimc->slock, flags); - if (!fimc_m2m_pending(fimc)) { - spin_unlock_irqrestore(&fimc->slock, flags); - return 0; - } - clear_bit(ST_M2M_SUSPENDED, &fimc->state); - set_bit(ST_M2M_SUSPENDING, &fimc->state); - spin_unlock_irqrestore(&fimc->slock, flags); - - timeout = wait_event_timeout(fimc->irq_queue, - test_bit(ST_M2M_SUSPENDED, &fimc->state), - FIMC_SHUTDOWN_TIMEOUT); - - clear_bit(ST_M2M_SUSPENDING, &fimc->state); - return timeout == 0 ? -EAGAIN : 0; -} - -static int fimc_m2m_resume(struct fimc_dev *fimc) -{ - unsigned long flags; - - spin_lock_irqsave(&fimc->slock, flags); - /* Clear for full H/W setup in first run after resume */ - fimc->m2m.ctx = NULL; - spin_unlock_irqrestore(&fimc->slock, flags); - - if (test_and_clear_bit(ST_M2M_SUSPENDED, &fimc->state)) - fimc_m2m_job_finish(fimc->m2m.ctx, - VB2_BUF_STATE_ERROR); - return 0; -} - -static const struct of_device_id fimc_of_match[]; - -static int fimc_parse_dt(struct fimc_dev *fimc, u32 *clk_freq) -{ - struct device *dev = &fimc->pdev->dev; - struct device_node *node = dev->of_node; - const struct of_device_id *of_id; - struct fimc_variant *v; - struct fimc_pix_limit *lim; - u32 args[FIMC_PIX_LIMITS_MAX]; - int ret; - - if (of_property_read_bool(node, "samsung,lcd-wb")) - return -ENODEV; - - v = devm_kzalloc(dev, sizeof(*v) + sizeof(*lim), GFP_KERNEL); - if (!v) - return -ENOMEM; - - of_id = of_match_node(fimc_of_match, node); - if (!of_id) - return -EINVAL; - fimc->drv_data = of_id->data; - ret = of_property_read_u32_array(node, "samsung,pix-limits", - args, FIMC_PIX_LIMITS_MAX); - if (ret < 0) - return ret; - - lim = (struct fimc_pix_limit *)&v[1]; - - lim->scaler_en_w = args[0]; - lim->scaler_dis_w = args[1]; - lim->out_rot_en_w = args[2]; - lim->out_rot_dis_w = args[3]; - v->pix_limit = lim; - - ret = of_property_read_u32_array(node, "samsung,min-pix-sizes", - args, 2); - v->min_inp_pixsize = ret ? FIMC_DEF_MIN_SIZE : args[0]; - v->min_out_pixsize = ret ? FIMC_DEF_MIN_SIZE : args[1]; - ret = of_property_read_u32_array(node, "samsung,min-pix-alignment", - args, 2); - v->min_vsize_align = ret ? FIMC_DEF_HEIGHT_ALIGN : args[0]; - v->hor_offs_align = ret ? FIMC_DEF_HOR_OFFS_ALIGN : args[1]; - - ret = of_property_read_u32(node, "samsung,rotators", &args[1]); - v->has_inp_rot = ret ? 1 : args[1] & 0x01; - v->has_out_rot = ret ? 1 : args[1] & 0x10; - v->has_mainscaler_ext = of_property_read_bool(node, - "samsung,mainscaler-ext"); - - v->has_isp_wb = of_property_read_bool(node, "samsung,isp-wb"); - v->has_cam_if = of_property_read_bool(node, "samsung,cam-if"); - of_property_read_u32(node, "clock-frequency", clk_freq); - fimc->id = of_alias_get_id(node, "fimc"); - - fimc->variant = v; - return 0; -} - -static int fimc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - u32 lclk_freq = 0; - struct fimc_dev *fimc; - struct resource *res; - int ret = 0; - - fimc = devm_kzalloc(dev, sizeof(*fimc), GFP_KERNEL); - if (!fimc) - return -ENOMEM; - - fimc->pdev = pdev; - - if (dev->of_node) { - ret = fimc_parse_dt(fimc, &lclk_freq); - if (ret < 0) - return ret; - } else { - fimc->drv_data = fimc_get_drvdata(pdev); - fimc->id = pdev->id; - } - if (!fimc->drv_data || fimc->id >= fimc->drv_data->num_entities || - fimc->id < 0) { - dev_err(dev, "Invalid driver data or device id (%d/%d)\n", - fimc->id, fimc->drv_data->num_entities); - return -EINVAL; - } - if (!dev->of_node) - fimc->variant = fimc->drv_data->variant[fimc->id]; - - init_waitqueue_head(&fimc->irq_queue); - spin_lock_init(&fimc->slock); - mutex_init(&fimc->lock); - - fimc->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, - "samsung,sysreg"); - if (IS_ERR(fimc->sysreg)) - return PTR_ERR(fimc->sysreg); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - fimc->regs = devm_ioremap_resource(dev, res); - if (IS_ERR(fimc->regs)) - return PTR_ERR(fimc->regs); - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res == NULL) { - dev_err(dev, "Failed to get IRQ resource\n"); - return -ENXIO; - } - - ret = fimc_clk_get(fimc); - if (ret) - return ret; - - if (lclk_freq == 0) - lclk_freq = fimc->drv_data->lclk_frequency; - - ret = clk_set_rate(fimc->clock[CLK_BUS], lclk_freq); - if (ret < 0) - return ret; - - ret = clk_enable(fimc->clock[CLK_BUS]); - if (ret < 0) - return ret; - - ret = devm_request_irq(dev, res->start, fimc_irq_handler, - 0, dev_name(dev), fimc); - if (ret) { - dev_err(dev, "failed to install irq (%d)\n", ret); - goto err_clk; - } - - ret = fimc_initialize_capture_subdev(fimc); - if (ret) - goto err_clk; - - platform_set_drvdata(pdev, fimc); - pm_runtime_enable(dev); - ret = pm_runtime_get_sync(dev); - if (ret < 0) - goto err_sd; - /* Initialize contiguous memory allocator */ - fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); - if (IS_ERR(fimc->alloc_ctx)) { - ret = PTR_ERR(fimc->alloc_ctx); - goto err_pm; - } - - dev_dbg(dev, "FIMC.%d registered successfully\n", fimc->id); - - pm_runtime_put(dev); - return 0; -err_pm: - pm_runtime_put(dev); -err_sd: - fimc_unregister_capture_subdev(fimc); -err_clk: - clk_disable(fimc->clock[CLK_BUS]); - fimc_clk_put(fimc); - return ret; -} - -static int fimc_runtime_resume(struct device *dev) -{ - struct fimc_dev *fimc = dev_get_drvdata(dev); - - dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state); - - /* Enable clocks and perform basic initalization */ - clk_enable(fimc->clock[CLK_GATE]); - fimc_hw_reset(fimc); - - /* Resume the capture or mem-to-mem device */ - if (fimc_capture_busy(fimc)) - return fimc_capture_resume(fimc); - - return fimc_m2m_resume(fimc); -} - -static int fimc_runtime_suspend(struct device *dev) -{ - struct fimc_dev *fimc = dev_get_drvdata(dev); - int ret = 0; - - if (fimc_capture_busy(fimc)) - ret = fimc_capture_suspend(fimc); - else - ret = fimc_m2m_suspend(fimc); - if (!ret) - clk_disable(fimc->clock[CLK_GATE]); - - dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state); - return ret; -} - -#ifdef CONFIG_PM_SLEEP -static int fimc_resume(struct device *dev) -{ - struct fimc_dev *fimc = dev_get_drvdata(dev); - unsigned long flags; - - dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state); - - /* Do not resume if the device was idle before system suspend */ - spin_lock_irqsave(&fimc->slock, flags); - if (!test_and_clear_bit(ST_LPM, &fimc->state) || - (!fimc_m2m_active(fimc) && !fimc_capture_busy(fimc))) { - spin_unlock_irqrestore(&fimc->slock, flags); - return 0; - } - fimc_hw_reset(fimc); - spin_unlock_irqrestore(&fimc->slock, flags); - - if (fimc_capture_busy(fimc)) - return fimc_capture_resume(fimc); - - return fimc_m2m_resume(fimc); -} - -static int fimc_suspend(struct device *dev) -{ - struct fimc_dev *fimc = dev_get_drvdata(dev); - - dbg("fimc%d: state: 0x%lx", fimc->id, fimc->state); - - if (test_and_set_bit(ST_LPM, &fimc->state)) - return 0; - if (fimc_capture_busy(fimc)) - return fimc_capture_suspend(fimc); - - return fimc_m2m_suspend(fimc); -} -#endif /* CONFIG_PM_SLEEP */ - -static int fimc_remove(struct platform_device *pdev) -{ - struct fimc_dev *fimc = platform_get_drvdata(pdev); - - pm_runtime_disable(&pdev->dev); - pm_runtime_set_suspended(&pdev->dev); - - fimc_unregister_capture_subdev(fimc); - vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); - - clk_disable(fimc->clock[CLK_BUS]); - fimc_clk_put(fimc); - - dev_info(&pdev->dev, "driver unloaded\n"); - return 0; -} - -/* Image pixel limits, similar across several FIMC HW revisions. */ -static const struct fimc_pix_limit s5p_pix_limit[4] = { - [0] = { - .scaler_en_w = 3264, - .scaler_dis_w = 8192, - .out_rot_en_w = 1920, - .out_rot_dis_w = 4224, - }, - [1] = { - .scaler_en_w = 4224, - .scaler_dis_w = 8192, - .out_rot_en_w = 1920, - .out_rot_dis_w = 4224, - }, - [2] = { - .scaler_en_w = 1920, - .scaler_dis_w = 8192, - .out_rot_en_w = 1280, - .out_rot_dis_w = 1920, - }, - [3] = { - .scaler_en_w = 1920, - .scaler_dis_w = 8192, - .in_rot_en_h = 1366, - .in_rot_dis_w = 8192, - .out_rot_en_w = 1366, - .out_rot_dis_w = 1920, - }, -}; - -static const struct fimc_variant fimc0_variant_s5p = { - .has_inp_rot = 1, - .has_out_rot = 1, - .has_cam_if = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 8, - .min_vsize_align = 16, - .pix_limit = &s5p_pix_limit[0], -}; - -static const struct fimc_variant fimc2_variant_s5p = { - .has_cam_if = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 8, - .min_vsize_align = 16, - .pix_limit = &s5p_pix_limit[1], -}; - -static const struct fimc_variant fimc0_variant_s5pv210 = { - .has_inp_rot = 1, - .has_out_rot = 1, - .has_cam_if = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 8, - .min_vsize_align = 16, - .pix_limit = &s5p_pix_limit[1], -}; - -static const struct fimc_variant fimc1_variant_s5pv210 = { - .has_inp_rot = 1, - .has_out_rot = 1, - .has_cam_if = 1, - .has_mainscaler_ext = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 1, - .min_vsize_align = 1, - .pix_limit = &s5p_pix_limit[2], -}; - -static const struct fimc_variant fimc2_variant_s5pv210 = { - .has_cam_if = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 8, - .min_vsize_align = 16, - .pix_limit = &s5p_pix_limit[2], -}; - -static const struct fimc_variant fimc0_variant_exynos4210 = { - .has_inp_rot = 1, - .has_out_rot = 1, - .has_cam_if = 1, - .has_mainscaler_ext = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 2, - .min_vsize_align = 1, - .pix_limit = &s5p_pix_limit[1], -}; - -static const struct fimc_variant fimc3_variant_exynos4210 = { - .has_mainscaler_ext = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 2, - .min_vsize_align = 1, - .pix_limit = &s5p_pix_limit[3], -}; - -/* S5PC100 */ -static const struct fimc_drvdata fimc_drvdata_s5p = { - .variant = { - [0] = &fimc0_variant_s5p, - [1] = &fimc0_variant_s5p, - [2] = &fimc2_variant_s5p, - }, - .num_entities = 3, - .lclk_frequency = 133000000UL, - .out_buf_count = 4, -}; - -/* S5PV210, S5PC110 */ -static const struct fimc_drvdata fimc_drvdata_s5pv210 = { - .variant = { - [0] = &fimc0_variant_s5pv210, - [1] = &fimc1_variant_s5pv210, - [2] = &fimc2_variant_s5pv210, - }, - .num_entities = 3, - .lclk_frequency = 166000000UL, - .out_buf_count = 4, - .dma_pix_hoff = 1, -}; - -/* EXYNOS4210, S5PV310, S5PC210 */ -static const struct fimc_drvdata fimc_drvdata_exynos4210 = { - .variant = { - [0] = &fimc0_variant_exynos4210, - [1] = &fimc0_variant_exynos4210, - [2] = &fimc0_variant_exynos4210, - [3] = &fimc3_variant_exynos4210, - }, - .num_entities = 4, - .lclk_frequency = 166000000UL, - .dma_pix_hoff = 1, - .cistatus2 = 1, - .alpha_color = 1, - .out_buf_count = 32, -}; - -/* EXYNOS4212, EXYNOS4412 */ -static const struct fimc_drvdata fimc_drvdata_exynos4x12 = { - .num_entities = 4, - .lclk_frequency = 166000000UL, - .dma_pix_hoff = 1, - .cistatus2 = 1, - .alpha_color = 1, - .out_buf_count = 32, -}; - -static const struct platform_device_id fimc_driver_ids[] = { - { - .name = "s5p-fimc", - .driver_data = (unsigned long)&fimc_drvdata_s5p, - }, { - .name = "s5pv210-fimc", - .driver_data = (unsigned long)&fimc_drvdata_s5pv210, - }, { - .name = "exynos4-fimc", - .driver_data = (unsigned long)&fimc_drvdata_exynos4210, - }, { - .name = "exynos4x12-fimc", - .driver_data = (unsigned long)&fimc_drvdata_exynos4x12, - }, - { }, -}; - -static const struct of_device_id fimc_of_match[] = { - { - .compatible = "samsung,s5pv210-fimc", - .data = &fimc_drvdata_s5pv210, - }, { - .compatible = "samsung,exynos4210-fimc", - .data = &fimc_drvdata_exynos4210, - }, { - .compatible = "samsung,exynos4212-fimc", - .data = &fimc_drvdata_exynos4x12, - }, - { /* sentinel */ }, -}; - -static const struct dev_pm_ops fimc_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(fimc_suspend, fimc_resume) - SET_RUNTIME_PM_OPS(fimc_runtime_suspend, fimc_runtime_resume, NULL) -}; - -static struct platform_driver fimc_driver = { - .probe = fimc_probe, - .remove = fimc_remove, - .id_table = fimc_driver_ids, - .driver = { - .of_match_table = fimc_of_match, - .name = FIMC_MODULE_NAME, - .owner = THIS_MODULE, - .pm = &fimc_pm_ops, - } -}; - -int __init fimc_register_driver(void) -{ - return platform_driver_register(&fimc_driver); -} - -void __exit fimc_unregister_driver(void) -{ - platform_driver_unregister(&fimc_driver); -} diff --git a/drivers/media/platform/s5p-fimc/fimc-core.h b/drivers/media/platform/s5p-fimc/fimc-core.h deleted file mode 100644 index 793333a33b24..000000000000 --- a/drivers/media/platform/s5p-fimc/fimc-core.h +++ /dev/null @@ -1,718 +0,0 @@ -/* - * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef FIMC_CORE_H_ -#define FIMC_CORE_H_ - -/*#define DEBUG*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define dbg(fmt, args...) \ - pr_debug("%s:%d: " fmt "\n", __func__, __LINE__, ##args) - -/* Time to wait for next frame VSYNC interrupt while stopping operation. */ -#define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000) -#define MAX_FIMC_CLOCKS 2 -#define FIMC_MODULE_NAME "s5p-fimc" -#define FIMC_MAX_DEVS 4 -#define FIMC_MAX_OUT_BUFS 4 -#define SCALER_MAX_HRATIO 64 -#define SCALER_MAX_VRATIO 64 -#define DMA_MIN_SIZE 8 -#define FIMC_CAMIF_MAX_HEIGHT 0x2000 -#define FIMC_MAX_JPEG_BUF_SIZE (10 * SZ_1M) -#define FIMC_MAX_PLANES 3 -#define FIMC_PIX_LIMITS_MAX 4 -#define FIMC_DEF_MIN_SIZE 16 -#define FIMC_DEF_HEIGHT_ALIGN 2 -#define FIMC_DEF_HOR_OFFS_ALIGN 1 - -/* indices to the clocks array */ -enum { - CLK_BUS, - CLK_GATE, -}; - -enum fimc_dev_flags { - ST_LPM, - /* m2m node */ - ST_M2M_RUN, - ST_M2M_PEND, - ST_M2M_SUSPENDING, - ST_M2M_SUSPENDED, - /* capture node */ - ST_CAPT_PEND, - ST_CAPT_RUN, - ST_CAPT_STREAM, - ST_CAPT_ISP_STREAM, - ST_CAPT_SUSPENDED, - ST_CAPT_SHUT, - ST_CAPT_BUSY, - ST_CAPT_APPLY_CFG, - ST_CAPT_JPEG, -}; - -#define fimc_m2m_active(dev) test_bit(ST_M2M_RUN, &(dev)->state) -#define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state) - -#define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state) -#define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state) -#define fimc_capture_busy(dev) test_bit(ST_CAPT_BUSY, &(dev)->state) - -enum fimc_datapath { - FIMC_IO_NONE, - FIMC_IO_CAMERA, - FIMC_IO_DMA, - FIMC_IO_LCDFIFO, - FIMC_IO_WRITEBACK, - FIMC_IO_ISP, -}; - -enum fimc_color_fmt { - FIMC_FMT_RGB444 = 0x10, - FIMC_FMT_RGB555, - FIMC_FMT_RGB565, - FIMC_FMT_RGB666, - FIMC_FMT_RGB888, - FIMC_FMT_RGB30_LOCAL, - FIMC_FMT_YCBCR420 = 0x20, - FIMC_FMT_YCBYCR422, - FIMC_FMT_YCRYCB422, - FIMC_FMT_CBYCRY422, - FIMC_FMT_CRYCBY422, - FIMC_FMT_YCBCR444_LOCAL, - FIMC_FMT_RAW8 = 0x40, - FIMC_FMT_RAW10, - FIMC_FMT_RAW12, - FIMC_FMT_JPEG = 0x80, - FIMC_FMT_YUYV_JPEG = 0x100, -}; - -#define fimc_fmt_is_user_defined(x) (!!((x) & 0x180)) -#define fimc_fmt_is_rgb(x) (!!((x) & 0x10)) - -#define IS_M2M(__strt) ((__strt) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || \ - __strt == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - -/* The hardware context state. */ -#define FIMC_PARAMS (1 << 0) -#define FIMC_COMPOSE (1 << 1) -#define FIMC_CTX_M2M (1 << 16) -#define FIMC_CTX_CAP (1 << 17) -#define FIMC_CTX_SHUT (1 << 18) - -/* Image conversion flags */ -#define FIMC_IN_DMA_ACCESS_TILED (1 << 0) -#define FIMC_IN_DMA_ACCESS_LINEAR (0 << 0) -#define FIMC_OUT_DMA_ACCESS_TILED (1 << 1) -#define FIMC_OUT_DMA_ACCESS_LINEAR (0 << 1) -#define FIMC_SCAN_MODE_PROGRESSIVE (0 << 2) -#define FIMC_SCAN_MODE_INTERLACED (1 << 2) -/* - * YCbCr data dynamic range for RGB-YUV color conversion. - * Y/Cb/Cr: (0 ~ 255) */ -#define FIMC_COLOR_RANGE_WIDE (0 << 3) -/* Y (16 ~ 235), Cb/Cr (16 ~ 240) */ -#define FIMC_COLOR_RANGE_NARROW (1 << 3) - -/** - * struct fimc_dma_offset - pixel offset information for DMA - * @y_h: y value horizontal offset - * @y_v: y value vertical offset - * @cb_h: cb value horizontal offset - * @cb_v: cb value vertical offset - * @cr_h: cr value horizontal offset - * @cr_v: cr value vertical offset - */ -struct fimc_dma_offset { - int y_h; - int y_v; - int cb_h; - int cb_v; - int cr_h; - int cr_v; -}; - -/** - * struct fimc_effect - color effect information - * @type: effect type - * @pat_cb: cr value when type is "arbitrary" - * @pat_cr: cr value when type is "arbitrary" - */ -struct fimc_effect { - u32 type; - u8 pat_cb; - u8 pat_cr; -}; - -/** - * struct fimc_scaler - the configuration data for FIMC inetrnal scaler - * @scaleup_h: flag indicating scaling up horizontally - * @scaleup_v: flag indicating scaling up vertically - * @copy_mode: flag indicating transparent DMA transfer (no scaling - * and color format conversion) - * @enabled: flag indicating if the scaler is used - * @hfactor: horizontal shift factor - * @vfactor: vertical shift factor - * @pre_hratio: horizontal ratio of the prescaler - * @pre_vratio: vertical ratio of the prescaler - * @pre_dst_width: the prescaler's destination width - * @pre_dst_height: the prescaler's destination height - * @main_hratio: the main scaler's horizontal ratio - * @main_vratio: the main scaler's vertical ratio - * @real_width: source pixel (width - offset) - * @real_height: source pixel (height - offset) - */ -struct fimc_scaler { - unsigned int scaleup_h:1; - unsigned int scaleup_v:1; - unsigned int copy_mode:1; - unsigned int enabled:1; - u32 hfactor; - u32 vfactor; - u32 pre_hratio; - u32 pre_vratio; - u32 pre_dst_width; - u32 pre_dst_height; - u32 main_hratio; - u32 main_vratio; - u32 real_width; - u32 real_height; -}; - -/** - * struct fimc_addr - the FIMC physical address set for DMA - * @y: luminance plane physical address - * @cb: Cb plane physical address - * @cr: Cr plane physical address - */ -struct fimc_addr { - u32 y; - u32 cb; - u32 cr; -}; - -/** - * struct fimc_vid_buffer - the driver's video buffer - * @vb: v4l videobuf buffer - * @list: linked list structure for buffer queue - * @paddr: precalculated physical address set - * @index: buffer index for the output DMA engine - */ -struct fimc_vid_buffer { - struct vb2_buffer vb; - struct list_head list; - struct fimc_addr paddr; - int index; -}; - -/** - * struct fimc_frame - source/target frame properties - * @f_width: image full width (virtual screen size) - * @f_height: image full height (virtual screen size) - * @o_width: original image width as set by S_FMT - * @o_height: original image height as set by S_FMT - * @offs_h: image horizontal pixel offset - * @offs_v: image vertical pixel offset - * @width: image pixel width - * @height: image pixel weight - * @payload: image size in bytes (w x h x bpp) - * @bytesperline: bytesperline value for each plane - * @paddr: image frame buffer physical addresses - * @dma_offset: DMA offset in bytes - * @fmt: fimc color format pointer - */ -struct fimc_frame { - u32 f_width; - u32 f_height; - u32 o_width; - u32 o_height; - u32 offs_h; - u32 offs_v; - u32 width; - u32 height; - unsigned int payload[VIDEO_MAX_PLANES]; - unsigned int bytesperline[VIDEO_MAX_PLANES]; - struct fimc_addr paddr; - struct fimc_dma_offset dma_offset; - struct fimc_fmt *fmt; - u8 alpha; -}; - -/** - * struct fimc_m2m_device - v4l2 memory-to-memory device data - * @vfd: the video device node for v4l2 m2m mode - * @m2m_dev: v4l2 memory-to-memory device data - * @ctx: hardware context data - * @refcnt: the reference counter - */ -struct fimc_m2m_device { - struct video_device vfd; - struct v4l2_m2m_dev *m2m_dev; - struct fimc_ctx *ctx; - int refcnt; -}; - -#define FIMC_SD_PAD_SINK_CAM 0 -#define FIMC_SD_PAD_SINK_FIFO 1 -#define FIMC_SD_PAD_SOURCE 2 -#define FIMC_SD_PADS_NUM 3 - -/** - * struct fimc_vid_cap - camera capture device information - * @ctx: hardware context data - * @vfd: video device node for camera capture mode - * @subdev: subdev exposing the FIMC processing block - * @vd_pad: fimc video capture node pad - * @sd_pads: fimc video processing block pads - * @ci_fmt: image format at the FIMC camera input (and the scaler output) - * @wb_fmt: image format at the FIMC ISP Writeback input - * @source_config: external image source related configuration structure - * @pending_buf_q: the pending buffer queue head - * @active_buf_q: the queue head of buffers scheduled in hardware - * @vbq: the capture am video buffer queue - * @active_buf_cnt: number of video buffers scheduled in hardware - * @buf_index: index for managing the output DMA buffers - * @frame_count: the frame counter for statistics - * @reqbufs_count: the number of buffers requested in REQBUFS ioctl - * @input_index: input (camera sensor) index - * @refcnt: driver's private reference counter - * @input: capture input type, grp_id of the attached subdev - * @user_subdev_api: true if subdevs are not configured by the host driver - */ -struct fimc_vid_cap { - struct fimc_ctx *ctx; - struct vb2_alloc_ctx *alloc_ctx; - struct video_device vfd; - struct v4l2_subdev subdev; - struct media_pad vd_pad; - struct media_pad sd_pads[FIMC_SD_PADS_NUM]; - struct v4l2_mbus_framefmt ci_fmt; - struct v4l2_mbus_framefmt wb_fmt; - struct fimc_source_info source_config; - struct list_head pending_buf_q; - struct list_head active_buf_q; - struct vb2_queue vbq; - int active_buf_cnt; - int buf_index; - unsigned int frame_count; - unsigned int reqbufs_count; - int input_index; - int refcnt; - u32 input; - bool user_subdev_api; -}; - -/** - * struct fimc_pix_limit - image pixel size limits in various IP configurations - * - * @scaler_en_w: max input pixel width when the scaler is enabled - * @scaler_dis_w: max input pixel width when the scaler is disabled - * @in_rot_en_h: max input width with the input rotator is on - * @in_rot_dis_w: max input width with the input rotator is off - * @out_rot_en_w: max output width with the output rotator on - * @out_rot_dis_w: max output width with the output rotator off - */ -struct fimc_pix_limit { - u16 scaler_en_w; - u16 scaler_dis_w; - u16 in_rot_en_h; - u16 in_rot_dis_w; - u16 out_rot_en_w; - u16 out_rot_dis_w; -}; - -/** - * struct fimc_variant - FIMC device variant information - * @has_inp_rot: set if has input rotator - * @has_out_rot: set if has output rotator - * @has_mainscaler_ext: 1 if extended mainscaler ratios in CIEXTEN register - * are present in this IP revision - * @has_cam_if: set if this instance has a camera input interface - * @has_isp_wb: set if this instance has ISP writeback input - * @pix_limit: pixel size constraints for the scaler - * @min_inp_pixsize: minimum input pixel size - * @min_out_pixsize: minimum output pixel size - * @hor_offs_align: horizontal pixel offset aligment - * @min_vsize_align: minimum vertical pixel size alignment - */ -struct fimc_variant { - unsigned int has_inp_rot:1; - unsigned int has_out_rot:1; - unsigned int has_mainscaler_ext:1; - unsigned int has_cam_if:1; - unsigned int has_isp_wb:1; - const struct fimc_pix_limit *pix_limit; - u16 min_inp_pixsize; - u16 min_out_pixsize; - u16 hor_offs_align; - u16 min_vsize_align; -}; - -/** - * struct fimc_drvdata - per device type driver data - * @variant: variant information for this device - * @num_entities: number of fimc instances available in a SoC - * @lclk_frequency: local bus clock frequency - * @cistatus2: 1 if the FIMC IPs have CISTATUS2 register - * @dma_pix_hoff: the horizontal DMA offset unit: 1 - pixels, 0 - bytes - * @alpha_color: 1 if alpha color component is supported - * @out_buf_count: maximum number of output DMA buffers supported - */ -struct fimc_drvdata { - const struct fimc_variant *variant[FIMC_MAX_DEVS]; - int num_entities; - unsigned long lclk_frequency; - /* Fields common to all FIMC IP instances */ - u8 cistatus2; - u8 dma_pix_hoff; - u8 alpha_color; - u8 out_buf_count; -}; - -#define fimc_get_drvdata(_pdev) \ - ((struct fimc_drvdata *) platform_get_device_id(_pdev)->driver_data) - -struct fimc_ctx; - -/** - * struct fimc_dev - abstraction for FIMC entity - * @slock: the spinlock protecting this data structure - * @lock: the mutex protecting this data structure - * @pdev: pointer to the FIMC platform device - * @pdata: pointer to the device platform data - * @sysreg: pointer to the SYSREG regmap - * @variant: the IP variant information - * @id: FIMC device index (0..FIMC_MAX_DEVS) - * @clock: clocks required for FIMC operation - * @regs: the mapped hardware registers - * @irq_queue: interrupt handler waitqueue - * @v4l2_dev: root v4l2_device - * @m2m: memory-to-memory V4L2 device information - * @vid_cap: camera capture device information - * @state: flags used to synchronize m2m and capture mode operation - * @alloc_ctx: videobuf2 memory allocator context - * @pipeline: fimc video capture pipeline data structure - */ -struct fimc_dev { - spinlock_t slock; - struct mutex lock; - struct platform_device *pdev; - struct s5p_platform_fimc *pdata; - struct regmap *sysreg; - const struct fimc_variant *variant; - const struct fimc_drvdata *drv_data; - u16 id; - struct clk *clock[MAX_FIMC_CLOCKS]; - void __iomem *regs; - wait_queue_head_t irq_queue; - struct v4l2_device *v4l2_dev; - struct fimc_m2m_device m2m; - struct fimc_vid_cap vid_cap; - unsigned long state; - struct vb2_alloc_ctx *alloc_ctx; - struct fimc_pipeline pipeline; - const struct fimc_pipeline_ops *pipeline_ops; -}; - -/** - * struct fimc_ctrls - v4l2 controls structure - * @handler: the control handler - * @colorfx: image effect control - * @colorfx_cbcr: Cb/Cr coefficients control - * @rotate: image rotation control - * @hflip: horizontal flip control - * @vflip: vertical flip control - * @alpha: RGB alpha control - * @ready: true if @handler is initialized - */ -struct fimc_ctrls { - struct v4l2_ctrl_handler handler; - struct { - struct v4l2_ctrl *colorfx; - struct v4l2_ctrl *colorfx_cbcr; - }; - struct v4l2_ctrl *rotate; - struct v4l2_ctrl *hflip; - struct v4l2_ctrl *vflip; - struct v4l2_ctrl *alpha; - bool ready; -}; - -/** - * fimc_ctx - the device context data - * @s_frame: source frame properties - * @d_frame: destination frame properties - * @out_order_1p: output 1-plane YCBCR order - * @out_order_2p: output 2-plane YCBCR order - * @in_order_1p input 1-plane YCBCR order - * @in_order_2p: input 2-plane YCBCR order - * @in_path: input mode (DMA or camera) - * @out_path: output mode (DMA or FIFO) - * @scaler: image scaler properties - * @effect: image effect - * @rotation: image clockwise rotation in degrees - * @hflip: indicates image horizontal flip if set - * @vflip: indicates image vertical flip if set - * @flags: additional flags for image conversion - * @state: flags to keep track of user configuration - * @fimc_dev: the FIMC device this context applies to - * @m2m_ctx: memory-to-memory device context - * @fh: v4l2 file handle - * @ctrls: v4l2 controls structure - */ -struct fimc_ctx { - struct fimc_frame s_frame; - struct fimc_frame d_frame; - u32 out_order_1p; - u32 out_order_2p; - u32 in_order_1p; - u32 in_order_2p; - enum fimc_datapath in_path; - enum fimc_datapath out_path; - struct fimc_scaler scaler; - struct fimc_effect effect; - int rotation; - unsigned int hflip:1; - unsigned int vflip:1; - u32 flags; - u32 state; - struct fimc_dev *fimc_dev; - struct v4l2_m2m_ctx *m2m_ctx; - struct v4l2_fh fh; - struct fimc_ctrls ctrls; -}; - -#define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh) - -static inline void set_frame_bounds(struct fimc_frame *f, u32 width, u32 height) -{ - f->o_width = width; - f->o_height = height; - f->f_width = width; - f->f_height = height; -} - -static inline void set_frame_crop(struct fimc_frame *f, - u32 left, u32 top, u32 width, u32 height) -{ - f->offs_h = left; - f->offs_v = top; - f->width = width; - f->height = height; -} - -static inline u32 fimc_get_format_depth(struct fimc_fmt *ff) -{ - u32 i, depth = 0; - - if (ff != NULL) - for (i = 0; i < ff->colplanes; i++) - depth += ff->depth[i]; - return depth; -} - -static inline bool fimc_capture_active(struct fimc_dev *fimc) -{ - unsigned long flags; - bool ret; - - spin_lock_irqsave(&fimc->slock, flags); - ret = !!(fimc->state & (1 << ST_CAPT_RUN) || - fimc->state & (1 << ST_CAPT_PEND)); - spin_unlock_irqrestore(&fimc->slock, flags); - return ret; -} - -static inline void fimc_ctx_state_set(u32 state, struct fimc_ctx *ctx) -{ - unsigned long flags; - - spin_lock_irqsave(&ctx->fimc_dev->slock, flags); - ctx->state |= state; - spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags); -} - -static inline bool fimc_ctx_state_is_set(u32 mask, struct fimc_ctx *ctx) -{ - unsigned long flags; - bool ret; - - spin_lock_irqsave(&ctx->fimc_dev->slock, flags); - ret = (ctx->state & mask) == mask; - spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags); - return ret; -} - -static inline int tiled_fmt(struct fimc_fmt *fmt) -{ - return fmt->fourcc == V4L2_PIX_FMT_NV12MT; -} - -static inline bool fimc_jpeg_fourcc(u32 pixelformat) -{ - return (pixelformat == V4L2_PIX_FMT_JPEG || - pixelformat == V4L2_PIX_FMT_S5C_UYVY_JPG); -} - -static inline bool fimc_user_defined_mbus_fmt(u32 code) -{ - return (code == V4L2_MBUS_FMT_JPEG_1X8 || - code == V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8); -} - -/* Return the alpha component bit mask */ -static inline int fimc_get_alpha_mask(struct fimc_fmt *fmt) -{ - switch (fmt->color) { - case FIMC_FMT_RGB444: return 0x0f; - case FIMC_FMT_RGB555: return 0x01; - case FIMC_FMT_RGB888: return 0xff; - default: return 0; - }; -} - -static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx, - enum v4l2_buf_type type) -{ - struct fimc_frame *frame; - - if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) { - if (fimc_ctx_state_is_set(FIMC_CTX_M2M, ctx)) - frame = &ctx->s_frame; - else - return ERR_PTR(-EINVAL); - } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) { - frame = &ctx->d_frame; - } else { - v4l2_err(ctx->fimc_dev->v4l2_dev, - "Wrong buffer/video queue type (%d)\n", type); - return ERR_PTR(-EINVAL); - } - - return frame; -} - -/* -----------------------------------------------------*/ -/* fimc-core.c */ -int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f); -int fimc_ctrls_create(struct fimc_ctx *ctx); -void fimc_ctrls_delete(struct fimc_ctx *ctx); -void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active); -void fimc_alpha_ctrl_update(struct fimc_ctx *ctx); -void __fimc_get_format(struct fimc_frame *frame, struct v4l2_format *f); -void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, - struct v4l2_pix_format_mplane *pix); -struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code, - unsigned int mask, int index); -struct fimc_fmt *fimc_get_format(unsigned int index); - -int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh, - int dw, int dh, int rotation); -int fimc_set_scaler_info(struct fimc_ctx *ctx); -int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags); -int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, - struct fimc_frame *frame, struct fimc_addr *paddr); -void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f); -void fimc_set_yuv_order(struct fimc_ctx *ctx); -void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf); - -int fimc_register_m2m_device(struct fimc_dev *fimc, - struct v4l2_device *v4l2_dev); -void fimc_unregister_m2m_device(struct fimc_dev *fimc); -int fimc_register_driver(void); -void fimc_unregister_driver(void); - -/* -----------------------------------------------------*/ -/* fimc-m2m.c */ -void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state); - -/* -----------------------------------------------------*/ -/* fimc-capture.c */ -int fimc_initialize_capture_subdev(struct fimc_dev *fimc); -void fimc_unregister_capture_subdev(struct fimc_dev *fimc); -int fimc_capture_ctrls_create(struct fimc_dev *fimc); -void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification, - void *arg); -int fimc_capture_suspend(struct fimc_dev *fimc); -int fimc_capture_resume(struct fimc_dev *fimc); - -/* - * Buffer list manipulation functions. Must be called with fimc.slock held. - */ - -/** - * fimc_active_queue_add - add buffer to the capture active buffers queue - * @buf: buffer to add to the active buffers list - */ -static inline void fimc_active_queue_add(struct fimc_vid_cap *vid_cap, - struct fimc_vid_buffer *buf) -{ - list_add_tail(&buf->list, &vid_cap->active_buf_q); - vid_cap->active_buf_cnt++; -} - -/** - * fimc_active_queue_pop - pop buffer from the capture active buffers queue - * - * The caller must assure the active_buf_q list is not empty. - */ -static inline struct fimc_vid_buffer *fimc_active_queue_pop( - struct fimc_vid_cap *vid_cap) -{ - struct fimc_vid_buffer *buf; - buf = list_entry(vid_cap->active_buf_q.next, - struct fimc_vid_buffer, list); - list_del(&buf->list); - vid_cap->active_buf_cnt--; - return buf; -} - -/** - * fimc_pending_queue_add - add buffer to the capture pending buffers queue - * @buf: buffer to add to the pending buffers list - */ -static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap, - struct fimc_vid_buffer *buf) -{ - list_add_tail(&buf->list, &vid_cap->pending_buf_q); -} - -/** - * fimc_pending_queue_pop - pop buffer from the capture pending buffers queue - * - * The caller must assure the pending_buf_q list is not empty. - */ -static inline struct fimc_vid_buffer *fimc_pending_queue_pop( - struct fimc_vid_cap *vid_cap) -{ - struct fimc_vid_buffer *buf; - buf = list_entry(vid_cap->pending_buf_q.next, - struct fimc_vid_buffer, list); - list_del(&buf->list); - return buf; -} - -#endif /* FIMC_CORE_H_ */ diff --git a/drivers/media/platform/s5p-fimc/fimc-lite-reg.c b/drivers/media/platform/s5p-fimc/fimc-lite-reg.c deleted file mode 100644 index f0af0754a7b4..000000000000 --- a/drivers/media/platform/s5p-fimc/fimc-lite-reg.c +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Register interface file for EXYNOS FIMC-LITE (camera interface) driver - * - * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include -#include -#include - -#include "fimc-lite-reg.h" -#include "fimc-lite.h" -#include "fimc-core.h" - -#define FLITE_RESET_TIMEOUT 50 /* in ms */ - -void flite_hw_reset(struct fimc_lite *dev) -{ - unsigned long end = jiffies + msecs_to_jiffies(FLITE_RESET_TIMEOUT); - u32 cfg; - - cfg = readl(dev->regs + FLITE_REG_CIGCTRL); - cfg |= FLITE_REG_CIGCTRL_SWRST_REQ; - writel(cfg, dev->regs + FLITE_REG_CIGCTRL); - - while (time_is_after_jiffies(end)) { - cfg = readl(dev->regs + FLITE_REG_CIGCTRL); - if (cfg & FLITE_REG_CIGCTRL_SWRST_RDY) - break; - usleep_range(1000, 5000); - } - - cfg |= FLITE_REG_CIGCTRL_SWRST; - writel(cfg, dev->regs + FLITE_REG_CIGCTRL); -} - -void flite_hw_clear_pending_irq(struct fimc_lite *dev) -{ - u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS); - cfg &= ~FLITE_REG_CISTATUS_IRQ_CAM; - writel(cfg, dev->regs + FLITE_REG_CISTATUS); -} - -u32 flite_hw_get_interrupt_source(struct fimc_lite *dev) -{ - u32 intsrc = readl(dev->regs + FLITE_REG_CISTATUS); - return intsrc & FLITE_REG_CISTATUS_IRQ_MASK; -} - -void flite_hw_clear_last_capture_end(struct fimc_lite *dev) -{ - - u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS2); - cfg &= ~FLITE_REG_CISTATUS2_LASTCAPEND; - writel(cfg, dev->regs + FLITE_REG_CISTATUS2); -} - -void flite_hw_set_interrupt_mask(struct fimc_lite *dev) -{ - u32 cfg, intsrc; - - /* Select interrupts to be enabled for each output mode */ - if (atomic_read(&dev->out_path) == FIMC_IO_DMA) { - intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN | - FLITE_REG_CIGCTRL_IRQ_LASTEN | - FLITE_REG_CIGCTRL_IRQ_STARTEN; - } else { - /* An output to the FIMC-IS */ - intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN | - FLITE_REG_CIGCTRL_IRQ_LASTEN; - } - - cfg = readl(dev->regs + FLITE_REG_CIGCTRL); - cfg |= FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK; - cfg &= ~intsrc; - writel(cfg, dev->regs + FLITE_REG_CIGCTRL); -} - -void flite_hw_capture_start(struct fimc_lite *dev) -{ - u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT); - cfg |= FLITE_REG_CIIMGCPT_IMGCPTEN; - writel(cfg, dev->regs + FLITE_REG_CIIMGCPT); -} - -void flite_hw_capture_stop(struct fimc_lite *dev) -{ - u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT); - cfg &= ~FLITE_REG_CIIMGCPT_IMGCPTEN; - writel(cfg, dev->regs + FLITE_REG_CIIMGCPT); -} - -/* - * Test pattern (color bars) enable/disable. External sensor - * pixel clock must be active for the test pattern to work. - */ -void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on) -{ - u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL); - if (on) - cfg |= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR; - else - cfg &= ~FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR; - writel(cfg, dev->regs + FLITE_REG_CIGCTRL); -} - -static const u32 src_pixfmt_map[8][3] = { - { V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR, - FLITE_REG_CIGCTRL_YUV422_1P }, - { V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB, - FLITE_REG_CIGCTRL_YUV422_1P }, - { V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY, - FLITE_REG_CIGCTRL_YUV422_1P }, - { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY, - FLITE_REG_CIGCTRL_YUV422_1P }, - { V4L2_MBUS_FMT_SGRBG8_1X8, 0, FLITE_REG_CIGCTRL_RAW8 }, - { V4L2_MBUS_FMT_SGRBG10_1X10, 0, FLITE_REG_CIGCTRL_RAW10 }, - { V4L2_MBUS_FMT_SGRBG12_1X12, 0, FLITE_REG_CIGCTRL_RAW12 }, - { V4L2_MBUS_FMT_JPEG_1X8, 0, FLITE_REG_CIGCTRL_USER(1) }, -}; - -/* Set camera input pixel format and resolution */ -void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f) -{ - enum v4l2_mbus_pixelcode pixelcode = dev->fmt->mbus_code; - unsigned int i = ARRAY_SIZE(src_pixfmt_map); - u32 cfg; - - while (i-- >= 0) { - if (src_pixfmt_map[i][0] == pixelcode) - break; - } - - if (i == 0 && src_pixfmt_map[i][0] != pixelcode) { - v4l2_err(&dev->vfd, - "Unsupported pixel code, falling back to %#08x\n", - src_pixfmt_map[i][0]); - } - - cfg = readl(dev->regs + FLITE_REG_CIGCTRL); - cfg &= ~FLITE_REG_CIGCTRL_FMT_MASK; - cfg |= src_pixfmt_map[i][2]; - writel(cfg, dev->regs + FLITE_REG_CIGCTRL); - - cfg = readl(dev->regs + FLITE_REG_CISRCSIZE); - cfg &= ~(FLITE_REG_CISRCSIZE_ORDER422_MASK | - FLITE_REG_CISRCSIZE_SIZE_CAM_MASK); - cfg |= (f->f_width << 16) | f->f_height; - cfg |= src_pixfmt_map[i][1]; - writel(cfg, dev->regs + FLITE_REG_CISRCSIZE); -} - -/* Set the camera host input window offsets (cropping) */ -void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f) -{ - u32 hoff2, voff2; - u32 cfg; - - cfg = readl(dev->regs + FLITE_REG_CIWDOFST); - cfg &= ~FLITE_REG_CIWDOFST_OFST_MASK; - cfg |= (f->rect.left << 16) | f->rect.top; - cfg |= FLITE_REG_CIWDOFST_WINOFSEN; - writel(cfg, dev->regs + FLITE_REG_CIWDOFST); - - hoff2 = f->f_width - f->rect.width - f->rect.left; - voff2 = f->f_height - f->rect.height - f->rect.top; - - cfg = (hoff2 << 16) | voff2; - writel(cfg, dev->regs + FLITE_REG_CIWDOFST2); -} - -/* Select camera port (A, B) */ -static void flite_hw_set_camera_port(struct fimc_lite *dev, int id) -{ - u32 cfg = readl(dev->regs + FLITE_REG_CIGENERAL); - if (id == 0) - cfg &= ~FLITE_REG_CIGENERAL_CAM_B; - else - cfg |= FLITE_REG_CIGENERAL_CAM_B; - writel(cfg, dev->regs + FLITE_REG_CIGENERAL); -} - -/* Select serial or parallel bus, camera port (A,B) and set signals polarity */ -void flite_hw_set_camera_bus(struct fimc_lite *dev, - struct fimc_source_info *si) -{ - u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL); - unsigned int flags = si->flags; - - if (si->sensor_bus_type != FIMC_BUS_TYPE_MIPI_CSI2) { - cfg &= ~(FLITE_REG_CIGCTRL_SELCAM_MIPI | - FLITE_REG_CIGCTRL_INVPOLPCLK | - FLITE_REG_CIGCTRL_INVPOLVSYNC | - FLITE_REG_CIGCTRL_INVPOLHREF); - - if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) - cfg |= FLITE_REG_CIGCTRL_INVPOLPCLK; - - if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - cfg |= FLITE_REG_CIGCTRL_INVPOLVSYNC; - - if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - cfg |= FLITE_REG_CIGCTRL_INVPOLHREF; - } else { - cfg |= FLITE_REG_CIGCTRL_SELCAM_MIPI; - } - - writel(cfg, dev->regs + FLITE_REG_CIGCTRL); - - flite_hw_set_camera_port(dev, si->mux_id); -} - -static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f) -{ - static const u32 pixcode[4][2] = { - { V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR }, - { V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CIODMAFMT_YCRYCB }, - { V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CIODMAFMT_CBYCRY }, - { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY }, - }; - u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT); - unsigned int i = ARRAY_SIZE(pixcode); - - while (i-- >= 0) - if (pixcode[i][0] == dev->fmt->mbus_code) - break; - cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK; - writel(cfg | pixcode[i][1], dev->regs + FLITE_REG_CIODMAFMT); -} - -void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f) -{ - u32 cfg; - - /* Maximum output pixel size */ - cfg = readl(dev->regs + FLITE_REG_CIOCAN); - cfg &= ~FLITE_REG_CIOCAN_MASK; - cfg = (f->f_height << 16) | f->f_width; - writel(cfg, dev->regs + FLITE_REG_CIOCAN); - - /* DMA offsets */ - cfg = readl(dev->regs + FLITE_REG_CIOOFF); - cfg &= ~FLITE_REG_CIOOFF_MASK; - cfg |= (f->rect.top << 16) | f->rect.left; - writel(cfg, dev->regs + FLITE_REG_CIOOFF); -} - -/* Enable/disable output DMA, set output pixel size and offsets (composition) */ -void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f, - bool enable) -{ - u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL); - - if (!enable) { - cfg |= FLITE_REG_CIGCTRL_ODMA_DISABLE; - writel(cfg, dev->regs + FLITE_REG_CIGCTRL); - return; - } - - cfg &= ~FLITE_REG_CIGCTRL_ODMA_DISABLE; - writel(cfg, dev->regs + FLITE_REG_CIGCTRL); - - flite_hw_set_out_order(dev, f); - flite_hw_set_dma_window(dev, f); -} - -void flite_hw_dump_regs(struct fimc_lite *dev, const char *label) -{ - struct { - u32 offset; - const char * const name; - } registers[] = { - { 0x00, "CISRCSIZE" }, - { 0x04, "CIGCTRL" }, - { 0x08, "CIIMGCPT" }, - { 0x0c, "CICPTSEQ" }, - { 0x10, "CIWDOFST" }, - { 0x14, "CIWDOFST2" }, - { 0x18, "CIODMAFMT" }, - { 0x20, "CIOCAN" }, - { 0x24, "CIOOFF" }, - { 0x30, "CIOSA" }, - { 0x40, "CISTATUS" }, - { 0x44, "CISTATUS2" }, - { 0xf0, "CITHOLD" }, - { 0xfc, "CIGENERAL" }, - }; - u32 i; - - v4l2_info(&dev->subdev, "--- %s ---\n", label); - - for (i = 0; i < ARRAY_SIZE(registers); i++) { - u32 cfg = readl(dev->regs + registers[i].offset); - v4l2_info(&dev->subdev, "%9s: 0x%08x\n", - registers[i].name, cfg); - } -} diff --git a/drivers/media/platform/s5p-fimc/fimc-lite-reg.h b/drivers/media/platform/s5p-fimc/fimc-lite-reg.h deleted file mode 100644 index 0e345844c13a..000000000000 --- a/drivers/media/platform/s5p-fimc/fimc-lite-reg.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef FIMC_LITE_REG_H_ -#define FIMC_LITE_REG_H_ - -#include "fimc-lite.h" - -/* Camera Source size */ -#define FLITE_REG_CISRCSIZE 0x00 -#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR (0 << 14) -#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB (1 << 14) -#define FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY (2 << 14) -#define FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY (3 << 14) -#define FLITE_REG_CISRCSIZE_ORDER422_MASK (0x3 << 14) -#define FLITE_REG_CISRCSIZE_SIZE_CAM_MASK (0x3fff << 16 | 0x3fff) - -/* Global control */ -#define FLITE_REG_CIGCTRL 0x04 -#define FLITE_REG_CIGCTRL_YUV422_1P (0x1e << 24) -#define FLITE_REG_CIGCTRL_RAW8 (0x2a << 24) -#define FLITE_REG_CIGCTRL_RAW10 (0x2b << 24) -#define FLITE_REG_CIGCTRL_RAW12 (0x2c << 24) -#define FLITE_REG_CIGCTRL_RAW14 (0x2d << 24) -/* User defined formats. x = 0...15 */ -#define FLITE_REG_CIGCTRL_USER(x) ((0x30 + x - 1) << 24) -#define FLITE_REG_CIGCTRL_FMT_MASK (0x3f << 24) -#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE (1 << 21) -#define FLITE_REG_CIGCTRL_ODMA_DISABLE (1 << 20) -#define FLITE_REG_CIGCTRL_SWRST_REQ (1 << 19) -#define FLITE_REG_CIGCTRL_SWRST_RDY (1 << 18) -#define FLITE_REG_CIGCTRL_SWRST (1 << 17) -#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR (1 << 15) -#define FLITE_REG_CIGCTRL_INVPOLPCLK (1 << 14) -#define FLITE_REG_CIGCTRL_INVPOLVSYNC (1 << 13) -#define FLITE_REG_CIGCTRL_INVPOLHREF (1 << 12) -/* Interrupts mask bits (1 disables an interrupt) */ -#define FLITE_REG_CIGCTRL_IRQ_LASTEN (1 << 8) -#define FLITE_REG_CIGCTRL_IRQ_ENDEN (1 << 7) -#define FLITE_REG_CIGCTRL_IRQ_STARTEN (1 << 6) -#define FLITE_REG_CIGCTRL_IRQ_OVFEN (1 << 5) -#define FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK (0xf << 5) -#define FLITE_REG_CIGCTRL_SELCAM_MIPI (1 << 3) - -/* Image Capture Enable */ -#define FLITE_REG_CIIMGCPT 0x08 -#define FLITE_REG_CIIMGCPT_IMGCPTEN (1 << 31) -#define FLITE_REG_CIIMGCPT_CPT_FREN (1 << 25) -#define FLITE_REG_CIIMGCPT_CPT_MOD_FRCNT (1 << 18) -#define FLITE_REG_CIIMGCPT_CPT_MOD_FREN (0 << 18) - -/* Capture Sequence */ -#define FLITE_REG_CICPTSEQ 0x0c - -/* Camera Window Offset */ -#define FLITE_REG_CIWDOFST 0x10 -#define FLITE_REG_CIWDOFST_WINOFSEN (1 << 31) -#define FLITE_REG_CIWDOFST_CLROVIY (1 << 31) -#define FLITE_REG_CIWDOFST_CLROVFICB (1 << 15) -#define FLITE_REG_CIWDOFST_CLROVFICR (1 << 14) -#define FLITE_REG_CIWDOFST_OFST_MASK ((0x1fff << 16) | 0x1fff) - -/* Camera Window Offset2 */ -#define FLITE_REG_CIWDOFST2 0x14 - -/* Camera Output DMA Format */ -#define FLITE_REG_CIODMAFMT 0x18 -#define FLITE_REG_CIODMAFMT_RAW_CON (1 << 15) -#define FLITE_REG_CIODMAFMT_PACK12 (1 << 14) -#define FLITE_REG_CIODMAFMT_CRYCBY (0 << 4) -#define FLITE_REG_CIODMAFMT_CBYCRY (1 << 4) -#define FLITE_REG_CIODMAFMT_YCRYCB (2 << 4) -#define FLITE_REG_CIODMAFMT_YCBYCR (3 << 4) -#define FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK (0x3 << 4) - -/* Camera Output Canvas */ -#define FLITE_REG_CIOCAN 0x20 -#define FLITE_REG_CIOCAN_MASK ((0x3fff << 16) | 0x3fff) - -/* Camera Output DMA Offset */ -#define FLITE_REG_CIOOFF 0x24 -#define FLITE_REG_CIOOFF_MASK ((0x3fff << 16) | 0x3fff) - -/* Camera Output DMA Start Address */ -#define FLITE_REG_CIOSA 0x30 - -/* Camera Status */ -#define FLITE_REG_CISTATUS 0x40 -#define FLITE_REG_CISTATUS_MIPI_VVALID (1 << 22) -#define FLITE_REG_CISTATUS_MIPI_HVALID (1 << 21) -#define FLITE_REG_CISTATUS_MIPI_DVALID (1 << 20) -#define FLITE_REG_CISTATUS_ITU_VSYNC (1 << 14) -#define FLITE_REG_CISTATUS_ITU_HREFF (1 << 13) -#define FLITE_REG_CISTATUS_OVFIY (1 << 10) -#define FLITE_REG_CISTATUS_OVFICB (1 << 9) -#define FLITE_REG_CISTATUS_OVFICR (1 << 8) -#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW (1 << 7) -#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND (1 << 6) -#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART (1 << 5) -#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND (1 << 4) -#define FLITE_REG_CISTATUS_IRQ_CAM (1 << 0) -#define FLITE_REG_CISTATUS_IRQ_MASK (0xf << 4) - -/* Camera Status2 */ -#define FLITE_REG_CISTATUS2 0x44 -#define FLITE_REG_CISTATUS2_LASTCAPEND (1 << 1) -#define FLITE_REG_CISTATUS2_FRMEND (1 << 0) - -/* Qos Threshold */ -#define FLITE_REG_CITHOLD 0xf0 -#define FLITE_REG_CITHOLD_W_QOS_EN (1 << 30) - -/* Camera General Purpose */ -#define FLITE_REG_CIGENERAL 0xfc -/* b0: 1 - camera B, 0 - camera A */ -#define FLITE_REG_CIGENERAL_CAM_B (1 << 0) - -/* ---------------------------------------------------------------------------- - * Function declarations - */ -void flite_hw_reset(struct fimc_lite *dev); -void flite_hw_clear_pending_irq(struct fimc_lite *dev); -u32 flite_hw_get_interrupt_source(struct fimc_lite *dev); -void flite_hw_clear_last_capture_end(struct fimc_lite *dev); -void flite_hw_set_interrupt_mask(struct fimc_lite *dev); -void flite_hw_capture_start(struct fimc_lite *dev); -void flite_hw_capture_stop(struct fimc_lite *dev); -void flite_hw_set_camera_bus(struct fimc_lite *dev, - struct fimc_source_info *s_info); -void flite_hw_set_camera_polarity(struct fimc_lite *dev, - struct fimc_source_info *cam); -void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f); -void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f); - -void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f, - bool enable); -void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f); -void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on); -void flite_hw_dump_regs(struct fimc_lite *dev, const char *label); - -static inline void flite_hw_set_output_addr(struct fimc_lite *dev, u32 paddr) -{ - writel(paddr, dev->regs + FLITE_REG_CIOSA); -} -#endif /* FIMC_LITE_REG_H */ diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c deleted file mode 100644 index a37282e27cb0..000000000000 --- a/drivers/media/platform/s5p-fimc/fimc-lite.c +++ /dev/null @@ -1,1626 +0,0 @@ -/* - * Samsung EXYNOS FIMC-LITE (camera host interface) driver -* - * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "fimc-mdevice.h" -#include "fimc-lite.h" -#include "fimc-lite-reg.h" - -static int debug; -module_param(debug, int, 0644); - -static const struct fimc_fmt fimc_lite_formats[] = { - { - .name = "YUV 4:2:2 packed, YCbYCr", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = { 16 }, - .color = FIMC_FMT_YCBYCR422, - .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, - }, { - .name = "YUV 4:2:2 packed, CbYCrY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = { 16 }, - .color = FIMC_FMT_CBYCRY422, - .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, - }, { - .name = "YUV 4:2:2 packed, CrYCbY", - .fourcc = V4L2_PIX_FMT_VYUY, - .depth = { 16 }, - .color = FIMC_FMT_CRYCBY422, - .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8, - }, { - .name = "YUV 4:2:2 packed, YCrYCb", - .fourcc = V4L2_PIX_FMT_YVYU, - .depth = { 16 }, - .color = FIMC_FMT_YCRYCB422, - .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8, - }, { - .name = "RAW8 (GRBG)", - .fourcc = V4L2_PIX_FMT_SGRBG8, - .depth = { 8 }, - .color = FIMC_FMT_RAW8, - .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8, - }, { - .name = "RAW10 (GRBG)", - .fourcc = V4L2_PIX_FMT_SGRBG10, - .depth = { 10 }, - .color = FIMC_FMT_RAW10, - .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10, - }, { - .name = "RAW12 (GRBG)", - .fourcc = V4L2_PIX_FMT_SGRBG12, - .depth = { 12 }, - .color = FIMC_FMT_RAW12, - .memplanes = 1, - .mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12, - }, -}; - -/** - * fimc_lite_find_format - lookup fimc color format by fourcc or media bus code - * @pixelformat: fourcc to match, ignored if null - * @mbus_code: media bus code to match, ignored if null - * @index: index to the fimc_lite_formats array, ignored if negative - */ -static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat, - const u32 *mbus_code, int index) -{ - const struct fimc_fmt *fmt, *def_fmt = NULL; - unsigned int i; - int id = 0; - - if (index >= (int)ARRAY_SIZE(fimc_lite_formats)) - return NULL; - - for (i = 0; i < ARRAY_SIZE(fimc_lite_formats); ++i) { - fmt = &fimc_lite_formats[i]; - if (pixelformat && fmt->fourcc == *pixelformat) - return fmt; - if (mbus_code && fmt->mbus_code == *mbus_code) - return fmt; - if (index == id) - def_fmt = fmt; - id++; - } - return def_fmt; -} - -static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output) -{ - struct fimc_pipeline *pipeline = &fimc->pipeline; - struct v4l2_subdev *sensor; - struct fimc_sensor_info *si; - unsigned long flags; - - sensor = isp_output ? fimc->sensor : pipeline->subdevs[IDX_SENSOR]; - - if (sensor == NULL) - return -ENXIO; - - if (fimc->fmt == NULL) - return -EINVAL; - - /* Get sensor configuration data from the sensor subdev */ - si = v4l2_get_subdev_hostdata(sensor); - spin_lock_irqsave(&fimc->slock, flags); - - flite_hw_set_camera_bus(fimc, &si->pdata); - flite_hw_set_source_format(fimc, &fimc->inp_frame); - flite_hw_set_window_offset(fimc, &fimc->inp_frame); - flite_hw_set_output_dma(fimc, &fimc->out_frame, !isp_output); - flite_hw_set_interrupt_mask(fimc); - flite_hw_set_test_pattern(fimc, fimc->test_pattern->val); - - if (debug > 0) - flite_hw_dump_regs(fimc, __func__); - - spin_unlock_irqrestore(&fimc->slock, flags); - return 0; -} - -/* - * Reinitialize the driver so it is ready to start the streaming again. - * Set fimc->state to indicate stream off and the hardware shut down state. - * If not suspending (@suspend is false), return any buffers to videobuf2. - * Otherwise put any owned buffers onto the pending buffers queue, so they - * can be re-spun when the device is being resumed. Also perform FIMC - * software reset and disable streaming on the whole pipeline if required. - */ -static int fimc_lite_reinit(struct fimc_lite *fimc, bool suspend) -{ - struct flite_buffer *buf; - unsigned long flags; - bool streaming; - - spin_lock_irqsave(&fimc->slock, flags); - streaming = fimc->state & (1 << ST_SENSOR_STREAM); - - fimc->state &= ~(1 << ST_FLITE_RUN | 1 << ST_FLITE_OFF | - 1 << ST_FLITE_STREAM | 1 << ST_SENSOR_STREAM); - if (suspend) - fimc->state |= (1 << ST_FLITE_SUSPENDED); - else - fimc->state &= ~(1 << ST_FLITE_PENDING | - 1 << ST_FLITE_SUSPENDED); - - /* Release unused buffers */ - while (!suspend && !list_empty(&fimc->pending_buf_q)) { - buf = fimc_lite_pending_queue_pop(fimc); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); - } - /* If suspending put unused buffers onto pending queue */ - while (!list_empty(&fimc->active_buf_q)) { - buf = fimc_lite_active_queue_pop(fimc); - if (suspend) - fimc_lite_pending_queue_add(fimc, buf); - else - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); - } - - spin_unlock_irqrestore(&fimc->slock, flags); - - flite_hw_reset(fimc); - - if (!streaming) - return 0; - - return fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 0); -} - -static int fimc_lite_stop_capture(struct fimc_lite *fimc, bool suspend) -{ - unsigned long flags; - - if (!fimc_lite_active(fimc)) - return 0; - - spin_lock_irqsave(&fimc->slock, flags); - set_bit(ST_FLITE_OFF, &fimc->state); - flite_hw_capture_stop(fimc); - spin_unlock_irqrestore(&fimc->slock, flags); - - wait_event_timeout(fimc->irq_queue, - !test_bit(ST_FLITE_OFF, &fimc->state), - (2*HZ/10)); /* 200 ms */ - - return fimc_lite_reinit(fimc, suspend); -} - -/* Must be called with fimc.slock spinlock held. */ -static void fimc_lite_config_update(struct fimc_lite *fimc) -{ - flite_hw_set_window_offset(fimc, &fimc->inp_frame); - flite_hw_set_dma_window(fimc, &fimc->out_frame); - flite_hw_set_test_pattern(fimc, fimc->test_pattern->val); - clear_bit(ST_FLITE_CONFIG, &fimc->state); -} - -static irqreturn_t flite_irq_handler(int irq, void *priv) -{ - struct fimc_lite *fimc = priv; - struct flite_buffer *vbuf; - unsigned long flags; - struct timeval *tv; - struct timespec ts; - u32 intsrc; - - spin_lock_irqsave(&fimc->slock, flags); - - intsrc = flite_hw_get_interrupt_source(fimc); - flite_hw_clear_pending_irq(fimc); - - if (test_and_clear_bit(ST_FLITE_OFF, &fimc->state)) { - wake_up(&fimc->irq_queue); - goto done; - } - - if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW) { - clear_bit(ST_FLITE_RUN, &fimc->state); - fimc->events.data_overflow++; - } - - if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND) { - flite_hw_clear_last_capture_end(fimc); - clear_bit(ST_FLITE_STREAM, &fimc->state); - wake_up(&fimc->irq_queue); - } - - if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) - goto done; - - if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) && - test_bit(ST_FLITE_RUN, &fimc->state) && - !list_empty(&fimc->active_buf_q) && - !list_empty(&fimc->pending_buf_q)) { - vbuf = fimc_lite_active_queue_pop(fimc); - ktime_get_ts(&ts); - tv = &vbuf->vb.v4l2_buf.timestamp; - tv->tv_sec = ts.tv_sec; - tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; - vbuf->vb.v4l2_buf.sequence = fimc->frame_count++; - vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE); - - vbuf = fimc_lite_pending_queue_pop(fimc); - flite_hw_set_output_addr(fimc, vbuf->paddr); - fimc_lite_active_queue_add(fimc, vbuf); - } - - if (test_bit(ST_FLITE_CONFIG, &fimc->state)) - fimc_lite_config_update(fimc); - - if (list_empty(&fimc->pending_buf_q)) { - flite_hw_capture_stop(fimc); - clear_bit(ST_FLITE_STREAM, &fimc->state); - } -done: - set_bit(ST_FLITE_RUN, &fimc->state); - spin_unlock_irqrestore(&fimc->slock, flags); - return IRQ_HANDLED; -} - -static int start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct fimc_lite *fimc = q->drv_priv; - int ret; - - fimc->frame_count = 0; - - ret = fimc_lite_hw_init(fimc, false); - if (ret) { - fimc_lite_reinit(fimc, false); - return ret; - } - - set_bit(ST_FLITE_PENDING, &fimc->state); - - if (!list_empty(&fimc->active_buf_q) && - !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) { - flite_hw_capture_start(fimc); - - if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state)) - fimc_pipeline_call(fimc, set_stream, - &fimc->pipeline, 1); - } - if (debug > 0) - flite_hw_dump_regs(fimc, __func__); - - return 0; -} - -static int stop_streaming(struct vb2_queue *q) -{ - struct fimc_lite *fimc = q->drv_priv; - - if (!fimc_lite_active(fimc)) - return -EINVAL; - - return fimc_lite_stop_capture(fimc, false); -} - -static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, - unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *allocators[]) -{ - const struct v4l2_pix_format_mplane *pixm = NULL; - struct fimc_lite *fimc = vq->drv_priv; - struct flite_frame *frame = &fimc->out_frame; - const struct fimc_fmt *fmt = fimc->fmt; - unsigned long wh; - int i; - - if (pfmt) { - pixm = &pfmt->fmt.pix_mp; - fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, -1); - wh = pixm->width * pixm->height; - } else { - wh = frame->f_width * frame->f_height; - } - - if (fmt == NULL) - return -EINVAL; - - *num_planes = fmt->memplanes; - - for (i = 0; i < fmt->memplanes; i++) { - unsigned int size = (wh * fmt->depth[i]) / 8; - if (pixm) - sizes[i] = max(size, pixm->plane_fmt[i].sizeimage); - else - sizes[i] = size; - allocators[i] = fimc->alloc_ctx; - } - - return 0; -} - -static int buffer_prepare(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct fimc_lite *fimc = vq->drv_priv; - int i; - - if (fimc->fmt == NULL) - return -EINVAL; - - for (i = 0; i < fimc->fmt->memplanes; i++) { - unsigned long size = fimc->payload[i]; - - if (vb2_plane_size(vb, i) < size) { - v4l2_err(&fimc->vfd, - "User buffer too small (%ld < %ld)\n", - vb2_plane_size(vb, i), size); - return -EINVAL; - } - vb2_set_plane_payload(vb, i, size); - } - - return 0; -} - -static void buffer_queue(struct vb2_buffer *vb) -{ - struct flite_buffer *buf - = container_of(vb, struct flite_buffer, vb); - struct fimc_lite *fimc = vb2_get_drv_priv(vb->vb2_queue); - unsigned long flags; - - spin_lock_irqsave(&fimc->slock, flags); - buf->paddr = vb2_dma_contig_plane_dma_addr(vb, 0); - - if (!test_bit(ST_FLITE_SUSPENDED, &fimc->state) && - !test_bit(ST_FLITE_STREAM, &fimc->state) && - list_empty(&fimc->active_buf_q)) { - flite_hw_set_output_addr(fimc, buf->paddr); - fimc_lite_active_queue_add(fimc, buf); - } else { - fimc_lite_pending_queue_add(fimc, buf); - } - - if (vb2_is_streaming(&fimc->vb_queue) && - !list_empty(&fimc->pending_buf_q) && - !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) { - flite_hw_capture_start(fimc); - spin_unlock_irqrestore(&fimc->slock, flags); - - if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state)) - fimc_pipeline_call(fimc, set_stream, - &fimc->pipeline, 1); - return; - } - spin_unlock_irqrestore(&fimc->slock, flags); -} - -static const struct vb2_ops fimc_lite_qops = { - .queue_setup = queue_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .start_streaming = start_streaming, - .stop_streaming = stop_streaming, -}; - -static void fimc_lite_clear_event_counters(struct fimc_lite *fimc) -{ - unsigned long flags; - - spin_lock_irqsave(&fimc->slock, flags); - memset(&fimc->events, 0, sizeof(fimc->events)); - spin_unlock_irqrestore(&fimc->slock, flags); -} - -static int fimc_lite_open(struct file *file) -{ - struct fimc_lite *fimc = video_drvdata(file); - struct media_entity *me = &fimc->vfd.entity; - int ret; - - mutex_lock(&me->parent->graph_mutex); - - mutex_lock(&fimc->lock); - if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) { - ret = -EBUSY; - goto unlock; - } - - set_bit(ST_FLITE_IN_USE, &fimc->state); - ret = pm_runtime_get_sync(&fimc->pdev->dev); - if (ret < 0) - goto unlock; - - ret = v4l2_fh_open(file); - if (ret < 0) - goto err_pm; - - if (!v4l2_fh_is_singular_file(file) || - atomic_read(&fimc->out_path) != FIMC_IO_DMA) - goto unlock; - - ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, - me, true); - if (!ret) { - fimc_lite_clear_event_counters(fimc); - fimc->ref_count++; - goto unlock; - } - - v4l2_fh_release(file); -err_pm: - pm_runtime_put_sync(&fimc->pdev->dev); - clear_bit(ST_FLITE_IN_USE, &fimc->state); -unlock: - mutex_unlock(&fimc->lock); - mutex_unlock(&me->parent->graph_mutex); - return ret; -} - -static int fimc_lite_release(struct file *file) -{ - struct fimc_lite *fimc = video_drvdata(file); - - mutex_lock(&fimc->lock); - - if (v4l2_fh_is_singular_file(file) && - atomic_read(&fimc->out_path) == FIMC_IO_DMA) { - clear_bit(ST_FLITE_IN_USE, &fimc->state); - fimc_lite_stop_capture(fimc, false); - fimc_pipeline_call(fimc, close, &fimc->pipeline); - fimc->ref_count--; - } - - vb2_fop_release(file); - pm_runtime_put(&fimc->pdev->dev); - clear_bit(ST_FLITE_SUSPENDED, &fimc->state); - - mutex_unlock(&fimc->lock); - return 0; -} - -static const struct v4l2_file_operations fimc_lite_fops = { - .owner = THIS_MODULE, - .open = fimc_lite_open, - .release = fimc_lite_release, - .poll = vb2_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = vb2_fop_mmap, -}; - -/* - * Format and crop negotiation helpers - */ - -static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc, - u32 *width, u32 *height, - u32 *code, u32 *fourcc, int pad) -{ - struct flite_variant *variant = fimc->variant; - const struct fimc_fmt *fmt; - - fmt = fimc_lite_find_format(fourcc, code, 0); - if (WARN_ON(!fmt)) - return NULL; - - if (code) - *code = fmt->mbus_code; - if (fourcc) - *fourcc = fmt->fourcc; - - if (pad == FLITE_SD_PAD_SINK) { - v4l_bound_align_image(width, 8, variant->max_width, - ffs(variant->out_width_align) - 1, - height, 0, variant->max_height, 0, 0); - } else { - v4l_bound_align_image(width, 8, fimc->inp_frame.rect.width, - ffs(variant->out_width_align) - 1, - height, 0, fimc->inp_frame.rect.height, - 0, 0); - } - - v4l2_dbg(1, debug, &fimc->subdev, "code: 0x%x, %dx%d\n", - code ? *code : 0, *width, *height); - - return fmt; -} - -static void fimc_lite_try_crop(struct fimc_lite *fimc, struct v4l2_rect *r) -{ - struct flite_frame *frame = &fimc->inp_frame; - - v4l_bound_align_image(&r->width, 0, frame->f_width, 0, - &r->height, 0, frame->f_height, 0, 0); - - /* Adjust left/top if cropping rectangle got out of bounds */ - r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width); - r->left = round_down(r->left, fimc->variant->win_hor_offs_align); - r->top = clamp_t(u32, r->top, 0, frame->f_height - r->height); - - v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, sink fmt: %dx%d\n", - r->left, r->top, r->width, r->height, - frame->f_width, frame->f_height); -} - -static void fimc_lite_try_compose(struct fimc_lite *fimc, struct v4l2_rect *r) -{ - struct flite_frame *frame = &fimc->out_frame; - struct v4l2_rect *crop_rect = &fimc->inp_frame.rect; - - /* Scaling is not supported so we enforce compose rectangle size - same as size of the sink crop rectangle. */ - r->width = crop_rect->width; - r->height = crop_rect->height; - - /* Adjust left/top if the composing rectangle got out of bounds */ - r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width); - r->left = round_down(r->left, fimc->variant->out_hor_offs_align); - r->top = clamp_t(u32, r->top, 0, fimc->out_frame.f_height - r->height); - - v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, source fmt: %dx%d\n", - r->left, r->top, r->width, r->height, - frame->f_width, frame->f_height); -} - -/* - * Video node ioctl operations - */ -static int fimc_vidioc_querycap_capture(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - strlcpy(cap->driver, FIMC_LITE_DRV_NAME, sizeof(cap->driver)); - cap->bus_info[0] = 0; - cap->card[0] = 0; - cap->capabilities = V4L2_CAP_STREAMING; - return 0; -} - -static int fimc_lite_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - const struct fimc_fmt *fmt; - - if (f->index >= ARRAY_SIZE(fimc_lite_formats)) - return -EINVAL; - - fmt = &fimc_lite_formats[f->index]; - strlcpy(f->description, fmt->name, sizeof(f->description)); - f->pixelformat = fmt->fourcc; - - return 0; -} - -static int fimc_lite_g_fmt_mplane(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct fimc_lite *fimc = video_drvdata(file); - struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; - struct v4l2_plane_pix_format *plane_fmt = &pixm->plane_fmt[0]; - struct flite_frame *frame = &fimc->out_frame; - const struct fimc_fmt *fmt = fimc->fmt; - - plane_fmt->bytesperline = (frame->f_width * fmt->depth[0]) / 8; - plane_fmt->sizeimage = plane_fmt->bytesperline * frame->f_height; - - pixm->num_planes = fmt->memplanes; - pixm->pixelformat = fmt->fourcc; - pixm->width = frame->f_width; - pixm->height = frame->f_height; - pixm->field = V4L2_FIELD_NONE; - pixm->colorspace = V4L2_COLORSPACE_JPEG; - return 0; -} - -static int fimc_lite_try_fmt(struct fimc_lite *fimc, - struct v4l2_pix_format_mplane *pixm, - const struct fimc_fmt **ffmt) -{ - struct flite_variant *variant = fimc->variant; - u32 bpl = pixm->plane_fmt[0].bytesperline; - const struct fimc_fmt *fmt; - - fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0); - if (WARN_ON(fmt == NULL)) - return -EINVAL; - if (ffmt) - *ffmt = fmt; - v4l_bound_align_image(&pixm->width, 8, variant->max_width, - ffs(variant->out_width_align) - 1, - &pixm->height, 0, variant->max_height, 0, 0); - - if ((bpl == 0 || ((bpl * 8) / fmt->depth[0]) < pixm->width)) - pixm->plane_fmt[0].bytesperline = (pixm->width * - fmt->depth[0]) / 8; - - if (pixm->plane_fmt[0].sizeimage == 0) - pixm->plane_fmt[0].sizeimage = (pixm->width * pixm->height * - fmt->depth[0]) / 8; - pixm->num_planes = fmt->memplanes; - pixm->pixelformat = fmt->fourcc; - pixm->colorspace = V4L2_COLORSPACE_JPEG; - pixm->field = V4L2_FIELD_NONE; - return 0; -} - -static int fimc_lite_try_fmt_mplane(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct fimc_lite *fimc = video_drvdata(file); - return fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, NULL); -} - -static int fimc_lite_s_fmt_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; - struct fimc_lite *fimc = video_drvdata(file); - struct flite_frame *frame = &fimc->out_frame; - const struct fimc_fmt *fmt = NULL; - int ret; - - if (vb2_is_busy(&fimc->vb_queue)) - return -EBUSY; - - ret = fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, &fmt); - if (ret < 0) - return ret; - - fimc->fmt = fmt; - fimc->payload[0] = max((pixm->width * pixm->height * fmt->depth[0]) / 8, - pixm->plane_fmt[0].sizeimage); - frame->f_width = pixm->width; - frame->f_height = pixm->height; - - return 0; -} - -static int fimc_pipeline_validate(struct fimc_lite *fimc) -{ - struct v4l2_subdev *sd = &fimc->subdev; - struct v4l2_subdev_format sink_fmt, src_fmt; - struct media_pad *pad; - int ret; - - while (1) { - /* Retrieve format at the sink pad */ - pad = &sd->entity.pads[0]; - if (!(pad->flags & MEDIA_PAD_FL_SINK)) - break; - /* Don't call FIMC subdev operation to avoid nested locking */ - if (sd == &fimc->subdev) { - struct flite_frame *ff = &fimc->out_frame; - sink_fmt.format.width = ff->f_width; - sink_fmt.format.height = ff->f_height; - sink_fmt.format.code = fimc->fmt->mbus_code; - } else { - sink_fmt.pad = pad->index; - sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, - &sink_fmt); - if (ret < 0 && ret != -ENOIOCTLCMD) - return -EPIPE; - } - /* Retrieve format at the source pad */ - pad = media_entity_remote_source(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - break; - - sd = media_entity_to_v4l2_subdev(pad->entity); - src_fmt.pad = pad->index; - src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt); - if (ret < 0 && ret != -ENOIOCTLCMD) - return -EPIPE; - - if (src_fmt.format.width != sink_fmt.format.width || - src_fmt.format.height != sink_fmt.format.height || - src_fmt.format.code != sink_fmt.format.code) - return -EPIPE; - } - return 0; -} - -static int fimc_lite_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct fimc_lite *fimc = video_drvdata(file); - struct media_entity *entity = &fimc->vfd.entity; - struct fimc_pipeline *p = &fimc->pipeline; - int ret; - - if (fimc_lite_active(fimc)) - return -EBUSY; - - ret = media_entity_pipeline_start(entity, p->m_pipeline); - if (ret < 0) - return ret; - - ret = fimc_pipeline_validate(fimc); - if (ret < 0) - goto err_p_stop; - - ret = vb2_ioctl_streamon(file, priv, type); - if (!ret) - return ret; -err_p_stop: - media_entity_pipeline_stop(entity); - return 0; -} - -static int fimc_lite_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct fimc_lite *fimc = video_drvdata(file); - int ret; - - ret = vb2_ioctl_streamoff(file, priv, type); - if (ret == 0) - media_entity_pipeline_stop(&fimc->vfd.entity); - return ret; -} - -static int fimc_lite_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) -{ - struct fimc_lite *fimc = video_drvdata(file); - int ret; - - reqbufs->count = max_t(u32, FLITE_REQ_BUFS_MIN, reqbufs->count); - ret = vb2_ioctl_reqbufs(file, priv, reqbufs); - if (!ret) - fimc->reqbufs_count = reqbufs->count; - - return ret; -} - -/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */ -static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b) -{ - if (a->left < b->left || a->top < b->top) - return 0; - if (a->left + a->width > b->left + b->width) - return 0; - if (a->top + a->height > b->top + b->height) - return 0; - - return 1; -} - -static int fimc_lite_g_selection(struct file *file, void *fh, - struct v4l2_selection *sel) -{ - struct fimc_lite *fimc = video_drvdata(file); - struct flite_frame *f = &fimc->out_frame; - - if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return -EINVAL; - - switch (sel->target) { - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - sel->r.left = 0; - sel->r.top = 0; - sel->r.width = f->f_width; - sel->r.height = f->f_height; - return 0; - - case V4L2_SEL_TGT_COMPOSE: - sel->r = f->rect; - return 0; - } - - return -EINVAL; -} - -static int fimc_lite_s_selection(struct file *file, void *fh, - struct v4l2_selection *sel) -{ - struct fimc_lite *fimc = video_drvdata(file); - struct flite_frame *f = &fimc->out_frame; - struct v4l2_rect rect = sel->r; - unsigned long flags; - - if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE || - sel->target != V4L2_SEL_TGT_COMPOSE) - return -EINVAL; - - fimc_lite_try_compose(fimc, &rect); - - if ((sel->flags & V4L2_SEL_FLAG_LE) && - !enclosed_rectangle(&rect, &sel->r)) - return -ERANGE; - - if ((sel->flags & V4L2_SEL_FLAG_GE) && - !enclosed_rectangle(&sel->r, &rect)) - return -ERANGE; - - sel->r = rect; - spin_lock_irqsave(&fimc->slock, flags); - f->rect = rect; - set_bit(ST_FLITE_CONFIG, &fimc->state); - spin_unlock_irqrestore(&fimc->slock, flags); - - return 0; -} - -static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = { - .vidioc_querycap = fimc_vidioc_querycap_capture, - .vidioc_enum_fmt_vid_cap_mplane = fimc_lite_enum_fmt_mplane, - .vidioc_try_fmt_vid_cap_mplane = fimc_lite_try_fmt_mplane, - .vidioc_s_fmt_vid_cap_mplane = fimc_lite_s_fmt_mplane, - .vidioc_g_fmt_vid_cap_mplane = fimc_lite_g_fmt_mplane, - .vidioc_g_selection = fimc_lite_g_selection, - .vidioc_s_selection = fimc_lite_s_selection, - .vidioc_reqbufs = fimc_lite_reqbufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_streamon = fimc_lite_streamon, - .vidioc_streamoff = fimc_lite_streamoff, -}; - -/* Called with the media graph mutex held */ -static struct v4l2_subdev *__find_remote_sensor(struct media_entity *me) -{ - struct media_pad *pad = &me->pads[0]; - struct v4l2_subdev *sd; - - while (pad->flags & MEDIA_PAD_FL_SINK) { - /* source pad */ - pad = media_entity_remote_source(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - break; - - sd = media_entity_to_v4l2_subdev(pad->entity); - - if (sd->grp_id == GRP_ID_FIMC_IS_SENSOR) - return sd; - /* sink pad */ - pad = &sd->entity.pads[0]; - } - return NULL; -} - -/* Capture subdev media entity operations */ -static int fimc_lite_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct fimc_lite *fimc = v4l2_get_subdevdata(sd); - unsigned int remote_ent_type = media_entity_type(remote->entity); - int ret = 0; - - if (WARN_ON(fimc == NULL)) - return 0; - - v4l2_dbg(1, debug, sd, "%s: %s --> %s, flags: 0x%x. source_id: 0x%x\n", - __func__, remote->entity->name, local->entity->name, - flags, fimc->source_subdev_grp_id); - - mutex_lock(&fimc->lock); - - switch (local->index) { - case FLITE_SD_PAD_SINK: - if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV) { - ret = -EINVAL; - break; - } - if (flags & MEDIA_LNK_FL_ENABLED) { - if (fimc->source_subdev_grp_id == 0) - fimc->source_subdev_grp_id = sd->grp_id; - else - ret = -EBUSY; - } else { - fimc->source_subdev_grp_id = 0; - fimc->sensor = NULL; - } - break; - - case FLITE_SD_PAD_SOURCE_DMA: - if (!(flags & MEDIA_LNK_FL_ENABLED)) - atomic_set(&fimc->out_path, FIMC_IO_NONE); - else if (remote_ent_type == MEDIA_ENT_T_DEVNODE) - atomic_set(&fimc->out_path, FIMC_IO_DMA); - else - ret = -EINVAL; - break; - - case FLITE_SD_PAD_SOURCE_ISP: - if (!(flags & MEDIA_LNK_FL_ENABLED)) - atomic_set(&fimc->out_path, FIMC_IO_NONE); - else if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV) - atomic_set(&fimc->out_path, FIMC_IO_ISP); - else - ret = -EINVAL; - break; - - default: - v4l2_err(sd, "Invalid pad index\n"); - ret = -EINVAL; - } - mb(); - - mutex_unlock(&fimc->lock); - return ret; -} - -static const struct media_entity_operations fimc_lite_subdev_media_ops = { - .link_setup = fimc_lite_link_setup, -}; - -static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_mbus_code_enum *code) -{ - const struct fimc_fmt *fmt; - - fmt = fimc_lite_find_format(NULL, NULL, code->index); - if (!fmt) - return -EINVAL; - code->code = fmt->mbus_code; - return 0; -} - -static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct fimc_lite *fimc = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *mf = &fmt->format; - struct flite_frame *f = &fimc->out_frame; - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); - fmt->format = *mf; - return 0; - } - mf->colorspace = V4L2_COLORSPACE_JPEG; - - mutex_lock(&fimc->lock); - mf->code = fimc->fmt->mbus_code; - - if (fmt->pad == FLITE_SD_PAD_SINK) { - /* full camera input frame size */ - mf->width = f->f_width; - mf->height = f->f_height; - } else { - /* crop size */ - mf->width = f->rect.width; - mf->height = f->rect.height; - } - mutex_unlock(&fimc->lock); - return 0; -} - -static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct fimc_lite *fimc = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *mf = &fmt->format; - struct flite_frame *sink = &fimc->inp_frame; - struct flite_frame *source = &fimc->out_frame; - const struct fimc_fmt *ffmt; - - v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %dx%d\n", - fmt->pad, mf->code, mf->width, mf->height); - - mf->colorspace = V4L2_COLORSPACE_JPEG; - mutex_lock(&fimc->lock); - - if ((atomic_read(&fimc->out_path) == FIMC_IO_ISP && - sd->entity.stream_count > 0) || - (atomic_read(&fimc->out_path) == FIMC_IO_DMA && - vb2_is_busy(&fimc->vb_queue))) { - mutex_unlock(&fimc->lock); - return -EBUSY; - } - - ffmt = fimc_lite_try_format(fimc, &mf->width, &mf->height, - &mf->code, NULL, fmt->pad); - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); - *mf = fmt->format; - mutex_unlock(&fimc->lock); - return 0; - } - - if (fmt->pad == FLITE_SD_PAD_SINK) { - sink->f_width = mf->width; - sink->f_height = mf->height; - fimc->fmt = ffmt; - /* Set sink crop rectangle */ - sink->rect.width = mf->width; - sink->rect.height = mf->height; - sink->rect.left = 0; - sink->rect.top = 0; - /* Reset source format and crop rectangle */ - source->rect = sink->rect; - source->f_width = mf->width; - source->f_height = mf->height; - } else { - /* Allow changing format only on sink pad */ - mf->code = fimc->fmt->mbus_code; - mf->width = sink->rect.width; - mf->height = sink->rect.height; - } - - mutex_unlock(&fimc->lock); - return 0; -} - -static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_selection *sel) -{ - struct fimc_lite *fimc = v4l2_get_subdevdata(sd); - struct flite_frame *f = &fimc->inp_frame; - - if ((sel->target != V4L2_SEL_TGT_CROP && - sel->target != V4L2_SEL_TGT_CROP_BOUNDS) || - sel->pad != FLITE_SD_PAD_SINK) - return -EINVAL; - - if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad); - return 0; - } - - mutex_lock(&fimc->lock); - if (sel->target == V4L2_SEL_TGT_CROP) { - sel->r = f->rect; - } else { - sel->r.left = 0; - sel->r.top = 0; - sel->r.width = f->f_width; - sel->r.height = f->f_height; - } - mutex_unlock(&fimc->lock); - - v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d\n", - __func__, f->rect.left, f->rect.top, f->rect.width, - f->rect.height, f->f_width, f->f_height); - - return 0; -} - -static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_selection *sel) -{ - struct fimc_lite *fimc = v4l2_get_subdevdata(sd); - struct flite_frame *f = &fimc->inp_frame; - int ret = 0; - - if (sel->target != V4L2_SEL_TGT_CROP || sel->pad != FLITE_SD_PAD_SINK) - return -EINVAL; - - mutex_lock(&fimc->lock); - fimc_lite_try_crop(fimc, &sel->r); - - if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - *v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r; - } else { - unsigned long flags; - spin_lock_irqsave(&fimc->slock, flags); - f->rect = sel->r; - /* Same crop rectangle on the source pad */ - fimc->out_frame.rect = sel->r; - set_bit(ST_FLITE_CONFIG, &fimc->state); - spin_unlock_irqrestore(&fimc->slock, flags); - } - mutex_unlock(&fimc->lock); - - v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d\n", - __func__, f->rect.left, f->rect.top, f->rect.width, - f->rect.height, f->f_width, f->f_height); - - return ret; -} - -static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on) -{ - struct fimc_lite *fimc = v4l2_get_subdevdata(sd); - unsigned long flags; - int ret; - - /* - * Find sensor subdev linked to FIMC-LITE directly or through - * MIPI-CSIS. This is required for configuration where FIMC-LITE - * is used as a subdev only and feeds data internally to FIMC-IS. - * The pipeline links are protected through entity.stream_count - * so there is no need to take the media graph mutex here. - */ - fimc->sensor = __find_remote_sensor(&sd->entity); - - if (atomic_read(&fimc->out_path) != FIMC_IO_ISP) - return -ENOIOCTLCMD; - - mutex_lock(&fimc->lock); - if (on) { - flite_hw_reset(fimc); - ret = fimc_lite_hw_init(fimc, true); - if (!ret) { - spin_lock_irqsave(&fimc->slock, flags); - flite_hw_capture_start(fimc); - spin_unlock_irqrestore(&fimc->slock, flags); - } - } else { - set_bit(ST_FLITE_OFF, &fimc->state); - - spin_lock_irqsave(&fimc->slock, flags); - flite_hw_capture_stop(fimc); - spin_unlock_irqrestore(&fimc->slock, flags); - - ret = wait_event_timeout(fimc->irq_queue, - !test_bit(ST_FLITE_OFF, &fimc->state), - msecs_to_jiffies(200)); - if (ret == 0) - v4l2_err(sd, "s_stream(0) timeout\n"); - clear_bit(ST_FLITE_RUN, &fimc->state); - } - - mutex_unlock(&fimc->lock); - return ret; -} - -static int fimc_lite_log_status(struct v4l2_subdev *sd) -{ - struct fimc_lite *fimc = v4l2_get_subdevdata(sd); - - flite_hw_dump_regs(fimc, __func__); - return 0; -} - -static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) -{ - struct fimc_lite *fimc = v4l2_get_subdevdata(sd); - struct vb2_queue *q = &fimc->vb_queue; - struct video_device *vfd = &fimc->vfd; - int ret; - - memset(vfd, 0, sizeof(*vfd)); - - fimc->fmt = &fimc_lite_formats[0]; - atomic_set(&fimc->out_path, FIMC_IO_DMA); - - snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture", - fimc->index); - - vfd->fops = &fimc_lite_fops; - vfd->ioctl_ops = &fimc_lite_ioctl_ops; - vfd->v4l2_dev = sd->v4l2_dev; - vfd->minor = -1; - vfd->release = video_device_release_empty; - vfd->queue = q; - fimc->reqbufs_count = 0; - - INIT_LIST_HEAD(&fimc->pending_buf_q); - INIT_LIST_HEAD(&fimc->active_buf_q); - - memset(q, 0, sizeof(*q)); - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - q->io_modes = VB2_MMAP | VB2_USERPTR; - q->ops = &fimc_lite_qops; - q->mem_ops = &vb2_dma_contig_memops; - q->buf_struct_size = sizeof(struct flite_buffer); - q->drv_priv = fimc; - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->lock = &fimc->lock; - - ret = vb2_queue_init(q); - if (ret < 0) - return ret; - - fimc->vd_pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_init(&vfd->entity, 1, &fimc->vd_pad, 0); - if (ret < 0) - return ret; - - video_set_drvdata(vfd, fimc); - fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd); - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); - if (ret < 0) { - media_entity_cleanup(&vfd->entity); - fimc->pipeline_ops = NULL; - return ret; - } - - v4l2_info(sd->v4l2_dev, "Registered %s as /dev/%s\n", - vfd->name, video_device_node_name(vfd)); - return 0; -} - -static void fimc_lite_subdev_unregistered(struct v4l2_subdev *sd) -{ - struct fimc_lite *fimc = v4l2_get_subdevdata(sd); - - if (fimc == NULL) - return; - - if (video_is_registered(&fimc->vfd)) { - video_unregister_device(&fimc->vfd); - media_entity_cleanup(&fimc->vfd.entity); - fimc->pipeline_ops = NULL; - } -} - -static const struct v4l2_subdev_internal_ops fimc_lite_subdev_internal_ops = { - .registered = fimc_lite_subdev_registered, - .unregistered = fimc_lite_subdev_unregistered, -}; - -static const struct v4l2_subdev_pad_ops fimc_lite_subdev_pad_ops = { - .enum_mbus_code = fimc_lite_subdev_enum_mbus_code, - .get_selection = fimc_lite_subdev_get_selection, - .set_selection = fimc_lite_subdev_set_selection, - .get_fmt = fimc_lite_subdev_get_fmt, - .set_fmt = fimc_lite_subdev_set_fmt, -}; - -static const struct v4l2_subdev_video_ops fimc_lite_subdev_video_ops = { - .s_stream = fimc_lite_subdev_s_stream, -}; - -static const struct v4l2_subdev_core_ops fimc_lite_core_ops = { - .log_status = fimc_lite_log_status, -}; - -static struct v4l2_subdev_ops fimc_lite_subdev_ops = { - .core = &fimc_lite_core_ops, - .video = &fimc_lite_subdev_video_ops, - .pad = &fimc_lite_subdev_pad_ops, -}; - -static int fimc_lite_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct fimc_lite *fimc = container_of(ctrl->handler, struct fimc_lite, - ctrl_handler); - set_bit(ST_FLITE_CONFIG, &fimc->state); - return 0; -} - -static const struct v4l2_ctrl_ops fimc_lite_ctrl_ops = { - .s_ctrl = fimc_lite_s_ctrl, -}; - -static const struct v4l2_ctrl_config fimc_lite_ctrl = { - .ops = &fimc_lite_ctrl_ops, - .id = V4L2_CTRL_CLASS_USER | 0x1001, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Test Pattern 640x480", -}; - -static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc) -{ - struct v4l2_ctrl_handler *handler = &fimc->ctrl_handler; - struct v4l2_subdev *sd = &fimc->subdev; - int ret; - - v4l2_subdev_init(sd, &fimc_lite_subdev_ops); - sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; - snprintf(sd->name, sizeof(sd->name), "FIMC-LITE.%d", fimc->index); - - fimc->subdev_pads[FLITE_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - fimc->subdev_pads[FLITE_SD_PAD_SOURCE_DMA].flags = MEDIA_PAD_FL_SOURCE; - fimc->subdev_pads[FLITE_SD_PAD_SOURCE_ISP].flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&sd->entity, FLITE_SD_PADS_NUM, - fimc->subdev_pads, 0); - if (ret) - return ret; - - v4l2_ctrl_handler_init(handler, 1); - fimc->test_pattern = v4l2_ctrl_new_custom(handler, &fimc_lite_ctrl, - NULL); - if (handler->error) { - media_entity_cleanup(&sd->entity); - return handler->error; - } - - sd->ctrl_handler = handler; - sd->internal_ops = &fimc_lite_subdev_internal_ops; - sd->entity.ops = &fimc_lite_subdev_media_ops; - v4l2_set_subdevdata(sd, fimc); - - return 0; -} - -static void fimc_lite_unregister_capture_subdev(struct fimc_lite *fimc) -{ - struct v4l2_subdev *sd = &fimc->subdev; - - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&sd->entity); - v4l2_ctrl_handler_free(&fimc->ctrl_handler); - v4l2_set_subdevdata(sd, NULL); -} - -static void fimc_lite_clk_put(struct fimc_lite *fimc) -{ - if (IS_ERR_OR_NULL(fimc->clock)) - return; - - clk_unprepare(fimc->clock); - clk_put(fimc->clock); - fimc->clock = NULL; -} - -static int fimc_lite_clk_get(struct fimc_lite *fimc) -{ - int ret; - - fimc->clock = clk_get(&fimc->pdev->dev, FLITE_CLK_NAME); - if (IS_ERR(fimc->clock)) - return PTR_ERR(fimc->clock); - - ret = clk_prepare(fimc->clock); - if (ret < 0) { - clk_put(fimc->clock); - fimc->clock = NULL; - } - return ret; -} - -static const struct of_device_id flite_of_match[]; - -static int fimc_lite_probe(struct platform_device *pdev) -{ - struct flite_drvdata *drv_data = NULL; - struct device *dev = &pdev->dev; - const struct of_device_id *of_id; - struct fimc_lite *fimc; - struct resource *res; - int ret; - - fimc = devm_kzalloc(dev, sizeof(*fimc), GFP_KERNEL); - if (!fimc) - return -ENOMEM; - - if (dev->of_node) { - of_id = of_match_node(flite_of_match, dev->of_node); - if (of_id) - drv_data = (struct flite_drvdata *)of_id->data; - fimc->index = of_alias_get_id(dev->of_node, "fimc-lite"); - } else { - drv_data = fimc_lite_get_drvdata(pdev); - fimc->index = pdev->id; - } - - if (!drv_data || fimc->index < 0 || fimc->index >= FIMC_LITE_MAX_DEVS) - return -EINVAL; - - fimc->variant = drv_data->variant[fimc->index]; - fimc->pdev = pdev; - - init_waitqueue_head(&fimc->irq_queue); - spin_lock_init(&fimc->slock); - mutex_init(&fimc->lock); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - fimc->regs = devm_ioremap_resource(dev, res); - if (IS_ERR(fimc->regs)) - return PTR_ERR(fimc->regs); - - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res == NULL) { - dev_err(dev, "Failed to get IRQ resource\n"); - return -ENXIO; - } - - ret = fimc_lite_clk_get(fimc); - if (ret) - return ret; - - ret = devm_request_irq(dev, res->start, flite_irq_handler, - 0, dev_name(dev), fimc); - if (ret) { - dev_err(dev, "Failed to install irq (%d)\n", ret); - goto err_clk; - } - - /* The video node will be created within the subdev's registered() op */ - ret = fimc_lite_create_capture_subdev(fimc); - if (ret) - goto err_clk; - - platform_set_drvdata(pdev, fimc); - pm_runtime_enable(dev); - ret = pm_runtime_get_sync(dev); - if (ret < 0) - goto err_sd; - - fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev); - if (IS_ERR(fimc->alloc_ctx)) { - ret = PTR_ERR(fimc->alloc_ctx); - goto err_pm; - } - pm_runtime_put(dev); - - dev_dbg(dev, "FIMC-LITE.%d registered successfully\n", - fimc->index); - return 0; -err_pm: - pm_runtime_put(dev); -err_sd: - fimc_lite_unregister_capture_subdev(fimc); -err_clk: - fimc_lite_clk_put(fimc); - return ret; -} - -static int fimc_lite_runtime_resume(struct device *dev) -{ - struct fimc_lite *fimc = dev_get_drvdata(dev); - - clk_enable(fimc->clock); - return 0; -} - -static int fimc_lite_runtime_suspend(struct device *dev) -{ - struct fimc_lite *fimc = dev_get_drvdata(dev); - - clk_disable(fimc->clock); - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int fimc_lite_resume(struct device *dev) -{ - struct fimc_lite *fimc = dev_get_drvdata(dev); - struct flite_buffer *buf; - unsigned long flags; - int i; - - spin_lock_irqsave(&fimc->slock, flags); - if (!test_and_clear_bit(ST_LPM, &fimc->state) || - !test_bit(ST_FLITE_IN_USE, &fimc->state)) { - spin_unlock_irqrestore(&fimc->slock, flags); - return 0; - } - flite_hw_reset(fimc); - spin_unlock_irqrestore(&fimc->slock, flags); - - if (!test_and_clear_bit(ST_FLITE_SUSPENDED, &fimc->state)) - return 0; - - INIT_LIST_HEAD(&fimc->active_buf_q); - fimc_pipeline_call(fimc, open, &fimc->pipeline, - &fimc->vfd.entity, false); - fimc_lite_hw_init(fimc, atomic_read(&fimc->out_path) == FIMC_IO_ISP); - clear_bit(ST_FLITE_SUSPENDED, &fimc->state); - - for (i = 0; i < fimc->reqbufs_count; i++) { - if (list_empty(&fimc->pending_buf_q)) - break; - buf = fimc_lite_pending_queue_pop(fimc); - buffer_queue(&buf->vb); - } - return 0; -} - -static int fimc_lite_suspend(struct device *dev) -{ - struct fimc_lite *fimc = dev_get_drvdata(dev); - bool suspend = test_bit(ST_FLITE_IN_USE, &fimc->state); - int ret; - - if (test_and_set_bit(ST_LPM, &fimc->state)) - return 0; - - ret = fimc_lite_stop_capture(fimc, suspend); - if (ret < 0 || !fimc_lite_active(fimc)) - return ret; - - return fimc_pipeline_call(fimc, close, &fimc->pipeline); -} -#endif /* CONFIG_PM_SLEEP */ - -static int fimc_lite_remove(struct platform_device *pdev) -{ - struct fimc_lite *fimc = platform_get_drvdata(pdev); - struct device *dev = &pdev->dev; - - pm_runtime_disable(dev); - pm_runtime_set_suspended(dev); - fimc_lite_unregister_capture_subdev(fimc); - vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); - fimc_lite_clk_put(fimc); - - dev_info(dev, "Driver unloaded\n"); - return 0; -} - -static const struct dev_pm_ops fimc_lite_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(fimc_lite_suspend, fimc_lite_resume) - SET_RUNTIME_PM_OPS(fimc_lite_runtime_suspend, fimc_lite_runtime_resume, - NULL) -}; - -static struct flite_variant fimc_lite0_variant_exynos4 = { - .max_width = 8192, - .max_height = 8192, - .out_width_align = 8, - .win_hor_offs_align = 2, - .out_hor_offs_align = 8, -}; - -/* EXYNOS4212, EXYNOS4412 */ -static struct flite_drvdata fimc_lite_drvdata_exynos4 = { - .variant = { - [0] = &fimc_lite0_variant_exynos4, - [1] = &fimc_lite0_variant_exynos4, - }, -}; - -static struct platform_device_id fimc_lite_driver_ids[] = { - { - .name = "exynos-fimc-lite", - .driver_data = (unsigned long)&fimc_lite_drvdata_exynos4, - }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(platform, fimc_lite_driver_ids); - -static const struct of_device_id flite_of_match[] = { - { - .compatible = "samsung,exynos4212-fimc-lite", - .data = &fimc_lite_drvdata_exynos4, - }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, flite_of_match); - -static struct platform_driver fimc_lite_driver = { - .probe = fimc_lite_probe, - .remove = fimc_lite_remove, - .id_table = fimc_lite_driver_ids, - .driver = { - .of_match_table = flite_of_match, - .name = FIMC_LITE_DRV_NAME, - .owner = THIS_MODULE, - .pm = &fimc_lite_pm_ops, - } -}; -module_platform_driver(fimc_lite_driver); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" FIMC_LITE_DRV_NAME); diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.h b/drivers/media/platform/s5p-fimc/fimc-lite.h deleted file mode 100644 index 4c2345086366..000000000000 --- a/drivers/media/platform/s5p-fimc/fimc-lite.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef FIMC_LITE_H_ -#define FIMC_LITE_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define FIMC_LITE_DRV_NAME "exynos-fimc-lite" -#define FLITE_CLK_NAME "flite" -#define FIMC_LITE_MAX_DEVS 2 -#define FLITE_REQ_BUFS_MIN 2 - -/* Bit index definitions for struct fimc_lite::state */ -enum { - ST_FLITE_LPM, - ST_FLITE_PENDING, - ST_FLITE_RUN, - ST_FLITE_STREAM, - ST_FLITE_SUSPENDED, - ST_FLITE_OFF, - ST_FLITE_IN_USE, - ST_FLITE_CONFIG, - ST_SENSOR_STREAM, -}; - -#define FLITE_SD_PAD_SINK 0 -#define FLITE_SD_PAD_SOURCE_DMA 1 -#define FLITE_SD_PAD_SOURCE_ISP 2 -#define FLITE_SD_PADS_NUM 3 - -struct flite_variant { - unsigned short max_width; - unsigned short max_height; - unsigned short out_width_align; - unsigned short win_hor_offs_align; - unsigned short out_hor_offs_align; -}; - -struct flite_drvdata { - struct flite_variant *variant[FIMC_LITE_MAX_DEVS]; -}; - -#define fimc_lite_get_drvdata(_pdev) \ - ((struct flite_drvdata *) platform_get_device_id(_pdev)->driver_data) - -struct fimc_lite_events { - unsigned int data_overflow; -}; - -#define FLITE_MAX_PLANES 1 - -/** - * struct flite_frame - source/target frame properties - * @f_width: full pixel width - * @f_height: full pixel height - * @rect: crop/composition rectangle - */ -struct flite_frame { - u16 f_width; - u16 f_height; - struct v4l2_rect rect; -}; - -/** - * struct flite_buffer - video buffer structure - * @vb: vb2 buffer - * @list: list head for the buffers queue - * @paddr: precalculated physical address - */ -struct flite_buffer { - struct vb2_buffer vb; - struct list_head list; - dma_addr_t paddr; -}; - -/** - * struct fimc_lite - fimc lite structure - * @pdev: pointer to FIMC-LITE platform device - * @variant: variant information for this IP - * @v4l2_dev: pointer to top the level v4l2_device - * @vfd: video device node - * @fh: v4l2 file handle - * @alloc_ctx: videobuf2 memory allocator context - * @subdev: FIMC-LITE subdev - * @vd_pad: media (sink) pad for the capture video node - * @subdev_pads: the subdev media pads - * @sensor: sensor subdev attached to FIMC-LITE directly or through MIPI-CSIS - * @ctrl_handler: v4l2 control handler - * @test_pattern: test pattern controls - * @index: FIMC-LITE platform device index - * @pipeline: video capture pipeline data structure - * @pipeline_ops: media pipeline ops for the video node driver - * @slock: spinlock protecting this data structure and the hw registers - * @lock: mutex serializing video device and the subdev operations - * @clock: FIMC-LITE gate clock - * @regs: memory mapped io registers - * @irq_queue: interrupt handler waitqueue - * @fmt: pointer to color format description structure - * @payload: image size in bytes (w x h x bpp) - * @inp_frame: camera input frame structure - * @out_frame: DMA output frame structure - * @out_path: output data path (DMA or FIFO) - * @source_subdev_grp_id: source subdev group id - * @state: driver state flags - * @pending_buf_q: pending buffers queue head - * @active_buf_q: the queue head of buffers scheduled in hardware - * @vb_queue: vb2 buffers queue - * @active_buf_count: number of video buffers scheduled in hardware - * @frame_count: the captured frames counter - * @reqbufs_count: the number of buffers requested with REQBUFS ioctl - * @ref_count: driver's private reference counter - */ -struct fimc_lite { - struct platform_device *pdev; - struct flite_variant *variant; - struct v4l2_device *v4l2_dev; - struct video_device vfd; - struct v4l2_fh fh; - struct vb2_alloc_ctx *alloc_ctx; - struct v4l2_subdev subdev; - struct media_pad vd_pad; - struct media_pad subdev_pads[FLITE_SD_PADS_NUM]; - struct v4l2_subdev *sensor; - struct v4l2_ctrl_handler ctrl_handler; - struct v4l2_ctrl *test_pattern; - u32 index; - struct fimc_pipeline pipeline; - const struct fimc_pipeline_ops *pipeline_ops; - - struct mutex lock; - spinlock_t slock; - - struct clk *clock; - void __iomem *regs; - wait_queue_head_t irq_queue; - - const struct fimc_fmt *fmt; - unsigned long payload[FLITE_MAX_PLANES]; - struct flite_frame inp_frame; - struct flite_frame out_frame; - atomic_t out_path; - unsigned int source_subdev_grp_id; - - unsigned long state; - struct list_head pending_buf_q; - struct list_head active_buf_q; - struct vb2_queue vb_queue; - unsigned int frame_count; - unsigned int reqbufs_count; - int ref_count; - - struct fimc_lite_events events; -}; - -static inline bool fimc_lite_active(struct fimc_lite *fimc) -{ - unsigned long flags; - bool ret; - - spin_lock_irqsave(&fimc->slock, flags); - ret = fimc->state & (1 << ST_FLITE_RUN) || - fimc->state & (1 << ST_FLITE_PENDING); - spin_unlock_irqrestore(&fimc->slock, flags); - return ret; -} - -static inline void fimc_lite_active_queue_add(struct fimc_lite *dev, - struct flite_buffer *buf) -{ - list_add_tail(&buf->list, &dev->active_buf_q); -} - -static inline struct flite_buffer *fimc_lite_active_queue_pop( - struct fimc_lite *dev) -{ - struct flite_buffer *buf = list_entry(dev->active_buf_q.next, - struct flite_buffer, list); - list_del(&buf->list); - return buf; -} - -static inline void fimc_lite_pending_queue_add(struct fimc_lite *dev, - struct flite_buffer *buf) -{ - list_add_tail(&buf->list, &dev->pending_buf_q); -} - -static inline struct flite_buffer *fimc_lite_pending_queue_pop( - struct fimc_lite *dev) -{ - struct flite_buffer *buf = list_entry(dev->pending_buf_q.next, - struct flite_buffer, list); - list_del(&buf->list); - return buf; -} - -#endif /* FIMC_LITE_H_ */ diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c deleted file mode 100644 index a224dac36b3a..000000000000 --- a/drivers/media/platform/s5p-fimc/fimc-m2m.c +++ /dev/null @@ -1,864 +0,0 @@ -/* - * Samsung S5P/EXYNOS4 SoC series FIMC (video postprocessor) driver - * - * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation, either version 2 of the License, - * or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "fimc-core.h" -#include "fimc-reg.h" -#include "fimc-mdevice.h" - - -static unsigned int get_m2m_fmt_flags(unsigned int stream_type) -{ - if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - return FMT_FLAGS_M2M_IN; - else - return FMT_FLAGS_M2M_OUT; -} - -void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state) -{ - struct vb2_buffer *src_vb, *dst_vb; - - if (!ctx || !ctx->m2m_ctx) - return; - - src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); - dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); - - if (src_vb && dst_vb) { - v4l2_m2m_buf_done(src_vb, vb_state); - v4l2_m2m_buf_done(dst_vb, vb_state); - v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev, - ctx->m2m_ctx); - } -} - -/* Complete the transaction which has been scheduled for execution. */ -static int fimc_m2m_shutdown(struct fimc_ctx *ctx) -{ - struct fimc_dev *fimc = ctx->fimc_dev; - int ret; - - if (!fimc_m2m_pending(fimc)) - return 0; - - fimc_ctx_state_set(FIMC_CTX_SHUT, ctx); - - ret = wait_event_timeout(fimc->irq_queue, - !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx), - FIMC_SHUTDOWN_TIMEOUT); - - return ret == 0 ? -ETIMEDOUT : ret; -} - -static int start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct fimc_ctx *ctx = q->drv_priv; - int ret; - - ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev); - return ret > 0 ? 0 : ret; -} - -static int stop_streaming(struct vb2_queue *q) -{ - struct fimc_ctx *ctx = q->drv_priv; - int ret; - - ret = fimc_m2m_shutdown(ctx); - if (ret == -ETIMEDOUT) - fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); - - pm_runtime_put(&ctx->fimc_dev->pdev->dev); - return 0; -} - -static void fimc_device_run(void *priv) -{ - struct vb2_buffer *vb = NULL; - struct fimc_ctx *ctx = priv; - struct fimc_frame *sf, *df; - struct fimc_dev *fimc; - unsigned long flags; - int ret; - - if (WARN(!ctx, "Null context\n")) - return; - - fimc = ctx->fimc_dev; - spin_lock_irqsave(&fimc->slock, flags); - - set_bit(ST_M2M_PEND, &fimc->state); - sf = &ctx->s_frame; - df = &ctx->d_frame; - - if (ctx->state & FIMC_PARAMS) { - /* Prepare the DMA offsets for scaler */ - fimc_prepare_dma_offset(ctx, sf); - fimc_prepare_dma_offset(ctx, df); - } - - vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - ret = fimc_prepare_addr(ctx, vb, sf, &sf->paddr); - if (ret) - goto dma_unlock; - - vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - ret = fimc_prepare_addr(ctx, vb, df, &df->paddr); - if (ret) - goto dma_unlock; - - /* Reconfigure hardware if the context has changed. */ - if (fimc->m2m.ctx != ctx) { - ctx->state |= FIMC_PARAMS; - fimc->m2m.ctx = ctx; - } - - if (ctx->state & FIMC_PARAMS) { - fimc_set_yuv_order(ctx); - fimc_hw_set_input_path(ctx); - fimc_hw_set_in_dma(ctx); - ret = fimc_set_scaler_info(ctx); - if (ret) - goto dma_unlock; - fimc_hw_set_prescaler(ctx); - fimc_hw_set_mainscaler(ctx); - fimc_hw_set_target_format(ctx); - fimc_hw_set_rotation(ctx); - fimc_hw_set_effect(ctx); - fimc_hw_set_out_dma(ctx); - if (fimc->drv_data->alpha_color) - fimc_hw_set_rgb_alpha(ctx); - fimc_hw_set_output_path(ctx); - } - fimc_hw_set_input_addr(fimc, &sf->paddr); - fimc_hw_set_output_addr(fimc, &df->paddr, -1); - - fimc_activate_capture(ctx); - ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP); - fimc_hw_activate_input_dma(fimc, true); - -dma_unlock: - spin_unlock_irqrestore(&fimc->slock, flags); -} - -static void fimc_job_abort(void *priv) -{ - fimc_m2m_shutdown(priv); -} - -static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, - unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *allocators[]) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vq); - struct fimc_frame *f; - int i; - - f = ctx_get_frame(ctx, vq->type); - if (IS_ERR(f)) - return PTR_ERR(f); - /* - * Return number of non-contigous planes (plane buffers) - * depending on the configured color format. - */ - if (!f->fmt) - return -EINVAL; - - *num_planes = f->fmt->memplanes; - for (i = 0; i < f->fmt->memplanes; i++) { - sizes[i] = (f->f_width * f->f_height * f->fmt->depth[i]) / 8; - allocators[i] = ctx->fimc_dev->alloc_ctx; - } - return 0; -} - -static int fimc_buf_prepare(struct vb2_buffer *vb) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct fimc_frame *frame; - int i; - - frame = ctx_get_frame(ctx, vb->vb2_queue->type); - if (IS_ERR(frame)) - return PTR_ERR(frame); - - for (i = 0; i < frame->fmt->memplanes; i++) - vb2_set_plane_payload(vb, i, frame->payload[i]); - - return 0; -} - -static void fimc_buf_queue(struct vb2_buffer *vb) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - - dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state); - - if (ctx->m2m_ctx) - v4l2_m2m_buf_queue(ctx->m2m_ctx, vb); -} - -static void fimc_lock(struct vb2_queue *vq) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vq); - mutex_lock(&ctx->fimc_dev->lock); -} - -static void fimc_unlock(struct vb2_queue *vq) -{ - struct fimc_ctx *ctx = vb2_get_drv_priv(vq); - mutex_unlock(&ctx->fimc_dev->lock); -} - -static struct vb2_ops fimc_qops = { - .queue_setup = fimc_queue_setup, - .buf_prepare = fimc_buf_prepare, - .buf_queue = fimc_buf_queue, - .wait_prepare = fimc_unlock, - .wait_finish = fimc_lock, - .stop_streaming = stop_streaming, - .start_streaming = start_streaming, -}; - -/* - * V4L2 ioctl handlers - */ -static int fimc_m2m_querycap(struct file *file, void *fh, - struct v4l2_capability *cap) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - struct fimc_dev *fimc = ctx->fimc_dev; - - strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1); - strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1); - cap->bus_info[0] = 0; - /* - * This is only a mem-to-mem video device. The capture and output - * device capability flags are left only for backward compatibility - * and are scheduled for removal. - */ - cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE | - V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; - - return 0; -} - -static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct fimc_fmt *fmt; - - fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type), - f->index); - if (!fmt) - return -EINVAL; - - strncpy(f->description, fmt->name, sizeof(f->description) - 1); - f->pixelformat = fmt->fourcc; - return 0; -} - -static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - struct fimc_frame *frame = ctx_get_frame(ctx, f->type); - - if (IS_ERR(frame)) - return PTR_ERR(frame); - - __fimc_get_format(frame, f); - return 0; -} - -static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) -{ - struct fimc_dev *fimc = ctx->fimc_dev; - const struct fimc_variant *variant = fimc->variant; - struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct fimc_fmt *fmt; - u32 max_w, mod_x, mod_y; - - if (!IS_M2M(f->type)) - return -EINVAL; - - fmt = fimc_find_format(&pix->pixelformat, NULL, - get_m2m_fmt_flags(f->type), 0); - if (WARN(fmt == NULL, "Pixel format lookup failed")) - return -EINVAL; - - if (pix->field == V4L2_FIELD_ANY) - pix->field = V4L2_FIELD_NONE; - else if (pix->field != V4L2_FIELD_NONE) - return -EINVAL; - - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - max_w = variant->pix_limit->scaler_dis_w; - mod_x = ffs(variant->min_inp_pixsize) - 1; - } else { - max_w = variant->pix_limit->out_rot_dis_w; - mod_x = ffs(variant->min_out_pixsize) - 1; - } - - if (tiled_fmt(fmt)) { - mod_x = 6; /* 64 x 32 pixels tile */ - mod_y = 5; - } else { - if (variant->min_vsize_align == 1) - mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1; - else - mod_y = ffs(variant->min_vsize_align) - 1; - } - - v4l_bound_align_image(&pix->width, 16, max_w, mod_x, - &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0); - - fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp); - return 0; -} - -static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - return fimc_try_fmt_mplane(ctx, f); -} - -static void __set_frame_format(struct fimc_frame *frame, struct fimc_fmt *fmt, - struct v4l2_pix_format_mplane *pixm) -{ - int i; - - for (i = 0; i < fmt->colplanes; i++) { - frame->bytesperline[i] = pixm->plane_fmt[i].bytesperline; - frame->payload[i] = pixm->plane_fmt[i].sizeimage; - } - - frame->f_width = pixm->width; - frame->f_height = pixm->height; - frame->o_width = pixm->width; - frame->o_height = pixm->height; - frame->width = pixm->width; - frame->height = pixm->height; - frame->offs_h = 0; - frame->offs_v = 0; - frame->fmt = fmt; -} - -static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, - struct v4l2_format *f) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_fmt *fmt; - struct vb2_queue *vq; - struct fimc_frame *frame; - int ret; - - ret = fimc_try_fmt_mplane(ctx, f); - if (ret) - return ret; - - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); - - if (vb2_is_busy(vq)) { - v4l2_err(&fimc->m2m.vfd, "queue (%d) busy\n", f->type); - return -EBUSY; - } - - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - frame = &ctx->s_frame; - else - frame = &ctx->d_frame; - - fmt = fimc_find_format(&f->fmt.pix_mp.pixelformat, NULL, - get_m2m_fmt_flags(f->type), 0); - if (!fmt) - return -EINVAL; - - __set_frame_format(frame, fmt, &f->fmt.pix_mp); - - /* Update RGB Alpha control state and value range */ - fimc_alpha_ctrl_update(ctx); - - return 0; -} - -static int fimc_m2m_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *reqbufs) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); -} - -static int fimc_m2m_querybuf(struct file *file, void *fh, - struct v4l2_buffer *buf) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); -} - -static int fimc_m2m_qbuf(struct file *file, void *fh, - struct v4l2_buffer *buf) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); -} - -static int fimc_m2m_dqbuf(struct file *file, void *fh, - struct v4l2_buffer *buf) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); -} - -static int fimc_m2m_expbuf(struct file *file, void *fh, - struct v4l2_exportbuffer *eb) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb); -} - - -static int fimc_m2m_streamon(struct file *file, void *fh, - enum v4l2_buf_type type) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); -} - -static int fimc_m2m_streamoff(struct file *file, void *fh, - enum v4l2_buf_type type) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); -} - -static int fimc_m2m_cropcap(struct file *file, void *fh, - struct v4l2_cropcap *cr) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - struct fimc_frame *frame; - - frame = ctx_get_frame(ctx, cr->type); - if (IS_ERR(frame)) - return PTR_ERR(frame); - - cr->bounds.left = 0; - cr->bounds.top = 0; - cr->bounds.width = frame->o_width; - cr->bounds.height = frame->o_height; - cr->defrect = cr->bounds; - - return 0; -} - -static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - struct fimc_frame *frame; - - frame = ctx_get_frame(ctx, cr->type); - if (IS_ERR(frame)) - return PTR_ERR(frame); - - cr->c.left = frame->offs_h; - cr->c.top = frame->offs_v; - cr->c.width = frame->width; - cr->c.height = frame->height; - - return 0; -} - -static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) -{ - struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_frame *f; - u32 min_size, halign, depth = 0; - int i; - - if (cr->c.top < 0 || cr->c.left < 0) { - v4l2_err(&fimc->m2m.vfd, - "doesn't support negative values for top & left\n"); - return -EINVAL; - } - if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - f = &ctx->d_frame; - else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - f = &ctx->s_frame; - else - return -EINVAL; - - min_size = (f == &ctx->s_frame) ? - fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; - - /* Get pixel alignment constraints. */ - if (fimc->variant->min_vsize_align == 1) - halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1; - else - halign = ffs(fimc->variant->min_vsize_align) - 1; - - for (i = 0; i < f->fmt->colplanes; i++) - depth += f->fmt->depth[i]; - - v4l_bound_align_image(&cr->c.width, min_size, f->o_width, - ffs(min_size) - 1, - &cr->c.height, min_size, f->o_height, - halign, 64/(ALIGN(depth, 8))); - - /* adjust left/top if cropping rectangle is out of bounds */ - if (cr->c.left + cr->c.width > f->o_width) - cr->c.left = f->o_width - cr->c.width; - if (cr->c.top + cr->c.height > f->o_height) - cr->c.top = f->o_height - cr->c.height; - - cr->c.left = round_down(cr->c.left, min_size); - cr->c.top = round_down(cr->c.top, fimc->variant->hor_offs_align); - - dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d", - cr->c.left, cr->c.top, cr->c.width, cr->c.height, - f->f_width, f->f_height); - - return 0; -} - -static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) -{ - struct fimc_ctx *ctx = fh_to_ctx(fh); - struct fimc_dev *fimc = ctx->fimc_dev; - struct v4l2_crop cr = *crop; - struct fimc_frame *f; - int ret; - - ret = fimc_m2m_try_crop(ctx, &cr); - if (ret) - return ret; - - f = (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? - &ctx->s_frame : &ctx->d_frame; - - /* Check to see if scaling ratio is within supported range */ - if (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = fimc_check_scaler_ratio(ctx, cr.c.width, - cr.c.height, ctx->d_frame.width, - ctx->d_frame.height, ctx->rotation); - } else { - ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, - ctx->s_frame.height, cr.c.width, - cr.c.height, ctx->rotation); - } - if (ret) { - v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n"); - return -EINVAL; - } - - f->offs_h = cr.c.left; - f->offs_v = cr.c.top; - f->width = cr.c.width; - f->height = cr.c.height; - - fimc_ctx_state_set(FIMC_PARAMS, ctx); - - return 0; -} - -static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { - .vidioc_querycap = fimc_m2m_querycap, - .vidioc_enum_fmt_vid_cap_mplane = fimc_m2m_enum_fmt_mplane, - .vidioc_enum_fmt_vid_out_mplane = fimc_m2m_enum_fmt_mplane, - .vidioc_g_fmt_vid_cap_mplane = fimc_m2m_g_fmt_mplane, - .vidioc_g_fmt_vid_out_mplane = fimc_m2m_g_fmt_mplane, - .vidioc_try_fmt_vid_cap_mplane = fimc_m2m_try_fmt_mplane, - .vidioc_try_fmt_vid_out_mplane = fimc_m2m_try_fmt_mplane, - .vidioc_s_fmt_vid_cap_mplane = fimc_m2m_s_fmt_mplane, - .vidioc_s_fmt_vid_out_mplane = fimc_m2m_s_fmt_mplane, - .vidioc_reqbufs = fimc_m2m_reqbufs, - .vidioc_querybuf = fimc_m2m_querybuf, - .vidioc_qbuf = fimc_m2m_qbuf, - .vidioc_dqbuf = fimc_m2m_dqbuf, - .vidioc_expbuf = fimc_m2m_expbuf, - .vidioc_streamon = fimc_m2m_streamon, - .vidioc_streamoff = fimc_m2m_streamoff, - .vidioc_g_crop = fimc_m2m_g_crop, - .vidioc_s_crop = fimc_m2m_s_crop, - .vidioc_cropcap = fimc_m2m_cropcap - -}; - -static int queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) -{ - struct fimc_ctx *ctx = priv; - int ret; - - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - src_vq->drv_priv = ctx; - src_vq->ops = &fimc_qops; - src_vq->mem_ops = &vb2_dma_contig_memops; - src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - - ret = vb2_queue_init(src_vq); - if (ret) - return ret; - - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - dst_vq->drv_priv = ctx; - dst_vq->ops = &fimc_qops; - dst_vq->mem_ops = &vb2_dma_contig_memops; - dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - - return vb2_queue_init(dst_vq); -} - -static int fimc_m2m_set_default_format(struct fimc_ctx *ctx) -{ - struct v4l2_pix_format_mplane pixm = { - .pixelformat = V4L2_PIX_FMT_RGB32, - .width = 800, - .height = 600, - .plane_fmt[0] = { - .bytesperline = 800 * 4, - .sizeimage = 800 * 4 * 600, - }, - }; - struct fimc_fmt *fmt; - - fmt = fimc_find_format(&pixm.pixelformat, NULL, FMT_FLAGS_M2M, 0); - if (!fmt) - return -EINVAL; - - __set_frame_format(&ctx->s_frame, fmt, &pixm); - __set_frame_format(&ctx->d_frame, fmt, &pixm); - - return 0; -} - -static int fimc_m2m_open(struct file *file) -{ - struct fimc_dev *fimc = video_drvdata(file); - struct fimc_ctx *ctx; - int ret = -EBUSY; - - pr_debug("pid: %d, state: %#lx\n", task_pid_nr(current), fimc->state); - - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - /* - * Don't allow simultaneous open() of the mem-to-mem and the - * capture video node that belong to same FIMC IP instance. - */ - if (test_bit(ST_CAPT_BUSY, &fimc->state)) - goto unlock; - - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) { - ret = -ENOMEM; - goto unlock; - } - v4l2_fh_init(&ctx->fh, &fimc->m2m.vfd); - ctx->fimc_dev = fimc; - - /* Default color format */ - ctx->s_frame.fmt = fimc_get_format(0); - ctx->d_frame.fmt = fimc_get_format(0); - - ret = fimc_ctrls_create(ctx); - if (ret) - goto error_fh; - - /* Use separate control handler per file handle */ - ctx->fh.ctrl_handler = &ctx->ctrls.handler; - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); - - /* Setup the device context for memory-to-memory mode */ - ctx->state = FIMC_CTX_M2M; - ctx->flags = 0; - ctx->in_path = FIMC_IO_DMA; - ctx->out_path = FIMC_IO_DMA; - ctx->scaler.enabled = 1; - - ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); - if (IS_ERR(ctx->m2m_ctx)) { - ret = PTR_ERR(ctx->m2m_ctx); - goto error_c; - } - - if (fimc->m2m.refcnt++ == 0) - set_bit(ST_M2M_RUN, &fimc->state); - - ret = fimc_m2m_set_default_format(ctx); - if (ret < 0) - goto error_m2m_ctx; - - mutex_unlock(&fimc->lock); - return 0; - -error_m2m_ctx: - v4l2_m2m_ctx_release(ctx->m2m_ctx); -error_c: - fimc_ctrls_delete(ctx); -error_fh: - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - kfree(ctx); -unlock: - mutex_unlock(&fimc->lock); - return ret; -} - -static int fimc_m2m_release(struct file *file) -{ - struct fimc_ctx *ctx = fh_to_ctx(file->private_data); - struct fimc_dev *fimc = ctx->fimc_dev; - - dbg("pid: %d, state: 0x%lx, refcnt= %d", - task_pid_nr(current), fimc->state, fimc->m2m.refcnt); - - mutex_lock(&fimc->lock); - - v4l2_m2m_ctx_release(ctx->m2m_ctx); - fimc_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - - if (--fimc->m2m.refcnt <= 0) - clear_bit(ST_M2M_RUN, &fimc->state); - kfree(ctx); - - mutex_unlock(&fimc->lock); - return 0; -} - -static unsigned int fimc_m2m_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct fimc_ctx *ctx = fh_to_ctx(file->private_data); - struct fimc_dev *fimc = ctx->fimc_dev; - int ret; - - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - - ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); - mutex_unlock(&fimc->lock); - - return ret; -} - - -static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct fimc_ctx *ctx = fh_to_ctx(file->private_data); - struct fimc_dev *fimc = ctx->fimc_dev; - int ret; - - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; - - ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); - mutex_unlock(&fimc->lock); - - return ret; -} - -static const struct v4l2_file_operations fimc_m2m_fops = { - .owner = THIS_MODULE, - .open = fimc_m2m_open, - .release = fimc_m2m_release, - .poll = fimc_m2m_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = fimc_m2m_mmap, -}; - -static struct v4l2_m2m_ops m2m_ops = { - .device_run = fimc_device_run, - .job_abort = fimc_job_abort, -}; - -int fimc_register_m2m_device(struct fimc_dev *fimc, - struct v4l2_device *v4l2_dev) -{ - struct video_device *vfd = &fimc->m2m.vfd; - int ret; - - fimc->v4l2_dev = v4l2_dev; - - memset(vfd, 0, sizeof(*vfd)); - vfd->fops = &fimc_m2m_fops; - vfd->ioctl_ops = &fimc_m2m_ioctl_ops; - vfd->v4l2_dev = v4l2_dev; - vfd->minor = -1; - vfd->release = video_device_release_empty; - vfd->lock = &fimc->lock; - vfd->vfl_dir = VFL_DIR_M2M; - - snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id); - video_set_drvdata(vfd, fimc); - - fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops); - if (IS_ERR(fimc->m2m.m2m_dev)) { - v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n"); - return PTR_ERR(fimc->m2m.m2m_dev); - } - - ret = media_entity_init(&vfd->entity, 0, NULL, 0); - if (ret) - goto err_me; - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); - if (ret) - goto err_vd; - - v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n", - vfd->name, video_device_node_name(vfd)); - return 0; - -err_vd: - media_entity_cleanup(&vfd->entity); -err_me: - v4l2_m2m_release(fimc->m2m.m2m_dev); - return ret; -} - -void fimc_unregister_m2m_device(struct fimc_dev *fimc) -{ - if (!fimc) - return; - - if (fimc->m2m.m2m_dev) - v4l2_m2m_release(fimc->m2m.m2m_dev); - - if (video_is_registered(&fimc->m2m.vfd)) { - video_unregister_device(&fimc->m2m.vfd); - media_entity_cleanup(&fimc->m2m.vfd.entity); - } -} diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c deleted file mode 100644 index 77075a4d1145..000000000000 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ /dev/null @@ -1,1437 +0,0 @@ -/* - * S5P/EXYNOS4 SoC series camera host interface media device driver - * - * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation, either version 2 of the License, - * or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "fimc-core.h" -#include "fimc-lite.h" -#include "fimc-mdevice.h" -#include "mipi-csis.h" - -static int __fimc_md_set_camclk(struct fimc_md *fmd, - struct fimc_sensor_info *s_info, - bool on); -/** - * fimc_pipeline_prepare - update pipeline information with subdevice pointers - * @me: media entity terminating the pipeline - * - * Caller holds the graph mutex. - */ -static void fimc_pipeline_prepare(struct fimc_pipeline *p, - struct media_entity *me) -{ - struct v4l2_subdev *sd; - int i; - - for (i = 0; i < IDX_MAX; i++) - p->subdevs[i] = NULL; - - while (1) { - struct media_pad *pad = NULL; - - /* Find remote source pad */ - for (i = 0; i < me->num_pads; i++) { - struct media_pad *spad = &me->pads[i]; - if (!(spad->flags & MEDIA_PAD_FL_SINK)) - continue; - pad = media_entity_remote_source(spad); - if (pad) - break; - } - - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - break; - sd = media_entity_to_v4l2_subdev(pad->entity); - - switch (sd->grp_id) { - case GRP_ID_FIMC_IS_SENSOR: - case GRP_ID_SENSOR: - p->subdevs[IDX_SENSOR] = sd; - break; - case GRP_ID_CSIS: - p->subdevs[IDX_CSIS] = sd; - break; - case GRP_ID_FLITE: - p->subdevs[IDX_FLITE] = sd; - break; - case GRP_ID_FIMC: - /* No need to control FIMC subdev through subdev ops */ - break; - default: - pr_warn("%s: Unknown subdev grp_id: %#x\n", - __func__, sd->grp_id); - } - me = &sd->entity; - if (me->num_pads == 1) - break; - } -} - -/** - * __subdev_set_power - change power state of a single subdev - * @sd: subdevice to change power state for - * @on: 1 to enable power or 0 to disable - * - * Return result of s_power subdev operation or -ENXIO if sd argument - * is NULL. Return 0 if the subdevice does not implement s_power. - */ -static int __subdev_set_power(struct v4l2_subdev *sd, int on) -{ - int *use_count; - int ret; - - if (sd == NULL) - return -ENXIO; - - use_count = &sd->entity.use_count; - if (on && (*use_count)++ > 0) - return 0; - else if (!on && (*use_count == 0 || --(*use_count) > 0)) - return 0; - ret = v4l2_subdev_call(sd, core, s_power, on); - - return ret != -ENOIOCTLCMD ? ret : 0; -} - -/** - * fimc_pipeline_s_power - change power state of all pipeline subdevs - * @fimc: fimc device terminating the pipeline - * @state: true to power on, false to power off - * - * Needs to be called with the graph mutex held. - */ -static int fimc_pipeline_s_power(struct fimc_pipeline *p, bool on) -{ - static const u8 seq[2][IDX_MAX - 1] = { - { IDX_IS_ISP, IDX_SENSOR, IDX_CSIS, IDX_FLITE }, - { IDX_CSIS, IDX_FLITE, IDX_SENSOR, IDX_IS_ISP }, - }; - int i, ret = 0; - - if (p->subdevs[IDX_SENSOR] == NULL) - return -ENXIO; - - for (i = 0; i < IDX_MAX - 1; i++) { - unsigned int idx = seq[on][i]; - - ret = __subdev_set_power(p->subdevs[idx], on); - - - if (ret < 0 && ret != -ENXIO) - goto error; - } - return 0; -error: - for (; i >= 0; i--) { - unsigned int idx = seq[on][i]; - __subdev_set_power(p->subdevs[idx], !on); - } - return ret; -} - -/** - * __fimc_pipeline_open - update the pipeline information, enable power - * of all pipeline subdevs and the sensor clock - * @me: media entity to start graph walk with - * @prepare: true to walk the current pipeline and acquire all subdevs - * - * Called with the graph mutex held. - */ -static int __fimc_pipeline_open(struct fimc_pipeline *p, - struct media_entity *me, bool prepare) -{ - struct fimc_md *fmd = entity_to_fimc_mdev(me); - struct v4l2_subdev *sd; - int ret; - - if (WARN_ON(p == NULL || me == NULL)) - return -EINVAL; - - if (prepare) - fimc_pipeline_prepare(p, me); - - sd = p->subdevs[IDX_SENSOR]; - if (sd == NULL) - return -EINVAL; - - /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */ - if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) { - ret = clk_prepare_enable(fmd->wbclk[CLK_IDX_WB_B]); - if (ret < 0) - return ret; - } - ret = fimc_md_set_camclk(sd, true); - if (ret < 0) - goto err_wbclk; - - ret = fimc_pipeline_s_power(p, 1); - if (!ret) - return 0; - - fimc_md_set_camclk(sd, false); - -err_wbclk: - if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) - clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); - - return ret; -} - -/** - * __fimc_pipeline_close - disable the sensor clock and pipeline power - * @fimc: fimc device terminating the pipeline - * - * Disable power of all subdevs and turn the external sensor clock off. - */ -static int __fimc_pipeline_close(struct fimc_pipeline *p) -{ - struct v4l2_subdev *sd = p ? p->subdevs[IDX_SENSOR] : NULL; - struct fimc_md *fmd; - int ret = 0; - - if (WARN_ON(sd == NULL)) - return -EINVAL; - - if (p->subdevs[IDX_SENSOR]) { - ret = fimc_pipeline_s_power(p, 0); - fimc_md_set_camclk(sd, false); - } - - fmd = entity_to_fimc_mdev(&sd->entity); - - /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */ - if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) - clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); - - return ret == -ENXIO ? 0 : ret; -} - -/** - * __fimc_pipeline_s_stream - call s_stream() on pipeline subdevs - * @pipeline: video pipeline structure - * @on: passed as the s_stream() callback argument - */ -static int __fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on) -{ - static const u8 seq[2][IDX_MAX] = { - { IDX_FIMC, IDX_SENSOR, IDX_IS_ISP, IDX_CSIS, IDX_FLITE }, - { IDX_CSIS, IDX_FLITE, IDX_FIMC, IDX_SENSOR, IDX_IS_ISP }, - }; - int i, ret = 0; - - if (p->subdevs[IDX_SENSOR] == NULL) - return -ENODEV; - - for (i = 0; i < IDX_MAX; i++) { - unsigned int idx = seq[on][i]; - - ret = v4l2_subdev_call(p->subdevs[idx], video, s_stream, on); - - if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) - goto error; - } - return 0; -error: - for (; i >= 0; i--) { - unsigned int idx = seq[on][i]; - v4l2_subdev_call(p->subdevs[idx], video, s_stream, !on); - } - return ret; -} - -/* Media pipeline operations for the FIMC/FIMC-LITE video device driver */ -static const struct fimc_pipeline_ops fimc_pipeline_ops = { - .open = __fimc_pipeline_open, - .close = __fimc_pipeline_close, - .set_stream = __fimc_pipeline_s_stream, -}; - -/* - * Sensor subdevice helper functions - */ -static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd, - struct fimc_sensor_info *s_info) -{ - struct i2c_adapter *adapter; - struct v4l2_subdev *sd = NULL; - - if (!s_info || !fmd) - return NULL; - /* - * If FIMC bus type is not Writeback FIFO assume it is same - * as sensor_bus_type. - */ - s_info->pdata.fimc_bus_type = s_info->pdata.sensor_bus_type; - - adapter = i2c_get_adapter(s_info->pdata.i2c_bus_num); - if (!adapter) { - v4l2_warn(&fmd->v4l2_dev, - "Failed to get I2C adapter %d, deferring probe\n", - s_info->pdata.i2c_bus_num); - return ERR_PTR(-EPROBE_DEFER); - } - sd = v4l2_i2c_new_subdev_board(&fmd->v4l2_dev, adapter, - s_info->pdata.board_info, NULL); - if (IS_ERR_OR_NULL(sd)) { - i2c_put_adapter(adapter); - v4l2_warn(&fmd->v4l2_dev, - "Failed to acquire subdev %s, deferring probe\n", - s_info->pdata.board_info->type); - return ERR_PTR(-EPROBE_DEFER); - } - v4l2_set_subdev_hostdata(sd, s_info); - sd->grp_id = GRP_ID_SENSOR; - - v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice %s\n", - sd->name); - return sd; -} - -static void fimc_md_unregister_sensor(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct i2c_adapter *adapter; - - if (!client) - return; - v4l2_device_unregister_subdev(sd); - - if (!client->dev.of_node) { - adapter = client->adapter; - i2c_unregister_device(client); - if (adapter) - i2c_put_adapter(adapter); - } -} - -#ifdef CONFIG_OF -/* Register I2C client subdev associated with @node. */ -static int fimc_md_of_add_sensor(struct fimc_md *fmd, - struct device_node *node, int index) -{ - struct fimc_sensor_info *si; - struct i2c_client *client; - struct v4l2_subdev *sd; - int ret; - - if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor))) - return -EINVAL; - si = &fmd->sensor[index]; - - client = of_find_i2c_device_by_node(node); - if (!client) - return -EPROBE_DEFER; - - device_lock(&client->dev); - - if (!client->driver || - !try_module_get(client->driver->driver.owner)) { - ret = -EPROBE_DEFER; - v4l2_info(&fmd->v4l2_dev, "No driver found for %s\n", - node->full_name); - goto dev_put; - } - - /* Enable sensor's master clock */ - ret = __fimc_md_set_camclk(fmd, si, true); - if (ret < 0) - goto mod_put; - sd = i2c_get_clientdata(client); - - ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); - __fimc_md_set_camclk(fmd, si, false); - if (ret < 0) - goto mod_put; - - v4l2_set_subdev_hostdata(sd, si); - sd->grp_id = GRP_ID_SENSOR; - si->subdev = sd; - v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice: %s (%d)\n", - sd->name, fmd->num_sensors); - fmd->num_sensors++; - -mod_put: - module_put(client->driver->driver.owner); -dev_put: - device_unlock(&client->dev); - put_device(&client->dev); - return ret; -} - -/* Parse port node and register as a sub-device any sensor specified there. */ -static int fimc_md_parse_port_node(struct fimc_md *fmd, - struct device_node *port, - unsigned int index) -{ - struct device_node *rem, *ep, *np; - struct fimc_source_info *pd; - struct v4l2_of_endpoint endpoint; - int ret; - u32 val; - - pd = &fmd->sensor[index].pdata; - - /* Assume here a port node can have only one endpoint node. */ - ep = of_get_next_child(port, NULL); - if (!ep) - return 0; - - v4l2_of_parse_endpoint(ep, &endpoint); - if (WARN_ON(endpoint.port == 0) || index >= FIMC_MAX_SENSORS) - return -EINVAL; - - pd->mux_id = (endpoint.port - 1) & 0x1; - - rem = v4l2_of_get_remote_port_parent(ep); - of_node_put(ep); - if (rem == NULL) { - v4l2_info(&fmd->v4l2_dev, "Remote device at %s not found\n", - ep->full_name); - return 0; - } - if (!of_property_read_u32(rem, "samsung,camclk-out", &val)) - pd->clk_id = val; - - if (!of_property_read_u32(rem, "clock-frequency", &val)) - pd->clk_frequency = val; - - if (pd->clk_frequency == 0) { - v4l2_err(&fmd->v4l2_dev, "Wrong clock frequency at node %s\n", - rem->full_name); - of_node_put(rem); - return -EINVAL; - } - - if (fimc_input_is_parallel(endpoint.port)) { - if (endpoint.bus_type == V4L2_MBUS_PARALLEL) - pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_601; - else - pd->sensor_bus_type = FIMC_BUS_TYPE_ITU_656; - pd->flags = endpoint.bus.parallel.flags; - } else if (fimc_input_is_mipi_csi(endpoint.port)) { - /* - * MIPI CSI-2: only input mux selection and - * the sensor's clock frequency is needed. - */ - pd->sensor_bus_type = FIMC_BUS_TYPE_MIPI_CSI2; - } else { - v4l2_err(&fmd->v4l2_dev, "Wrong port id (%u) at node %s\n", - endpoint.port, rem->full_name); - } - /* - * For FIMC-IS handled sensors, that are placed under i2c-isp device - * node, FIMC is connected to the FIMC-IS through its ISP Writeback - * input. Sensors are attached to the FIMC-LITE hostdata interface - * directly or through MIPI-CSIS, depending on the external media bus - * used. This needs to be handled in a more reliable way, not by just - * checking parent's node name. - */ - np = of_get_parent(rem); - - if (np && !of_node_cmp(np->name, "i2c-isp")) - pd->fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK; - else - pd->fimc_bus_type = pd->sensor_bus_type; - - ret = fimc_md_of_add_sensor(fmd, rem, index); - of_node_put(rem); - - return ret; -} - -/* Register all SoC external sub-devices */ -static int fimc_md_of_sensors_register(struct fimc_md *fmd, - struct device_node *np) -{ - struct device_node *parent = fmd->pdev->dev.of_node; - struct device_node *node, *ports; - int index = 0; - int ret; - - /* Attach sensors linked to MIPI CSI-2 receivers */ - for_each_available_child_of_node(parent, node) { - struct device_node *port; - - if (of_node_cmp(node->name, "csis")) - continue; - /* The csis node can have only port subnode. */ - port = of_get_next_child(node, NULL); - if (!port) - continue; - - ret = fimc_md_parse_port_node(fmd, port, index); - if (ret < 0) - return ret; - index++; - } - - /* Attach sensors listed in the parallel-ports node */ - ports = of_get_child_by_name(parent, "parallel-ports"); - if (!ports) - return 0; - - for_each_child_of_node(ports, node) { - ret = fimc_md_parse_port_node(fmd, node, index); - if (ret < 0) - break; - index++; - } - - return 0; -} - -static int __of_get_csis_id(struct device_node *np) -{ - u32 reg = 0; - - np = of_get_child_by_name(np, "port"); - if (!np) - return -EINVAL; - of_property_read_u32(np, "reg", ®); - return reg - FIMC_INPUT_MIPI_CSI2_0; -} -#else -#define fimc_md_of_sensors_register(fmd, np) (-ENOSYS) -#define __of_get_csis_id(np) (-ENOSYS) -#endif - -static int fimc_md_register_sensor_entities(struct fimc_md *fmd) -{ - struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data; - struct device_node *of_node = fmd->pdev->dev.of_node; - int num_clients = 0; - int ret, i; - - /* - * Runtime resume one of the FIMC entities to make sure - * the sclk_cam clocks are not globally disabled. - */ - if (!fmd->pmf) - return -ENXIO; - - ret = pm_runtime_get_sync(fmd->pmf); - if (ret < 0) - return ret; - - if (of_node) { - fmd->num_sensors = 0; - ret = fimc_md_of_sensors_register(fmd, of_node); - } else if (pdata) { - WARN_ON(pdata->num_clients > ARRAY_SIZE(fmd->sensor)); - num_clients = min_t(u32, pdata->num_clients, - ARRAY_SIZE(fmd->sensor)); - fmd->num_sensors = num_clients; - - for (i = 0; i < num_clients; i++) { - struct v4l2_subdev *sd; - - fmd->sensor[i].pdata = pdata->source_info[i]; - ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], true); - if (ret) - break; - sd = fimc_md_register_sensor(fmd, &fmd->sensor[i]); - ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], false); - - if (IS_ERR(sd)) { - fmd->sensor[i].subdev = NULL; - ret = PTR_ERR(sd); - break; - } - fmd->sensor[i].subdev = sd; - if (ret) - break; - } - } - - pm_runtime_put(fmd->pmf); - return ret; -} - -/* - * MIPI-CSIS, FIMC and FIMC-LITE platform devices registration. - */ - -static int register_fimc_lite_entity(struct fimc_md *fmd, - struct fimc_lite *fimc_lite) -{ - struct v4l2_subdev *sd; - int ret; - - if (WARN_ON(fimc_lite->index >= FIMC_LITE_MAX_DEVS || - fmd->fimc_lite[fimc_lite->index])) - return -EBUSY; - - sd = &fimc_lite->subdev; - sd->grp_id = GRP_ID_FLITE; - v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops); - - ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); - if (!ret) - fmd->fimc_lite[fimc_lite->index] = fimc_lite; - else - v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.LITE%d\n", - fimc_lite->index); - return ret; -} - -static int register_fimc_entity(struct fimc_md *fmd, struct fimc_dev *fimc) -{ - struct v4l2_subdev *sd; - int ret; - - if (WARN_ON(fimc->id >= FIMC_MAX_DEVS || fmd->fimc[fimc->id])) - return -EBUSY; - - sd = &fimc->vid_cap.subdev; - sd->grp_id = GRP_ID_FIMC; - v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops); - - ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); - if (!ret) { - if (!fmd->pmf && fimc->pdev) - fmd->pmf = &fimc->pdev->dev; - fmd->fimc[fimc->id] = fimc; - fimc->vid_cap.user_subdev_api = fmd->user_subdev_api; - } else { - v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.%d (%d)\n", - fimc->id, ret); - } - return ret; -} - -static int register_csis_entity(struct fimc_md *fmd, - struct platform_device *pdev, - struct v4l2_subdev *sd) -{ - struct device_node *node = pdev->dev.of_node; - int id, ret; - - id = node ? __of_get_csis_id(node) : max(0, pdev->id); - - if (WARN_ON(id < 0 || id >= CSIS_MAX_ENTITIES)) - return -ENOENT; - - if (WARN_ON(fmd->csis[id].sd)) - return -EBUSY; - - sd->grp_id = GRP_ID_CSIS; - ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); - if (!ret) - fmd->csis[id].sd = sd; - else - v4l2_err(&fmd->v4l2_dev, - "Failed to register MIPI-CSIS.%d (%d)\n", id, ret); - return ret; -} - -static int fimc_md_register_platform_entity(struct fimc_md *fmd, - struct platform_device *pdev, - int plat_entity) -{ - struct device *dev = &pdev->dev; - int ret = -EPROBE_DEFER; - void *drvdata; - - /* Lock to ensure dev->driver won't change. */ - device_lock(dev); - - if (!dev->driver || !try_module_get(dev->driver->owner)) - goto dev_unlock; - - drvdata = dev_get_drvdata(dev); - /* Some subdev didn't probe succesfully id drvdata is NULL */ - if (drvdata) { - switch (plat_entity) { - case IDX_FIMC: - ret = register_fimc_entity(fmd, drvdata); - break; - case IDX_FLITE: - ret = register_fimc_lite_entity(fmd, drvdata); - break; - case IDX_CSIS: - ret = register_csis_entity(fmd, pdev, drvdata); - break; - default: - ret = -ENODEV; - } - } - - module_put(dev->driver->owner); -dev_unlock: - device_unlock(dev); - if (ret == -EPROBE_DEFER) - dev_info(&fmd->pdev->dev, "deferring %s device registration\n", - dev_name(dev)); - else if (ret < 0) - dev_err(&fmd->pdev->dev, "%s device registration failed (%d)\n", - dev_name(dev), ret); - return ret; -} - -static int fimc_md_pdev_match(struct device *dev, void *data) -{ - struct platform_device *pdev = to_platform_device(dev); - int plat_entity = -1; - int ret; - char *p; - - if (!get_device(dev)) - return -ENODEV; - - if (!strcmp(pdev->name, CSIS_DRIVER_NAME)) { - plat_entity = IDX_CSIS; - } else if (!strcmp(pdev->name, FIMC_LITE_DRV_NAME)) { - plat_entity = IDX_FLITE; - } else { - p = strstr(pdev->name, "fimc"); - if (p && *(p + 4) == 0) - plat_entity = IDX_FIMC; - } - - if (plat_entity >= 0) - ret = fimc_md_register_platform_entity(data, pdev, - plat_entity); - put_device(dev); - return 0; -} - -/* Register FIMC, FIMC-LITE and CSIS media entities */ -#ifdef CONFIG_OF -static int fimc_md_register_of_platform_entities(struct fimc_md *fmd, - struct device_node *parent) -{ - struct device_node *node; - int ret = 0; - - for_each_available_child_of_node(parent, node) { - struct platform_device *pdev; - int plat_entity = -1; - - pdev = of_find_device_by_node(node); - if (!pdev) - continue; - - /* If driver of any entity isn't ready try all again later. */ - if (!strcmp(node->name, CSIS_OF_NODE_NAME)) - plat_entity = IDX_CSIS; - else if (!strcmp(node->name, FIMC_LITE_OF_NODE_NAME)) - plat_entity = IDX_FLITE; - else if (!strcmp(node->name, FIMC_OF_NODE_NAME) && - !of_property_read_bool(node, "samsung,lcd-wb")) - plat_entity = IDX_FIMC; - - if (plat_entity >= 0) - ret = fimc_md_register_platform_entity(fmd, pdev, - plat_entity); - put_device(&pdev->dev); - if (ret < 0) - break; - } - - return ret; -} -#else -#define fimc_md_register_of_platform_entities(fmd, node) (-ENOSYS) -#endif - -static void fimc_md_unregister_entities(struct fimc_md *fmd) -{ - int i; - - for (i = 0; i < FIMC_MAX_DEVS; i++) { - if (fmd->fimc[i] == NULL) - continue; - v4l2_device_unregister_subdev(&fmd->fimc[i]->vid_cap.subdev); - fmd->fimc[i]->pipeline_ops = NULL; - fmd->fimc[i] = NULL; - } - for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) { - if (fmd->fimc_lite[i] == NULL) - continue; - v4l2_device_unregister_subdev(&fmd->fimc_lite[i]->subdev); - fmd->fimc_lite[i]->pipeline_ops = NULL; - fmd->fimc_lite[i] = NULL; - } - for (i = 0; i < CSIS_MAX_ENTITIES; i++) { - if (fmd->csis[i].sd == NULL) - continue; - v4l2_device_unregister_subdev(fmd->csis[i].sd); - module_put(fmd->csis[i].sd->owner); - fmd->csis[i].sd = NULL; - } - for (i = 0; i < fmd->num_sensors; i++) { - if (fmd->sensor[i].subdev == NULL) - continue; - fimc_md_unregister_sensor(fmd->sensor[i].subdev); - fmd->sensor[i].subdev = NULL; - } - v4l2_info(&fmd->v4l2_dev, "Unregistered all entities\n"); -} - -/** - * __fimc_md_create_fimc_links - create links to all FIMC entities - * @fmd: fimc media device - * @source: the source entity to create links to all fimc entities from - * @sensor: sensor subdev linked to FIMC[fimc_id] entity, may be null - * @pad: the source entity pad index - * @link_mask: bitmask of the fimc devices for which link should be enabled - */ -static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, - struct media_entity *source, - struct v4l2_subdev *sensor, - int pad, int link_mask) -{ - struct fimc_sensor_info *s_info = NULL; - struct media_entity *sink; - unsigned int flags = 0; - int ret, i; - - for (i = 0; i < FIMC_MAX_DEVS; i++) { - if (!fmd->fimc[i]) - continue; - /* - * Some FIMC variants are not fitted with camera capture - * interface. Skip creating a link from sensor for those. - */ - if (!fmd->fimc[i]->variant->has_cam_if) - continue; - - flags = ((1 << i) & link_mask) ? MEDIA_LNK_FL_ENABLED : 0; - - sink = &fmd->fimc[i]->vid_cap.subdev.entity; - ret = media_entity_create_link(source, pad, sink, - FIMC_SD_PAD_SINK_CAM, flags); - if (ret) - return ret; - - /* Notify FIMC capture subdev entity */ - ret = media_entity_call(sink, link_setup, &sink->pads[0], - &source->pads[pad], flags); - if (ret) - break; - - v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]\n", - source->name, flags ? '=' : '-', sink->name); - - if (flags == 0 || sensor == NULL) - continue; - s_info = v4l2_get_subdev_hostdata(sensor); - if (!WARN_ON(s_info == NULL)) { - unsigned long irq_flags; - spin_lock_irqsave(&fmd->slock, irq_flags); - s_info->host = fmd->fimc[i]; - spin_unlock_irqrestore(&fmd->slock, irq_flags); - } - } - - for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) { - if (!fmd->fimc_lite[i]) - continue; - - if (link_mask & (1 << (i + FIMC_MAX_DEVS))) - flags = MEDIA_LNK_FL_ENABLED; - else - flags = 0; - - sink = &fmd->fimc_lite[i]->subdev.entity; - ret = media_entity_create_link(source, pad, sink, - FLITE_SD_PAD_SINK, flags); - if (ret) - return ret; - - /* Notify FIMC-LITE subdev entity */ - ret = media_entity_call(sink, link_setup, &sink->pads[0], - &source->pads[pad], flags); - if (ret) - break; - - v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]\n", - source->name, flags ? '=' : '-', sink->name); - } - return 0; -} - -/* Create links from FIMC-LITE source pads to other entities */ -static int __fimc_md_create_flite_source_links(struct fimc_md *fmd) -{ - struct media_entity *source, *sink; - unsigned int flags = MEDIA_LNK_FL_ENABLED; - int i, ret = 0; - - for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) { - struct fimc_lite *fimc = fmd->fimc_lite[i]; - if (fimc == NULL) - continue; - source = &fimc->subdev.entity; - sink = &fimc->vfd.entity; - /* FIMC-LITE's subdev and video node */ - ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_DMA, - sink, 0, flags); - if (ret) - break; - /* TODO: create links to other entities */ - } - - return ret; -} - -/** - * fimc_md_create_links - create default links between registered entities - * - * Parallel interface sensor entities are connected directly to FIMC capture - * entities. The sensors using MIPI CSIS bus are connected through immutable - * link with CSI receiver entity specified by mux_id. Any registered CSIS - * entity has a link to each registered FIMC capture entity. Enabled links - * are created by default between each subsequent registered sensor and - * subsequent FIMC capture entity. The number of default active links is - * determined by the number of available sensors or FIMC entities, - * whichever is less. - */ -static int fimc_md_create_links(struct fimc_md *fmd) -{ - struct v4l2_subdev *csi_sensors[CSIS_MAX_ENTITIES] = { NULL }; - struct v4l2_subdev *sensor, *csis; - struct fimc_source_info *pdata; - struct fimc_sensor_info *s_info; - struct media_entity *source, *sink; - int i, pad, fimc_id = 0, ret = 0; - u32 flags, link_mask = 0; - - for (i = 0; i < fmd->num_sensors; i++) { - if (fmd->sensor[i].subdev == NULL) - continue; - - sensor = fmd->sensor[i].subdev; - s_info = v4l2_get_subdev_hostdata(sensor); - if (!s_info) - continue; - - source = NULL; - pdata = &s_info->pdata; - - switch (pdata->sensor_bus_type) { - case FIMC_BUS_TYPE_MIPI_CSI2: - if (WARN(pdata->mux_id >= CSIS_MAX_ENTITIES, - "Wrong CSI channel id: %d\n", pdata->mux_id)) - return -EINVAL; - - csis = fmd->csis[pdata->mux_id].sd; - if (WARN(csis == NULL, - "MIPI-CSI interface specified " - "but s5p-csis module is not loaded!\n")) - return -EINVAL; - - pad = sensor->entity.num_pads - 1; - ret = media_entity_create_link(&sensor->entity, pad, - &csis->entity, CSIS_PAD_SINK, - MEDIA_LNK_FL_IMMUTABLE | - MEDIA_LNK_FL_ENABLED); - if (ret) - return ret; - - v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]\n", - sensor->entity.name, csis->entity.name); - - source = NULL; - csi_sensors[pdata->mux_id] = sensor; - break; - - case FIMC_BUS_TYPE_ITU_601...FIMC_BUS_TYPE_ITU_656: - source = &sensor->entity; - pad = 0; - break; - - default: - v4l2_err(&fmd->v4l2_dev, "Wrong bus_type: %x\n", - pdata->sensor_bus_type); - return -EINVAL; - } - if (source == NULL) - continue; - - link_mask = 1 << fimc_id++; - ret = __fimc_md_create_fimc_sink_links(fmd, source, sensor, - pad, link_mask); - } - - for (i = 0; i < CSIS_MAX_ENTITIES; i++) { - if (fmd->csis[i].sd == NULL) - continue; - source = &fmd->csis[i].sd->entity; - pad = CSIS_PAD_SOURCE; - sensor = csi_sensors[i]; - - link_mask = 1 << fimc_id++; - ret = __fimc_md_create_fimc_sink_links(fmd, source, sensor, - pad, link_mask); - } - - /* Create immutable links between each FIMC's subdev and video node */ - flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED; - for (i = 0; i < FIMC_MAX_DEVS; i++) { - if (!fmd->fimc[i]) - continue; - source = &fmd->fimc[i]->vid_cap.subdev.entity; - sink = &fmd->fimc[i]->vid_cap.vfd.entity; - ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE, - sink, 0, flags); - if (ret) - break; - } - - return __fimc_md_create_flite_source_links(fmd); -} - -/* - * The peripheral sensor and CAM_BLK (PIXELASYNCMx) clocks management. - */ -static void fimc_md_put_clocks(struct fimc_md *fmd) -{ - int i = FIMC_MAX_CAMCLKS; - - while (--i >= 0) { - if (IS_ERR(fmd->camclk[i].clock)) - continue; - clk_unprepare(fmd->camclk[i].clock); - clk_put(fmd->camclk[i].clock); - fmd->camclk[i].clock = ERR_PTR(-EINVAL); - } - - /* Writeback (PIXELASYNCMx) clocks */ - for (i = 0; i < FIMC_MAX_WBCLKS; i++) { - if (IS_ERR(fmd->wbclk[i])) - continue; - clk_put(fmd->wbclk[i]); - fmd->wbclk[i] = ERR_PTR(-EINVAL); - } -} - -static int fimc_md_get_clocks(struct fimc_md *fmd) -{ - struct device *dev = NULL; - char clk_name[32]; - struct clk *clock; - int ret, i; - - for (i = 0; i < FIMC_MAX_CAMCLKS; i++) - fmd->camclk[i].clock = ERR_PTR(-EINVAL); - - if (fmd->pdev->dev.of_node) - dev = &fmd->pdev->dev; - - for (i = 0; i < FIMC_MAX_CAMCLKS; i++) { - snprintf(clk_name, sizeof(clk_name), "sclk_cam%u", i); - clock = clk_get(dev, clk_name); - - if (IS_ERR(clock)) { - dev_err(&fmd->pdev->dev, "Failed to get clock: %s\n", - clk_name); - ret = PTR_ERR(clock); - break; - } - ret = clk_prepare(clock); - if (ret < 0) { - clk_put(clock); - fmd->camclk[i].clock = ERR_PTR(-EINVAL); - break; - } - fmd->camclk[i].clock = clock; - } - if (ret) - fimc_md_put_clocks(fmd); - - if (!fmd->use_isp) - return 0; - /* - * For now get only PIXELASYNCM1 clock (Writeback B/ISP), - * leave PIXELASYNCM0 out for the LCD Writeback driver. - */ - fmd->wbclk[CLK_IDX_WB_A] = ERR_PTR(-EINVAL); - - for (i = CLK_IDX_WB_B; i < FIMC_MAX_WBCLKS; i++) { - snprintf(clk_name, sizeof(clk_name), "pxl_async%u", i); - clock = clk_get(dev, clk_name); - if (IS_ERR(clock)) { - v4l2_err(&fmd->v4l2_dev, "Failed to get clock: %s\n", - clk_name); - ret = PTR_ERR(clock); - break; - } - fmd->wbclk[i] = clock; - } - if (ret) - fimc_md_put_clocks(fmd); - - return ret; -} - -static int __fimc_md_set_camclk(struct fimc_md *fmd, - struct fimc_sensor_info *s_info, - bool on) -{ - struct fimc_source_info *pdata = &s_info->pdata; - struct fimc_camclk_info *camclk; - int ret = 0; - - if (WARN_ON(pdata->clk_id >= FIMC_MAX_CAMCLKS) || !fmd || !fmd->pmf) - return -EINVAL; - - camclk = &fmd->camclk[pdata->clk_id]; - - dbg("camclk %d, f: %lu, use_count: %d, on: %d", - pdata->clk_id, pdata->clk_frequency, camclk->use_count, on); - - if (on) { - if (camclk->use_count > 0 && - camclk->frequency != pdata->clk_frequency) - return -EINVAL; - - if (camclk->use_count++ == 0) { - clk_set_rate(camclk->clock, pdata->clk_frequency); - camclk->frequency = pdata->clk_frequency; - ret = pm_runtime_get_sync(fmd->pmf); - if (ret < 0) - return ret; - ret = clk_enable(camclk->clock); - dbg("Enabled camclk %d: f: %lu", pdata->clk_id, - clk_get_rate(camclk->clock)); - } - return ret; - } - - if (WARN_ON(camclk->use_count == 0)) - return 0; - - if (--camclk->use_count == 0) { - clk_disable(camclk->clock); - pm_runtime_put(fmd->pmf); - dbg("Disabled camclk %d", pdata->clk_id); - } - return ret; -} - -/** - * fimc_md_set_camclk - peripheral sensor clock setup - * @sd: sensor subdev to configure sclk_cam clock for - * @on: 1 to enable or 0 to disable the clock - * - * There are 2 separate clock outputs available in the SoC for external - * image processors. These clocks are shared between all registered FIMC - * devices to which sensors can be attached, either directly or through - * the MIPI CSI receiver. The clock is allowed here to be used by - * multiple sensors concurrently if they use same frequency. - * This function should only be called when the graph mutex is held. - */ -int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on) -{ - struct fimc_sensor_info *s_info = v4l2_get_subdev_hostdata(sd); - struct fimc_md *fmd = entity_to_fimc_mdev(&sd->entity); - - return __fimc_md_set_camclk(fmd, s_info, on); -} - -static int fimc_md_link_notify(struct media_pad *source, - struct media_pad *sink, u32 flags) -{ - struct fimc_lite *fimc_lite = NULL; - struct fimc_dev *fimc = NULL; - struct fimc_pipeline *pipeline; - struct v4l2_subdev *sd; - struct mutex *lock; - int ret = 0; - int ref_count; - - if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - return 0; - - sd = media_entity_to_v4l2_subdev(sink->entity); - - switch (sd->grp_id) { - case GRP_ID_FLITE: - fimc_lite = v4l2_get_subdevdata(sd); - if (WARN_ON(fimc_lite == NULL)) - return 0; - pipeline = &fimc_lite->pipeline; - lock = &fimc_lite->lock; - break; - case GRP_ID_FIMC: - fimc = v4l2_get_subdevdata(sd); - if (WARN_ON(fimc == NULL)) - return 0; - pipeline = &fimc->pipeline; - lock = &fimc->lock; - break; - default: - return 0; - } - - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - int i; - mutex_lock(lock); - ret = __fimc_pipeline_close(pipeline); - for (i = 0; i < IDX_MAX; i++) - pipeline->subdevs[i] = NULL; - if (fimc) - fimc_ctrls_delete(fimc->vid_cap.ctx); - mutex_unlock(lock); - return ret; - } - /* - * Link activation. Enable power of pipeline elements only if the - * pipeline is already in use, i.e. its video node is opened. - * Recreate the controls destroyed during the link deactivation. - */ - mutex_lock(lock); - - ref_count = fimc ? fimc->vid_cap.refcnt : fimc_lite->ref_count; - if (ref_count > 0) - ret = __fimc_pipeline_open(pipeline, source->entity, true); - if (!ret && fimc) - ret = fimc_capture_ctrls_create(fimc); - - mutex_unlock(lock); - return ret ? -EPIPE : ret; -} - -static ssize_t fimc_md_sysfs_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct platform_device *pdev = to_platform_device(dev); - struct fimc_md *fmd = platform_get_drvdata(pdev); - - if (fmd->user_subdev_api) - return strlcpy(buf, "Sub-device API (sub-dev)\n", PAGE_SIZE); - - return strlcpy(buf, "V4L2 video node only API (vid-dev)\n", PAGE_SIZE); -} - -static ssize_t fimc_md_sysfs_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct platform_device *pdev = to_platform_device(dev); - struct fimc_md *fmd = platform_get_drvdata(pdev); - bool subdev_api; - int i; - - if (!strcmp(buf, "vid-dev\n")) - subdev_api = false; - else if (!strcmp(buf, "sub-dev\n")) - subdev_api = true; - else - return count; - - fmd->user_subdev_api = subdev_api; - for (i = 0; i < FIMC_MAX_DEVS; i++) - if (fmd->fimc[i]) - fmd->fimc[i]->vid_cap.user_subdev_api = subdev_api; - return count; -} -/* - * This device attribute is to select video pipeline configuration method. - * There are following valid values: - * vid-dev - for V4L2 video node API only, subdevice will be configured - * by the host driver. - * sub-dev - for media controller API, subdevs must be configured in user - * space before starting streaming. - */ -static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO, - fimc_md_sysfs_show, fimc_md_sysfs_store); - -static int fimc_md_get_pinctrl(struct fimc_md *fmd) -{ - struct device *dev = &fmd->pdev->dev; - struct fimc_pinctrl *pctl = &fmd->pinctl; - - pctl->pinctrl = devm_pinctrl_get(dev); - if (IS_ERR(pctl->pinctrl)) - return PTR_ERR(pctl->pinctrl); - - pctl->state_default = pinctrl_lookup_state(pctl->pinctrl, - PINCTRL_STATE_DEFAULT); - if (IS_ERR(pctl->state_default)) - return PTR_ERR(pctl->state_default); - - pctl->state_idle = pinctrl_lookup_state(pctl->pinctrl, - PINCTRL_STATE_IDLE); - return 0; -} - -static int fimc_md_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct v4l2_device *v4l2_dev; - struct fimc_md *fmd; - int ret; - - fmd = devm_kzalloc(dev, sizeof(*fmd), GFP_KERNEL); - if (!fmd) - return -ENOMEM; - - spin_lock_init(&fmd->slock); - fmd->pdev = pdev; - - strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC", - sizeof(fmd->media_dev.model)); - fmd->media_dev.link_notify = fimc_md_link_notify; - fmd->media_dev.dev = dev; - - v4l2_dev = &fmd->v4l2_dev; - v4l2_dev->mdev = &fmd->media_dev; - v4l2_dev->notify = fimc_sensor_notify; - strlcpy(v4l2_dev->name, "s5p-fimc-md", sizeof(v4l2_dev->name)); - - ret = v4l2_device_register(dev, &fmd->v4l2_dev); - if (ret < 0) { - v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); - return ret; - } - ret = media_device_register(&fmd->media_dev); - if (ret < 0) { - v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret); - goto err_md; - } - ret = fimc_md_get_clocks(fmd); - if (ret) - goto err_clk; - - fmd->user_subdev_api = (dev->of_node != NULL); - - /* Protect the media graph while we're registering entities */ - mutex_lock(&fmd->media_dev.graph_mutex); - - ret = fimc_md_get_pinctrl(fmd); - if (ret < 0) { - if (ret != EPROBE_DEFER) - dev_err(dev, "Failed to get pinctrl: %d\n", ret); - goto err_unlock; - } - - if (dev->of_node) - ret = fimc_md_register_of_platform_entities(fmd, dev->of_node); - else - ret = bus_for_each_dev(&platform_bus_type, NULL, fmd, - fimc_md_pdev_match); - if (ret) - goto err_unlock; - - if (dev->platform_data || dev->of_node) { - ret = fimc_md_register_sensor_entities(fmd); - if (ret) - goto err_unlock; - } - - ret = fimc_md_create_links(fmd); - if (ret) - goto err_unlock; - ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev); - if (ret) - goto err_unlock; - - ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode); - if (ret) - goto err_unlock; - - platform_set_drvdata(pdev, fmd); - mutex_unlock(&fmd->media_dev.graph_mutex); - return 0; - -err_unlock: - mutex_unlock(&fmd->media_dev.graph_mutex); -err_clk: - media_device_unregister(&fmd->media_dev); - fimc_md_put_clocks(fmd); - fimc_md_unregister_entities(fmd); -err_md: - v4l2_device_unregister(&fmd->v4l2_dev); - return ret; -} - -static int fimc_md_remove(struct platform_device *pdev) -{ - struct fimc_md *fmd = platform_get_drvdata(pdev); - - if (!fmd) - return 0; - device_remove_file(&pdev->dev, &dev_attr_subdev_conf_mode); - fimc_md_unregister_entities(fmd); - media_device_unregister(&fmd->media_dev); - fimc_md_put_clocks(fmd); - return 0; -} - -static struct platform_device_id fimc_driver_ids[] __always_unused = { - { .name = "s5p-fimc-md" }, - { }, -}; -MODULE_DEVICE_TABLE(platform, fimc_driver_ids); - -static const struct of_device_id fimc_md_of_match[] = { - { .compatible = "samsung,fimc" }, - { }, -}; -MODULE_DEVICE_TABLE(of, fimc_md_of_match); - -static struct platform_driver fimc_md_driver = { - .probe = fimc_md_probe, - .remove = fimc_md_remove, - .driver = { - .of_match_table = of_match_ptr(fimc_md_of_match), - .name = "s5p-fimc-md", - .owner = THIS_MODULE, - } -}; - -static int __init fimc_md_init(void) -{ - int ret; - - request_module("s5p-csis"); - ret = fimc_register_driver(); - if (ret) - return ret; - - return platform_driver_register(&fimc_md_driver); -} - -static void __exit fimc_md_exit(void) -{ - platform_driver_unregister(&fimc_md_driver); - fimc_unregister_driver(); -} - -module_init(fimc_md_init); -module_exit(fimc_md_exit); - -MODULE_AUTHOR("Sylwester Nawrocki "); -MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("2.0.1"); diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.h b/drivers/media/platform/s5p-fimc/fimc-mdevice.h deleted file mode 100644 index 1d5cea5a6bbe..000000000000 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef FIMC_MDEVICE_H_ -#define FIMC_MDEVICE_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "fimc-core.h" -#include "fimc-lite.h" -#include "mipi-csis.h" - -#define FIMC_OF_NODE_NAME "fimc" -#define FIMC_LITE_OF_NODE_NAME "fimc-lite" -#define FIMC_IS_OF_NODE_NAME "fimc-is" -#define CSIS_OF_NODE_NAME "csis" - -#define PINCTRL_STATE_IDLE "idle" - -/* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */ -#define GRP_ID_SENSOR (1 << 8) -#define GRP_ID_FIMC_IS_SENSOR (1 << 9) -#define GRP_ID_WRITEBACK (1 << 10) -#define GRP_ID_CSIS (1 << 11) -#define GRP_ID_FIMC (1 << 12) -#define GRP_ID_FLITE (1 << 13) -#define GRP_ID_FIMC_IS (1 << 14) - -#define FIMC_MAX_SENSORS 8 -#define FIMC_MAX_CAMCLKS 2 - -/* LCD/ISP Writeback clocks (PIXELASYNCMx) */ -enum { - CLK_IDX_WB_A, - CLK_IDX_WB_B, - FIMC_MAX_WBCLKS -}; - -struct fimc_csis_info { - struct v4l2_subdev *sd; - int id; -}; - -struct fimc_camclk_info { - struct clk *clock; - int use_count; - unsigned long frequency; -}; - -/** - * struct fimc_sensor_info - image data source subdev information - * @pdata: sensor's atrributes passed as media device's platform data - * @subdev: image sensor v4l2 subdev - * @host: fimc device the sensor is currently linked to - * - * This data structure applies to image sensor and the writeback subdevs. - */ -struct fimc_sensor_info { - struct fimc_source_info pdata; - struct v4l2_subdev *subdev; - struct fimc_dev *host; -}; - -/** - * struct fimc_md - fimc media device information - * @csis: MIPI CSIS subdevs data - * @sensor: array of registered sensor subdevs - * @num_sensors: actual number of registered sensors - * @camclk: external sensor clock information - * @fimc: array of registered fimc devices - * @use_isp: set to true when FIMC-IS subsystem is used - * @pmf: handle to the CAMCLK clock control FIMC helper device - * @media_dev: top level media device - * @v4l2_dev: top level v4l2_device holding up the subdevs - * @pdev: platform device this media device is hooked up into - * @pinctrl: camera port pinctrl handle - * @state_default: pinctrl default state handle - * @state_idle: pinctrl idle state handle - * @user_subdev_api: true if subdevs are not configured by the host driver - * @slock: spinlock protecting @sensor array - */ -struct fimc_md { - struct fimc_csis_info csis[CSIS_MAX_ENTITIES]; - struct fimc_sensor_info sensor[FIMC_MAX_SENSORS]; - int num_sensors; - struct fimc_camclk_info camclk[FIMC_MAX_CAMCLKS]; - struct clk *wbclk[FIMC_MAX_WBCLKS]; - struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS]; - struct fimc_dev *fimc[FIMC_MAX_DEVS]; - bool use_isp; - struct device *pmf; - struct media_device media_dev; - struct v4l2_device v4l2_dev; - struct platform_device *pdev; - struct fimc_pinctrl { - struct pinctrl *pinctrl; - struct pinctrl_state *state_default; - struct pinctrl_state *state_idle; - } pinctl; - bool user_subdev_api; - spinlock_t slock; -}; - -#define is_subdev_pad(pad) (pad == NULL || \ - media_entity_type(pad->entity) == MEDIA_ENT_T_V4L2_SUBDEV) - -#define me_subtype(me) \ - ((me->type) & (MEDIA_ENT_TYPE_MASK | MEDIA_ENT_SUBTYPE_MASK)) - -#define subdev_has_devnode(__sd) (__sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE) - -static inline struct fimc_md *entity_to_fimc_mdev(struct media_entity *me) -{ - return me->parent == NULL ? NULL : - container_of(me->parent, struct fimc_md, media_dev); -} - -static inline void fimc_md_graph_lock(struct fimc_dev *fimc) -{ - mutex_lock(&fimc->vid_cap.vfd.entity.parent->graph_mutex); -} - -static inline void fimc_md_graph_unlock(struct fimc_dev *fimc) -{ - mutex_unlock(&fimc->vid_cap.vfd.entity.parent->graph_mutex); -} - -int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on); - -#endif diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.c b/drivers/media/platform/s5p-fimc/fimc-reg.c deleted file mode 100644 index ee88b94682d0..000000000000 --- a/drivers/media/platform/s5p-fimc/fimc-reg.c +++ /dev/null @@ -1,837 +0,0 @@ -/* - * Register interface file for Samsung Camera Interface (FIMC) driver - * - * Copyright (C) 2010 - 2013 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include -#include -#include - -#include -#include "fimc-mdevice.h" - -#include "fimc-reg.h" -#include "fimc-core.h" - -void fimc_hw_reset(struct fimc_dev *dev) -{ - u32 cfg; - - cfg = readl(dev->regs + FIMC_REG_CISRCFMT); - cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; - writel(cfg, dev->regs + FIMC_REG_CISRCFMT); - - /* Software reset. */ - cfg = readl(dev->regs + FIMC_REG_CIGCTRL); - cfg |= (FIMC_REG_CIGCTRL_SWRST | FIMC_REG_CIGCTRL_IRQ_LEVEL); - writel(cfg, dev->regs + FIMC_REG_CIGCTRL); - udelay(10); - - cfg = readl(dev->regs + FIMC_REG_CIGCTRL); - cfg &= ~FIMC_REG_CIGCTRL_SWRST; - writel(cfg, dev->regs + FIMC_REG_CIGCTRL); - - if (dev->drv_data->out_buf_count > 4) - fimc_hw_set_dma_seq(dev, 0xF); -} - -static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx) -{ - u32 flip = FIMC_REG_MSCTRL_FLIP_NORMAL; - - if (ctx->hflip) - flip = FIMC_REG_MSCTRL_FLIP_Y_MIRROR; - if (ctx->vflip) - flip = FIMC_REG_MSCTRL_FLIP_X_MIRROR; - - if (ctx->rotation <= 90) - return flip; - - return (flip ^ FIMC_REG_MSCTRL_FLIP_180) & FIMC_REG_MSCTRL_FLIP_180; -} - -static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx) -{ - u32 flip = FIMC_REG_CITRGFMT_FLIP_NORMAL; - - if (ctx->hflip) - flip |= FIMC_REG_CITRGFMT_FLIP_Y_MIRROR; - if (ctx->vflip) - flip |= FIMC_REG_CITRGFMT_FLIP_X_MIRROR; - - if (ctx->rotation <= 90) - return flip; - - return (flip ^ FIMC_REG_CITRGFMT_FLIP_180) & FIMC_REG_CITRGFMT_FLIP_180; -} - -void fimc_hw_set_rotation(struct fimc_ctx *ctx) -{ - u32 cfg, flip; - struct fimc_dev *dev = ctx->fimc_dev; - - cfg = readl(dev->regs + FIMC_REG_CITRGFMT); - cfg &= ~(FIMC_REG_CITRGFMT_INROT90 | FIMC_REG_CITRGFMT_OUTROT90 | - FIMC_REG_CITRGFMT_FLIP_180); - - /* - * The input and output rotator cannot work simultaneously. - * Use the output rotator in output DMA mode or the input rotator - * in direct fifo output mode. - */ - if (ctx->rotation == 90 || ctx->rotation == 270) { - if (ctx->out_path == FIMC_IO_LCDFIFO) - cfg |= FIMC_REG_CITRGFMT_INROT90; - else - cfg |= FIMC_REG_CITRGFMT_OUTROT90; - } - - if (ctx->out_path == FIMC_IO_DMA) { - cfg |= fimc_hw_get_target_flip(ctx); - writel(cfg, dev->regs + FIMC_REG_CITRGFMT); - } else { - /* LCD FIFO path */ - flip = readl(dev->regs + FIMC_REG_MSCTRL); - flip &= ~FIMC_REG_MSCTRL_FLIP_MASK; - flip |= fimc_hw_get_in_flip(ctx); - writel(flip, dev->regs + FIMC_REG_MSCTRL); - } -} - -void fimc_hw_set_target_format(struct fimc_ctx *ctx) -{ - u32 cfg; - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->d_frame; - - dbg("w= %d, h= %d color: %d", frame->width, - frame->height, frame->fmt->color); - - cfg = readl(dev->regs + FIMC_REG_CITRGFMT); - cfg &= ~(FIMC_REG_CITRGFMT_FMT_MASK | FIMC_REG_CITRGFMT_HSIZE_MASK | - FIMC_REG_CITRGFMT_VSIZE_MASK); - - switch (frame->fmt->color) { - case FIMC_FMT_RGB444...FIMC_FMT_RGB888: - cfg |= FIMC_REG_CITRGFMT_RGB; - break; - case FIMC_FMT_YCBCR420: - cfg |= FIMC_REG_CITRGFMT_YCBCR420; - break; - case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422: - if (frame->fmt->colplanes == 1) - cfg |= FIMC_REG_CITRGFMT_YCBCR422_1P; - else - cfg |= FIMC_REG_CITRGFMT_YCBCR422; - break; - default: - break; - } - - if (ctx->rotation == 90 || ctx->rotation == 270) - cfg |= (frame->height << 16) | frame->width; - else - cfg |= (frame->width << 16) | frame->height; - - writel(cfg, dev->regs + FIMC_REG_CITRGFMT); - - cfg = readl(dev->regs + FIMC_REG_CITAREA); - cfg &= ~FIMC_REG_CITAREA_MASK; - cfg |= (frame->width * frame->height); - writel(cfg, dev->regs + FIMC_REG_CITAREA); -} - -static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->d_frame; - u32 cfg; - - cfg = (frame->f_height << 16) | frame->f_width; - writel(cfg, dev->regs + FIMC_REG_ORGOSIZE); - - /* Select color space conversion equation (HD/SD size).*/ - cfg = readl(dev->regs + FIMC_REG_CIGCTRL); - if (frame->f_width >= 1280) /* HD */ - cfg |= FIMC_REG_CIGCTRL_CSC_ITU601_709; - else /* SD */ - cfg &= ~FIMC_REG_CIGCTRL_CSC_ITU601_709; - writel(cfg, dev->regs + FIMC_REG_CIGCTRL); - -} - -void fimc_hw_set_out_dma(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->d_frame; - struct fimc_dma_offset *offset = &frame->dma_offset; - struct fimc_fmt *fmt = frame->fmt; - u32 cfg; - - /* Set the input dma offsets. */ - cfg = (offset->y_v << 16) | offset->y_h; - writel(cfg, dev->regs + FIMC_REG_CIOYOFF); - - cfg = (offset->cb_v << 16) | offset->cb_h; - writel(cfg, dev->regs + FIMC_REG_CIOCBOFF); - - cfg = (offset->cr_v << 16) | offset->cr_h; - writel(cfg, dev->regs + FIMC_REG_CIOCROFF); - - fimc_hw_set_out_dma_size(ctx); - - /* Configure chroma components order. */ - cfg = readl(dev->regs + FIMC_REG_CIOCTRL); - - cfg &= ~(FIMC_REG_CIOCTRL_ORDER2P_MASK | - FIMC_REG_CIOCTRL_ORDER422_MASK | - FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK | - FIMC_REG_CIOCTRL_RGB16FMT_MASK); - - if (fmt->colplanes == 1) - cfg |= ctx->out_order_1p; - else if (fmt->colplanes == 2) - cfg |= ctx->out_order_2p | FIMC_REG_CIOCTRL_YCBCR_2PLANE; - else if (fmt->colplanes == 3) - cfg |= FIMC_REG_CIOCTRL_YCBCR_3PLANE; - - if (fmt->color == FIMC_FMT_RGB565) - cfg |= FIMC_REG_CIOCTRL_RGB565; - else if (fmt->color == FIMC_FMT_RGB555) - cfg |= FIMC_REG_CIOCTRL_ARGB1555; - else if (fmt->color == FIMC_FMT_RGB444) - cfg |= FIMC_REG_CIOCTRL_ARGB4444; - - writel(cfg, dev->regs + FIMC_REG_CIOCTRL); -} - -static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable) -{ - u32 cfg = readl(dev->regs + FIMC_REG_ORGISIZE); - if (enable) - cfg |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN; - else - cfg &= ~FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN; - writel(cfg, dev->regs + FIMC_REG_ORGISIZE); -} - -void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable) -{ - u32 cfg = readl(dev->regs + FIMC_REG_CIOCTRL); - if (enable) - cfg |= FIMC_REG_CIOCTRL_LASTIRQ_ENABLE; - else - cfg &= ~FIMC_REG_CIOCTRL_LASTIRQ_ENABLE; - writel(cfg, dev->regs + FIMC_REG_CIOCTRL); -} - -void fimc_hw_set_prescaler(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_scaler *sc = &ctx->scaler; - u32 cfg, shfactor; - - shfactor = 10 - (sc->hfactor + sc->vfactor); - cfg = shfactor << 28; - - cfg |= (sc->pre_hratio << 16) | sc->pre_vratio; - writel(cfg, dev->regs + FIMC_REG_CISCPRERATIO); - - cfg = (sc->pre_dst_width << 16) | sc->pre_dst_height; - writel(cfg, dev->regs + FIMC_REG_CISCPREDST); -} - -static void fimc_hw_set_scaler(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_scaler *sc = &ctx->scaler; - struct fimc_frame *src_frame = &ctx->s_frame; - struct fimc_frame *dst_frame = &ctx->d_frame; - - u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); - - cfg &= ~(FIMC_REG_CISCCTRL_CSCR2Y_WIDE | FIMC_REG_CISCCTRL_CSCY2R_WIDE | - FIMC_REG_CISCCTRL_SCALEUP_H | FIMC_REG_CISCCTRL_SCALEUP_V | - FIMC_REG_CISCCTRL_SCALERBYPASS | FIMC_REG_CISCCTRL_ONE2ONE | - FIMC_REG_CISCCTRL_INRGB_FMT_MASK | FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK | - FIMC_REG_CISCCTRL_INTERLACE | FIMC_REG_CISCCTRL_RGB_EXT); - - if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW)) - cfg |= (FIMC_REG_CISCCTRL_CSCR2Y_WIDE | - FIMC_REG_CISCCTRL_CSCY2R_WIDE); - - if (!sc->enabled) - cfg |= FIMC_REG_CISCCTRL_SCALERBYPASS; - - if (sc->scaleup_h) - cfg |= FIMC_REG_CISCCTRL_SCALEUP_H; - - if (sc->scaleup_v) - cfg |= FIMC_REG_CISCCTRL_SCALEUP_V; - - if (sc->copy_mode) - cfg |= FIMC_REG_CISCCTRL_ONE2ONE; - - if (ctx->in_path == FIMC_IO_DMA) { - switch (src_frame->fmt->color) { - case FIMC_FMT_RGB565: - cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB565; - break; - case FIMC_FMT_RGB666: - cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB666; - break; - case FIMC_FMT_RGB888: - cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB888; - break; - } - } - - if (ctx->out_path == FIMC_IO_DMA) { - u32 color = dst_frame->fmt->color; - - if (color >= FIMC_FMT_RGB444 && color <= FIMC_FMT_RGB565) - cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB565; - else if (color == FIMC_FMT_RGB666) - cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666; - else if (color == FIMC_FMT_RGB888) - cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888; - } else { - cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888; - - if (ctx->flags & FIMC_SCAN_MODE_INTERLACED) - cfg |= FIMC_REG_CISCCTRL_INTERLACE; - } - - writel(cfg, dev->regs + FIMC_REG_CISCCTRL); -} - -void fimc_hw_set_mainscaler(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - const struct fimc_variant *variant = dev->variant; - struct fimc_scaler *sc = &ctx->scaler; - u32 cfg; - - dbg("main_hratio= 0x%X main_vratio= 0x%X", - sc->main_hratio, sc->main_vratio); - - fimc_hw_set_scaler(ctx); - - cfg = readl(dev->regs + FIMC_REG_CISCCTRL); - cfg &= ~(FIMC_REG_CISCCTRL_MHRATIO_MASK | - FIMC_REG_CISCCTRL_MVRATIO_MASK); - - if (variant->has_mainscaler_ext) { - cfg |= FIMC_REG_CISCCTRL_MHRATIO_EXT(sc->main_hratio); - cfg |= FIMC_REG_CISCCTRL_MVRATIO_EXT(sc->main_vratio); - writel(cfg, dev->regs + FIMC_REG_CISCCTRL); - - cfg = readl(dev->regs + FIMC_REG_CIEXTEN); - - cfg &= ~(FIMC_REG_CIEXTEN_MVRATIO_EXT_MASK | - FIMC_REG_CIEXTEN_MHRATIO_EXT_MASK); - cfg |= FIMC_REG_CIEXTEN_MHRATIO_EXT(sc->main_hratio); - cfg |= FIMC_REG_CIEXTEN_MVRATIO_EXT(sc->main_vratio); - writel(cfg, dev->regs + FIMC_REG_CIEXTEN); - } else { - cfg |= FIMC_REG_CISCCTRL_MHRATIO(sc->main_hratio); - cfg |= FIMC_REG_CISCCTRL_MVRATIO(sc->main_vratio); - writel(cfg, dev->regs + FIMC_REG_CISCCTRL); - } -} - -void fimc_hw_enable_capture(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - u32 cfg; - - cfg = readl(dev->regs + FIMC_REG_CIIMGCPT); - cfg |= FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE; - - if (ctx->scaler.enabled) - cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN_SC; - else - cfg &= FIMC_REG_CIIMGCPT_IMGCPTEN_SC; - - cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN; - writel(cfg, dev->regs + FIMC_REG_CIIMGCPT); -} - -void fimc_hw_disable_capture(struct fimc_dev *dev) -{ - u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT); - cfg &= ~(FIMC_REG_CIIMGCPT_IMGCPTEN | - FIMC_REG_CIIMGCPT_IMGCPTEN_SC); - writel(cfg, dev->regs + FIMC_REG_CIIMGCPT); -} - -void fimc_hw_set_effect(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_effect *effect = &ctx->effect; - u32 cfg = 0; - - if (effect->type != FIMC_REG_CIIMGEFF_FIN_BYPASS) { - cfg |= FIMC_REG_CIIMGEFF_IE_SC_AFTER | - FIMC_REG_CIIMGEFF_IE_ENABLE; - cfg |= effect->type; - if (effect->type == FIMC_REG_CIIMGEFF_FIN_ARBITRARY) - cfg |= (effect->pat_cb << 13) | effect->pat_cr; - } - - writel(cfg, dev->regs + FIMC_REG_CIIMGEFF); -} - -void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->d_frame; - u32 cfg; - - if (!(frame->fmt->flags & FMT_HAS_ALPHA)) - return; - - cfg = readl(dev->regs + FIMC_REG_CIOCTRL); - cfg &= ~FIMC_REG_CIOCTRL_ALPHA_OUT_MASK; - cfg |= (frame->alpha << 4); - writel(cfg, dev->regs + FIMC_REG_CIOCTRL); -} - -static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->s_frame; - u32 cfg_o = 0; - u32 cfg_r = 0; - - if (FIMC_IO_LCDFIFO == ctx->out_path) - cfg_r |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN; - - cfg_o |= (frame->f_height << 16) | frame->f_width; - cfg_r |= (frame->height << 16) | frame->width; - - writel(cfg_o, dev->regs + FIMC_REG_ORGISIZE); - writel(cfg_r, dev->regs + FIMC_REG_CIREAL_ISIZE); -} - -void fimc_hw_set_in_dma(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->s_frame; - struct fimc_dma_offset *offset = &frame->dma_offset; - u32 cfg; - - /* Set the pixel offsets. */ - cfg = (offset->y_v << 16) | offset->y_h; - writel(cfg, dev->regs + FIMC_REG_CIIYOFF); - - cfg = (offset->cb_v << 16) | offset->cb_h; - writel(cfg, dev->regs + FIMC_REG_CIICBOFF); - - cfg = (offset->cr_v << 16) | offset->cr_h; - writel(cfg, dev->regs + FIMC_REG_CIICROFF); - - /* Input original and real size. */ - fimc_hw_set_in_dma_size(ctx); - - /* Use DMA autoload only in FIFO mode. */ - fimc_hw_en_autoload(dev, ctx->out_path == FIMC_IO_LCDFIFO); - - /* Set the input DMA to process single frame only. */ - cfg = readl(dev->regs + FIMC_REG_MSCTRL); - cfg &= ~(FIMC_REG_MSCTRL_INFORMAT_MASK - | FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK - | FIMC_REG_MSCTRL_INPUT_MASK - | FIMC_REG_MSCTRL_C_INT_IN_MASK - | FIMC_REG_MSCTRL_2P_IN_ORDER_MASK); - - cfg |= (FIMC_REG_MSCTRL_IN_BURST_COUNT(4) - | FIMC_REG_MSCTRL_INPUT_MEMORY - | FIMC_REG_MSCTRL_FIFO_CTRL_FULL); - - switch (frame->fmt->color) { - case FIMC_FMT_RGB565...FIMC_FMT_RGB888: - cfg |= FIMC_REG_MSCTRL_INFORMAT_RGB; - break; - case FIMC_FMT_YCBCR420: - cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR420; - - if (frame->fmt->colplanes == 2) - cfg |= ctx->in_order_2p | FIMC_REG_MSCTRL_C_INT_IN_2PLANE; - else - cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE; - - break; - case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422: - if (frame->fmt->colplanes == 1) { - cfg |= ctx->in_order_1p - | FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P; - } else { - cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR422; - - if (frame->fmt->colplanes == 2) - cfg |= ctx->in_order_2p - | FIMC_REG_MSCTRL_C_INT_IN_2PLANE; - else - cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE; - } - break; - default: - break; - } - - writel(cfg, dev->regs + FIMC_REG_MSCTRL); - - /* Input/output DMA linear/tiled mode. */ - cfg = readl(dev->regs + FIMC_REG_CIDMAPARAM); - cfg &= ~FIMC_REG_CIDMAPARAM_TILE_MASK; - - if (tiled_fmt(ctx->s_frame.fmt)) - cfg |= FIMC_REG_CIDMAPARAM_R_64X32; - - if (tiled_fmt(ctx->d_frame.fmt)) - cfg |= FIMC_REG_CIDMAPARAM_W_64X32; - - writel(cfg, dev->regs + FIMC_REG_CIDMAPARAM); -} - - -void fimc_hw_set_input_path(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - - u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL); - cfg &= ~FIMC_REG_MSCTRL_INPUT_MASK; - - if (ctx->in_path == FIMC_IO_DMA) - cfg |= FIMC_REG_MSCTRL_INPUT_MEMORY; - else - cfg |= FIMC_REG_MSCTRL_INPUT_EXTCAM; - - writel(cfg, dev->regs + FIMC_REG_MSCTRL); -} - -void fimc_hw_set_output_path(struct fimc_ctx *ctx) -{ - struct fimc_dev *dev = ctx->fimc_dev; - - u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); - cfg &= ~FIMC_REG_CISCCTRL_LCDPATHEN_FIFO; - if (ctx->out_path == FIMC_IO_LCDFIFO) - cfg |= FIMC_REG_CISCCTRL_LCDPATHEN_FIFO; - writel(cfg, dev->regs + FIMC_REG_CISCCTRL); -} - -void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr) -{ - u32 cfg = readl(dev->regs + FIMC_REG_CIREAL_ISIZE); - cfg |= FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS; - writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE); - - writel(paddr->y, dev->regs + FIMC_REG_CIIYSA(0)); - writel(paddr->cb, dev->regs + FIMC_REG_CIICBSA(0)); - writel(paddr->cr, dev->regs + FIMC_REG_CIICRSA(0)); - - cfg &= ~FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS; - writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE); -} - -void fimc_hw_set_output_addr(struct fimc_dev *dev, - struct fimc_addr *paddr, int index) -{ - int i = (index == -1) ? 0 : index; - do { - writel(paddr->y, dev->regs + FIMC_REG_CIOYSA(i)); - writel(paddr->cb, dev->regs + FIMC_REG_CIOCBSA(i)); - writel(paddr->cr, dev->regs + FIMC_REG_CIOCRSA(i)); - dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X", - i, paddr->y, paddr->cb, paddr->cr); - } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS); -} - -int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, - struct fimc_source_info *cam) -{ - u32 cfg = readl(fimc->regs + FIMC_REG_CIGCTRL); - - cfg &= ~(FIMC_REG_CIGCTRL_INVPOLPCLK | FIMC_REG_CIGCTRL_INVPOLVSYNC | - FIMC_REG_CIGCTRL_INVPOLHREF | FIMC_REG_CIGCTRL_INVPOLHSYNC | - FIMC_REG_CIGCTRL_INVPOLFIELD); - - if (cam->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) - cfg |= FIMC_REG_CIGCTRL_INVPOLPCLK; - - if (cam->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - cfg |= FIMC_REG_CIGCTRL_INVPOLVSYNC; - - if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - cfg |= FIMC_REG_CIGCTRL_INVPOLHREF; - - if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - cfg |= FIMC_REG_CIGCTRL_INVPOLHSYNC; - - if (cam->flags & V4L2_MBUS_FIELD_EVEN_LOW) - cfg |= FIMC_REG_CIGCTRL_INVPOLFIELD; - - writel(cfg, fimc->regs + FIMC_REG_CIGCTRL); - - return 0; -} - -struct mbus_pixfmt_desc { - u32 pixelcode; - u32 cisrcfmt; - u16 bus_width; -}; - -static const struct mbus_pixfmt_desc pix_desc[] = { - { V4L2_MBUS_FMT_YUYV8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCBYCR, 8 }, - { V4L2_MBUS_FMT_YVYU8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCRYCB, 8 }, - { V4L2_MBUS_FMT_VYUY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CRYCBY, 8 }, - { V4L2_MBUS_FMT_UYVY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CBYCRY, 8 }, -}; - -int fimc_hw_set_camera_source(struct fimc_dev *fimc, - struct fimc_source_info *source) -{ - struct fimc_vid_cap *vc = &fimc->vid_cap; - struct fimc_frame *f = &vc->ctx->s_frame; - u32 bus_width, cfg = 0; - int i; - - switch (source->fimc_bus_type) { - case FIMC_BUS_TYPE_ITU_601: - case FIMC_BUS_TYPE_ITU_656: - for (i = 0; i < ARRAY_SIZE(pix_desc); i++) { - if (vc->ci_fmt.code == pix_desc[i].pixelcode) { - cfg = pix_desc[i].cisrcfmt; - bus_width = pix_desc[i].bus_width; - break; - } - } - - if (i == ARRAY_SIZE(pix_desc)) { - v4l2_err(&vc->vfd, - "Camera color format not supported: %d\n", - vc->ci_fmt.code); - return -EINVAL; - } - - if (source->fimc_bus_type == FIMC_BUS_TYPE_ITU_601) { - if (bus_width == 8) - cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; - else if (bus_width == 16) - cfg |= FIMC_REG_CISRCFMT_ITU601_16BIT; - } /* else defaults to ITU-R BT.656 8-bit */ - break; - case FIMC_BUS_TYPE_MIPI_CSI2: - if (fimc_fmt_is_user_defined(f->fmt->color)) - cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT; - break; - default: - case FIMC_BUS_TYPE_ISP_WRITEBACK: - /* Anything to do here ? */ - break; - } - - cfg |= (f->o_width << 16) | f->o_height; - writel(cfg, fimc->regs + FIMC_REG_CISRCFMT); - return 0; -} - -void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f) -{ - u32 hoff2, voff2; - - u32 cfg = readl(fimc->regs + FIMC_REG_CIWDOFST); - - cfg &= ~(FIMC_REG_CIWDOFST_HOROFF_MASK | FIMC_REG_CIWDOFST_VEROFF_MASK); - cfg |= FIMC_REG_CIWDOFST_OFF_EN | - (f->offs_h << 16) | f->offs_v; - - writel(cfg, fimc->regs + FIMC_REG_CIWDOFST); - - /* See CIWDOFSTn register description in the datasheet for details. */ - hoff2 = f->o_width - f->width - f->offs_h; - voff2 = f->o_height - f->height - f->offs_v; - cfg = (hoff2 << 16) | voff2; - writel(cfg, fimc->regs + FIMC_REG_CIWDOFST2); -} - -int fimc_hw_set_camera_type(struct fimc_dev *fimc, - struct fimc_source_info *source) -{ - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; - u32 csis_data_alignment = 32; - u32 cfg, tmp; - - cfg = readl(fimc->regs + FIMC_REG_CIGCTRL); - - /* Select ITU B interface, disable Writeback path and test pattern. */ - cfg &= ~(FIMC_REG_CIGCTRL_TESTPAT_MASK | FIMC_REG_CIGCTRL_SELCAM_ITU_A | - FIMC_REG_CIGCTRL_SELCAM_MIPI | FIMC_REG_CIGCTRL_CAMIF_SELWB | - FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG | - FIMC_REG_CIGCTRL_SELWB_A); - - switch (source->fimc_bus_type) { - case FIMC_BUS_TYPE_MIPI_CSI2: - cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI; - - if (source->mux_id == 0) - cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI_A; - - /* TODO: add remaining supported formats. */ - switch (vid_cap->ci_fmt.code) { - case V4L2_MBUS_FMT_VYUY8_2X8: - tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT; - break; - case V4L2_MBUS_FMT_JPEG_1X8: - case V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8: - tmp = FIMC_REG_CSIIMGFMT_USER(1); - cfg |= FIMC_REG_CIGCTRL_CAM_JPEG; - break; - default: - v4l2_err(&vid_cap->vfd, - "Not supported camera pixel format: %#x\n", - vid_cap->ci_fmt.code); - return -EINVAL; - } - tmp |= (csis_data_alignment == 32) << 8; - - writel(tmp, fimc->regs + FIMC_REG_CSIIMGFMT); - break; - case FIMC_BUS_TYPE_ITU_601...FIMC_BUS_TYPE_ITU_656: - if (source->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */ - cfg |= FIMC_REG_CIGCTRL_SELCAM_ITU_A; - break; - case FIMC_BUS_TYPE_LCD_WRITEBACK_A: - cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; - /* fall through */ - case FIMC_BUS_TYPE_ISP_WRITEBACK: - if (fimc->variant->has_isp_wb) - cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB; - else - WARN_ONCE(1, "ISP Writeback input is not supported\n"); - break; - default: - v4l2_err(&vid_cap->vfd, "Invalid FIMC bus type selected: %d\n", - source->fimc_bus_type); - return -EINVAL; - } - writel(cfg, fimc->regs + FIMC_REG_CIGCTRL); - - return 0; -} - -void fimc_hw_clear_irq(struct fimc_dev *dev) -{ - u32 cfg = readl(dev->regs + FIMC_REG_CIGCTRL); - cfg |= FIMC_REG_CIGCTRL_IRQ_CLR; - writel(cfg, dev->regs + FIMC_REG_CIGCTRL); -} - -void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on) -{ - u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); - if (on) - cfg |= FIMC_REG_CISCCTRL_SCALERSTART; - else - cfg &= ~FIMC_REG_CISCCTRL_SCALERSTART; - writel(cfg, dev->regs + FIMC_REG_CISCCTRL); -} - -void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on) -{ - u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL); - if (on) - cfg |= FIMC_REG_MSCTRL_ENVID; - else - cfg &= ~FIMC_REG_MSCTRL_ENVID; - writel(cfg, dev->regs + FIMC_REG_MSCTRL); -} - -/* Return an index to the buffer actually being written. */ -s32 fimc_hw_get_frame_index(struct fimc_dev *dev) -{ - s32 reg; - - if (dev->drv_data->cistatus2) { - reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3f; - return reg - 1; - } - - reg = readl(dev->regs + FIMC_REG_CISTATUS); - - return (reg & FIMC_REG_CISTATUS_FRAMECNT_MASK) >> - FIMC_REG_CISTATUS_FRAMECNT_SHIFT; -} - -/* Return an index to the buffer being written previously. */ -s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev) -{ - s32 reg; - - if (!dev->drv_data->cistatus2) - return -1; - - reg = readl(dev->regs + FIMC_REG_CISTATUS2); - return ((reg >> 7) & 0x3f) - 1; -} - -/* Locking: the caller holds fimc->slock */ -void fimc_activate_capture(struct fimc_ctx *ctx) -{ - fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled); - fimc_hw_enable_capture(ctx); -} - -void fimc_deactivate_capture(struct fimc_dev *fimc) -{ - fimc_hw_en_lastirq(fimc, true); - fimc_hw_disable_capture(fimc); - fimc_hw_enable_scaler(fimc, false); - fimc_hw_en_lastirq(fimc, false); -} - -int fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc) -{ - struct regmap *map = fimc->sysreg; - unsigned int mask, val, camblk_cfg; - int ret; - - ret = regmap_read(map, SYSREG_CAMBLK, &camblk_cfg); - if (ret < 0 || ((camblk_cfg & 0x00700000) >> 20 != 0x3)) - return ret; - - if (!WARN(fimc->id >= 3, "not supported id: %d\n", fimc->id)) - val = 0x1 << (fimc->id + 20); - else - val = 0; - - mask = SYSREG_CAMBLK_FIFORST_ISP | SYSREG_CAMBLK_ISPWB_FULL_EN; - ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val); - if (ret < 0) - return ret; - - usleep_range(1000, 2000); - - val |= SYSREG_CAMBLK_FIFORST_ISP; - ret = regmap_update_bits(map, SYSREG_CAMBLK, mask, val); - if (ret < 0) - return ret; - - mask = SYSREG_ISPBLK_FIFORST_CAM_BLK; - ret = regmap_update_bits(map, SYSREG_ISPBLK, mask, ~mask); - if (ret < 0) - return ret; - - usleep_range(1000, 2000); - - return regmap_update_bits(map, SYSREG_ISPBLK, mask, mask); -} diff --git a/drivers/media/platform/s5p-fimc/fimc-reg.h b/drivers/media/platform/s5p-fimc/fimc-reg.h deleted file mode 100644 index 01da7f3622bf..000000000000 --- a/drivers/media/platform/s5p-fimc/fimc-reg.h +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Samsung camera host interface (FIMC) registers definition - * - * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef FIMC_REG_H_ -#define FIMC_REG_H_ - -#include "fimc-core.h" - -/* Input source format */ -#define FIMC_REG_CISRCFMT 0x00 -#define FIMC_REG_CISRCFMT_ITU601_8BIT (1 << 31) -#define FIMC_REG_CISRCFMT_ITU601_16BIT (1 << 29) -#define FIMC_REG_CISRCFMT_ORDER422_YCBYCR (0 << 14) -#define FIMC_REG_CISRCFMT_ORDER422_YCRYCB (1 << 14) -#define FIMC_REG_CISRCFMT_ORDER422_CBYCRY (2 << 14) -#define FIMC_REG_CISRCFMT_ORDER422_CRYCBY (3 << 14) - -/* Window offset */ -#define FIMC_REG_CIWDOFST 0x04 -#define FIMC_REG_CIWDOFST_OFF_EN (1 << 31) -#define FIMC_REG_CIWDOFST_CLROVFIY (1 << 30) -#define FIMC_REG_CIWDOFST_CLROVRLB (1 << 29) -#define FIMC_REG_CIWDOFST_HOROFF_MASK (0x7ff << 16) -#define FIMC_REG_CIWDOFST_CLROVFICB (1 << 15) -#define FIMC_REG_CIWDOFST_CLROVFICR (1 << 14) -#define FIMC_REG_CIWDOFST_VEROFF_MASK (0xfff << 0) - -/* Global control */ -#define FIMC_REG_CIGCTRL 0x08 -#define FIMC_REG_CIGCTRL_SWRST (1 << 31) -#define FIMC_REG_CIGCTRL_CAMRST_A (1 << 30) -#define FIMC_REG_CIGCTRL_SELCAM_ITU_A (1 << 29) -#define FIMC_REG_CIGCTRL_TESTPAT_NORMAL (0 << 27) -#define FIMC_REG_CIGCTRL_TESTPAT_COLOR_BAR (1 << 27) -#define FIMC_REG_CIGCTRL_TESTPAT_HOR_INC (2 << 27) -#define FIMC_REG_CIGCTRL_TESTPAT_VER_INC (3 << 27) -#define FIMC_REG_CIGCTRL_TESTPAT_MASK (3 << 27) -#define FIMC_REG_CIGCTRL_TESTPAT_SHIFT 27 -#define FIMC_REG_CIGCTRL_INVPOLPCLK (1 << 26) -#define FIMC_REG_CIGCTRL_INVPOLVSYNC (1 << 25) -#define FIMC_REG_CIGCTRL_INVPOLHREF (1 << 24) -#define FIMC_REG_CIGCTRL_IRQ_OVFEN (1 << 22) -#define FIMC_REG_CIGCTRL_HREF_MASK (1 << 21) -#define FIMC_REG_CIGCTRL_IRQ_LEVEL (1 << 20) -#define FIMC_REG_CIGCTRL_IRQ_CLR (1 << 19) -#define FIMC_REG_CIGCTRL_IRQ_ENABLE (1 << 16) -#define FIMC_REG_CIGCTRL_SHDW_DISABLE (1 << 12) -/* 0 - selects Writeback A (LCD), 1 - selects Writeback B (LCD/ISP) */ -#define FIMC_REG_CIGCTRL_SELWB_A (1 << 10) -#define FIMC_REG_CIGCTRL_CAM_JPEG (1 << 8) -#define FIMC_REG_CIGCTRL_SELCAM_MIPI_A (1 << 7) -#define FIMC_REG_CIGCTRL_CAMIF_SELWB (1 << 6) -/* 0 - ITU601; 1 - ITU709 */ -#define FIMC_REG_CIGCTRL_CSC_ITU601_709 (1 << 5) -#define FIMC_REG_CIGCTRL_INVPOLHSYNC (1 << 4) -#define FIMC_REG_CIGCTRL_SELCAM_MIPI (1 << 3) -#define FIMC_REG_CIGCTRL_INVPOLFIELD (1 << 1) -#define FIMC_REG_CIGCTRL_INTERLACE (1 << 0) - -/* Window offset 2 */ -#define FIMC_REG_CIWDOFST2 0x14 -#define FIMC_REG_CIWDOFST2_HOROFF_MASK (0xfff << 16) -#define FIMC_REG_CIWDOFST2_VEROFF_MASK (0xfff << 0) - -/* Output DMA Y/Cb/Cr plane start addresses */ -#define FIMC_REG_CIOYSA(n) (0x18 + (n) * 4) -#define FIMC_REG_CIOCBSA(n) (0x28 + (n) * 4) -#define FIMC_REG_CIOCRSA(n) (0x38 + (n) * 4) - -/* Target image format */ -#define FIMC_REG_CITRGFMT 0x48 -#define FIMC_REG_CITRGFMT_INROT90 (1 << 31) -#define FIMC_REG_CITRGFMT_YCBCR420 (0 << 29) -#define FIMC_REG_CITRGFMT_YCBCR422 (1 << 29) -#define FIMC_REG_CITRGFMT_YCBCR422_1P (2 << 29) -#define FIMC_REG_CITRGFMT_RGB (3 << 29) -#define FIMC_REG_CITRGFMT_FMT_MASK (3 << 29) -#define FIMC_REG_CITRGFMT_HSIZE_MASK (0xfff << 16) -#define FIMC_REG_CITRGFMT_FLIP_SHIFT 14 -#define FIMC_REG_CITRGFMT_FLIP_NORMAL (0 << 14) -#define FIMC_REG_CITRGFMT_FLIP_X_MIRROR (1 << 14) -#define FIMC_REG_CITRGFMT_FLIP_Y_MIRROR (2 << 14) -#define FIMC_REG_CITRGFMT_FLIP_180 (3 << 14) -#define FIMC_REG_CITRGFMT_FLIP_MASK (3 << 14) -#define FIMC_REG_CITRGFMT_OUTROT90 (1 << 13) -#define FIMC_REG_CITRGFMT_VSIZE_MASK (0xfff << 0) - -/* Output DMA control */ -#define FIMC_REG_CIOCTRL 0x4c -#define FIMC_REG_CIOCTRL_ORDER422_MASK (3 << 0) -#define FIMC_REG_CIOCTRL_ORDER422_CRYCBY (0 << 0) -#define FIMC_REG_CIOCTRL_ORDER422_CBYCRY (1 << 0) -#define FIMC_REG_CIOCTRL_ORDER422_YCRYCB (2 << 0) -#define FIMC_REG_CIOCTRL_ORDER422_YCBYCR (3 << 0) -#define FIMC_REG_CIOCTRL_LASTIRQ_ENABLE (1 << 2) -#define FIMC_REG_CIOCTRL_YCBCR_3PLANE (0 << 3) -#define FIMC_REG_CIOCTRL_YCBCR_2PLANE (1 << 3) -#define FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK (1 << 3) -#define FIMC_REG_CIOCTRL_ALPHA_OUT_MASK (0xff << 4) -#define FIMC_REG_CIOCTRL_RGB16FMT_MASK (3 << 16) -#define FIMC_REG_CIOCTRL_RGB565 (0 << 16) -#define FIMC_REG_CIOCTRL_ARGB1555 (1 << 16) -#define FIMC_REG_CIOCTRL_ARGB4444 (2 << 16) -#define FIMC_REG_CIOCTRL_ORDER2P_SHIFT 24 -#define FIMC_REG_CIOCTRL_ORDER2P_MASK (3 << 24) -#define FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB (0 << 24) - -/* Pre-scaler control 1 */ -#define FIMC_REG_CISCPRERATIO 0x50 - -#define FIMC_REG_CISCPREDST 0x54 - -/* Main scaler control */ -#define FIMC_REG_CISCCTRL 0x58 -#define FIMC_REG_CISCCTRL_SCALERBYPASS (1 << 31) -#define FIMC_REG_CISCCTRL_SCALEUP_H (1 << 30) -#define FIMC_REG_CISCCTRL_SCALEUP_V (1 << 29) -#define FIMC_REG_CISCCTRL_CSCR2Y_WIDE (1 << 28) -#define FIMC_REG_CISCCTRL_CSCY2R_WIDE (1 << 27) -#define FIMC_REG_CISCCTRL_LCDPATHEN_FIFO (1 << 26) -#define FIMC_REG_CISCCTRL_INTERLACE (1 << 25) -#define FIMC_REG_CISCCTRL_SCALERSTART (1 << 15) -#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB565 (0 << 13) -#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB666 (1 << 13) -#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB888 (2 << 13) -#define FIMC_REG_CISCCTRL_INRGB_FMT_MASK (3 << 13) -#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB565 (0 << 11) -#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666 (1 << 11) -#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888 (2 << 11) -#define FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK (3 << 11) -#define FIMC_REG_CISCCTRL_RGB_EXT (1 << 10) -#define FIMC_REG_CISCCTRL_ONE2ONE (1 << 9) -#define FIMC_REG_CISCCTRL_MHRATIO(x) ((x) << 16) -#define FIMC_REG_CISCCTRL_MVRATIO(x) ((x) << 0) -#define FIMC_REG_CISCCTRL_MHRATIO_MASK (0x1ff << 16) -#define FIMC_REG_CISCCTRL_MVRATIO_MASK (0x1ff << 0) -#define FIMC_REG_CISCCTRL_MHRATIO_EXT(x) (((x) >> 6) << 16) -#define FIMC_REG_CISCCTRL_MVRATIO_EXT(x) (((x) >> 6) << 0) - -/* Target area */ -#define FIMC_REG_CITAREA 0x5c -#define FIMC_REG_CITAREA_MASK 0x0fffffff - -/* General status */ -#define FIMC_REG_CISTATUS 0x64 -#define FIMC_REG_CISTATUS_OVFIY (1 << 31) -#define FIMC_REG_CISTATUS_OVFICB (1 << 30) -#define FIMC_REG_CISTATUS_OVFICR (1 << 29) -#define FIMC_REG_CISTATUS_VSYNC (1 << 28) -#define FIMC_REG_CISTATUS_FRAMECNT_MASK (3 << 26) -#define FIMC_REG_CISTATUS_FRAMECNT_SHIFT 26 -#define FIMC_REG_CISTATUS_WINOFF_EN (1 << 25) -#define FIMC_REG_CISTATUS_IMGCPT_EN (1 << 22) -#define FIMC_REG_CISTATUS_IMGCPT_SCEN (1 << 21) -#define FIMC_REG_CISTATUS_VSYNC_A (1 << 20) -#define FIMC_REG_CISTATUS_VSYNC_B (1 << 19) -#define FIMC_REG_CISTATUS_OVRLB (1 << 18) -#define FIMC_REG_CISTATUS_FRAME_END (1 << 17) -#define FIMC_REG_CISTATUS_LASTCAPT_END (1 << 16) -#define FIMC_REG_CISTATUS_VVALID_A (1 << 15) -#define FIMC_REG_CISTATUS_VVALID_B (1 << 14) - -/* Indexes to the last and the currently processed buffer. */ -#define FIMC_REG_CISTATUS2 0x68 - -/* Image capture control */ -#define FIMC_REG_CIIMGCPT 0xc0 -#define FIMC_REG_CIIMGCPT_IMGCPTEN (1 << 31) -#define FIMC_REG_CIIMGCPT_IMGCPTEN_SC (1 << 30) -#define FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE (1 << 25) -#define FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT (1 << 18) - -/* Frame capture sequence */ -#define FIMC_REG_CICPTSEQ 0xc4 - -/* Image effect */ -#define FIMC_REG_CIIMGEFF 0xd0 -#define FIMC_REG_CIIMGEFF_IE_ENABLE (1 << 30) -#define FIMC_REG_CIIMGEFF_IE_SC_BEFORE (0 << 29) -#define FIMC_REG_CIIMGEFF_IE_SC_AFTER (1 << 29) -#define FIMC_REG_CIIMGEFF_FIN_BYPASS (0 << 26) -#define FIMC_REG_CIIMGEFF_FIN_ARBITRARY (1 << 26) -#define FIMC_REG_CIIMGEFF_FIN_NEGATIVE (2 << 26) -#define FIMC_REG_CIIMGEFF_FIN_ARTFREEZE (3 << 26) -#define FIMC_REG_CIIMGEFF_FIN_EMBOSSING (4 << 26) -#define FIMC_REG_CIIMGEFF_FIN_SILHOUETTE (5 << 26) -#define FIMC_REG_CIIMGEFF_FIN_MASK (7 << 26) -#define FIMC_REG_CIIMGEFF_PAT_CBCR_MASK ((0xff << 13) | 0xff) - -/* Input DMA Y/Cb/Cr plane start address 0/1 */ -#define FIMC_REG_CIIYSA(n) (0xd4 + (n) * 0x70) -#define FIMC_REG_CIICBSA(n) (0xd8 + (n) * 0x70) -#define FIMC_REG_CIICRSA(n) (0xdc + (n) * 0x70) - -/* Real input DMA image size */ -#define FIMC_REG_CIREAL_ISIZE 0xf8 -#define FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN (1 << 31) -#define FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS (1 << 30) - -/* Input DMA control */ -#define FIMC_REG_MSCTRL 0xfc -#define FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK (0xf << 24) -#define FIMC_REG_MSCTRL_2P_IN_ORDER_MASK (3 << 16) -#define FIMC_REG_MSCTRL_2P_IN_ORDER_SHIFT 16 -#define FIMC_REG_MSCTRL_C_INT_IN_3PLANE (0 << 15) -#define FIMC_REG_MSCTRL_C_INT_IN_2PLANE (1 << 15) -#define FIMC_REG_MSCTRL_C_INT_IN_MASK (1 << 15) -#define FIMC_REG_MSCTRL_FLIP_SHIFT 13 -#define FIMC_REG_MSCTRL_FLIP_MASK (3 << 13) -#define FIMC_REG_MSCTRL_FLIP_NORMAL (0 << 13) -#define FIMC_REG_MSCTRL_FLIP_X_MIRROR (1 << 13) -#define FIMC_REG_MSCTRL_FLIP_Y_MIRROR (2 << 13) -#define FIMC_REG_MSCTRL_FLIP_180 (3 << 13) -#define FIMC_REG_MSCTRL_FIFO_CTRL_FULL (1 << 12) -#define FIMC_REG_MSCTRL_ORDER422_SHIFT 4 -#define FIMC_REG_MSCTRL_ORDER422_YCBYCR (0 << 4) -#define FIMC_REG_MSCTRL_ORDER422_CBYCRY (1 << 4) -#define FIMC_REG_MSCTRL_ORDER422_YCRYCB (2 << 4) -#define FIMC_REG_MSCTRL_ORDER422_CRYCBY (3 << 4) -#define FIMC_REG_MSCTRL_ORDER422_MASK (3 << 4) -#define FIMC_REG_MSCTRL_INPUT_EXTCAM (0 << 3) -#define FIMC_REG_MSCTRL_INPUT_MEMORY (1 << 3) -#define FIMC_REG_MSCTRL_INPUT_MASK (1 << 3) -#define FIMC_REG_MSCTRL_INFORMAT_YCBCR420 (0 << 1) -#define FIMC_REG_MSCTRL_INFORMAT_YCBCR422 (1 << 1) -#define FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P (2 << 1) -#define FIMC_REG_MSCTRL_INFORMAT_RGB (3 << 1) -#define FIMC_REG_MSCTRL_INFORMAT_MASK (3 << 1) -#define FIMC_REG_MSCTRL_ENVID (1 << 0) -#define FIMC_REG_MSCTRL_IN_BURST_COUNT(x) ((x) << 24) - -/* Output DMA Y/Cb/Cr offset */ -#define FIMC_REG_CIOYOFF 0x168 -#define FIMC_REG_CIOCBOFF 0x16c -#define FIMC_REG_CIOCROFF 0x170 - -/* Input DMA Y/Cb/Cr offset */ -#define FIMC_REG_CIIYOFF 0x174 -#define FIMC_REG_CIICBOFF 0x178 -#define FIMC_REG_CIICROFF 0x17c - -/* Input DMA original image size */ -#define FIMC_REG_ORGISIZE 0x180 - -/* Output DMA original image size */ -#define FIMC_REG_ORGOSIZE 0x184 - -/* Real output DMA image size (extension register) */ -#define FIMC_REG_CIEXTEN 0x188 -#define FIMC_REG_CIEXTEN_MHRATIO_EXT(x) (((x) & 0x3f) << 10) -#define FIMC_REG_CIEXTEN_MVRATIO_EXT(x) ((x) & 0x3f) -#define FIMC_REG_CIEXTEN_MHRATIO_EXT_MASK (0x3f << 10) -#define FIMC_REG_CIEXTEN_MVRATIO_EXT_MASK 0x3f - -#define FIMC_REG_CIDMAPARAM 0x18c -#define FIMC_REG_CIDMAPARAM_R_LINEAR (0 << 29) -#define FIMC_REG_CIDMAPARAM_R_64X32 (3 << 29) -#define FIMC_REG_CIDMAPARAM_W_LINEAR (0 << 13) -#define FIMC_REG_CIDMAPARAM_W_64X32 (3 << 13) -#define FIMC_REG_CIDMAPARAM_TILE_MASK ((3 << 29) | (3 << 13)) - -/* MIPI CSI image format */ -#define FIMC_REG_CSIIMGFMT 0x194 -#define FIMC_REG_CSIIMGFMT_YCBCR422_8BIT 0x1e -#define FIMC_REG_CSIIMGFMT_RAW8 0x2a -#define FIMC_REG_CSIIMGFMT_RAW10 0x2b -#define FIMC_REG_CSIIMGFMT_RAW12 0x2c -/* User defined formats. x = 0...16. */ -#define FIMC_REG_CSIIMGFMT_USER(x) (0x30 + x - 1) - -/* Output frame buffer sequence mask */ -#define FIMC_REG_CIFCNTSEQ 0x1fc - -/* SYSREG ISP Writeback register address offsets */ -#define SYSREG_ISPBLK 0x020c -#define SYSREG_ISPBLK_FIFORST_CAM_BLK (1 << 7) - -#define SYSREG_CAMBLK 0x0218 -#define SYSREG_CAMBLK_FIFORST_ISP (1 << 15) -#define SYSREG_CAMBLK_ISPWB_FULL_EN (7 << 20) - -/* - * Function declarations - */ -void fimc_hw_reset(struct fimc_dev *fimc); -void fimc_hw_set_rotation(struct fimc_ctx *ctx); -void fimc_hw_set_target_format(struct fimc_ctx *ctx); -void fimc_hw_set_out_dma(struct fimc_ctx *ctx); -void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable); -void fimc_hw_en_irq(struct fimc_dev *fimc, int enable); -void fimc_hw_set_prescaler(struct fimc_ctx *ctx); -void fimc_hw_set_mainscaler(struct fimc_ctx *ctx); -void fimc_hw_enable_capture(struct fimc_ctx *ctx); -void fimc_hw_set_effect(struct fimc_ctx *ctx); -void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx); -void fimc_hw_set_in_dma(struct fimc_ctx *ctx); -void fimc_hw_set_input_path(struct fimc_ctx *ctx); -void fimc_hw_set_output_path(struct fimc_ctx *ctx); -void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr); -void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr, - int index); -int fimc_hw_set_camera_source(struct fimc_dev *fimc, - struct fimc_source_info *cam); -void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f); -int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, - struct fimc_source_info *cam); -int fimc_hw_set_camera_type(struct fimc_dev *fimc, - struct fimc_source_info *cam); -void fimc_hw_clear_irq(struct fimc_dev *dev); -void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on); -void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on); -void fimc_hw_disable_capture(struct fimc_dev *dev); -s32 fimc_hw_get_frame_index(struct fimc_dev *dev); -s32 fimc_hw_get_prev_frame_index(struct fimc_dev *dev); -int fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc); -void fimc_activate_capture(struct fimc_ctx *ctx); -void fimc_deactivate_capture(struct fimc_dev *fimc); - -/** - * fimc_hw_set_dma_seq - configure output DMA buffer sequence - * @mask: bitmask for the DMA output buffer registers, set to 0 to skip buffer - * This function masks output DMA ring buffers, it allows to select which of - * the 32 available output buffer address registers will be used by the DMA - * engine. - */ -static inline void fimc_hw_set_dma_seq(struct fimc_dev *dev, u32 mask) -{ - writel(mask, dev->regs + FIMC_REG_CIFCNTSEQ); -} - -#endif /* FIMC_REG_H_ */ diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c deleted file mode 100644 index 8636bcddde1b..000000000000 --- a/drivers/media/platform/s5p-fimc/mipi-csis.c +++ /dev/null @@ -1,1025 +0,0 @@ -/* - * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver - * - * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mipi-csis.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-2)"); - -/* Register map definition */ - -/* CSIS global control */ -#define S5PCSIS_CTRL 0x00 -#define S5PCSIS_CTRL_DPDN_DEFAULT (0 << 31) -#define S5PCSIS_CTRL_DPDN_SWAP (1 << 31) -#define S5PCSIS_CTRL_ALIGN_32BIT (1 << 20) -#define S5PCSIS_CTRL_UPDATE_SHADOW (1 << 16) -#define S5PCSIS_CTRL_WCLK_EXTCLK (1 << 8) -#define S5PCSIS_CTRL_RESET (1 << 4) -#define S5PCSIS_CTRL_ENABLE (1 << 0) - -/* D-PHY control */ -#define S5PCSIS_DPHYCTRL 0x04 -#define S5PCSIS_DPHYCTRL_HSS_MASK (0x1f << 27) -#define S5PCSIS_DPHYCTRL_ENABLE (0x1f << 0) - -#define S5PCSIS_CONFIG 0x08 -#define S5PCSIS_CFG_FMT_YCBCR422_8BIT (0x1e << 2) -#define S5PCSIS_CFG_FMT_RAW8 (0x2a << 2) -#define S5PCSIS_CFG_FMT_RAW10 (0x2b << 2) -#define S5PCSIS_CFG_FMT_RAW12 (0x2c << 2) -/* User defined formats, x = 1...4 */ -#define S5PCSIS_CFG_FMT_USER(x) ((0x30 + x - 1) << 2) -#define S5PCSIS_CFG_FMT_MASK (0x3f << 2) -#define S5PCSIS_CFG_NR_LANE_MASK 3 - -/* Interrupt mask */ -#define S5PCSIS_INTMSK 0x10 -#define S5PCSIS_INTMSK_EN_ALL 0xf000103f -#define S5PCSIS_INTMSK_EVEN_BEFORE (1 << 31) -#define S5PCSIS_INTMSK_EVEN_AFTER (1 << 30) -#define S5PCSIS_INTMSK_ODD_BEFORE (1 << 29) -#define S5PCSIS_INTMSK_ODD_AFTER (1 << 28) -#define S5PCSIS_INTMSK_ERR_SOT_HS (1 << 12) -#define S5PCSIS_INTMSK_ERR_LOST_FS (1 << 5) -#define S5PCSIS_INTMSK_ERR_LOST_FE (1 << 4) -#define S5PCSIS_INTMSK_ERR_OVER (1 << 3) -#define S5PCSIS_INTMSK_ERR_ECC (1 << 2) -#define S5PCSIS_INTMSK_ERR_CRC (1 << 1) -#define S5PCSIS_INTMSK_ERR_UNKNOWN (1 << 0) - -/* Interrupt source */ -#define S5PCSIS_INTSRC 0x14 -#define S5PCSIS_INTSRC_EVEN_BEFORE (1 << 31) -#define S5PCSIS_INTSRC_EVEN_AFTER (1 << 30) -#define S5PCSIS_INTSRC_EVEN (0x3 << 30) -#define S5PCSIS_INTSRC_ODD_BEFORE (1 << 29) -#define S5PCSIS_INTSRC_ODD_AFTER (1 << 28) -#define S5PCSIS_INTSRC_ODD (0x3 << 28) -#define S5PCSIS_INTSRC_NON_IMAGE_DATA (0xff << 28) -#define S5PCSIS_INTSRC_ERR_SOT_HS (0xf << 12) -#define S5PCSIS_INTSRC_ERR_LOST_FS (1 << 5) -#define S5PCSIS_INTSRC_ERR_LOST_FE (1 << 4) -#define S5PCSIS_INTSRC_ERR_OVER (1 << 3) -#define S5PCSIS_INTSRC_ERR_ECC (1 << 2) -#define S5PCSIS_INTSRC_ERR_CRC (1 << 1) -#define S5PCSIS_INTSRC_ERR_UNKNOWN (1 << 0) -#define S5PCSIS_INTSRC_ERRORS 0xf03f - -/* Pixel resolution */ -#define S5PCSIS_RESOL 0x2c -#define CSIS_MAX_PIX_WIDTH 0xffff -#define CSIS_MAX_PIX_HEIGHT 0xffff - -/* Non-image packet data buffers */ -#define S5PCSIS_PKTDATA_ODD 0x2000 -#define S5PCSIS_PKTDATA_EVEN 0x3000 -#define S5PCSIS_PKTDATA_SIZE SZ_4K - -enum { - CSIS_CLK_MUX, - CSIS_CLK_GATE, -}; - -static char *csi_clock_name[] = { - [CSIS_CLK_MUX] = "sclk_csis", - [CSIS_CLK_GATE] = "csis", -}; -#define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name) -#define DEFAULT_SCLK_CSIS_FREQ 166000000UL - -static const char * const csis_supply_name[] = { - "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */ - "vddio", /* CSIS I/O and PLL (1.8V) supply */ -}; -#define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name) - -enum { - ST_POWERED = 1, - ST_STREAMING = 2, - ST_SUSPENDED = 4, -}; - -struct s5pcsis_event { - u32 mask; - const char * const name; - unsigned int counter; -}; - -static const struct s5pcsis_event s5pcsis_events[] = { - /* Errors */ - { S5PCSIS_INTSRC_ERR_SOT_HS, "SOT Error" }, - { S5PCSIS_INTSRC_ERR_LOST_FS, "Lost Frame Start Error" }, - { S5PCSIS_INTSRC_ERR_LOST_FE, "Lost Frame End Error" }, - { S5PCSIS_INTSRC_ERR_OVER, "FIFO Overflow Error" }, - { S5PCSIS_INTSRC_ERR_ECC, "ECC Error" }, - { S5PCSIS_INTSRC_ERR_CRC, "CRC Error" }, - { S5PCSIS_INTSRC_ERR_UNKNOWN, "Unknown Error" }, - /* Non-image data receive events */ - { S5PCSIS_INTSRC_EVEN_BEFORE, "Non-image data before even frame" }, - { S5PCSIS_INTSRC_EVEN_AFTER, "Non-image data after even frame" }, - { S5PCSIS_INTSRC_ODD_BEFORE, "Non-image data before odd frame" }, - { S5PCSIS_INTSRC_ODD_AFTER, "Non-image data after odd frame" }, -}; -#define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events) - -struct csis_pktbuf { - u32 *data; - unsigned int len; -}; - -/** - * struct csis_state - the driver's internal state data structure - * @lock: mutex serializing the subdev and power management operations, - * protecting @format and @flags members - * @pads: CSIS pads array - * @sd: v4l2_subdev associated with CSIS device instance - * @index: the hardware instance index - * @pdev: CSIS platform device - * @regs: mmaped I/O registers memory - * @supplies: CSIS regulator supplies - * @clock: CSIS clocks - * @irq: requested s5p-mipi-csis irq number - * @flags: the state variable for power and streaming control - * @clock_frequency: device bus clock frequency - * @hs_settle: HS-RX settle time - * @num_lanes: number of MIPI-CSI data lanes used - * @max_num_lanes: maximum number of MIPI-CSI data lanes supported - * @wclk_ext: CSI wrapper clock: 0 - bus clock, 1 - external SCLK_CAM - * @csis_fmt: current CSIS pixel format - * @format: common media bus format for the source and sink pad - * @slock: spinlock protecting structure members below - * @pkt_buf: the frame embedded (non-image) data buffer - * @events: MIPI-CSIS event (error) counters - */ -struct csis_state { - struct mutex lock; - struct media_pad pads[CSIS_PADS_NUM]; - struct v4l2_subdev sd; - u8 index; - struct platform_device *pdev; - void __iomem *regs; - struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; - struct clk *clock[NUM_CSIS_CLOCKS]; - int irq; - u32 flags; - - u32 clk_frequency; - u32 hs_settle; - u32 num_lanes; - u32 max_num_lanes; - u8 wclk_ext; - - const struct csis_pix_format *csis_fmt; - struct v4l2_mbus_framefmt format; - - spinlock_t slock; - struct csis_pktbuf pkt_buf; - struct s5pcsis_event events[S5PCSIS_NUM_EVENTS]; -}; - -/** - * struct csis_pix_format - CSIS pixel format description - * @pix_width_alignment: horizontal pixel alignment, width will be - * multiple of 2^pix_width_alignment - * @code: corresponding media bus code - * @fmt_reg: S5PCSIS_CONFIG register value - * @data_alignment: MIPI-CSI data alignment in bits - */ -struct csis_pix_format { - unsigned int pix_width_alignment; - enum v4l2_mbus_pixelcode code; - u32 fmt_reg; - u8 data_alignment; -}; - -static const struct csis_pix_format s5pcsis_formats[] = { - { - .code = V4L2_MBUS_FMT_VYUY8_2X8, - .fmt_reg = S5PCSIS_CFG_FMT_YCBCR422_8BIT, - .data_alignment = 32, - }, { - .code = V4L2_MBUS_FMT_JPEG_1X8, - .fmt_reg = S5PCSIS_CFG_FMT_USER(1), - .data_alignment = 32, - }, { - .code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8, - .fmt_reg = S5PCSIS_CFG_FMT_USER(1), - .data_alignment = 32, - }, { - .code = V4L2_MBUS_FMT_SGRBG8_1X8, - .fmt_reg = S5PCSIS_CFG_FMT_RAW8, - .data_alignment = 24, - }, { - .code = V4L2_MBUS_FMT_SGRBG10_1X10, - .fmt_reg = S5PCSIS_CFG_FMT_RAW10, - .data_alignment = 24, - }, { - .code = V4L2_MBUS_FMT_SGRBG12_1X12, - .fmt_reg = S5PCSIS_CFG_FMT_RAW12, - .data_alignment = 24, - } -}; - -#define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r) -#define s5pcsis_read(__csis, __r) readl(__csis->regs + __r) - -static struct csis_state *sd_to_csis_state(struct v4l2_subdev *sdev) -{ - return container_of(sdev, struct csis_state, sd); -} - -static const struct csis_pix_format *find_csis_format( - struct v4l2_mbus_framefmt *mf) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(s5pcsis_formats); i++) - if (mf->code == s5pcsis_formats[i].code) - return &s5pcsis_formats[i]; - return NULL; -} - -static void s5pcsis_enable_interrupts(struct csis_state *state, bool on) -{ - u32 val = s5pcsis_read(state, S5PCSIS_INTMSK); - - val = on ? val | S5PCSIS_INTMSK_EN_ALL : - val & ~S5PCSIS_INTMSK_EN_ALL; - s5pcsis_write(state, S5PCSIS_INTMSK, val); -} - -static void s5pcsis_reset(struct csis_state *state) -{ - u32 val = s5pcsis_read(state, S5PCSIS_CTRL); - - s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_RESET); - udelay(10); -} - -static void s5pcsis_system_enable(struct csis_state *state, int on) -{ - u32 val, mask; - - val = s5pcsis_read(state, S5PCSIS_CTRL); - if (on) - val |= S5PCSIS_CTRL_ENABLE; - else - val &= ~S5PCSIS_CTRL_ENABLE; - s5pcsis_write(state, S5PCSIS_CTRL, val); - - val = s5pcsis_read(state, S5PCSIS_DPHYCTRL); - val &= ~S5PCSIS_DPHYCTRL_ENABLE; - if (on) { - mask = (1 << (state->num_lanes + 1)) - 1; - val |= (mask & S5PCSIS_DPHYCTRL_ENABLE); - } - s5pcsis_write(state, S5PCSIS_DPHYCTRL, val); -} - -/* Called with the state.lock mutex held */ -static void __s5pcsis_set_format(struct csis_state *state) -{ - struct v4l2_mbus_framefmt *mf = &state->format; - u32 val; - - v4l2_dbg(1, debug, &state->sd, "fmt: %#x, %d x %d\n", - mf->code, mf->width, mf->height); - - /* Color format */ - val = s5pcsis_read(state, S5PCSIS_CONFIG); - val = (val & ~S5PCSIS_CFG_FMT_MASK) | state->csis_fmt->fmt_reg; - s5pcsis_write(state, S5PCSIS_CONFIG, val); - - /* Pixel resolution */ - val = (mf->width << 16) | mf->height; - s5pcsis_write(state, S5PCSIS_RESOL, val); -} - -static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle) -{ - u32 val = s5pcsis_read(state, S5PCSIS_DPHYCTRL); - - val = (val & ~S5PCSIS_DPHYCTRL_HSS_MASK) | (settle << 27); - s5pcsis_write(state, S5PCSIS_DPHYCTRL, val); -} - -static void s5pcsis_set_params(struct csis_state *state) -{ - u32 val; - - val = s5pcsis_read(state, S5PCSIS_CONFIG); - val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (state->num_lanes - 1); - s5pcsis_write(state, S5PCSIS_CONFIG, val); - - __s5pcsis_set_format(state); - s5pcsis_set_hsync_settle(state, state->hs_settle); - - val = s5pcsis_read(state, S5PCSIS_CTRL); - if (state->csis_fmt->data_alignment == 32) - val |= S5PCSIS_CTRL_ALIGN_32BIT; - else /* 24-bits */ - val &= ~S5PCSIS_CTRL_ALIGN_32BIT; - - val &= ~S5PCSIS_CTRL_WCLK_EXTCLK; - if (state->wclk_ext) - val |= S5PCSIS_CTRL_WCLK_EXTCLK; - s5pcsis_write(state, S5PCSIS_CTRL, val); - - /* Update the shadow register. */ - val = s5pcsis_read(state, S5PCSIS_CTRL); - s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_UPDATE_SHADOW); -} - -static void s5pcsis_clk_put(struct csis_state *state) -{ - int i; - - for (i = 0; i < NUM_CSIS_CLOCKS; i++) { - if (IS_ERR(state->clock[i])) - continue; - clk_unprepare(state->clock[i]); - clk_put(state->clock[i]); - state->clock[i] = ERR_PTR(-EINVAL); - } -} - -static int s5pcsis_clk_get(struct csis_state *state) -{ - struct device *dev = &state->pdev->dev; - int i, ret; - - for (i = 0; i < NUM_CSIS_CLOCKS; i++) - state->clock[i] = ERR_PTR(-EINVAL); - - for (i = 0; i < NUM_CSIS_CLOCKS; i++) { - state->clock[i] = clk_get(dev, csi_clock_name[i]); - if (IS_ERR(state->clock[i])) { - ret = PTR_ERR(state->clock[i]); - goto err; - } - ret = clk_prepare(state->clock[i]); - if (ret < 0) { - clk_put(state->clock[i]); - state->clock[i] = ERR_PTR(-EINVAL); - goto err; - } - } - return 0; -err: - s5pcsis_clk_put(state); - dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]); - return ret; -} - -static void dump_regs(struct csis_state *state, const char *label) -{ - struct { - u32 offset; - const char * const name; - } registers[] = { - { 0x00, "CTRL" }, - { 0x04, "DPHYCTRL" }, - { 0x08, "CONFIG" }, - { 0x0c, "DPHYSTS" }, - { 0x10, "INTMSK" }, - { 0x2c, "RESOL" }, - { 0x38, "SDW_CONFIG" }, - }; - u32 i; - - v4l2_info(&state->sd, "--- %s ---\n", label); - - for (i = 0; i < ARRAY_SIZE(registers); i++) { - u32 cfg = s5pcsis_read(state, registers[i].offset); - v4l2_info(&state->sd, "%10s: 0x%08x\n", registers[i].name, cfg); - } -} - -static void s5pcsis_start_stream(struct csis_state *state) -{ - s5pcsis_reset(state); - s5pcsis_set_params(state); - s5pcsis_system_enable(state, true); - s5pcsis_enable_interrupts(state, true); -} - -static void s5pcsis_stop_stream(struct csis_state *state) -{ - s5pcsis_enable_interrupts(state, false); - s5pcsis_system_enable(state, false); -} - -static void s5pcsis_clear_counters(struct csis_state *state) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&state->slock, flags); - for (i = 0; i < S5PCSIS_NUM_EVENTS; i++) - state->events[i].counter = 0; - spin_unlock_irqrestore(&state->slock, flags); -} - -static void s5pcsis_log_counters(struct csis_state *state, bool non_errors) -{ - int i = non_errors ? S5PCSIS_NUM_EVENTS : S5PCSIS_NUM_EVENTS - 4; - unsigned long flags; - - spin_lock_irqsave(&state->slock, flags); - - for (i--; i >= 0; i--) { - if (state->events[i].counter > 0 || debug) - v4l2_info(&state->sd, "%s events: %d\n", - state->events[i].name, - state->events[i].counter); - } - spin_unlock_irqrestore(&state->slock, flags); -} - -/* - * V4L2 subdev operations - */ -static int s5pcsis_s_power(struct v4l2_subdev *sd, int on) -{ - struct csis_state *state = sd_to_csis_state(sd); - struct device *dev = &state->pdev->dev; - - if (on) - return pm_runtime_get_sync(dev); - - return pm_runtime_put_sync(dev); -} - -static int s5pcsis_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct csis_state *state = sd_to_csis_state(sd); - int ret = 0; - - v4l2_dbg(1, debug, sd, "%s: %d, state: 0x%x\n", - __func__, enable, state->flags); - - if (enable) { - s5pcsis_clear_counters(state); - ret = pm_runtime_get_sync(&state->pdev->dev); - if (ret && ret != 1) - return ret; - } - - mutex_lock(&state->lock); - if (enable) { - if (state->flags & ST_SUSPENDED) { - ret = -EBUSY; - goto unlock; - } - s5pcsis_start_stream(state); - state->flags |= ST_STREAMING; - } else { - s5pcsis_stop_stream(state); - state->flags &= ~ST_STREAMING; - if (debug > 0) - s5pcsis_log_counters(state, true); - } -unlock: - mutex_unlock(&state->lock); - if (!enable) - pm_runtime_put(&state->pdev->dev); - - return ret == 1 ? 0 : ret; -} - -static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index >= ARRAY_SIZE(s5pcsis_formats)) - return -EINVAL; - - code->code = s5pcsis_formats[code->index].code; - return 0; -} - -static struct csis_pix_format const *s5pcsis_try_format( - struct v4l2_mbus_framefmt *mf) -{ - struct csis_pix_format const *csis_fmt; - - csis_fmt = find_csis_format(mf); - if (csis_fmt == NULL) - csis_fmt = &s5pcsis_formats[0]; - - mf->code = csis_fmt->code; - v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH, - csis_fmt->pix_width_alignment, - &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1, - 0); - return csis_fmt; -} - -static struct v4l2_mbus_framefmt *__s5pcsis_get_format( - struct csis_state *state, struct v4l2_subdev_fh *fh, - u32 pad, enum v4l2_subdev_format_whence which) -{ - if (which == V4L2_SUBDEV_FORMAT_TRY) - return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL; - - return &state->format; -} - -static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct csis_state *state = sd_to_csis_state(sd); - struct csis_pix_format const *csis_fmt; - struct v4l2_mbus_framefmt *mf; - - if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK) - return -EINVAL; - - mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which); - - if (fmt->pad == CSIS_PAD_SOURCE) { - if (mf) { - mutex_lock(&state->lock); - fmt->format = *mf; - mutex_unlock(&state->lock); - } - return 0; - } - csis_fmt = s5pcsis_try_format(&fmt->format); - if (mf) { - mutex_lock(&state->lock); - *mf = fmt->format; - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) - state->csis_fmt = csis_fmt; - mutex_unlock(&state->lock); - } - return 0; -} - -static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, - struct v4l2_subdev_format *fmt) -{ - struct csis_state *state = sd_to_csis_state(sd); - struct v4l2_mbus_framefmt *mf; - - if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK) - return -EINVAL; - - mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which); - if (!mf) - return -EINVAL; - - mutex_lock(&state->lock); - fmt->format = *mf; - mutex_unlock(&state->lock); - return 0; -} - -static int s5pcsis_s_rx_buffer(struct v4l2_subdev *sd, void *buf, - unsigned int *size) -{ - struct csis_state *state = sd_to_csis_state(sd); - unsigned long flags; - - *size = min_t(unsigned int, *size, S5PCSIS_PKTDATA_SIZE); - - spin_lock_irqsave(&state->slock, flags); - state->pkt_buf.data = buf; - state->pkt_buf.len = *size; - spin_unlock_irqrestore(&state->slock, flags); - - return 0; -} - -static int s5pcsis_log_status(struct v4l2_subdev *sd) -{ - struct csis_state *state = sd_to_csis_state(sd); - - mutex_lock(&state->lock); - s5pcsis_log_counters(state, true); - if (debug && (state->flags & ST_POWERED)) - dump_regs(state, __func__); - mutex_unlock(&state->lock); - return 0; -} - -static int s5pcsis_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); - - format->colorspace = V4L2_COLORSPACE_JPEG; - format->code = s5pcsis_formats[0].code; - format->width = S5PCSIS_DEF_PIX_WIDTH; - format->height = S5PCSIS_DEF_PIX_HEIGHT; - format->field = V4L2_FIELD_NONE; - - return 0; -} - -static const struct v4l2_subdev_internal_ops s5pcsis_sd_internal_ops = { - .open = s5pcsis_open, -}; - -static struct v4l2_subdev_core_ops s5pcsis_core_ops = { - .s_power = s5pcsis_s_power, - .log_status = s5pcsis_log_status, -}; - -static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = { - .enum_mbus_code = s5pcsis_enum_mbus_code, - .get_fmt = s5pcsis_get_fmt, - .set_fmt = s5pcsis_set_fmt, -}; - -static struct v4l2_subdev_video_ops s5pcsis_video_ops = { - .s_rx_buffer = s5pcsis_s_rx_buffer, - .s_stream = s5pcsis_s_stream, -}; - -static struct v4l2_subdev_ops s5pcsis_subdev_ops = { - .core = &s5pcsis_core_ops, - .pad = &s5pcsis_pad_ops, - .video = &s5pcsis_video_ops, -}; - -static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id) -{ - struct csis_state *state = dev_id; - struct csis_pktbuf *pktbuf = &state->pkt_buf; - unsigned long flags; - u32 status; - - status = s5pcsis_read(state, S5PCSIS_INTSRC); - spin_lock_irqsave(&state->slock, flags); - - if ((status & S5PCSIS_INTSRC_NON_IMAGE_DATA) && pktbuf->data) { - u32 offset; - - if (status & S5PCSIS_INTSRC_EVEN) - offset = S5PCSIS_PKTDATA_EVEN; - else - offset = S5PCSIS_PKTDATA_ODD; - - memcpy(pktbuf->data, state->regs + offset, pktbuf->len); - pktbuf->data = NULL; - rmb(); - } - - /* Update the event/error counters */ - if ((status & S5PCSIS_INTSRC_ERRORS) || debug) { - int i; - for (i = 0; i < S5PCSIS_NUM_EVENTS; i++) { - if (!(status & state->events[i].mask)) - continue; - state->events[i].counter++; - v4l2_dbg(2, debug, &state->sd, "%s: %d\n", - state->events[i].name, - state->events[i].counter); - } - v4l2_dbg(2, debug, &state->sd, "status: %08x\n", status); - } - spin_unlock_irqrestore(&state->slock, flags); - - s5pcsis_write(state, S5PCSIS_INTSRC, status); - return IRQ_HANDLED; -} - -static int s5pcsis_get_platform_data(struct platform_device *pdev, - struct csis_state *state) -{ - struct s5p_platform_mipi_csis *pdata = pdev->dev.platform_data; - - if (pdata == NULL) { - dev_err(&pdev->dev, "Platform data not specified\n"); - return -EINVAL; - } - - state->clk_frequency = pdata->clk_rate; - state->num_lanes = pdata->lanes; - state->hs_settle = pdata->hs_settle; - state->index = max(0, pdev->id); - state->max_num_lanes = state->index ? CSIS1_MAX_LANES : - CSIS0_MAX_LANES; - return 0; -} - -#ifdef CONFIG_OF -static int s5pcsis_parse_dt(struct platform_device *pdev, - struct csis_state *state) -{ - struct device_node *node = pdev->dev.of_node; - struct v4l2_of_endpoint endpoint; - - if (of_property_read_u32(node, "clock-frequency", - &state->clk_frequency)) - state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; - if (of_property_read_u32(node, "bus-width", - &state->max_num_lanes)) - return -EINVAL; - - node = v4l2_of_get_next_endpoint(node, NULL); - if (!node) { - dev_err(&pdev->dev, "No port node at %s\n", - node->full_name); - return -EINVAL; - } - /* Get port node and validate MIPI-CSI channel id. */ - v4l2_of_parse_endpoint(node, &endpoint); - - state->index = endpoint.port - FIMC_INPUT_MIPI_CSI2_0; - if (state->index < 0 || state->index >= CSIS_MAX_ENTITIES) - return -ENXIO; - - /* Get MIPI CSI-2 bus configration from the endpoint node. */ - of_property_read_u32(node, "samsung,csis-hs-settle", - &state->hs_settle); - state->wclk_ext = of_property_read_bool(node, - "samsung,csis-wclk"); - - state->num_lanes = endpoint.bus.mipi_csi2.num_data_lanes; - - of_node_put(node); - return 0; -} -#else -#define s5pcsis_parse_dt(pdev, state) (-ENOSYS) -#endif - -static int s5pcsis_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct resource *mem_res; - struct csis_state *state; - int ret = -ENOMEM; - int i; - - state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); - if (!state) - return -ENOMEM; - - mutex_init(&state->lock); - spin_lock_init(&state->slock); - state->pdev = pdev; - - if (dev->of_node) - ret = s5pcsis_parse_dt(pdev, state); - else - ret = s5pcsis_get_platform_data(pdev, state); - if (ret < 0) - return ret; - - if (state->num_lanes == 0 || state->num_lanes > state->max_num_lanes) { - dev_err(dev, "Unsupported number of data lanes: %d (max. %d)\n", - state->num_lanes, state->max_num_lanes); - return -EINVAL; - } - - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - state->regs = devm_ioremap_resource(dev, mem_res); - if (IS_ERR(state->regs)) - return PTR_ERR(state->regs); - - state->irq = platform_get_irq(pdev, 0); - if (state->irq < 0) { - dev_err(dev, "Failed to get irq\n"); - return state->irq; - } - - for (i = 0; i < CSIS_NUM_SUPPLIES; i++) - state->supplies[i].supply = csis_supply_name[i]; - - ret = devm_regulator_bulk_get(dev, CSIS_NUM_SUPPLIES, - state->supplies); - if (ret) - return ret; - - ret = s5pcsis_clk_get(state); - if (ret < 0) - return ret; - - if (state->clk_frequency) - ret = clk_set_rate(state->clock[CSIS_CLK_MUX], - state->clk_frequency); - else - dev_WARN(dev, "No clock frequency specified!\n"); - if (ret < 0) - goto e_clkput; - - ret = clk_enable(state->clock[CSIS_CLK_MUX]); - if (ret < 0) - goto e_clkput; - - ret = devm_request_irq(dev, state->irq, s5pcsis_irq_handler, - 0, dev_name(dev), state); - if (ret) { - dev_err(dev, "Interrupt request failed\n"); - goto e_clkdis; - } - - v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops); - state->sd.owner = THIS_MODULE; - snprintf(state->sd.name, sizeof(state->sd.name), "%s.%d", - CSIS_SUBDEV_NAME, state->index); - state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - state->csis_fmt = &s5pcsis_formats[0]; - - state->format.code = s5pcsis_formats[0].code; - state->format.width = S5PCSIS_DEF_PIX_WIDTH; - state->format.height = S5PCSIS_DEF_PIX_HEIGHT; - - state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_init(&state->sd.entity, - CSIS_PADS_NUM, state->pads, 0); - if (ret < 0) - goto e_clkdis; - - /* This allows to retrieve the platform device id by the host driver */ - v4l2_set_subdevdata(&state->sd, pdev); - - /* .. and a pointer to the subdev. */ - platform_set_drvdata(pdev, &state->sd); - memcpy(state->events, s5pcsis_events, sizeof(state->events)); - pm_runtime_enable(dev); - - dev_info(&pdev->dev, "lanes: %d, hs_settle: %d, wclk: %d, freq: %u\n", - state->num_lanes, state->hs_settle, state->wclk_ext, - state->clk_frequency); - return 0; - -e_clkdis: - clk_disable(state->clock[CSIS_CLK_MUX]); -e_clkput: - s5pcsis_clk_put(state); - return ret; -} - -static int s5pcsis_pm_suspend(struct device *dev, bool runtime) -{ - struct platform_device *pdev = to_platform_device(dev); - struct v4l2_subdev *sd = platform_get_drvdata(pdev); - struct csis_state *state = sd_to_csis_state(sd); - int ret = 0; - - v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n", - __func__, state->flags); - - mutex_lock(&state->lock); - if (state->flags & ST_POWERED) { - s5pcsis_stop_stream(state); - ret = s5p_csis_phy_enable(state->index, false); - if (ret) - goto unlock; - ret = regulator_bulk_disable(CSIS_NUM_SUPPLIES, - state->supplies); - if (ret) - goto unlock; - clk_disable(state->clock[CSIS_CLK_GATE]); - state->flags &= ~ST_POWERED; - if (!runtime) - state->flags |= ST_SUSPENDED; - } - unlock: - mutex_unlock(&state->lock); - return ret ? -EAGAIN : 0; -} - -static int s5pcsis_pm_resume(struct device *dev, bool runtime) -{ - struct platform_device *pdev = to_platform_device(dev); - struct v4l2_subdev *sd = platform_get_drvdata(pdev); - struct csis_state *state = sd_to_csis_state(sd); - int ret = 0; - - v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n", - __func__, state->flags); - - mutex_lock(&state->lock); - if (!runtime && !(state->flags & ST_SUSPENDED)) - goto unlock; - - if (!(state->flags & ST_POWERED)) { - ret = regulator_bulk_enable(CSIS_NUM_SUPPLIES, - state->supplies); - if (ret) - goto unlock; - ret = s5p_csis_phy_enable(state->index, true); - if (!ret) { - state->flags |= ST_POWERED; - } else { - regulator_bulk_disable(CSIS_NUM_SUPPLIES, - state->supplies); - goto unlock; - } - clk_enable(state->clock[CSIS_CLK_GATE]); - } - if (state->flags & ST_STREAMING) - s5pcsis_start_stream(state); - - state->flags &= ~ST_SUSPENDED; - unlock: - mutex_unlock(&state->lock); - return ret ? -EAGAIN : 0; -} - -#ifdef CONFIG_PM_SLEEP -static int s5pcsis_suspend(struct device *dev) -{ - return s5pcsis_pm_suspend(dev, false); -} - -static int s5pcsis_resume(struct device *dev) -{ - return s5pcsis_pm_resume(dev, false); -} -#endif - -#ifdef CONFIG_PM_RUNTIME -static int s5pcsis_runtime_suspend(struct device *dev) -{ - return s5pcsis_pm_suspend(dev, true); -} - -static int s5pcsis_runtime_resume(struct device *dev) -{ - return s5pcsis_pm_resume(dev, true); -} -#endif - -static int s5pcsis_remove(struct platform_device *pdev) -{ - struct v4l2_subdev *sd = platform_get_drvdata(pdev); - struct csis_state *state = sd_to_csis_state(sd); - - pm_runtime_disable(&pdev->dev); - s5pcsis_pm_suspend(&pdev->dev, false); - clk_disable(state->clock[CSIS_CLK_MUX]); - pm_runtime_set_suspended(&pdev->dev); - s5pcsis_clk_put(state); - - media_entity_cleanup(&state->sd.entity); - - return 0; -} - -static const struct dev_pm_ops s5pcsis_pm_ops = { - SET_RUNTIME_PM_OPS(s5pcsis_runtime_suspend, s5pcsis_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_suspend, s5pcsis_resume) -}; - -static const struct of_device_id s5pcsis_of_match[] = { - { .compatible = "samsung,s5pv210-csis" }, - { .compatible = "samsung,exynos4210-csis" }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, s5pcsis_of_match); - -static struct platform_driver s5pcsis_driver = { - .probe = s5pcsis_probe, - .remove = s5pcsis_remove, - .driver = { - .of_match_table = s5pcsis_of_match, - .name = CSIS_DRIVER_NAME, - .owner = THIS_MODULE, - .pm = &s5pcsis_pm_ops, - }, -}; - -module_platform_driver(s5pcsis_driver); - -MODULE_AUTHOR("Sylwester Nawrocki "); -MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC MIPI-CSI2 receiver driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.h b/drivers/media/platform/s5p-fimc/mipi-csis.h deleted file mode 100644 index 28c11c4085d8..000000000000 --- a/drivers/media/platform/s5p-fimc/mipi-csis.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef S5P_MIPI_CSIS_H_ -#define S5P_MIPI_CSIS_H_ - -#define CSIS_DRIVER_NAME "s5p-mipi-csis" -#define CSIS_SUBDEV_NAME CSIS_DRIVER_NAME -#define CSIS_MAX_ENTITIES 2 -#define CSIS0_MAX_LANES 4 -#define CSIS1_MAX_LANES 2 - -#define CSIS_PAD_SINK 0 -#define CSIS_PAD_SOURCE 1 -#define CSIS_PADS_NUM 2 - -#define S5PCSIS_DEF_PIX_WIDTH 640 -#define S5PCSIS_DEF_PIX_HEIGHT 480 - -#endif -- cgit v1.2.3 From 46f85978687152c53a69fc06951e386f194e7f5d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 30 Mar 2013 05:31:42 -0300 Subject: [media] em28xx: fix typo in scale_to_size() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit em28xx: fix typo in scale_to_size(). The second hscale should be vscale. This bug caused xawtv to fail because it cannot find a workable image size. Signed-off-by: Hans Verkuil Acked-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index ef1959bbd23f..792ead1025d7 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -996,7 +996,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } size_to_scale(dev, width, height, &hscale, &vscale); - scale_to_size(dev, hscale, hscale, &width, &height); + scale_to_size(dev, hscale, vscale, &width, &height); f->fmt.pix.width = width; f->fmt.pix.height = height; -- cgit v1.2.3 From b0efc3ed0530b08e9e1cba5f63e9c251ca3d7428 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 31 Mar 2013 07:16:37 -0300 Subject: [media] m920x: Fix uninitialized variable warning drivers/media/usb/dvb-usb/m920x.c:91:6: warning: "ret" may be used uninitialized in this function [-Wuninitialized] drivers/media/usb/dvb-usb/m920x.c:70:6: note: "ret" was declared here This is real, if a remote control has an empty initialization sequence we would get success or failure randomly. OTOH the initialization of ret in m920x_init is needless, the function returns with an error as soon as an error happens, so the last return can only be a success and we can hard-code 0 there. Signed-off-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/m920x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index 79b31ae66a9c..c2b635d6a17a 100644 --- a/drivers/media/usb/dvb-usb/m920x.c +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -76,12 +76,12 @@ static inline int m920x_write_seq(struct usb_device *udev, u8 request, seq++; } while (seq->address); - return ret; + return 0; } static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq) { - int ret = 0, i, epi, flags = 0; + int ret, i, epi, flags = 0; int adap_enabled[M9206_MAX_ADAPTERS] = { 0 }; /* Remote controller init. */ @@ -124,7 +124,7 @@ static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq) } } - return ret; + return 0; } static int m920x_init_ep(struct usb_interface *intf) -- cgit v1.2.3 From 6bf7861fa2bb4be3cc70a6e9aed664ce65270027 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 29 Mar 2013 17:22:24 -0300 Subject: [media] si476x: Fix some config dependencies and a compile warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit radio-si476x depends on SND and SND_SOC, the mfd driver should select REGMAP_I2C. Also fix a small compile warning in a debug message: drivers/mfd/si476x-i2c.c: In function ‘si476x_core_drain_rds_fifo’: drivers/mfd/si476x-i2c.c:391:4: warning: field width specifier ‘*’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/Kconfig | 2 +- drivers/mfd/Kconfig | 1 + drivers/mfd/si476x-i2c.c | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 28ded247abc0..fef427e386c1 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -20,7 +20,7 @@ source "drivers/media/radio/si470x/Kconfig" config RADIO_SI476X tristate "Silicon Laboratories Si476x I2C FM Radio" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_V4L2 && SND && SND_SOC select MFD_CORE select MFD_SI476X_CORE select SND_SOC_SI476X diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 9b80e1edeeb6..2f97ad188fc2 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -980,6 +980,7 @@ config MFD_SI476X_CORE tristate "Support for Silicon Laboratories 4761/64/68 AM/FM radio." depends on I2C select MFD_CORE + select REGMAP_I2C help This is the core driver for the SI476x series of AM/FM radio. This MFD driver connects the radio-si476x V4L2 module diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c index 118c6b13d8cb..f5bc8e4bd4bf 100644 --- a/drivers/mfd/si476x-i2c.c +++ b/drivers/mfd/si476x-i2c.c @@ -389,7 +389,7 @@ static void si476x_core_drain_rds_fifo(struct work_struct *work) kfifo_in(&core->rds_fifo, report.rds, sizeof(report.rds)); dev_dbg(&core->client->dev, "RDS data:\n %*ph\n", - sizeof(report.rds), report.rds); + (int)sizeof(report.rds), report.rds); } dev_dbg(&core->client->dev, "Drrrrained!\n"); wake_up_interruptible(&core->rds_read_queue); -- cgit v1.2.3 From 53faa685fa7df0e12751eebbda30bc7e7bb5e71a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 1 Apr 2013 11:46:52 -0300 Subject: [media] siano: Fix array boundary at smscore_translate_msg() As reported by Dan Carpenter: FYI, there are new smatch warnings show up in tree: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next master head: da17d7bda957ae4697b6abc0793f74fb9b50b58f commit: 4c3bdb5e2f5612ceb99ac17dbbe673b59a94d105 [media] siano: better debug send/receive messages drivers/media/common/siano/smscoreapi.c:396 smscore_translate_msg() error: buffer overflow 'siano_msgs' 401 <= 401 While it is almost impossible for this error to happen in practice, as it would require the siano's firmware to return an special invalid answer to a message request, fixing it is trivial. So, let's do it. Reported-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smscoreapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index ebb9eceb1dca..45ac9eea4882 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -389,7 +389,7 @@ char *smscore_translate_msg(enum msg_types msgtype) int i = msgtype - MSG_TYPE_BASE_VAL; char *msg; - if (i < 0 || i > ARRAY_SIZE(siano_msgs)) + if (i < 0 || i >= ARRAY_SIZE(siano_msgs)) return "Unknown msg type"; msg = siano_msgs[i]; -- cgit v1.2.3 From 2400a1f89d329ad8948c08e6e08fef33ce42f73b Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 9 Jan 2013 09:14:48 -0300 Subject: [media] soc-camera: protect against racing open(2) and rmmod To protect against open() racing with rmmod, hold the list_lock also while obtaining a reference to the camera host driver and check that the video device hasn't been unregistered yet. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/soc_camera.c | 42 +++++++++++++++++--------- 1 file changed, 28 insertions(+), 14 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index bf55abfb7cbc..eea832c5fd01 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -508,36 +508,49 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd, static int soc_camera_open(struct file *file) { struct video_device *vdev = video_devdata(file); - struct soc_camera_device *icd = dev_get_drvdata(vdev->parent); - struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); + struct soc_camera_device *icd; struct soc_camera_host *ici; int ret; - if (!to_soc_camera_control(icd)) - /* No device driver attached */ - return -ENODEV; - /* * Don't mess with the host during probe: wait until the loop in - * scan_add_host() completes + * scan_add_host() completes. Also protect against a race with + * soc_camera_host_unregister(). */ if (mutex_lock_interruptible(&list_lock)) return -ERESTARTSYS; + + if (!vdev || !video_is_registered(vdev)) { + mutex_unlock(&list_lock); + return -ENODEV; + } + + icd = dev_get_drvdata(vdev->parent); ici = to_soc_camera_host(icd->parent); + + ret = try_module_get(ici->ops->owner) ? 0 : -ENODEV; mutex_unlock(&list_lock); - if (mutex_lock_interruptible(&ici->host_lock)) - return -ERESTARTSYS; - if (!try_module_get(ici->ops->owner)) { + if (ret < 0) { dev_err(icd->pdev, "Couldn't lock capture bus driver.\n"); - ret = -EINVAL; - goto emodule; + return ret; + } + + if (!to_soc_camera_control(icd)) { + /* No device driver attached */ + ret = -ENODEV; + goto econtrol; } + if (mutex_lock_interruptible(&ici->host_lock)) { + ret = -ERESTARTSYS; + goto elockhost; + } icd->use_count++; /* Now we really have to activate the camera */ if (icd->use_count == 1) { + struct soc_camera_desc *sdesc = to_soc_camera_desc(icd); /* Restore parameters before the last close() per V4L2 API */ struct v4l2_format f = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, @@ -609,9 +622,10 @@ epower: ici->ops->remove(icd); eiciadd: icd->use_count--; - module_put(ici->ops->owner); -emodule: mutex_unlock(&ici->host_lock); +elockhost: +econtrol: + module_put(ici->ops->owner); return ret; } -- cgit v1.2.3 From 8c31aeca6787d31dd4bd90bf573da944b44a2208 Mon Sep 17 00:00:00 2001 From: Fabio Porcedda Date: Thu, 14 Mar 2013 14:09:31 -0300 Subject: [media] drivers: media: use module_platform_driver_probe() This patch converts the drivers to use the module_platform_driver_probe() macro which makes the code smaller and a bit simpler. Signed-off-by: Fabio Porcedda [g.liakhovetski@gmx.de: also remove redundant .probe initialisation] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index c314ff9b98dc..e7ccc5e7bf39 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -1074,7 +1074,6 @@ err_clk_prepare_pclk: } static struct platform_driver atmel_isi_driver = { - .probe = atmel_isi_probe, .remove = atmel_isi_remove, .driver = { .name = "atmel_isi", @@ -1082,17 +1081,7 @@ static struct platform_driver atmel_isi_driver = { }, }; -static int __init atmel_isi_init_module(void) -{ - return platform_driver_probe(&atmel_isi_driver, &atmel_isi_probe); -} - -static void __exit atmel_isi_exit(void) -{ - platform_driver_unregister(&atmel_isi_driver); -} -module_init(atmel_isi_init_module); -module_exit(atmel_isi_exit); +module_platform_driver_probe(atmel_isi_driver, atmel_isi_probe); MODULE_AUTHOR("Josh Wu "); MODULE_DESCRIPTION("The V4L2 driver for Atmel Linux"); -- cgit v1.2.3 From 64e171e3f66d75d792029ad53d203e4c113e9f0d Mon Sep 17 00:00:00 2001 From: Fabio Porcedda Date: Mon, 18 Mar 2013 06:43:56 -0300 Subject: [media] mx2_camera: use module_platform_driver_probe() The commit 39793c6 "[media] mx2_camera: Convert it to platform driver" used module_platform_driver() to make code smaller, but since the driver used platform_driver_probe is more appropriate to use module_platform_driver_probe(). Signed-off-by: Fabio Porcedda Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/mx2_camera.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 048c26a27c34..7ca9dbaa9ffa 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -1620,10 +1620,9 @@ static struct platform_driver mx2_camera_driver = { }, .id_table = mx2_camera_devtype, .remove = mx2_camera_remove, - .probe = mx2_camera_probe, }; -module_platform_driver(mx2_camera_driver); +module_platform_driver_probe(mx2_camera_driver, mx2_camera_probe); MODULE_DESCRIPTION("i.MX27 SoC Camera Host driver"); MODULE_AUTHOR("Sascha Hauer "); -- cgit v1.2.3 From 7b88fc086a217be7d16ec68a7f66093d344e39d7 Mon Sep 17 00:00:00 2001 From: Phil Edworthy Date: Mon, 18 Mar 2013 08:47:59 -0300 Subject: [media] soc_camera: Add RGB666 & RGB888 formats Based on work done by Katsuya Matsubara. Signed-off-by: Phil Edworthy Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/subdev-formats.xml | 206 ++++++++++++++++++++- Documentation/DocBook/media_api.tmpl | 1 + drivers/media/platform/soc_camera/soc_mediabus.c | 42 +++++ include/media/soc_camera.h | 7 +- include/media/soc_mediabus.h | 3 + include/uapi/linux/v4l2-mediabus.h | 6 +- 6 files changed, 253 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index cc51372ed5e0..adc61982df7b 100644 --- a/Documentation/DocBook/media/v4l/subdev-formats.xml +++ b/Documentation/DocBook/media/v4l/subdev-formats.xml @@ -93,19 +93,35 @@ RGB formats - + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + Identifier @@ -117,6 +133,22 @@ Bit + 23 + 22 + 21 + 20 + 19 + 18 + 17 + 16 + 15 + 14 + 13 + 12 + 11 + 10 + 9 + 8 7 6 5 @@ -132,6 +164,7 @@ V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE 0x1001 + &dash-ent-16; 0 0 0 @@ -145,6 +178,7 @@ + &dash-ent-16; g3 g2 g1 @@ -158,6 +192,7 @@ V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE 0x1002 + &dash-ent-16; g3 g2 g1 @@ -171,6 +206,7 @@ + &dash-ent-16; 0 0 0 @@ -184,6 +220,7 @@ V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE 0x1003 + &dash-ent-16; 0 r4 r3 @@ -197,6 +234,7 @@ + &dash-ent-16; g2 g1 g0 @@ -210,6 +248,7 @@ V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE 0x1004 + &dash-ent-16; g2 g1 g0 @@ -223,6 +262,7 @@ + &dash-ent-16; 0 r4 r3 @@ -236,6 +276,7 @@ V4L2_MBUS_FMT_BGR565_2X8_BE 0x1005 + &dash-ent-16; b4 b3 b2 @@ -249,6 +290,7 @@ + &dash-ent-16; g2 g1 g0 @@ -262,6 +304,7 @@ V4L2_MBUS_FMT_BGR565_2X8_LE 0x1006 + &dash-ent-16; g2 g1 g0 @@ -275,6 +318,7 @@ + &dash-ent-16; b4 b3 b2 @@ -288,6 +332,7 @@ V4L2_MBUS_FMT_RGB565_2X8_BE 0x1007 + &dash-ent-16; r4 r3 r2 @@ -301,6 +346,7 @@ + &dash-ent-16; g2 g1 g0 @@ -314,6 +360,7 @@ V4L2_MBUS_FMT_RGB565_2X8_LE 0x1008 + &dash-ent-16; g2 g1 g0 @@ -327,6 +374,27 @@ + &dash-ent-16; + r4 + r3 + r2 + r1 + r0 + g5 + g4 + g3 + + + V4L2_MBUS_FMT_RGB666_1X18 + 0x1009 + + - + - + - + - + - + - + r5 r4 r3 r2 @@ -335,6 +403,124 @@ g5 g4 g3 + g2 + g1 + g0 + b5 + b4 + b3 + b2 + b1 + b0 + + + V4L2_MBUS_FMT_RGB888_1X24 + 0x100a + + r7 + r6 + r5 + r4 + r3 + r2 + r1 + r0 + g7 + g6 + g5 + g4 + g3 + g2 + g1 + g0 + b7 + b6 + b5 + b4 + b3 + b2 + b1 + b0 + + + V4L2_MBUS_FMT_RGB888_2X12_BE + 0x100b + + &dash-ent-10; + - + - + r7 + r6 + r5 + r4 + r3 + r2 + r1 + r0 + g7 + g6 + g5 + g4 + + + + + + &dash-ent-10; + - + - + g3 + g2 + g1 + g0 + b7 + b6 + b5 + b4 + b3 + b2 + b1 + b0 + + + V4L2_MBUS_FMT_RGB888_2X12_LE + 0x100c + + &dash-ent-10; + - + - + g3 + g2 + g1 + g0 + b7 + b6 + b5 + b4 + b3 + b2 + b1 + b0 + + + + + + &dash-ent-10; + - + - + r7 + r6 + r5 + r4 + r3 + r2 + r1 + r0 + g7 + g6 + g5 + g4 diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl index 1f6593deb995..6a8b7158697f 100644 --- a/Documentation/DocBook/media_api.tmpl +++ b/Documentation/DocBook/media_api.tmpl @@ -23,6 +23,7 @@ http://linuxtv.org/repo/"> ----------"> +----------------"> ]> diff --git a/drivers/media/platform/soc_camera/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c index 89dce097a827..7569e7746c92 100644 --- a/drivers/media/platform/soc_camera/soc_mediabus.c +++ b/drivers/media/platform/soc_camera/soc_mediabus.c @@ -96,6 +96,42 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .order = SOC_MBUS_ORDER_LE, .layout = SOC_MBUS_LAYOUT_PACKED, }, +}, { + .code = V4L2_MBUS_FMT_RGB666_1X18, + .fmt = { + .fourcc = V4L2_PIX_FMT_RGB32, + .name = "RGB666/32bpp", + .bits_per_sample = 18, + .packing = SOC_MBUS_PACKING_EXTEND32, + .order = SOC_MBUS_ORDER_LE, + }, +}, { + .code = V4L2_MBUS_FMT_RGB888_1X24, + .fmt = { + .fourcc = V4L2_PIX_FMT_RGB32, + .name = "RGB888/32bpp", + .bits_per_sample = 24, + .packing = SOC_MBUS_PACKING_EXTEND32, + .order = SOC_MBUS_ORDER_LE, + }, +}, { + .code = V4L2_MBUS_FMT_RGB888_2X12_BE, + .fmt = { + .fourcc = V4L2_PIX_FMT_RGB32, + .name = "RGB888/32bpp", + .bits_per_sample = 12, + .packing = SOC_MBUS_PACKING_EXTEND32, + .order = SOC_MBUS_ORDER_BE, + }, +}, { + .code = V4L2_MBUS_FMT_RGB888_2X12_LE, + .fmt = { + .fourcc = V4L2_PIX_FMT_RGB32, + .name = "RGB888/32bpp", + .bits_per_sample = 12, + .packing = SOC_MBUS_PACKING_EXTEND32, + .order = SOC_MBUS_ORDER_LE, + }, }, { .code = V4L2_MBUS_FMT_SBGGR8_1X8, .fmt = { @@ -358,6 +394,10 @@ int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf, *numerator = 1; *denominator = 1; return 0; + case SOC_MBUS_PACKING_EXTEND32: + *numerator = 1; + *denominator = 1; + return 0; case SOC_MBUS_PACKING_2X8_PADHI: case SOC_MBUS_PACKING_2X8_PADLO: *numerator = 2; @@ -392,6 +432,8 @@ s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf) return width * 3 / 2; case SOC_MBUS_PACKING_VARIABLE: return 0; + case SOC_MBUS_PACKING_EXTEND32: + return width * 4; } return -EINVAL; } diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h index 2cc70cf318bf..ff77d08c30fd 100644 --- a/include/media/soc_camera.h +++ b/include/media/soc_camera.h @@ -292,12 +292,17 @@ struct soc_camera_sense { #define SOCAM_DATAWIDTH_8 SOCAM_DATAWIDTH(8) #define SOCAM_DATAWIDTH_9 SOCAM_DATAWIDTH(9) #define SOCAM_DATAWIDTH_10 SOCAM_DATAWIDTH(10) +#define SOCAM_DATAWIDTH_12 SOCAM_DATAWIDTH(12) #define SOCAM_DATAWIDTH_15 SOCAM_DATAWIDTH(15) #define SOCAM_DATAWIDTH_16 SOCAM_DATAWIDTH(16) +#define SOCAM_DATAWIDTH_18 SOCAM_DATAWIDTH(18) +#define SOCAM_DATAWIDTH_24 SOCAM_DATAWIDTH(24) #define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_4 | SOCAM_DATAWIDTH_8 | \ SOCAM_DATAWIDTH_9 | SOCAM_DATAWIDTH_10 | \ - SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_16) + SOCAM_DATAWIDTH_12 | SOCAM_DATAWIDTH_15 | \ + SOCAM_DATAWIDTH_16 | SOCAM_DATAWIDTH_18 | \ + SOCAM_DATAWIDTH_24) static inline void soc_camera_limit_side(int *start, int *length, unsigned int start_min, diff --git a/include/media/soc_mediabus.h b/include/media/soc_mediabus.h index 0dc6f4625b92..d33f6d059692 100644 --- a/include/media/soc_mediabus.h +++ b/include/media/soc_mediabus.h @@ -26,6 +26,8 @@ * @SOC_MBUS_PACKING_VARIABLE: compressed formats with variable packing * @SOC_MBUS_PACKING_1_5X8: used for packed YUV 4:2:0 formats, where 4 * pixels occupy 6 bytes in RAM + * @SOC_MBUS_PACKING_EXTEND32: sample width (e.g., 24 bits) has to be extended + * to 32 bits */ enum soc_mbus_packing { SOC_MBUS_PACKING_NONE, @@ -34,6 +36,7 @@ enum soc_mbus_packing { SOC_MBUS_PACKING_EXTEND16, SOC_MBUS_PACKING_VARIABLE, SOC_MBUS_PACKING_1_5X8, + SOC_MBUS_PACKING_EXTEND32, }; /** diff --git a/include/uapi/linux/v4l2-mediabus.h b/include/uapi/linux/v4l2-mediabus.h index b9b7bea04537..6ee63d09b32d 100644 --- a/include/uapi/linux/v4l2-mediabus.h +++ b/include/uapi/linux/v4l2-mediabus.h @@ -37,7 +37,7 @@ enum v4l2_mbus_pixelcode { V4L2_MBUS_FMT_FIXED = 0x0001, - /* RGB - next is 0x1009 */ + /* RGB - next is 0x100d */ V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE = 0x1001, V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE = 0x1002, V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE = 0x1003, @@ -46,6 +46,10 @@ enum v4l2_mbus_pixelcode { V4L2_MBUS_FMT_BGR565_2X8_LE = 0x1006, V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007, V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008, + V4L2_MBUS_FMT_RGB666_1X18 = 0x1009, + V4L2_MBUS_FMT_RGB888_1X24 = 0x100a, + V4L2_MBUS_FMT_RGB888_2X12_BE = 0x100b, + V4L2_MBUS_FMT_RGB888_2X12_LE = 0x100c, /* YUV (including grey) - next is 0x2017 */ V4L2_MBUS_FMT_Y8_1X8 = 0x2001, -- cgit v1.2.3 From e35abd4472c4ef235a8c3873d4b37a6b5fb1cb90 Mon Sep 17 00:00:00 2001 From: Tushar Behera Date: Fri, 16 Nov 2012 03:50:37 -0300 Subject: [media] atmel-isi: Update error check for unsigned variables Checking '< 0' for unsigned variables always returns false. For error codes, use IS_ERR_VALUE() instead. Signed-off-by: Tushar Behera Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index e7ccc5e7bf39..1abbb36d0755 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -1021,7 +1021,7 @@ static int atmel_isi_probe(struct platform_device *pdev) isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); irq = platform_get_irq(pdev, 0); - if (irq < 0) { + if (IS_ERR_VALUE(irq)) { ret = irq; goto err_req_irq; } -- cgit v1.2.3 From 29407b93811d37d7243442d72e06c93894f2dd72 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 3 Apr 2013 02:00:35 -0300 Subject: [media] soc_camera/mx1_camera: Fix warnings related to spacing Fixes the following checkpatch warnings: WARNING: unnecessary whitespace before a quoted newline WARNING: please, no space before tabs Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/mx1_camera.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/mx1_camera.c b/drivers/media/platform/soc_camera/mx1_camera.c index 4389f43dd03c..a3fd8d63546c 100644 --- a/drivers/media/platform/soc_camera/mx1_camera.c +++ b/drivers/media/platform/soc_camera/mx1_camera.c @@ -776,7 +776,7 @@ static int __init mx1_camera_probe(struct platform_device *pdev) /* request irq */ err = claim_fiq(&fh); if (err) { - dev_err(&pdev->dev, "Camera interrupt register failed \n"); + dev_err(&pdev->dev, "Camera interrupt register failed\n"); goto exit_free_dma; } @@ -853,7 +853,7 @@ static int __exit mx1_camera_remove(struct platform_device *pdev) } static struct platform_driver mx1_camera_driver = { - .driver = { + .driver = { .name = DRIVER_NAME, }, .remove = __exit_p(mx1_camera_remove), -- cgit v1.2.3 From afb11967083b196e6711aab80e9e219c9942e735 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 3 Apr 2013 02:00:36 -0300 Subject: [media] soc_camera/mx2_camera: Fix warnings related to spacing Fixes the following checkpatch warnings: WARNING: unnecessary whitespace before a quoted newline WARNING: please, no space before tabs Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/mx2_camera.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 7ca9dbaa9ffa..5bbeb43e4531 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -1454,7 +1454,7 @@ static int mx27_camera_emma_init(struct platform_device *pdev) err = devm_request_irq(pcdev->dev, irq_emma, mx27_camera_emma_irq, 0, MX2_CAM_DRV_NAME, pcdev); if (err) { - dev_err(pcdev->dev, "Camera EMMA interrupt register failed \n"); + dev_err(pcdev->dev, "Camera EMMA interrupt register failed\n"); goto out; } @@ -1615,7 +1615,7 @@ static int mx2_camera_remove(struct platform_device *pdev) } static struct platform_driver mx2_camera_driver = { - .driver = { + .driver = { .name = MX2_CAM_DRV_NAME, }, .id_table = mx2_camera_devtype, -- cgit v1.2.3 From 0cb298688491ada5a01a85415bbf50da3b07961a Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 3 Apr 2013 02:00:37 -0300 Subject: [media] soc_camera/mx3_camera: Fix warning related to spacing Silences the following checkpatch warning: WARNING: please, no space before tabs Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/mx3_camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index 2c3bd69fb38c..5da337736cd8 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -1276,7 +1276,7 @@ static int mx3_camera_remove(struct platform_device *pdev) } static struct platform_driver mx3_camera_driver = { - .driver = { + .driver = { .name = MX3_CAM_DRV_NAME, }, .probe = mx3_camera_probe, -- cgit v1.2.3 From 6003b2add51e26f7831bba918a8e710ddc86a2d8 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 3 Apr 2013 02:00:38 -0300 Subject: [media] soc_camera/pxa_camera: Fix warning related to spacing Fixes the following checkpatch warning: WARNING: please, no space before tabs Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/pxa_camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index 42abbce650f7..b0e6f3bc0264 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -1802,7 +1802,7 @@ static struct dev_pm_ops pxa_camera_pm = { }; static struct platform_driver pxa_camera_driver = { - .driver = { + .driver = { .name = PXA_CAM_DRV_NAME, .pm = &pxa_camera_pm, }, -- cgit v1.2.3 From 56a49194048d00b127711d2f1f557cf3e4b5fece Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 3 Apr 2013 02:00:39 -0300 Subject: [media] soc_camera/pxa_camera: Constify struct dev_pm_ops struct dev_pm_ops should be const. Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/pxa_camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index b0e6f3bc0264..d665242e8207 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -1796,7 +1796,7 @@ static int pxa_camera_remove(struct platform_device *pdev) return 0; } -static struct dev_pm_ops pxa_camera_pm = { +static const struct dev_pm_ops pxa_camera_pm = { .suspend = pxa_camera_suspend, .resume = pxa_camera_resume, }; -- cgit v1.2.3 From ca0c4ba72d102fafcbd98f7f7d9c38e096f41570 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 3 Apr 2013 02:00:40 -0300 Subject: [media] soc_camera/sh_mobile_ceu_camera: Fix warning related to spacing Fixes the following checkpatch warning: WARNING: please, no space before tabs Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index d7294efc3199..143d29fe0137 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -2288,7 +2288,7 @@ static const struct dev_pm_ops sh_mobile_ceu_dev_pm_ops = { }; static struct platform_driver sh_mobile_ceu_driver = { - .driver = { + .driver = { .name = "sh_mobile_ceu", .pm = &sh_mobile_ceu_dev_pm_ops, }, -- cgit v1.2.3 From 992bc797deaf0765f77fda03bc0d0a846236c81c Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Wed, 3 Apr 2013 02:00:41 -0300 Subject: [media] soc_camera/soc_camera_platform: Fix warning related to spacing Fixes the following checkpatch warning: WARNING: please, no space before tabs Signed-off-by: Sachin Kamat Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/soc_camera_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c index ce3b1d6a4734..1b7a88ca195b 100644 --- a/drivers/media/platform/soc_camera/soc_camera_platform.c +++ b/drivers/media/platform/soc_camera/soc_camera_platform.c @@ -188,7 +188,7 @@ static int soc_camera_platform_remove(struct platform_device *pdev) } static struct platform_driver soc_camera_platform_driver = { - .driver = { + .driver = { .name = "soc_camera_platform", .owner = THIS_MODULE, }, -- cgit v1.2.3 From 474c890d67ca5a16817deb4c5b6b8c600d8dd247 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 5 Mar 2013 14:42:20 -0300 Subject: [media] exynos: remove unnecessary header inclusions In multiplatform configurations, we cannot include headers provided by only the exynos platform. Fortunately a number of drivers that include those headers do not actually need them, so we can just remove the inclusions. Signed-off-by: Arnd Bergmann Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-regs.c | 1 - drivers/media/platform/s5p-tv/sii9234_drv.c | 3 --- 2 files changed, 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.c b/drivers/media/platform/exynos-gsc/gsc-regs.c index 6f5b5a486cf3..e22d147a6940 100644 --- a/drivers/media/platform/exynos-gsc/gsc-regs.c +++ b/drivers/media/platform/exynos-gsc/gsc-regs.c @@ -12,7 +12,6 @@ #include #include -#include #include "gsc-core.h" diff --git a/drivers/media/platform/s5p-tv/sii9234_drv.c b/drivers/media/platform/s5p-tv/sii9234_drv.c index d90d2286090b..39b77d24b9c2 100644 --- a/drivers/media/platform/s5p-tv/sii9234_drv.c +++ b/drivers/media/platform/s5p-tv/sii9234_drv.c @@ -23,9 +23,6 @@ #include #include -#include -#include - #include #include -- cgit v1.2.3 From b3d8b559b1ce3b2d85ac57bbccbd38f25e3cc5db Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Sun, 31 Mar 2013 20:31:02 -0300 Subject: [media] exynos4-is: Remove dependency on SYSCON for non-dt platforms Currently the whole driver depends on MFD_SYSCON, which in turn depends on OF. To allow to use the driver on non-dt platforms (S5PV210) the SYSREG support is made conditional (it is needed only for dt enabled platforms) and MFD_SYSCON is selected if OF is enabled, instead of depending on OF. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/Kconfig | 2 +- drivers/media/platform/exynos4-is/fimc-core.c | 3 +-- drivers/media/platform/exynos4-is/fimc-core.h | 10 ++++++++++ drivers/media/platform/exynos4-is/fimc-reg.c | 3 +++ 4 files changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index 91dbd4b22362..ae579208565b 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -2,7 +2,6 @@ config VIDEO_SAMSUNG_EXYNOS4_IS bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && PLAT_S5P && PM_RUNTIME - depends on MFD_SYSCON help Say Y here to enable camera host interface devices for Samsung S5P and EXYNOS SoC series. @@ -14,6 +13,7 @@ config VIDEO_S5P_FIMC depends on I2C select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV + select MFD_SYSCON if OF help This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC camera host interface and video postprocessor (FIMC) devices. diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index 44239e5b3a47..6b4a244132fb 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -966,8 +966,7 @@ static int fimc_probe(struct platform_device *pdev) spin_lock_init(&fimc->slock); mutex_init(&fimc->lock); - fimc->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node, - "samsung,sysreg"); + fimc->sysreg = fimc_get_sysreg_regmap(dev->of_node); if (IS_ERR(fimc->sysreg)) return PTR_ERR(fimc->sysreg); diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h index 793333a33b24..7d361b24dfd7 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.h +++ b/drivers/media/platform/exynos4-is/fimc-core.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -645,6 +646,15 @@ void fimc_unregister_m2m_device(struct fimc_dev *fimc); int fimc_register_driver(void); void fimc_unregister_driver(void); +#ifdef CONFIG_MFD_SYSCON +static inline struct regmap * fimc_get_sysreg_regmap(struct device_node *node) +{ + return syscon_regmap_lookup_by_phandle(node, "samsung,sysreg"); +} +#else +#define fimc_get_sysreg_regmap(node) (NULL) +#endif + /* -----------------------------------------------------*/ /* fimc-m2m.c */ void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state); diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c index c276eb8e9711..c82e9bdaae94 100644 --- a/drivers/media/platform/exynos4-is/fimc-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-reg.c @@ -805,6 +805,9 @@ int fimc_hw_camblk_cfg_writeback(struct fimc_dev *fimc) unsigned int mask, val, camblk_cfg; int ret; + if (map == NULL) + return 0; + ret = regmap_read(map, SYSREG_CAMBLK, &camblk_cfg); if (ret < 0 || ((camblk_cfg & 0x00700000) >> 20 != 0x3)) return ret; -- cgit v1.2.3 From c6e8d96d420307ab4efbb083c47452917fabd5dd Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 2 Apr 2013 11:41:19 -0300 Subject: [media] V4L: Remove incorrect EXPORT_SYMBOL() usage at v4l2-of.c v4l2_of_parse_parallel_bus() function is now static and EXPORT_SYMBOL() doesn't apply to it any more. Drop this meaningless statement, which was supposed to be done in the original merged patch. While at it, edit the copyright notice so it is sorted in both the v4l2-of.c and v4l2-of.h file in newest entries on top order, and state clearly I'm just the author of parts of the code, not the copyright owner. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-of.c | 3 +-- include/media/v4l2-of.h | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c index e38e21064b5f..aa59639d013c 100644 --- a/drivers/media/v4l2-core/v4l2-of.c +++ b/drivers/media/v4l2-core/v4l2-of.c @@ -2,7 +2,7 @@ * V4L2 OF binding parsing library * * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki + * Author: Sylwester Nawrocki * * Copyright (C) 2012 Renesas Electronics Corp. * Author: Guennadi Liakhovetski @@ -103,7 +103,6 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node, bus->flags = flags; } -EXPORT_SYMBOL(v4l2_of_parse_parallel_bus); /** * v4l2_of_parse_endpoint() - parse all endpoint node properties diff --git a/include/media/v4l2-of.h b/include/media/v4l2-of.h index 00f91473498c..3a8a84124b44 100644 --- a/include/media/v4l2-of.h +++ b/include/media/v4l2-of.h @@ -1,12 +1,12 @@ /* * V4L2 OF binding parsing library * + * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. + * Author: Sylwester Nawrocki + * * Copyright (C) 2012 Renesas Electronics Corp. * Author: Guennadi Liakhovetski * - * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki - * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. -- cgit v1.2.3 From 9a761e436843f228eaa2decda6d2c6dbd5ef1480 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 11 Mar 2013 15:14:58 -0300 Subject: [media] exynos4-is: Add Exynos4x12 FIMC-IS driver This patch adds a set of core files of the Exynos4x12 FIMC-IS V4L2 driver. This includes main functionality like allocating memory, loading the firmware, FIMC-IS register interface and host CPU <-> IS command and error code definitions. The driver currently exposes a single subdev named FIMC-IS-ISP, which corresponds to the FIMC-IS ISP and DRC IP blocks. The FIMC-IS-ISP subdev currently supports only a subset of user controls. For other controls we need several extensions at the V4L2 API. The supported standard controls are: brightness, contrast, saturation, hue, sharpness, 3a_lock, exposure_time_absolute, white_balance_auto_preset, iso_sensitivity, iso_sensitivity_auto, exposure_metering_mode. Signed-off-by: Younghwan Joo Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/exynos4-is/fimc-is-command.h | 137 +++ drivers/media/platform/exynos4-is/fimc-is-errno.c | 272 ++++++ drivers/media/platform/exynos4-is/fimc-is-errno.h | 248 +++++ drivers/media/platform/exynos4-is/fimc-is-regs.c | 242 +++++ drivers/media/platform/exynos4-is/fimc-is-regs.h | 164 ++++ drivers/media/platform/exynos4-is/fimc-is.c | 1010 ++++++++++++++++++++ drivers/media/platform/exynos4-is/fimc-is.h | 345 +++++++ drivers/media/platform/exynos4-is/fimc-isp.c | 702 ++++++++++++++ drivers/media/platform/exynos4-is/fimc-isp.h | 181 ++++ 9 files changed, 3301 insertions(+) create mode 100644 drivers/media/platform/exynos4-is/fimc-is-command.h create mode 100644 drivers/media/platform/exynos4-is/fimc-is-errno.c create mode 100644 drivers/media/platform/exynos4-is/fimc-is-errno.h create mode 100644 drivers/media/platform/exynos4-is/fimc-is-regs.c create mode 100644 drivers/media/platform/exynos4-is/fimc-is-regs.h create mode 100644 drivers/media/platform/exynos4-is/fimc-is.c create mode 100644 drivers/media/platform/exynos4-is/fimc-is.h create mode 100644 drivers/media/platform/exynos4-is/fimc-isp.c create mode 100644 drivers/media/platform/exynos4-is/fimc-isp.h (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-is-command.h b/drivers/media/platform/exynos4-is/fimc-is-command.h new file mode 100644 index 000000000000..0d1f52e394b1 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-is-command.h @@ -0,0 +1,137 @@ +/* + * Samsung Exynos4x12 FIMC-IS (Imaging Subsystem) driver + * + * FIMC-IS command set definitions + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * + * Authors: Younghwan Joo + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef FIMC_IS_CMD_H_ +#define FIMC_IS_CMD_H_ + +#define FIMC_IS_COMMAND_VER 110 /* FIMC-IS command set version 1.10 */ + +/* Enumeration of commands beetween the FIMC-IS and the host processor. */ + +/* HOST to FIMC-IS */ +#define HIC_PREVIEW_STILL 0x0001 +#define HIC_PREVIEW_VIDEO 0x0002 +#define HIC_CAPTURE_STILL 0x0003 +#define HIC_CAPTURE_VIDEO 0x0004 +#define HIC_STREAM_ON 0x0005 +#define HIC_STREAM_OFF 0x0006 +#define HIC_SET_PARAMETER 0x0007 +#define HIC_GET_PARAMETER 0x0008 +#define HIC_SET_TUNE 0x0009 +#define HIC_GET_STATUS 0x000b +/* Sensor part */ +#define HIC_OPEN_SENSOR 0x000c +#define HIC_CLOSE_SENSOR 0x000d +#define HIC_SIMMIAN_INIT 0x000e +#define HIC_SIMMIAN_WRITE 0x000f +#define HIC_SIMMIAN_READ 0x0010 +#define HIC_POWER_DOWN 0x0011 +#define HIC_GET_SET_FILE_ADDR 0x0012 +#define HIC_LOAD_SET_FILE 0x0013 +#define HIC_MSG_CONFIG 0x0014 +#define HIC_MSG_TEST 0x0015 +/* FIMC-IS to HOST */ +#define IHC_GET_SENSOR_NUM 0x1000 +#define IHC_SET_SHOT_MARK 0x1001 +/* parameter1: frame number */ +/* parameter2: confidence level (smile 0~100) */ +/* parameter3: confidence level (blink 0~100) */ +#define IHC_SET_FACE_MARK 0x1002 +/* parameter1: coordinate count */ +/* parameter2: coordinate buffer address */ +#define IHC_FRAME_DONE 0x1003 +/* parameter1: frame start number */ +/* parameter2: frame count */ +#define IHC_AA_DONE 0x1004 +#define IHC_NOT_READY 0x1005 + +#define IH_REPLY_DONE 0x2000 +#define IH_REPLY_NOT_DONE 0x2001 + +enum fimc_is_scenario { + IS_SC_PREVIEW_STILL, + IS_SC_PREVIEW_VIDEO, + IS_SC_CAPTURE_STILL, + IS_SC_CAPTURE_VIDEO, + IS_SC_MAX +}; + +enum fimc_is_sub_scenario { + IS_SC_SUB_DEFAULT, + IS_SC_SUB_PS_VTCALL, + IS_SC_SUB_CS_VTCALL, + IS_SC_SUB_PV_VTCALL, + IS_SC_SUB_CV_VTCALL, +}; + +struct is_common_regs { + u32 hicmd; + u32 hic_sensorid; + u32 hic_param[4]; + u32 reserved1[4]; + + u32 ihcmd; + u32 ihc_sensorid; + u32 ihc_param[4]; + u32 reserved2[4]; + + u32 isp_sensor_id; + u32 isp_param[2]; + u32 reserved3[1]; + + u32 scc_sensor_id; + u32 scc_param[2]; + u32 reserved4[1]; + + u32 dnr_sensor_id; + u32 dnr_param[2]; + u32 reserved5[1]; + + u32 scp_sensor_id; + u32 scp_param[2]; + u32 reserved6[29]; +} __packed; + +struct is_mcuctl_reg { + u32 mcuctl; + u32 bboar; + + u32 intgr0; + u32 intcr0; + u32 intmr0; + u32 intsr0; + u32 intmsr0; + + u32 intgr1; + u32 intcr1; + u32 intmr1; + u32 intsr1; + u32 intmsr1; + + u32 intcr2; + u32 intmr2; + u32 intsr2; + u32 intmsr2; + + u32 gpoctrl; + u32 cpoenctlr; + u32 gpictlr; + + u32 reserved[0xd]; + + struct is_common_regs common; +} __packed; + +#endif /* FIMC_IS_CMD_H_ */ diff --git a/drivers/media/platform/exynos4-is/fimc-is-errno.c b/drivers/media/platform/exynos4-is/fimc-is-errno.c new file mode 100644 index 000000000000..e8519e151c1a --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-is-errno.c @@ -0,0 +1,272 @@ +/* + * Samsung Exynos4 SoC series FIMC-IS slave interface driver + * + * Error log interface functions + * + * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. + * + * Authors: Younghwan Joo + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "fimc-is-errno.h" + +const char * const fimc_is_param_strerr(unsigned int error) +{ + switch (error) { + case ERROR_COMMON_CMD: + return "ERROR_COMMON_CMD: Invalid Command"; + case ERROR_COMMON_PARAMETER: + return "ERROR_COMMON_PARAMETER: Invalid Parameter"; + case ERROR_COMMON_SETFILE_LOAD: + return "ERROR_COMMON_SETFILE_LOAD: Illegal Setfile Loading"; + case ERROR_COMMON_SETFILE_ADJUST: + return "ERROR_COMMON_SETFILE_ADJUST: Setfile isn't adjusted"; + case ERROR_COMMON_SETFILE_INDEX: + return "ERROR_COMMON_SETFILE_INDEX: Invalid setfile index"; + case ERROR_COMMON_INPUT_PATH: + return "ERROR_COMMON_INPUT_PATH: Input path can be changed in ready state"; + case ERROR_COMMON_INPUT_INIT: + return "ERROR_COMMON_INPUT_INIT: IP can not start if input path is not set"; + case ERROR_COMMON_OUTPUT_PATH: + return "ERROR_COMMON_OUTPUT_PATH: Output path can be changed in ready state (stop)"; + case ERROR_COMMON_OUTPUT_INIT: + return "ERROR_COMMON_OUTPUT_INIT: IP can not start if output path is not set"; + case ERROR_CONTROL_BYPASS: + return "ERROR_CONTROL_BYPASS"; + case ERROR_OTF_INPUT_FORMAT: + return "ERROR_OTF_INPUT_FORMAT: Invalid format (DRC: YUV444, FD: YUV444, 422, 420)"; + case ERROR_OTF_INPUT_WIDTH: + return "ERROR_OTF_INPUT_WIDTH: Invalid width (DRC: 128~8192, FD: 32~8190)"; + case ERROR_OTF_INPUT_HEIGHT: + return "ERROR_OTF_INPUT_HEIGHT: Invalid bit-width (DRC: 8~12bits, FD: 8bit)"; + case ERROR_OTF_INPUT_BIT_WIDTH: + return "ERROR_OTF_INPUT_BIT_WIDTH: Invalid bit-width (DRC: 8~12bits, FD: 8bit)"; + case ERROR_DMA_INPUT_WIDTH: + return "ERROR_DMA_INPUT_WIDTH: Invalid width (DRC: 128~8192, FD: 32~8190)"; + case ERROR_DMA_INPUT_HEIGHT: + return "ERROR_DMA_INPUT_HEIGHT: Invalid height (DRC: 64~8192, FD: 16~8190)"; + case ERROR_DMA_INPUT_FORMAT: + return "ERROR_DMA_INPUT_FORMAT: Invalid format (DRC: YUV444 or YUV422, FD: YUV444,422,420)"; + case ERROR_DMA_INPUT_BIT_WIDTH: + return "ERROR_DMA_INPUT_BIT_WIDTH: Invalid bit-width (DRC: 8~12bits, FD: 8bit)"; + case ERROR_DMA_INPUT_ORDER: + return "ERROR_DMA_INPUT_ORDER: Invalid order(DRC: YYCbCr,YCbYCr,FD:NO,YYCbCr,YCbYCr,CbCr,CrCb)"; + case ERROR_DMA_INPUT_PLANE: + return "ERROR_DMA_INPUT_PLANE: Invalid palne (DRC: 3, FD: 1, 2, 3)"; + case ERROR_OTF_OUTPUT_WIDTH: + return "ERROR_OTF_OUTPUT_WIDTH: Invalid width (DRC: 128~8192)"; + case ERROR_OTF_OUTPUT_HEIGHT: + return "ERROR_OTF_OUTPUT_HEIGHT: Invalid height (DRC: 64~8192)"; + case ERROR_OTF_OUTPUT_FORMAT: + return "ERROR_OTF_OUTPUT_FORMAT: Invalid format (DRC: YUV444)"; + case ERROR_OTF_OUTPUT_BIT_WIDTH: + return "ERROR_OTF_OUTPUT_BIT_WIDTH: Invalid bit-width (DRC: 8~12bits, FD: 8bit)"; + case ERROR_DMA_OUTPUT_WIDTH: + return "ERROR_DMA_OUTPUT_WIDTH"; + case ERROR_DMA_OUTPUT_HEIGHT: + return "ERROR_DMA_OUTPUT_HEIGHT"; + case ERROR_DMA_OUTPUT_FORMAT: + return "ERROR_DMA_OUTPUT_FORMAT"; + case ERROR_DMA_OUTPUT_BIT_WIDTH: + return "ERROR_DMA_OUTPUT_BIT_WIDTH"; + case ERROR_DMA_OUTPUT_PLANE: + return "ERROR_DMA_OUTPUT_PLANE"; + case ERROR_DMA_OUTPUT_ORDER: + return "ERROR_DMA_OUTPUT_ORDER"; + + /* Sensor Error(100~199) */ + case ERROR_SENSOR_I2C_FAIL: + return "ERROR_SENSOR_I2C_FAIL"; + case ERROR_SENSOR_INVALID_FRAMERATE: + return "ERROR_SENSOR_INVALID_FRAMERATE"; + case ERROR_SENSOR_INVALID_EXPOSURETIME: + return "ERROR_SENSOR_INVALID_EXPOSURETIME"; + case ERROR_SENSOR_INVALID_SIZE: + return "ERROR_SENSOR_INVALID_SIZE"; + case ERROR_SENSOR_INVALID_SETTING: + return "ERROR_SENSOR_INVALID_SETTING"; + case ERROR_SENSOR_ACTURATOR_INIT_FAIL: + return "ERROR_SENSOR_ACTURATOR_INIT_FAIL"; + case ERROR_SENSOR_INVALID_AF_POS: + return "ERROR_SENSOR_INVALID_AF_POS"; + case ERROR_SENSOR_UNSUPPORT_FUNC: + return "ERROR_SENSOR_UNSUPPORT_FUNC"; + case ERROR_SENSOR_UNSUPPORT_PERI: + return "ERROR_SENSOR_UNSUPPORT_PERI"; + case ERROR_SENSOR_UNSUPPORT_AF: + return "ERROR_SENSOR_UNSUPPORT_AF"; + + /* ISP Error (200~299) */ + case ERROR_ISP_AF_BUSY: + return "ERROR_ISP_AF_BUSY"; + case ERROR_ISP_AF_INVALID_COMMAND: + return "ERROR_ISP_AF_INVALID_COMMAND"; + case ERROR_ISP_AF_INVALID_MODE: + return "ERROR_ISP_AF_INVALID_MODE"; + + /* DRC Error (300~399) */ + /* FD Error (400~499) */ + case ERROR_FD_CONFIG_MAX_NUMBER_STATE: + return "ERROR_FD_CONFIG_MAX_NUMBER_STATE"; + case ERROR_FD_CONFIG_MAX_NUMBER_INVALID: + return "ERROR_FD_CONFIG_MAX_NUMBER_INVALID"; + case ERROR_FD_CONFIG_YAW_ANGLE_STATE: + return "ERROR_FD_CONFIG_YAW_ANGLE_STATE"; + case ERROR_FD_CONFIG_YAW_ANGLE_INVALID: + return "ERROR_FD_CONFIG_YAW_ANGLE_INVALID\n"; + case ERROR_FD_CONFIG_ROLL_ANGLE_STATE: + return "ERROR_FD_CONFIG_ROLL_ANGLE_STATE"; + case ERROR_FD_CONFIG_ROLL_ANGLE_INVALID: + return "ERROR_FD_CONFIG_ROLL_ANGLE_INVALID"; + case ERROR_FD_CONFIG_SMILE_MODE_INVALID: + return "ERROR_FD_CONFIG_SMILE_MODE_INVALID"; + case ERROR_FD_CONFIG_BLINK_MODE_INVALID: + return "ERROR_FD_CONFIG_BLINK_MODE_INVALID"; + case ERROR_FD_CONFIG_EYES_DETECT_INVALID: + return "ERROR_FD_CONFIG_EYES_DETECT_INVALID"; + case ERROR_FD_CONFIG_MOUTH_DETECT_INVALID: + return "ERROR_FD_CONFIG_MOUTH_DETECT_INVALID"; + case ERROR_FD_CONFIG_ORIENTATION_STATE: + return "ERROR_FD_CONFIG_ORIENTATION_STATE"; + case ERROR_FD_CONFIG_ORIENTATION_INVALID: + return "ERROR_FD_CONFIG_ORIENTATION_INVALID"; + case ERROR_FD_CONFIG_ORIENTATION_VALUE_INVALID: + return "ERROR_FD_CONFIG_ORIENTATION_VALUE_INVALID"; + case ERROR_FD_RESULT: + return "ERROR_FD_RESULT"; + case ERROR_FD_MODE: + return "ERROR_FD_MODE"; + default: + return "Unknown"; + } +} + +const char * const fimc_is_strerr(unsigned int error) +{ + error &= ~IS_ERROR_TIME_OUT_FLAG; + + switch (error) { + /* General */ + case IS_ERROR_INVALID_COMMAND: + return "IS_ERROR_INVALID_COMMAND"; + case IS_ERROR_REQUEST_FAIL: + return "IS_ERROR_REQUEST_FAIL"; + case IS_ERROR_INVALID_SCENARIO: + return "IS_ERROR_INVALID_SCENARIO"; + case IS_ERROR_INVALID_SENSORID: + return "IS_ERROR_INVALID_SENSORID"; + case IS_ERROR_INVALID_MODE_CHANGE: + return "IS_ERROR_INVALID_MODE_CHANGE"; + case IS_ERROR_INVALID_MAGIC_NUMBER: + return "IS_ERROR_INVALID_MAGIC_NUMBER"; + case IS_ERROR_INVALID_SETFILE_HDR: + return "IS_ERROR_INVALID_SETFILE_HDR"; + case IS_ERROR_BUSY: + return "IS_ERROR_BUSY"; + case IS_ERROR_SET_PARAMETER: + return "IS_ERROR_SET_PARAMETER"; + case IS_ERROR_INVALID_PATH: + return "IS_ERROR_INVALID_PATH"; + case IS_ERROR_OPEN_SENSOR_FAIL: + return "IS_ERROR_OPEN_SENSOR_FAIL"; + case IS_ERROR_ENTRY_MSG_THREAD_DOWN: + return "IS_ERROR_ENTRY_MSG_THREAD_DOWN"; + case IS_ERROR_ISP_FRAME_END_NOT_DONE: + return "IS_ERROR_ISP_FRAME_END_NOT_DONE"; + case IS_ERROR_DRC_FRAME_END_NOT_DONE: + return "IS_ERROR_DRC_FRAME_END_NOT_DONE"; + case IS_ERROR_SCALERC_FRAME_END_NOT_DONE: + return "IS_ERROR_SCALERC_FRAME_END_NOT_DONE"; + case IS_ERROR_ODC_FRAME_END_NOT_DONE: + return "IS_ERROR_ODC_FRAME_END_NOT_DONE"; + case IS_ERROR_DIS_FRAME_END_NOT_DONE: + return "IS_ERROR_DIS_FRAME_END_NOT_DONE"; + case IS_ERROR_TDNR_FRAME_END_NOT_DONE: + return "IS_ERROR_TDNR_FRAME_END_NOT_DONE"; + case IS_ERROR_SCALERP_FRAME_END_NOT_DONE: + return "IS_ERROR_SCALERP_FRAME_END_NOT_DONE"; + case IS_ERROR_WAIT_STREAM_OFF_NOT_DONE: + return "IS_ERROR_WAIT_STREAM_OFF_NOT_DONE"; + case IS_ERROR_NO_MSG_IS_RECEIVED: + return "IS_ERROR_NO_MSG_IS_RECEIVED"; + case IS_ERROR_SENSOR_MSG_FAIL: + return "IS_ERROR_SENSOR_MSG_FAIL"; + case IS_ERROR_ISP_MSG_FAIL: + return "IS_ERROR_ISP_MSG_FAIL"; + case IS_ERROR_DRC_MSG_FAIL: + return "IS_ERROR_DRC_MSG_FAIL"; + case IS_ERROR_LHFD_MSG_FAIL: + return "IS_ERROR_LHFD_MSG_FAIL"; + case IS_ERROR_UNKNOWN: + return "IS_ERROR_UNKNOWN"; + + /* Sensor */ + case IS_ERROR_SENSOR_PWRDN_FAIL: + return "IS_ERROR_SENSOR_PWRDN_FAIL"; + + /* ISP */ + case IS_ERROR_ISP_PWRDN_FAIL: + return "IS_ERROR_ISP_PWRDN_FAIL"; + case IS_ERROR_ISP_MULTIPLE_INPUT: + return "IS_ERROR_ISP_MULTIPLE_INPUT"; + case IS_ERROR_ISP_ABSENT_INPUT: + return "IS_ERROR_ISP_ABSENT_INPUT"; + case IS_ERROR_ISP_ABSENT_OUTPUT: + return "IS_ERROR_ISP_ABSENT_OUTPUT"; + case IS_ERROR_ISP_NONADJACENT_OUTPUT: + return "IS_ERROR_ISP_NONADJACENT_OUTPUT"; + case IS_ERROR_ISP_FORMAT_MISMATCH: + return "IS_ERROR_ISP_FORMAT_MISMATCH"; + case IS_ERROR_ISP_WIDTH_MISMATCH: + return "IS_ERROR_ISP_WIDTH_MISMATCH"; + case IS_ERROR_ISP_HEIGHT_MISMATCH: + return "IS_ERROR_ISP_HEIGHT_MISMATCH"; + case IS_ERROR_ISP_BITWIDTH_MISMATCH: + return "IS_ERROR_ISP_BITWIDTH_MISMATCH"; + case IS_ERROR_ISP_FRAME_END_TIME_OUT: + return "IS_ERROR_ISP_FRAME_END_TIME_OUT"; + + /* DRC */ + case IS_ERROR_DRC_PWRDN_FAIL: + return "IS_ERROR_DRC_PWRDN_FAIL"; + case IS_ERROR_DRC_MULTIPLE_INPUT: + return "IS_ERROR_DRC_MULTIPLE_INPUT"; + case IS_ERROR_DRC_ABSENT_INPUT: + return "IS_ERROR_DRC_ABSENT_INPUT"; + case IS_ERROR_DRC_NONADJACENT_INPUT: + return "IS_ERROR_DRC_NONADJACENT_INPUT"; + case IS_ERROR_DRC_ABSENT_OUTPUT: + return "IS_ERROR_DRC_ABSENT_OUTPUT"; + case IS_ERROR_DRC_NONADJACENT_OUTPUT: + return "IS_ERROR_DRC_NONADJACENT_OUTPUT"; + case IS_ERROR_DRC_FORMAT_MISMATCH: + return "IS_ERROR_DRC_FORMAT_MISMATCH"; + case IS_ERROR_DRC_WIDTH_MISMATCH: + return "IS_ERROR_DRC_WIDTH_MISMATCH"; + case IS_ERROR_DRC_HEIGHT_MISMATCH: + return "IS_ERROR_DRC_HEIGHT_MISMATCH"; + case IS_ERROR_DRC_BITWIDTH_MISMATCH: + return "IS_ERROR_DRC_BITWIDTH_MISMATCH"; + case IS_ERROR_DRC_FRAME_END_TIME_OUT: + return "IS_ERROR_DRC_FRAME_END_TIME_OUT"; + + /* FD */ + case IS_ERROR_FD_PWRDN_FAIL: + return "IS_ERROR_FD_PWRDN_FAIL"; + case IS_ERROR_FD_MULTIPLE_INPUT: + return "IS_ERROR_FD_MULTIPLE_INPUT"; + case IS_ERROR_FD_ABSENT_INPUT: + return "IS_ERROR_FD_ABSENT_INPUT"; + case IS_ERROR_FD_NONADJACENT_INPUT: + return "IS_ERROR_FD_NONADJACENT_INPUT"; + case IS_ERROR_LHFD_FRAME_END_TIME_OUT: + return "IS_ERROR_LHFD_FRAME_END_TIME_OUT"; + default: + return "Unknown"; + } +} diff --git a/drivers/media/platform/exynos4-is/fimc-is-errno.h b/drivers/media/platform/exynos4-is/fimc-is-errno.h new file mode 100644 index 000000000000..3de6f6da6f87 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-is-errno.h @@ -0,0 +1,248 @@ +/* + * Samsung Exynos4 SoC series FIMC-IS slave interface driver + * + * FIMC-IS error code definition + * + * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. + * + * Authors: Younghwan Joo + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef FIMC_IS_ERR_H_ +#define FIMC_IS_ERR_H_ + +#define IS_ERROR_VER 011 /* IS ERROR VERSION 0.11 */ + +enum { + IS_ERROR_NONE, + + /* General 1 ~ 99 */ + IS_ERROR_INVALID_COMMAND, + IS_ERROR_REQUEST_FAIL, + IS_ERROR_INVALID_SCENARIO, + IS_ERROR_INVALID_SENSORID, + IS_ERROR_INVALID_MODE_CHANGE, + IS_ERROR_INVALID_MAGIC_NUMBER, + IS_ERROR_INVALID_SETFILE_HDR, + IS_ERROR_BUSY, + IS_ERROR_SET_PARAMETER, + IS_ERROR_INVALID_PATH, + IS_ERROR_OPEN_SENSOR_FAIL, + IS_ERROR_ENTRY_MSG_THREAD_DOWN, + IS_ERROR_ISP_FRAME_END_NOT_DONE, + IS_ERROR_DRC_FRAME_END_NOT_DONE, + IS_ERROR_SCALERC_FRAME_END_NOT_DONE, + IS_ERROR_ODC_FRAME_END_NOT_DONE, + IS_ERROR_DIS_FRAME_END_NOT_DONE, + IS_ERROR_TDNR_FRAME_END_NOT_DONE, + IS_ERROR_SCALERP_FRAME_END_NOT_DONE, + IS_ERROR_WAIT_STREAM_OFF_NOT_DONE, + IS_ERROR_NO_MSG_IS_RECEIVED, + IS_ERROR_SENSOR_MSG_FAIL, + IS_ERROR_ISP_MSG_FAIL, + IS_ERROR_DRC_MSG_FAIL, + IS_ERROR_SCALERC_MSG_FAIL, + IS_ERROR_ODC_MSG_FAIL, + IS_ERROR_DIS_MSG_FAIL, + IS_ERROR_TDNR_MSG_FAIL, + IS_ERROR_SCALERP_MSG_FAIL, + IS_ERROR_LHFD_MSG_FAIL, + IS_ERROR_LHFD_INTERNAL_STOP, + + /* Sensor 100 ~ 199 */ + IS_ERROR_SENSOR_PWRDN_FAIL = 100, + IS_ERROR_SENSOR_STREAM_ON_FAIL, + IS_ERROR_SENSOR_STREAM_OFF_FAIL, + + /* ISP 200 ~ 299 */ + IS_ERROR_ISP_PWRDN_FAIL = 200, + IS_ERROR_ISP_MULTIPLE_INPUT, + IS_ERROR_ISP_ABSENT_INPUT, + IS_ERROR_ISP_ABSENT_OUTPUT, + IS_ERROR_ISP_NONADJACENT_OUTPUT, + IS_ERROR_ISP_FORMAT_MISMATCH, + IS_ERROR_ISP_WIDTH_MISMATCH, + IS_ERROR_ISP_HEIGHT_MISMATCH, + IS_ERROR_ISP_BITWIDTH_MISMATCH, + IS_ERROR_ISP_FRAME_END_TIME_OUT, + + /* DRC 300 ~ 399 */ + IS_ERROR_DRC_PWRDN_FAIL = 300, + IS_ERROR_DRC_MULTIPLE_INPUT, + IS_ERROR_DRC_ABSENT_INPUT, + IS_ERROR_DRC_NONADJACENT_INPUT, + IS_ERROR_DRC_ABSENT_OUTPUT, + IS_ERROR_DRC_NONADJACENT_OUTPUT, + IS_ERROR_DRC_FORMAT_MISMATCH, + IS_ERROR_DRC_WIDTH_MISMATCH, + IS_ERROR_DRC_HEIGHT_MISMATCH, + IS_ERROR_DRC_BITWIDTH_MISMATCH, + IS_ERROR_DRC_FRAME_END_TIME_OUT, + + /* SCALERC 400 ~ 499 */ + IS_ERROR_SCALERC_PWRDN_FAIL = 400, + + /* ODC 500 ~ 599 */ + IS_ERROR_ODC_PWRDN_FAIL = 500, + + /* DIS 600 ~ 699 */ + IS_ERROR_DIS_PWRDN_FAIL = 600, + + /* TDNR 700 ~ 799 */ + IS_ERROR_TDNR_PWRDN_FAIL = 700, + + /* SCALERC 800 ~ 899 */ + IS_ERROR_SCALERP_PWRDN_FAIL = 800, + + /* FD 900 ~ 999 */ + IS_ERROR_FD_PWRDN_FAIL = 900, + IS_ERROR_FD_MULTIPLE_INPUT, + IS_ERROR_FD_ABSENT_INPUT, + IS_ERROR_FD_NONADJACENT_INPUT, + IS_ERROR_LHFD_FRAME_END_TIME_OUT, + + IS_ERROR_UNKNOWN = 1000, +}; + +#define IS_ERROR_TIME_OUT_FLAG 0x80000000 + +/* Set parameter error enum */ +enum fimc_is_error { + /* Common error (0~99) */ + ERROR_COMMON_NONE = 0, + ERROR_COMMON_CMD = 1, /* Invalid command */ + ERROR_COMMON_PARAMETER = 2, /* Invalid parameter */ + /* setfile is not loaded before adjusting */ + ERROR_COMMON_SETFILE_LOAD = 3, + /* setfile is not Adjusted before runnng. */ + ERROR_COMMON_SETFILE_ADJUST = 4, + /* Index of setfile is not valid (0~MAX_SETFILE_NUM-1) */ + ERROR_COMMON_SETFILE_INDEX = 5, + /* Input path can be changed in ready state(stop) */ + ERROR_COMMON_INPUT_PATH = 6, + /* IP can not start if input path is not set */ + ERROR_COMMON_INPUT_INIT = 7, + /* Output path can be changed in ready state (stop) */ + ERROR_COMMON_OUTPUT_PATH = 8, + /* IP can not start if output path is not set */ + ERROR_COMMON_OUTPUT_INIT = 9, + + ERROR_CONTROL_NONE = ERROR_COMMON_NONE, + ERROR_CONTROL_BYPASS = 11, /* Enable or Disable */ + + ERROR_OTF_INPUT_NONE = ERROR_COMMON_NONE, + ERROR_OTF_INPUT_CMD = 21, + /* invalid format (DRC: YUV444, FD: YUV444, 422, 420) */ + ERROR_OTF_INPUT_FORMAT = 22, + /* invalid width (DRC: 128~8192, FD: 32~8190) */ + ERROR_OTF_INPUT_WIDTH = 23, + /* invalid height (DRC: 64~8192, FD: 16~8190) */ + ERROR_OTF_INPUT_HEIGHT = 24, + /* invalid bit-width (DRC: 8~12bits, FD: 8bit) */ + ERROR_OTF_INPUT_BIT_WIDTH = 25, + /* invalid FrameTime for ISP */ + ERROR_OTF_INPUT_USER_FRAMETIIME = 26, + + ERROR_DMA_INPUT_NONE = ERROR_COMMON_NONE, + /* invalid width (DRC: 128~8192, FD: 32~8190) */ + ERROR_DMA_INPUT_WIDTH = 31, + /* invalid height (DRC: 64~8192, FD: 16~8190) */ + ERROR_DMA_INPUT_HEIGHT = 32, + /* invalid format (DRC: YUV444 or YUV422, FD: YUV444, 422, 420) */ + ERROR_DMA_INPUT_FORMAT = 33, + /* invalid bit-width (DRC: 8~12bit, FD: 8bit) */ + ERROR_DMA_INPUT_BIT_WIDTH = 34, + /* invalid order(DRC: YYCbCrorYCbYCr, FD:NO,YYCbCr,YCbYCr,CbCr,CrCb) */ + ERROR_DMA_INPUT_ORDER = 35, + /* invalid palne (DRC: 3, FD: 1, 2, 3) */ + ERROR_DMA_INPUT_PLANE = 36, + + ERROR_OTF_OUTPUT_NONE = ERROR_COMMON_NONE, + /* invalid width (DRC: 128~8192) */ + ERROR_OTF_OUTPUT_WIDTH = 41, + /* invalid height (DRC: 64~8192) */ + ERROR_OTF_OUTPUT_HEIGHT = 42, + /* invalid format (DRC: YUV444) */ + ERROR_OTF_OUTPUT_FORMAT = 43, + /* invalid bit-width (DRC: 8~12bits) */ + ERROR_OTF_OUTPUT_BIT_WIDTH = 44, + + ERROR_DMA_OUTPUT_NONE = ERROR_COMMON_NONE, + ERROR_DMA_OUTPUT_WIDTH = 51, /* invalid width */ + ERROR_DMA_OUTPUT_HEIGHT = 52, /* invalid height */ + ERROR_DMA_OUTPUT_FORMAT = 53, /* invalid format */ + ERROR_DMA_OUTPUT_BIT_WIDTH = 54, /* invalid bit-width */ + ERROR_DMA_OUTPUT_PLANE = 55, /* invalid plane */ + ERROR_DMA_OUTPUT_ORDER = 56, /* invalid order */ + + ERROR_GLOBAL_SHOTMODE_NONE = ERROR_COMMON_NONE, + + /* SENSOR Error(100~199) */ + ERROR_SENSOR_NONE = ERROR_COMMON_NONE, + ERROR_SENSOR_I2C_FAIL = 101, + ERROR_SENSOR_INVALID_FRAMERATE, + ERROR_SENSOR_INVALID_EXPOSURETIME, + ERROR_SENSOR_INVALID_SIZE, + ERROR_SENSOR_INVALID_SETTING, + ERROR_SENSOR_ACTURATOR_INIT_FAIL, + ERROR_SENSOR_INVALID_AF_POS, + ERROR_SENSOR_UNSUPPORT_FUNC, + ERROR_SENSOR_UNSUPPORT_PERI, + ERROR_SENSOR_UNSUPPORT_AF, + + /* ISP Error (200~299) */ + ERROR_ISP_AF_NONE = ERROR_COMMON_NONE, + ERROR_ISP_AF_BUSY = 201, + ERROR_ISP_AF_INVALID_COMMAND = 202, + ERROR_ISP_AF_INVALID_MODE = 203, + ERROR_ISP_FLASH_NONE = ERROR_COMMON_NONE, + ERROR_ISP_AWB_NONE = ERROR_COMMON_NONE, + ERROR_ISP_IMAGE_EFFECT_NONE = ERROR_COMMON_NONE, + ERROR_ISP_ISO_NONE = ERROR_COMMON_NONE, + ERROR_ISP_ADJUST_NONE = ERROR_COMMON_NONE, + ERROR_ISP_METERING_NONE = ERROR_COMMON_NONE, + ERROR_ISP_AFC_NONE = ERROR_COMMON_NONE, + + /* DRC Error (300~399) */ + + /* FD Error (400~499) */ + ERROR_FD_NONE = ERROR_COMMON_NONE, + /* Invalid max number (1~16) */ + ERROR_FD_CONFIG_MAX_NUMBER_STATE = 401, + ERROR_FD_CONFIG_MAX_NUMBER_INVALID = 402, + ERROR_FD_CONFIG_YAW_ANGLE_STATE = 403, + ERROR_FD_CONFIG_YAW_ANGLE_INVALID = 404, + ERROR_FD_CONFIG_ROLL_ANGLE_STATE = 405, + ERROR_FD_CONFIG_ROLL_ANGLE_INVALID = 406, + ERROR_FD_CONFIG_SMILE_MODE_INVALID = 407, + ERROR_FD_CONFIG_BLINK_MODE_INVALID = 408, + ERROR_FD_CONFIG_EYES_DETECT_INVALID = 409, + ERROR_FD_CONFIG_MOUTH_DETECT_INVALID = 410, + ERROR_FD_CONFIG_ORIENTATION_STATE = 411, + ERROR_FD_CONFIG_ORIENTATION_INVALID = 412, + ERROR_FD_CONFIG_ORIENTATION_VALUE_INVALID = 413, + /* PARAM_FdResultStr can be only applied in ready-state or stream off */ + ERROR_FD_RESULT = 414, + /* PARAM_FdModeStr can be only applied in ready-state or stream off */ + ERROR_FD_MODE = 415, + /* Scaler Error (500 ~ 599) */ + ERROR_SCALER_NO_NONE = ERROR_COMMON_NONE, + ERROR_SCALER_DMA_OUTSEL = 501, + ERROR_SCALER_H_RATIO = 502, + ERROR_SCALER_V_RATIO = 503, + + ERROR_SCALER_IMAGE_EFFECT = 510, + + ERROR_SCALER_ROTATE = 520, + ERROR_SCALER_FLIP = 521, +}; + +const char * const fimc_is_strerr(unsigned int error); +const char * const fimc_is_param_strerr(unsigned int error); + +#endif /* FIMC_IS_ERR_H_ */ diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c new file mode 100644 index 000000000000..efb9da06052c --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c @@ -0,0 +1,242 @@ +/* + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. + * + * Authors: Younghwan Joo + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include + +#include "fimc-is.h" +#include "fimc-is-command.h" +#include "fimc-is-regs.h" +#include "fimc-is-sensor.h" + +void fimc_is_fw_clear_irq1(struct fimc_is *is, unsigned int nr) +{ + mcuctl_write(1UL << nr, is, MCUCTL_REG_INTCR1); +} + +void fimc_is_fw_clear_irq2(struct fimc_is *is) +{ + u32 cfg = mcuctl_read(is, MCUCTL_REG_INTSR2); + mcuctl_write(cfg, is, MCUCTL_REG_INTCR2); +} + +void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is) +{ + mcuctl_write(INTGR0_INTGD(0), is, MCUCTL_REG_INTGR0); +} + +int fimc_is_hw_wait_intsr0_intsd0(struct fimc_is *is) +{ + unsigned int timeout = 2000; + u32 cfg, status; + + cfg = mcuctl_read(is, MCUCTL_REG_INTSR0); + status = INTSR0_GET_INTSD(0, cfg); + + while (status) { + cfg = mcuctl_read(is, MCUCTL_REG_INTSR0); + status = INTSR0_GET_INTSD(0, cfg); + if (timeout == 0) { + dev_warn(&is->pdev->dev, "%s timeout\n", + __func__); + return -ETIME; + } + timeout--; + udelay(1); + } + return 0; +} + +int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is) +{ + unsigned int timeout = 2000; + u32 cfg, status; + + cfg = mcuctl_read(is, MCUCTL_REG_INTMSR0); + status = INTMSR0_GET_INTMSD(0, cfg); + + while (status) { + cfg = mcuctl_read(is, MCUCTL_REG_INTMSR0); + status = INTMSR0_GET_INTMSD(0, cfg); + if (timeout == 0) { + dev_warn(&is->pdev->dev, "%s timeout\n", + __func__); + return -ETIME; + } + timeout--; + udelay(1); + } + return 0; +} + +int fimc_is_hw_set_param(struct fimc_is *is) +{ + struct is_config_param *cfg = &is->cfg_param[is->scenario_id]; + + fimc_is_hw_wait_intmsr0_intmsd0(is); + + mcuctl_write(HIC_SET_PARAMETER, is, MCUCTL_REG_ISSR(0)); + mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); + mcuctl_write(is->scenario_id, is, MCUCTL_REG_ISSR(2)); + + mcuctl_write(atomic_read(&cfg->p_region_num), is, MCUCTL_REG_ISSR(3)); + mcuctl_write(cfg->p_region_index1, is, MCUCTL_REG_ISSR(4)); + mcuctl_write(cfg->p_region_index2, is, MCUCTL_REG_ISSR(5)); + + fimc_is_hw_set_intgr0_gd0(is); + return 0; +} + +int fimc_is_hw_set_tune(struct fimc_is *is) +{ + fimc_is_hw_wait_intmsr0_intmsd0(is); + + mcuctl_write(HIC_SET_TUNE, is, MCUCTL_REG_ISSR(0)); + mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); + mcuctl_write(is->h2i_cmd.entry_id, is, MCUCTL_REG_ISSR(2)); + + fimc_is_hw_set_intgr0_gd0(is); + return 0; +} + +#define FIMC_IS_MAX_PARAMS 4 + +int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num_args) +{ + int i; + + if (num_args > FIMC_IS_MAX_PARAMS) + return -EINVAL; + + is->i2h_cmd.num_args = num_args; + + for (i = 0; i < FIMC_IS_MAX_PARAMS; i++) { + if (i < num_args) + is->i2h_cmd.args[i] = mcuctl_read(is, + MCUCTL_REG_ISSR(12 + i)); + else + is->i2h_cmd.args[i] = 0; + } + return 0; +} + +void fimc_is_hw_set_sensor_num(struct fimc_is *is) +{ + pr_debug("setting sensor index to: %d\n", is->sensor_index); + + mcuctl_write(IH_REPLY_DONE, is, MCUCTL_REG_ISSR(0)); + mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); + mcuctl_write(IHC_GET_SENSOR_NUM, is, MCUCTL_REG_ISSR(2)); + mcuctl_write(FIMC_IS_SENSOR_NUM, is, MCUCTL_REG_ISSR(3)); +} + +void fimc_is_hw_close_sensor(struct fimc_is *is, unsigned int index) +{ + if (is->sensor_index != index) + return; + + fimc_is_hw_wait_intmsr0_intmsd0(is); + mcuctl_write(HIC_CLOSE_SENSOR, is, MCUCTL_REG_ISSR(0)); + mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); + mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(2)); + fimc_is_hw_set_intgr0_gd0(is); +} + +void fimc_is_hw_get_setfile_addr(struct fimc_is *is) +{ + fimc_is_hw_wait_intmsr0_intmsd0(is); + mcuctl_write(HIC_GET_SET_FILE_ADDR, is, MCUCTL_REG_ISSR(0)); + mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); + fimc_is_hw_set_intgr0_gd0(is); +} + +void fimc_is_hw_load_setfile(struct fimc_is *is) +{ + fimc_is_hw_wait_intmsr0_intmsd0(is); + mcuctl_write(HIC_LOAD_SET_FILE, is, MCUCTL_REG_ISSR(0)); + mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); + fimc_is_hw_set_intgr0_gd0(is); +} + +int fimc_is_hw_change_mode(struct fimc_is *is) +{ + const u8 cmd[] = { + HIC_PREVIEW_STILL, HIC_PREVIEW_VIDEO, + HIC_CAPTURE_STILL, HIC_CAPTURE_VIDEO, + }; + + if (WARN_ON(is->scenario_id > ARRAY_SIZE(cmd))) + return -EINVAL; + + mcuctl_write(cmd[is->scenario_id], is, MCUCTL_REG_ISSR(0)); + mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); + mcuctl_write(is->setfile.sub_index, is, MCUCTL_REG_ISSR(2)); + fimc_is_hw_set_intgr0_gd0(is); + return 0; +} + +void fimc_is_hw_stream_on(struct fimc_is *is) +{ + fimc_is_hw_wait_intmsr0_intmsd0(is); + mcuctl_write(HIC_STREAM_ON, is, MCUCTL_REG_ISSR(0)); + mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); + mcuctl_write(0, is, MCUCTL_REG_ISSR(2)); + fimc_is_hw_set_intgr0_gd0(is); +} + +void fimc_is_hw_stream_off(struct fimc_is *is) +{ + fimc_is_hw_wait_intmsr0_intmsd0(is); + mcuctl_write(HIC_STREAM_OFF, is, MCUCTL_REG_ISSR(0)); + mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); + fimc_is_hw_set_intgr0_gd0(is); +} + +void fimc_is_hw_subip_power_off(struct fimc_is *is) +{ + fimc_is_hw_wait_intmsr0_intmsd0(is); + mcuctl_write(HIC_POWER_DOWN, is, MCUCTL_REG_ISSR(0)); + mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); + fimc_is_hw_set_intgr0_gd0(is); +} + +int fimc_is_itf_s_param(struct fimc_is *is, bool update) +{ + int ret; + + if (update) + __is_hw_update_params(is); + + fimc_is_mem_barrier(); + + clear_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state); + fimc_is_hw_set_param(is); + ret = fimc_is_wait_event(is, IS_ST_BLOCK_CMD_CLEARED, 1, + FIMC_IS_CONFIG_TIMEOUT); + if (ret < 0) + dev_err(&is->pdev->dev, "%s() timeout\n", __func__); + + return ret; +} + +int fimc_is_itf_mode_change(struct fimc_is *is) +{ + int ret; + + clear_bit(IS_ST_CHANGE_MODE, &is->state); + fimc_is_hw_change_mode(is); + ret = fimc_is_wait_event(is, IS_ST_CHANGE_MODE, 1, + FIMC_IS_CONFIG_TIMEOUT); + if (!ret < 0) + dev_err(&is->pdev->dev, "%s(): mode change (%d) timeout\n", + __func__, is->scenario_id); + return ret; +} diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.h b/drivers/media/platform/exynos4-is/fimc-is-regs.h new file mode 100644 index 000000000000..5fa2fda46742 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.h @@ -0,0 +1,164 @@ +/* + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * + * Authors: Sylwester Nawrocki + * Younghwan Joo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef FIMC_IS_REG_H_ +#define FIMC_IS_REG_H_ + +/* WDT_ISP register */ +#define REG_WDT_ISP 0x00170000 + +/* MCUCTL registers base offset */ +#define MCUCTL_BASE 0x00180000 + +/* MCU Controller Register */ +#define MCUCTL_REG_MCUCTRL (MCUCTL_BASE + 0x00) +#define MCUCTRL_MSWRST (1 << 0) + +/* Boot Base Offset Address Register */ +#define MCUCTL_REG_BBOAR (MCUCTL_BASE + 0x04) + +/* Interrupt Generation Register 0 from Host CPU to VIC */ +#define MCUCTL_REG_INTGR0 (MCUCTL_BASE + 0x08) +/* __n = 0...9 */ +#define INTGR0_INTGC(__n) (1 << ((__n) + 16)) +/* __n = 0...5 */ +#define INTGR0_INTGD(__n) (1 << (__n)) + +/* Interrupt Clear Register 0 from Host CPU to VIC */ +#define MCUCTL_REG_INTCR0 (MCUCTL_BASE + 0x0c) +/* __n = 0...9 */ +#define INTCR0_INTGC(__n) (1 << ((__n) + 16)) +/* __n = 0...5 */ +#define INTCR0_INTCD(__n) (1 << ((__n) + 16)) + +/* Interrupt Mask Register 0 from Host CPU to VIC */ +#define MCUCTL_REG_INTMR0 (MCUCTL_BASE + 0x10) +/* __n = 0...9 */ +#define INTMR0_INTMC(__n) (1 << ((__n) + 16)) +/* __n = 0...5 */ +#define INTMR0_INTMD(__n) (1 << (__n)) + +/* Interrupt Status Register 0 from Host CPU to VIC */ +#define MCUCTL_REG_INTSR0 (MCUCTL_BASE + 0x14) +/* __n (bit number) = 0...4 */ +#define INTSR0_GET_INTSD(x, __n) (((x) >> (__n)) & 0x1) +/* __n (bit number) = 0...9 */ +#define INTSR0_GET_INTSC(x, __n) (((x) >> ((__n) + 16)) & 0x1) + +/* Interrupt Mask Status Register 0 from Host CPU to VIC */ +#define MCUCTL_REG_INTMSR0 (MCUCTL_BASE + 0x18) +/* __n (bit number) = 0...4 */ +#define INTMSR0_GET_INTMSD(x, __n) (((x) >> (__n)) & 0x1) +/* __n (bit number) = 0...9 */ +#define INTMSR0_GET_INTMSC(x, __n) (((x) >> ((__n) + 16)) & 0x1) + +/* Interrupt Generation Register 1 from ISP CPU to Host IC */ +#define MCUCTL_REG_INTGR1 (MCUCTL_BASE + 0x1c) +/* __n = 0...9 */ +#define INTGR1_INTGC(__n) (1 << (__n)) + +/* Interrupt Clear Register 1 from ISP CPU to Host IC */ +#define MCUCTL_REG_INTCR1 (MCUCTL_BASE + 0x20) +/* __n = 0...9 */ +#define INTCR1_INTCC(__n) (1 << (__n)) + +/* Interrupt Mask Register 1 from ISP CPU to Host IC */ +#define MCUCTL_REG_INTMR1 (MCUCTL_BASE + 0x24) +/* __n = 0...9 */ +#define INTMR1_INTMC(__n) (1 << (__n)) + +/* Interrupt Status Register 1 from ISP CPU to Host IC */ +#define MCUCTL_REG_INTSR1 (MCUCTL_BASE + 0x28) +/* Interrupt Mask Status Register 1 from ISP CPU to Host IC */ +#define MCUCTL_REG_INTMSR1 (MCUCTL_BASE + 0x2c) + +/* Interrupt Clear Register 2 from ISP BLK's interrupts to Host IC */ +#define MCUCTL_REG_INTCR2 (MCUCTL_BASE + 0x30) +/* __n = 0...5 */ +#define INTCR2_INTCC(__n) (1 << ((__n) + 16)) + +/* Interrupt Mask Register 2 from ISP BLK's interrupts to Host IC */ +#define MCUCTL_REG_INTMR2 (MCUCTL_BASE + 0x34) +/* __n = 0...25 */ +#define INTMR2_INTMCIS(__n) (1 << (__n)) + +/* Interrupt Status Register 2 from ISP BLK's interrupts to Host IC */ +#define MCUCTL_REG_INTSR2 (MCUCTL_BASE + 0x38) +/* Interrupt Mask Status Register 2 from ISP BLK's interrupts to Host IC */ +#define MCUCTL_REG_INTMSR2 (MCUCTL_BASE + 0x3c) + +/* General Purpose Output Control Register (0~17) */ +#define MCUCTL_REG_GPOCTLR (MCUCTL_BASE + 0x40) +/* __n = 0...17 */ +#define GPOCTLR_GPOG(__n) (1 << (__n)) + +/* General Purpose Pad Output Enable Register (0~17) */ +#define MCUCTL_REG_GPOENCTLR (MCUCTL_BASE + 0x44) +/* __n = 0...17 */ +#define GPOENCTLR_GPOEN(__n) (1 << (__n)) + +/* General Purpose Input Control Register (0~17) */ +#define MCUCTL_REG_GPICTLR (MCUCTL_BASE + 0x48) + +/* Shared registers between ISP CPU and the host CPU - ISSRxx */ + +/* ISSR(1): Command Host -> IS */ +/* ISSR(1): Sensor ID for Command, ISSR2...5 = Parameter 1...4 */ + +/* ISSR(10): Reply IS -> Host */ +/* ISSR(11): Sensor ID for Reply, ISSR12...15 = Parameter 1...4 */ + +/* ISSR(20): ISP_FRAME_DONE : SENSOR ID */ +/* ISSR(21): ISP_FRAME_DONE : PARAMETER 1 */ + +/* ISSR(24): SCALERC_FRAME_DONE : SENSOR ID */ +/* ISSR(25): SCALERC_FRAME_DONE : PARAMETER 1 */ + +/* ISSR(28): 3DNR_FRAME_DONE : SENSOR ID */ +/* ISSR(29): 3DNR_FRAME_DONE : PARAMETER 1 */ + +/* ISSR(32): SCALERP_FRAME_DONE : SENSOR ID */ +/* ISSR(33): SCALERP_FRAME_DONE : PARAMETER 1 */ + +/* __n = 0...63 */ +#define MCUCTL_REG_ISSR(__n) (MCUCTL_BASE + 0x80 + ((__n) * 4)) + +/* PMU ISP register offsets */ +#define REG_CMU_RESET_ISP_SYS_PWR_REG 0x1174 +#define REG_CMU_SYSCLK_ISP_SYS_PWR_REG 0x13b8 +#define REG_PMU_ISP_ARM_SYS 0x1050 +#define REG_PMU_ISP_ARM_CONFIGURATION 0x2280 +#define REG_PMU_ISP_ARM_STATUS 0x2284 +#define REG_PMU_ISP_ARM_OPTION 0x2288 + +void fimc_is_fw_clear_irq1(struct fimc_is *is, unsigned int bit); +void fimc_is_fw_clear_irq2(struct fimc_is *is); +int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num); + +void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is); +int fimc_is_hw_wait_intsr0_intsd0(struct fimc_is *is); +int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is); +void fimc_is_hw_set_sensor_num(struct fimc_is *is); +void fimc_is_hw_stream_on(struct fimc_is *is); +void fimc_is_hw_stream_off(struct fimc_is *is); +int fimc_is_hw_set_param(struct fimc_is *is); +int fimc_is_hw_change_mode(struct fimc_is *is); + +void fimc_is_hw_close_sensor(struct fimc_is *is, unsigned int index); +void fimc_is_hw_get_setfile_addr(struct fimc_is *is); +void fimc_is_hw_load_setfile(struct fimc_is *is); +void fimc_is_hw_subip_power_off(struct fimc_is *is); + +int fimc_is_itf_s_param(struct fimc_is *is, bool update); +int fimc_is_itf_mode_change(struct fimc_is *is); + +#endif /* FIMC_IS_REG_H_ */ diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c new file mode 100644 index 000000000000..c5e4c5380f24 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -0,0 +1,1010 @@ +/* + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * + * Authors: Sylwester Nawrocki + * Younghwan Joo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "media-dev.h" +#include "fimc-is.h" +#include "fimc-is-command.h" +#include "fimc-is-errno.h" +#include "fimc-is-i2c.h" +#include "fimc-is-param.h" +#include "fimc-is-regs.h" + + +static char *fimc_is_clocks[ISS_CLKS_MAX] = { + [ISS_CLK_PPMUISPX] = "ppmuispx", + [ISS_CLK_PPMUISPMX] = "ppmuispmx", + [ISS_CLK_LITE0] = "lite0", + [ISS_CLK_LITE1] = "lite1", + [ISS_CLK_MPLL] = "mpll", + [ISS_CLK_SYSREG] = "sysreg", + [ISS_CLK_ISP] = "isp", + [ISS_CLK_DRC] = "drc", + [ISS_CLK_FD] = "fd", + [ISS_CLK_MCUISP] = "mcuisp", + [ISS_CLK_UART] = "uart", + [ISS_CLK_ISP_DIV0] = "ispdiv0", + [ISS_CLK_ISP_DIV1] = "ispdiv1", + [ISS_CLK_MCUISP_DIV0] = "mcuispdiv0", + [ISS_CLK_MCUISP_DIV1] = "mcuispdiv1", + [ISS_CLK_ACLK200] = "aclk200", + [ISS_CLK_ACLK200_DIV] = "div_aclk200", + [ISS_CLK_ACLK400MCUISP] = "aclk400mcuisp", + [ISS_CLK_ACLK400MCUISP_DIV] = "div_aclk400mcuisp", +}; + +static void fimc_is_put_clocks(struct fimc_is *is) +{ + int i; + + for (i = 0; i < ISS_CLKS_MAX; i++) { + if (IS_ERR(is->clocks[i])) + continue; + clk_unprepare(is->clocks[i]); + clk_put(is->clocks[i]); + is->clocks[i] = ERR_PTR(-EINVAL); + } +} + +static int fimc_is_get_clocks(struct fimc_is *is) +{ + int i, ret; + + for (i = 0; i < ISS_CLKS_MAX; i++) + is->clocks[i] = ERR_PTR(-EINVAL); + + for (i = 0; i < ISS_CLKS_MAX; i++) { + is->clocks[i] = clk_get(&is->pdev->dev, fimc_is_clocks[i]); + if (IS_ERR(is->clocks[i])) { + ret = PTR_ERR(is->clocks[i]); + goto err; + } + ret = clk_prepare(is->clocks[i]); + if (ret < 0) { + clk_put(is->clocks[i]); + is->clocks[i] = ERR_PTR(-EINVAL); + goto err; + } + } + + return 0; +err: + fimc_is_put_clocks(is); + dev_err(&is->pdev->dev, "failed to get clock: %s\n", + fimc_is_clocks[i]); + return -ENXIO; +} + +static int fimc_is_setup_clocks(struct fimc_is *is) +{ + int ret; + + ret = clk_set_parent(is->clocks[ISS_CLK_ACLK200], + is->clocks[ISS_CLK_ACLK200_DIV]); + if (ret < 0) + return ret; + + ret = clk_set_parent(is->clocks[ISS_CLK_ACLK400MCUISP], + is->clocks[ISS_CLK_ACLK400MCUISP_DIV]); + if (ret < 0) + return ret; + + ret = clk_set_rate(is->clocks[ISS_CLK_ISP_DIV0], ACLK_AXI_FREQUENCY); + if (ret < 0) + return ret; + + ret = clk_set_rate(is->clocks[ISS_CLK_ISP_DIV1], ACLK_AXI_FREQUENCY); + if (ret < 0) + return ret; + + ret = clk_set_rate(is->clocks[ISS_CLK_MCUISP_DIV0], + ATCLK_MCUISP_FREQUENCY); + if (ret < 0) + return ret; + + return clk_set_rate(is->clocks[ISS_CLK_MCUISP_DIV1], + ATCLK_MCUISP_FREQUENCY); +} + +int fimc_is_enable_clocks(struct fimc_is *is) +{ + int i, ret; + + for (i = 0; i < ISS_GATE_CLKS_MAX; i++) { + if (IS_ERR(is->clocks[i])) + continue; + ret = clk_enable(is->clocks[i]); + if (ret < 0) { + dev_err(&is->pdev->dev, "clock %s enable failed\n", + fimc_is_clocks[i]); + for (--i; i >= 0; i--) + clk_disable(is->clocks[i]); + return ret; + } + pr_debug("enabled clock: %s\n", fimc_is_clocks[i]); + } + return 0; +} + +void fimc_is_disable_clocks(struct fimc_is *is) +{ + int i; + + for (i = 0; i < ISS_GATE_CLKS_MAX; i++) { + if (!IS_ERR(is->clocks[i])) { + clk_disable(is->clocks[i]); + pr_debug("disabled clock: %s\n", fimc_is_clocks[i]); + } + } +} + +static int fimc_is_parse_sensor_config(struct fimc_is_sensor *sensor, + struct device_node *np) +{ + u32 tmp = 0; + int ret; + + np = v4l2_of_get_next_endpoint(np, NULL); + if (!np) + return -ENXIO; + np = v4l2_of_get_remote_port(np); + if (!np) + return -ENXIO; + + /* Use MIPI-CSIS channel id to determine the ISP I2C bus index. */ + ret = of_property_read_u32(np, "reg", &tmp); + sensor->i2c_bus = tmp - FIMC_INPUT_MIPI_CSI2_0; + + return ret; +} + +static int fimc_is_register_subdevs(struct fimc_is *is) +{ + struct device_node *adapter, *child; + int ret; + + ret = fimc_isp_subdev_create(&is->isp); + if (ret < 0) + return ret; + + for_each_compatible_node(adapter, NULL, FIMC_IS_I2C_COMPATIBLE) { + if (!of_find_device_by_node(adapter)) { + of_node_put(adapter); + return -EPROBE_DEFER; + } + + for_each_available_child_of_node(adapter, child) { + struct i2c_client *client; + struct v4l2_subdev *sd; + + client = of_find_i2c_device_by_node(child); + if (!client) + goto e_retry; + + sd = i2c_get_clientdata(client); + if (!sd) + goto e_retry; + + /* FIXME: Add support for multiple sensors. */ + if (WARN_ON(is->sensor)) + continue; + + is->sensor = v4l2_get_subdevdata(sd); + + if (fimc_is_parse_sensor_config(is->sensor, child)) { + dev_warn(&is->pdev->dev, "DT parse error: %s\n", + child->full_name); + } + pr_debug("%s(): registered subdev: %p\n", + __func__, sd->name); + } + } + return 0; + +e_retry: + of_node_put(child); + return -EPROBE_DEFER; +} + +static int fimc_is_unregister_subdevs(struct fimc_is *is) +{ + fimc_isp_subdev_destroy(&is->isp); + is->sensor = NULL; + return 0; +} + +static int fimc_is_load_setfile(struct fimc_is *is, char *file_name) +{ + const struct firmware *fw; + void *buf; + int ret; + + ret = request_firmware(&fw, file_name, &is->pdev->dev); + if (ret < 0) { + dev_err(&is->pdev->dev, "firmware request failed (%d)\n", ret); + return ret; + } + buf = is->memory.vaddr + is->setfile.base; + memcpy(buf, fw->data, fw->size); + fimc_is_mem_barrier(); + is->setfile.size = fw->size; + + pr_debug("mem vaddr: %p, setfile buf: %p\n", is->memory.vaddr, buf); + + memcpy(is->fw.setfile_info, + fw->data + fw->size - FIMC_IS_SETFILE_INFO_LEN, + FIMC_IS_SETFILE_INFO_LEN - 1); + + is->fw.setfile_info[FIMC_IS_SETFILE_INFO_LEN - 1] = '\0'; + is->setfile.state = 1; + + pr_debug("FIMC-IS setfile loaded: base: %#x, size: %zu B\n", + is->setfile.base, fw->size); + + release_firmware(fw); + return ret; +} + +int fimc_is_cpu_set_power(struct fimc_is *is, int on) +{ + unsigned int timeout = FIMC_IS_POWER_ON_TIMEOUT; + + if (on) { + /* Disable watchdog */ + mcuctl_write(0, is, REG_WDT_ISP); + + /* Cortex-A5 start address setting */ + mcuctl_write(is->memory.paddr, is, MCUCTL_REG_BBOAR); + + /* Enable and start Cortex-A5 */ + pmuisp_write(0x18000, is, REG_PMU_ISP_ARM_OPTION); + pmuisp_write(0x1, is, REG_PMU_ISP_ARM_CONFIGURATION); + } else { + /* A5 power off */ + pmuisp_write(0x10000, is, REG_PMU_ISP_ARM_OPTION); + pmuisp_write(0x0, is, REG_PMU_ISP_ARM_CONFIGURATION); + + while (pmuisp_read(is, REG_PMU_ISP_ARM_STATUS) & 1) { + if (timeout == 0) + return -ETIME; + timeout--; + udelay(1); + } + } + + return 0; +} + +/* Wait until @bit of @is->state is set to @state in the interrupt handler. */ +int fimc_is_wait_event(struct fimc_is *is, unsigned long bit, + unsigned int state, unsigned int timeout) +{ + + int ret = wait_event_timeout(is->irq_queue, + !state ^ test_bit(bit, &is->state), + timeout); + if (ret == 0) { + dev_WARN(&is->pdev->dev, "%s() timed out\n", __func__); + return -ETIME; + } + return 0; +} + +int fimc_is_start_firmware(struct fimc_is *is) +{ + struct device *dev = &is->pdev->dev; + int ret; + + memcpy(is->memory.vaddr, is->fw.f_w->data, is->fw.f_w->size); + wmb(); + + ret = fimc_is_cpu_set_power(is, 1); + if (ret < 0) + return ret; + + ret = fimc_is_wait_event(is, IS_ST_A5_PWR_ON, 1, + msecs_to_jiffies(FIMC_IS_FW_LOAD_TIMEOUT)); + if (ret < 0) + dev_err(dev, "FIMC-IS CPU power on failed\n"); + + return ret; +} + +/* Allocate working memory for the FIMC-IS CPU. */ +static int fimc_is_alloc_cpu_memory(struct fimc_is *is) +{ + struct device *dev = &is->pdev->dev; + + is->memory.vaddr = dma_alloc_coherent(dev, FIMC_IS_CPU_MEM_SIZE, + &is->memory.paddr, GFP_KERNEL); + if (is->memory.vaddr == NULL) + return -ENOMEM; + + is->memory.size = FIMC_IS_CPU_MEM_SIZE; + memset(is->memory.vaddr, 0, is->memory.size); + + dev_info(dev, "FIMC-IS CPU memory base: %#x\n", (u32)is->memory.paddr); + + if (((u32)is->memory.paddr) & FIMC_IS_FW_ADDR_MASK) { + dev_err(dev, "invalid firmware memory alignment: %#x\n", + (u32)is->memory.paddr); + dma_free_coherent(dev, is->memory.size, is->memory.vaddr, + is->memory.paddr); + return -EIO; + } + + is->is_p_region = (struct is_region *)(is->memory.vaddr + + FIMC_IS_CPU_MEM_SIZE - FIMC_IS_REGION_SIZE); + + is->is_dma_p_region = is->memory.paddr + + FIMC_IS_CPU_MEM_SIZE - FIMC_IS_REGION_SIZE; + + is->is_shared_region = (struct is_share_region *)(is->memory.vaddr + + FIMC_IS_SHARED_REGION_OFFSET); + return 0; +} + +static void fimc_is_free_cpu_memory(struct fimc_is *is) +{ + struct device *dev = &is->pdev->dev; + + dma_free_coherent(dev, is->memory.size, is->memory.vaddr, + is->memory.paddr); +} + +static void fimc_is_load_firmware(const struct firmware *fw, void *context) +{ + struct fimc_is *is = context; + struct device *dev = &is->pdev->dev; + void *buf; + int ret; + + if (fw == NULL) { + dev_err(dev, "firmware request failed\n"); + return; + } + mutex_lock(&is->lock); + + if (fw->size < FIMC_IS_FW_SIZE_MIN || fw->size > FIMC_IS_FW_SIZE_MAX) { + dev_err(dev, "wrong firmware size: %d\n", fw->size); + goto done; + } + + is->fw.size = fw->size; + + ret = fimc_is_alloc_cpu_memory(is); + if (ret < 0) { + dev_err(dev, "failed to allocate FIMC-IS CPU memory\n"); + goto done; + } + + memcpy(is->memory.vaddr, fw->data, fw->size); + wmb(); + + /* Read firmware description. */ + buf = (void *)(is->memory.vaddr + fw->size - FIMC_IS_FW_DESC_LEN); + memcpy(&is->fw.info, buf, FIMC_IS_FW_INFO_LEN); + is->fw.info[FIMC_IS_FW_INFO_LEN] = 0; + + buf = (void *)(is->memory.vaddr + fw->size - FIMC_IS_FW_VER_LEN); + memcpy(&is->fw.version, buf, FIMC_IS_FW_VER_LEN); + is->fw.version[FIMC_IS_FW_VER_LEN - 1] = 0; + + is->fw.state = 1; + + dev_info(dev, "loaded firmware: %s, rev. %s\n", + is->fw.info, is->fw.version); + dev_dbg(dev, "FW size: %d, paddr: %#x\n", fw->size, is->memory.paddr); + + is->is_shared_region->chip_id = 0xe4412; + is->is_shared_region->chip_rev_no = 1; + + fimc_is_mem_barrier(); + + /* + * FIXME: The firmware is not being released for now, as it is + * needed around for copying to the IS working memory every + * time before the Cortex-A5 is restarted. + */ + if (is->fw.f_w) + release_firmware(is->fw.f_w); + is->fw.f_w = fw; +done: + mutex_unlock(&is->lock); +} + +static int fimc_is_request_firmware(struct fimc_is *is, const char *fw_name) +{ + return request_firmware_nowait(THIS_MODULE, + FW_ACTION_HOTPLUG, fw_name, &is->pdev->dev, + GFP_KERNEL, is, fimc_is_load_firmware); +} + +/* General IS interrupt handler */ +static void fimc_is_general_irq_handler(struct fimc_is *is) +{ + is->i2h_cmd.cmd = mcuctl_read(is, MCUCTL_REG_ISSR(10)); + + switch (is->i2h_cmd.cmd) { + case IHC_GET_SENSOR_NUM: + fimc_is_hw_get_params(is, 1); + fimc_is_hw_wait_intmsr0_intmsd0(is); + fimc_is_hw_set_sensor_num(is); + pr_debug("ISP FW version: %#x\n", is->i2h_cmd.args[0]); + break; + case IHC_SET_FACE_MARK: + case IHC_FRAME_DONE: + fimc_is_hw_get_params(is, 2); + break; + case IHC_SET_SHOT_MARK: + case IHC_AA_DONE: + case IH_REPLY_DONE: + fimc_is_hw_get_params(is, 3); + break; + case IH_REPLY_NOT_DONE: + fimc_is_hw_get_params(is, 4); + break; + case IHC_NOT_READY: + break; + default: + pr_info("unknown command: %#x\n", is->i2h_cmd.cmd); + } + + fimc_is_fw_clear_irq1(is, FIMC_IS_INT_GENERAL); + + switch (is->i2h_cmd.cmd) { + case IHC_GET_SENSOR_NUM: + fimc_is_hw_set_intgr0_gd0(is); + set_bit(IS_ST_A5_PWR_ON, &is->state); + break; + + case IHC_SET_SHOT_MARK: + break; + + case IHC_SET_FACE_MARK: + is->fd_header.count = is->i2h_cmd.args[0]; + is->fd_header.index = is->i2h_cmd.args[1]; + is->fd_header.offset = 0; + break; + + case IHC_FRAME_DONE: + break; + + case IHC_AA_DONE: + pr_debug("AA_DONE - %d, %d, %d\n", is->i2h_cmd.args[0], + is->i2h_cmd.args[1], is->i2h_cmd.args[2]); + break; + + case IH_REPLY_DONE: + pr_debug("ISR_DONE: args[0]: %#x\n", is->i2h_cmd.args[0]); + + switch (is->i2h_cmd.args[0]) { + case HIC_PREVIEW_STILL...HIC_CAPTURE_VIDEO: + /* Get CAC margin */ + set_bit(IS_ST_CHANGE_MODE, &is->state); + is->isp.cac_margin_x = is->i2h_cmd.args[1]; + is->isp.cac_margin_y = is->i2h_cmd.args[2]; + pr_debug("CAC margin (x,y): (%d,%d)\n", + is->isp.cac_margin_x, is->isp.cac_margin_y); + break; + + case HIC_STREAM_ON: + clear_bit(IS_ST_STREAM_OFF, &is->state); + set_bit(IS_ST_STREAM_ON, &is->state); + break; + + case HIC_STREAM_OFF: + clear_bit(IS_ST_STREAM_ON, &is->state); + set_bit(IS_ST_STREAM_OFF, &is->state); + break; + + case HIC_SET_PARAMETER: + is->cfg_param[is->scenario_id].p_region_index1 = 0; + is->cfg_param[is->scenario_id].p_region_index2 = 0; + atomic_set(&is->cfg_param[is->scenario_id].p_region_num, 0); + set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state); + pr_debug("HIC_SET_PARAMETER\n"); + break; + + case HIC_GET_PARAMETER: + break; + + case HIC_SET_TUNE: + break; + + case HIC_GET_STATUS: + break; + + case HIC_OPEN_SENSOR: + set_bit(IS_ST_OPEN_SENSOR, &is->state); + pr_debug("data lanes: %d, settle line: %d\n", + is->i2h_cmd.args[2], is->i2h_cmd.args[1]); + break; + + case HIC_CLOSE_SENSOR: + clear_bit(IS_ST_OPEN_SENSOR, &is->state); + is->sensor_index = 0; + break; + + case HIC_MSG_TEST: + pr_debug("config MSG level completed\n"); + break; + + case HIC_POWER_DOWN: + clear_bit(IS_ST_PWR_SUBIP_ON, &is->state); + break; + + case HIC_GET_SET_FILE_ADDR: + is->setfile.base = is->i2h_cmd.args[1]; + set_bit(IS_ST_SETFILE_LOADED, &is->state); + break; + + case HIC_LOAD_SET_FILE: + set_bit(IS_ST_SETFILE_LOADED, &is->state); + break; + } + break; + + case IH_REPLY_NOT_DONE: + pr_err("ISR_NDONE: %d: %#x, %s\n", is->i2h_cmd.args[0], + is->i2h_cmd.args[1], + fimc_is_strerr(is->i2h_cmd.args[1])); + + if (is->i2h_cmd.args[1] & IS_ERROR_TIME_OUT_FLAG) + pr_err("IS_ERROR_TIME_OUT\n"); + + switch (is->i2h_cmd.args[1]) { + case IS_ERROR_SET_PARAMETER: + fimc_is_mem_barrier(); + } + + switch (is->i2h_cmd.args[0]) { + case HIC_SET_PARAMETER: + is->cfg_param[is->scenario_id].p_region_index1 = 0; + is->cfg_param[is->scenario_id].p_region_index2 = 0; + atomic_set(&is->cfg_param[is->scenario_id].p_region_num, 0); + set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state); + break; + } + break; + + case IHC_NOT_READY: + pr_err("IS control sequence error: Not Ready\n"); + break; + } + + wake_up(&is->irq_queue); +} + +static irqreturn_t fimc_is_irq_handler(int irq, void *priv) +{ + struct fimc_is *is = priv; + unsigned long flags; + u32 status; + + spin_lock_irqsave(&is->slock, flags); + status = mcuctl_read(is, MCUCTL_REG_INTSR1); + + if (status & (1UL << FIMC_IS_INT_GENERAL)) + fimc_is_general_irq_handler(is); + + if (status & (1UL << FIMC_IS_INT_FRAME_DONE_ISP)) + fimc_isp_irq_handler(is); + + spin_unlock_irqrestore(&is->slock, flags); + return IRQ_HANDLED; +} + +static int fimc_is_hw_open_sensor(struct fimc_is *is, + struct fimc_is_sensor *sensor) +{ + struct sensor_open_extended *soe = (void *)&is->is_p_region->shared; + + fimc_is_hw_wait_intmsr0_intmsd0(is); + + soe->self_calibration_mode = 1; + soe->actuator_type = 0; + soe->mipi_lane_num = 0; + soe->mclk = 0; + soe->mipi_speed = 0; + soe->fast_open_sensor = 0; + soe->i2c_sclk = 88000000; + + fimc_is_mem_barrier(); + + mcuctl_write(HIC_OPEN_SENSOR, is, MCUCTL_REG_ISSR(0)); + mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); + mcuctl_write(sensor->drvdata->id, is, MCUCTL_REG_ISSR(2)); + mcuctl_write(sensor->i2c_bus, is, MCUCTL_REG_ISSR(3)); + mcuctl_write(is->is_dma_p_region, is, MCUCTL_REG_ISSR(4)); + + fimc_is_hw_set_intgr0_gd0(is); + + return fimc_is_wait_event(is, IS_ST_OPEN_SENSOR, 1, + FIMC_IS_SENSOR_OPEN_TIMEOUT); +} + + +int fimc_is_hw_initialize(struct fimc_is *is) +{ + const int scenario_ids[] = { + IS_SC_PREVIEW_STILL, IS_SC_PREVIEW_VIDEO, + IS_SC_CAPTURE_STILL, IS_SC_CAPTURE_VIDEO + }; + struct device *dev = &is->pdev->dev; + u32 prev_id; + int i, ret; + + /* Sensor initialization. */ + ret = fimc_is_hw_open_sensor(is, is->sensor); + if (ret < 0) + return ret; + + /* Get the setfile address. */ + fimc_is_hw_get_setfile_addr(is); + + ret = fimc_is_wait_event(is, IS_ST_SETFILE_LOADED, 1, + FIMC_IS_CONFIG_TIMEOUT); + if (ret < 0) { + dev_err(dev, "get setfile address timed out\n"); + return ret; + } + pr_debug("setfile.base: %#x\n", is->setfile.base); + + /* Load the setfile. */ + fimc_is_load_setfile(is, FIMC_IS_SETFILE_6A3); + clear_bit(IS_ST_SETFILE_LOADED, &is->state); + fimc_is_hw_load_setfile(is); + ret = fimc_is_wait_event(is, IS_ST_SETFILE_LOADED, 1, + FIMC_IS_CONFIG_TIMEOUT); + if (ret < 0) { + dev_err(dev, "loading setfile timed out\n"); + return ret; + } + + pr_debug("setfile: base: %#x, size: %d\n", + is->setfile.base, is->setfile.size); + pr_info("FIMC-IS Setfile info: %s\n", is->fw.setfile_info); + + /* Check magic number. */ + if (is->is_p_region->shared[MAX_SHARED_COUNT - 1] != + FIMC_IS_MAGIC_NUMBER) { + dev_err(dev, "magic number error!\n"); + return -EIO; + } + + pr_debug("shared region: %#x, parameter region: %#x\n", + is->memory.paddr + FIMC_IS_SHARED_REGION_OFFSET, + is->is_dma_p_region); + + is->setfile.sub_index = 0; + + /* Stream off. */ + fimc_is_hw_stream_off(is); + ret = fimc_is_wait_event(is, IS_ST_STREAM_OFF, 1, + FIMC_IS_CONFIG_TIMEOUT); + if (ret < 0) { + dev_err(dev, "stream off timeout\n"); + return ret; + } + + /* Preserve previous mode. */ + prev_id = is->scenario_id; + + /* Set initial parameter values. */ + for (i = 0; i < ARRAY_SIZE(scenario_ids); i++) { + is->scenario_id = scenario_ids[i]; + fimc_is_set_initial_params(is); + ret = fimc_is_itf_s_param(is, true); + if (ret < 0) { + is->scenario_id = prev_id; + return ret; + } + } + is->scenario_id = prev_id; + + set_bit(IS_ST_INIT_DONE, &is->state); + dev_info(dev, "initialization sequence completed (%d)\n", + is->scenario_id); + return 0; +} + +static int fimc_is_log_show(struct seq_file *s, void *data) +{ + struct fimc_is *is = s->private; + const u8 *buf = is->memory.vaddr + FIMC_IS_DEBUG_REGION_OFFSET; + + if (is->memory.vaddr == NULL) { + dev_err(&is->pdev->dev, "firmware memory is not initialized\n"); + return -EIO; + } + + seq_printf(s, "%s\n", buf); + return 0; +} + +static int fimc_is_debugfs_open(struct inode *inode, struct file *file) +{ + return single_open(file, fimc_is_log_show, inode->i_private); +} + +static const struct file_operations fimc_is_debugfs_fops = { + .open = fimc_is_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void fimc_is_debugfs_remove(struct fimc_is *is) +{ + debugfs_remove(is->debugfs_entry); + is->debugfs_entry = NULL; +} + +static int fimc_is_debugfs_create(struct fimc_is *is) +{ + struct dentry *dentry; + + is->debugfs_entry = debugfs_create_dir("fimc_is", NULL); + + dentry = debugfs_create_file("fw_log", S_IRUGO, is->debugfs_entry, + is, &fimc_is_debugfs_fops); + if (!dentry) + fimc_is_debugfs_remove(is); + + return is->debugfs_entry == NULL ? -EIO : 0; +} + +static int fimc_is_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct fimc_is *is; + struct resource res; + struct device_node *node; + int ret; + + is = devm_kzalloc(&pdev->dev, sizeof(*is), GFP_KERNEL); + if (!is) + return -ENOMEM; + + is->pdev = pdev; + is->isp.pdev = pdev; + + init_waitqueue_head(&is->irq_queue); + spin_lock_init(&is->slock); + mutex_init(&is->lock); + + ret = of_address_to_resource(dev->of_node, 0, &res); + if (ret < 0) + return ret; + + is->regs = devm_ioremap_resource(dev, &res); + if (IS_ERR(is->regs)) + return PTR_ERR(is->regs); + + node = of_get_child_by_name(dev->of_node, "pmu"); + if (!node) + return -ENODEV; + + is->pmu_regs = of_iomap(node, 0); + if (!is->pmu_regs) + return -ENOMEM; + + is->irq = irq_of_parse_and_map(dev->of_node, 0); + if (is->irq < 0) { + dev_err(dev, "no irq found\n"); + return is->irq; + } + + ret = fimc_is_get_clocks(is); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, is); + + ret = request_irq(is->irq, fimc_is_irq_handler, 0, dev_name(dev), is); + if (ret < 0) { + dev_err(dev, "irq request failed\n"); + goto err_clk; + } + pm_runtime_enable(dev); + /* + * Enable only the ISP power domain, keep FIMC-IS clocks off until + * the whole clock tree is configured. The ISP power domain needs + * be active in order to acces any CMU_ISP clock registers. + */ + ret = pm_runtime_get_sync(dev); + if (ret < 0) + goto err_irq; + + ret = fimc_is_setup_clocks(is); + if (ret < 0) + goto err_irq; + + pm_runtime_put_sync(dev); + is->clk_init = true; + + is->alloc_ctx = vb2_dma_contig_init_ctx(dev); + if (IS_ERR(is->alloc_ctx)) { + ret = PTR_ERR(is->alloc_ctx); + goto err_pm; + } + /* + * Register FIMC-IS V4L2 subdevs to this driver. The video nodes + * will be created within the subdev's registered() callback. + */ + ret = fimc_is_register_subdevs(is); + if (ret < 0) + goto err_vb; + + ret = fimc_is_debugfs_create(is); + if (ret < 0) + goto err_sd; + + ret = fimc_is_request_firmware(is, FIMC_IS_FW_FILENAME); + if (ret < 0) + goto err_dfs; + + dev_dbg(dev, "FIMC-IS registered successfully\n"); + return 0; + +err_dfs: + fimc_is_debugfs_remove(is); +err_vb: + vb2_dma_contig_cleanup_ctx(is->alloc_ctx); +err_sd: + fimc_is_unregister_subdevs(is); +err_irq: + free_irq(is->irq, is); +err_pm: + pm_runtime_put(dev); +err_clk: + fimc_is_put_clocks(is); + return ret; +} + +static int fimc_is_runtime_resume(struct device *dev) +{ + struct fimc_is *is = dev_get_drvdata(dev); + + if (!is->clk_init) + return 0; + + return fimc_is_enable_clocks(is); +} + +static int fimc_is_runtime_suspend(struct device *dev) +{ + struct fimc_is *is = dev_get_drvdata(dev); + + if (is->clk_init) + fimc_is_disable_clocks(is); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int fimc_is_resume(struct device *dev) +{ + /* TODO: */ + return 0; +} + +static int fimc_is_suspend(struct device *dev) +{ + struct fimc_is *is = dev_get_drvdata(dev); + + /* TODO: */ + if (test_bit(IS_ST_A5_PWR_ON, &is->state)) + return -EBUSY; + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static int fimc_is_remove(struct platform_device *pdev) +{ + struct fimc_is *is = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + free_irq(is->irq, is); + fimc_is_unregister_subdevs(is); + vb2_dma_contig_cleanup_ctx(is->alloc_ctx); + fimc_is_put_clocks(is); + fimc_is_debugfs_remove(is); + release_firmware(is->fw.f_w); + fimc_is_free_cpu_memory(is); + + return 0; +} + +static const struct of_device_id fimc_is_of_match[] = { + { .compatible = "samsung,exynos4212-fimc-is" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, fimc_is_of_match); + +static const struct dev_pm_ops fimc_is_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(fimc_is_suspend, fimc_is_resume) + SET_RUNTIME_PM_OPS(fimc_is_runtime_suspend, fimc_is_runtime_resume, + NULL) +}; + +static struct platform_driver fimc_is_driver = { + .probe = fimc_is_probe, + .remove = fimc_is_remove, + .driver = { + .of_match_table = fimc_is_of_match, + .name = FIMC_IS_DRV_NAME, + .owner = THIS_MODULE, + .pm = &fimc_is_pm_ops, + } +}; + +static int fimc_is_module_init(void) +{ + int ret; + + ret = fimc_is_register_sensor_driver(); + if (ret < 0) + return ret; + + ret = fimc_is_register_i2c_driver(); + if (ret < 0) + goto err_sens; + + ret = platform_driver_register(&fimc_is_driver); + if (!ret) + return ret; + + fimc_is_unregister_i2c_driver(); +err_sens: + fimc_is_unregister_sensor_driver(); + return ret; +} + +static void fimc_is_module_exit(void) +{ + platform_driver_unregister(&fimc_is_driver); + fimc_is_unregister_i2c_driver(); + fimc_is_unregister_sensor_driver(); +} + +module_init(fimc_is_module_init); +module_exit(fimc_is_module_exit); + +MODULE_ALIAS("platform:" FIMC_IS_DRV_NAME); +MODULE_AUTHOR("Younghwan Joo "); +MODULE_AUTHOR("Sylwester Nawrocki "); diff --git a/drivers/media/platform/exynos4-is/fimc-is.h b/drivers/media/platform/exynos4-is/fimc-is.h new file mode 100644 index 000000000000..936e2ca5c1d2 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-is.h @@ -0,0 +1,345 @@ +/* + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * + * Authors: Younghwan Joo + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef FIMC_IS_H_ +#define FIMC_IS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fimc-isp.h" +#include "fimc-is-command.h" +#include "fimc-is-sensor.h" +#include "fimc-is-param.h" +#include "fimc-is-regs.h" + +#define FIMC_IS_DRV_NAME "exynos4-fimc-is" + +#define FIMC_IS_FW_FILENAME "fimc_is_fw.bin" +#define FIMC_IS_SETFILE_6A3 "setfile.bin" + +#define FIMC_IS_FW_LOAD_TIMEOUT 1000 /* ms */ +#define FIMC_IS_POWER_ON_TIMEOUT 1000 /* us */ + +#define FIMC_IS_SENSOR_NUM 2 + +/* Memory definitions */ +#define FIMC_IS_CPU_MEM_SIZE (0xa00000) +#define FIMC_IS_CPU_BASE_MASK ((1 << 26) - 1) +#define FIMC_IS_REGION_SIZE 0x5000 + +#define FIMC_IS_DEBUG_REGION_OFFSET 0x0084b000 +#define FIMC_IS_SHARED_REGION_OFFSET 0x008c0000 +#define FIMC_IS_FW_INFO_LEN 31 +#define FIMC_IS_FW_VER_LEN 7 +#define FIMC_IS_FW_DESC_LEN (FIMC_IS_FW_INFO_LEN + \ + FIMC_IS_FW_VER_LEN) +#define FIMC_IS_SETFILE_INFO_LEN 39 + +#define FIMC_IS_EXTRA_MEM_SIZE (FIMC_IS_EXTRA_FW_SIZE + \ + FIMC_IS_EXTRA_SETFILE_SIZE + 0x1000) +#define FIMC_IS_EXTRA_FW_SIZE 0x180000 +#define FIMC_IS_EXTRA_SETFILE_SIZE 0x4b000 + +/* TODO: revisit */ +#define FIMC_IS_FW_ADDR_MASK ((1 << 26) - 1) +#define FIMC_IS_FW_SIZE_MAX (SZ_4M) +#define FIMC_IS_FW_SIZE_MIN (SZ_32K) + +#define ATCLK_MCUISP_FREQUENCY 100000000UL +#define ACLK_AXI_FREQUENCY 100000000UL + +enum { + ISS_CLK_PPMUISPX, + ISS_CLK_PPMUISPMX, + ISS_CLK_LITE0, + ISS_CLK_LITE1, + ISS_CLK_MPLL, + ISS_CLK_SYSREG, + ISS_CLK_ISP, + ISS_CLK_DRC, + ISS_CLK_FD, + ISS_CLK_MCUISP, + ISS_CLK_UART, + ISS_GATE_CLKS_MAX, + ISS_CLK_ISP_DIV0 = ISS_GATE_CLKS_MAX, + ISS_CLK_ISP_DIV1, + ISS_CLK_MCUISP_DIV0, + ISS_CLK_MCUISP_DIV1, + ISS_CLK_ACLK200, + ISS_CLK_ACLK200_DIV, + ISS_CLK_ACLK400MCUISP, + ISS_CLK_ACLK400MCUISP_DIV, + ISS_CLKS_MAX +}; + +/* The driver's internal state flags */ +enum { + IS_ST_IDLE, + IS_ST_PWR_ON, + IS_ST_A5_PWR_ON, + IS_ST_FW_LOADED, + IS_ST_OPEN_SENSOR, + IS_ST_SETFILE_LOADED, + IS_ST_INIT_DONE, + IS_ST_STREAM_ON, + IS_ST_STREAM_OFF, + IS_ST_CHANGE_MODE, + IS_ST_BLOCK_CMD_CLEARED, + IS_ST_SET_ZOOM, + IS_ST_PWR_SUBIP_ON, + IS_ST_END, +}; + +enum af_state { + FIMC_IS_AF_IDLE = 0, + FIMC_IS_AF_SETCONFIG = 1, + FIMC_IS_AF_RUNNING = 2, + FIMC_IS_AF_LOCK = 3, + FIMC_IS_AF_ABORT = 4, + FIMC_IS_AF_FAILED = 5, +}; + +enum af_lock_state { + FIMC_IS_AF_UNLOCKED = 0, + FIMC_IS_AF_LOCKED = 2 +}; + +enum ae_lock_state { + FIMC_IS_AE_UNLOCKED = 0, + FIMC_IS_AE_LOCKED = 1 +}; + +enum awb_lock_state { + FIMC_IS_AWB_UNLOCKED = 0, + FIMC_IS_AWB_LOCKED = 1 +}; + +enum { + IS_METERING_CONFIG_CMD, + IS_METERING_CONFIG_WIN_POS_X, + IS_METERING_CONFIG_WIN_POS_Y, + IS_METERING_CONFIG_WIN_WIDTH, + IS_METERING_CONFIG_WIN_HEIGHT, + IS_METERING_CONFIG_MAX +}; + +struct is_setfile { + const struct firmware *info; + int state; + u32 sub_index; + u32 base; + size_t size; +}; + +struct is_fd_result_header { + u32 offset; + u32 count; + u32 index; + u32 curr_index; + u32 width; + u32 height; +}; + +struct is_af_info { + u16 mode; + u32 af_state; + u32 af_lock_state; + u32 ae_lock_state; + u32 awb_lock_state; + u16 pos_x; + u16 pos_y; + u16 prev_pos_x; + u16 prev_pos_y; + u16 use_af; +}; + +struct fimc_is_firmware { + const struct firmware *f_w; + + dma_addr_t paddr; + void *vaddr; + unsigned int size; + + char info[FIMC_IS_FW_INFO_LEN + 1]; + char version[FIMC_IS_FW_VER_LEN + 1]; + char setfile_info[FIMC_IS_SETFILE_INFO_LEN + 1]; + u8 state; +}; + +struct fimc_is_memory { + /* physical base address */ + dma_addr_t paddr; + /* virtual base address */ + void *vaddr; + /* total length */ + unsigned int size; +}; + +#define FIMC_IS_I2H_MAX_ARGS 12 + +struct i2h_cmd { + u32 cmd; + u32 sensor_id; + u16 num_args; + u32 args[FIMC_IS_I2H_MAX_ARGS]; +}; + +struct h2i_cmd { + u16 cmd_type; + u32 entry_id; +}; + +#define FIMC_IS_DEBUG_MSG 0x3f +#define FIMC_IS_DEBUG_LEVEL 3 + +struct fimc_is_setfile { + const struct firmware *info; + unsigned int state; + unsigned int size; + u32 sub_index; + u32 base; +}; + +struct is_config_param { + struct global_param global; + struct sensor_param sensor; + struct isp_param isp; + struct drc_param drc; + struct fd_param fd; + + atomic_t p_region_num; + unsigned long p_region_index1; + unsigned long p_region_index2; +}; + +/** + * struct fimc_is - fimc-is data structure + * @pdev: pointer to FIMC-IS platform device + * @pctrl: pointer to pinctrl structure for this device + * @v4l2_dev: pointer to top the level v4l2_device + * @alloc_ctx: videobuf2 memory allocator context + * @lock: mutex serializing video device and the subdev operations + * @slock: spinlock protecting this data structure and the hw registers + * @clocks: FIMC-LITE gate clock + * @regs: MCUCTL mmapped registers region + * @pmu_regs: PMU ISP mmapped registers region + * @irq_queue: interrupt handling waitqueue + * @lpm: low power mode flag + * @state: internal driver's state flags + */ +struct fimc_is { + struct platform_device *pdev; + struct pinctrl *pctrl; + struct v4l2_device *v4l2_dev; + + struct fimc_is_firmware fw; + struct fimc_is_memory memory; + struct firmware *f_w; + + struct fimc_isp isp; + struct fimc_is_sensor *sensor; + struct fimc_is_setfile setfile; + + struct vb2_alloc_ctx *alloc_ctx; + struct v4l2_ctrl_handler ctrl_handler; + + struct mutex lock; + spinlock_t slock; + + struct clk *clocks[ISS_CLKS_MAX]; + bool clk_init; + void __iomem *regs; + void __iomem *pmu_regs; + int irq; + wait_queue_head_t irq_queue; + u8 lpm; + + unsigned long state; + unsigned int sensor_index; + + struct i2h_cmd i2h_cmd; + struct h2i_cmd h2i_cmd; + struct is_fd_result_header fd_header; + + struct is_config_param cfg_param[IS_SC_MAX]; + struct is_region *is_p_region; + dma_addr_t is_dma_p_region; + struct is_share_region *is_shared_region; + struct is_af_info af; + u32 scenario_id; + + struct dentry *debugfs_entry; +}; + +static inline struct fimc_is *fimc_isp_to_is(struct fimc_isp *isp) +{ + return container_of(isp, struct fimc_is, isp); +} + +static inline void fimc_is_mem_barrier(void) +{ + mb(); +} + +static inline void fimc_is_set_param_bit(struct fimc_is *is, int num) +{ + struct is_config_param *cfg = &is->cfg_param[is->scenario_id]; + + if (num >= 32) + set_bit(num - 32, &cfg->p_region_index2); + else + set_bit(num, &cfg->p_region_index1); +} + +static inline void fimc_is_set_param_ctrl_cmd(struct fimc_is *is, int cmd) +{ + is->is_p_region->parameter.isp.control.cmd = cmd; +} + +static inline void mcuctl_write(u32 v, struct fimc_is *is, unsigned int offset) +{ + writel(v, is->regs + offset); +} + +static inline u32 mcuctl_read(struct fimc_is *is, unsigned int offset) +{ + return readl(is->regs + offset); +} + +static inline void pmuisp_write(u32 v, struct fimc_is *is, unsigned int offset) +{ + writel(v, is->pmu_regs + offset); +} + +static inline u32 pmuisp_read(struct fimc_is *is, unsigned int offset) +{ + return readl(is->pmu_regs + offset); +} + +int fimc_is_wait_event(struct fimc_is *is, unsigned long bit, + unsigned int state, unsigned int timeout); +int fimc_is_cpu_set_power(struct fimc_is *is, int on); +int fimc_is_start_firmware(struct fimc_is *is); +int fimc_is_hw_initialize(struct fimc_is *is); +void fimc_is_log_dump(const char *level, const void *buf, size_t len); + +#endif /* FIMC_IS_H_ */ diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c new file mode 100644 index 000000000000..59502b111a8b --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -0,0 +1,702 @@ +/* + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * + * Authors: Sylwester Nawrocki + * Younghwan Joo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "media-dev.h" +#include "fimc-is-command.h" +#include "fimc-is-param.h" +#include "fimc-is-regs.h" +#include "fimc-is.h" + +static int debug = 10; +module_param_named(debug_isp, debug, int, S_IRUGO | S_IWUSR); + +static const struct fimc_fmt fimc_isp_formats[FIMC_ISP_NUM_FORMATS] = { + { + .name = "RAW8 (GRBG)", + .fourcc = V4L2_PIX_FMT_SGRBG8, + .depth = { 8 }, + .color = FIMC_FMT_RAW8, + .memplanes = 1, + .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8, + }, { + .name = "RAW10 (GRBG)", + .fourcc = V4L2_PIX_FMT_SGRBG10, + .depth = { 10 }, + .color = FIMC_FMT_RAW10, + .memplanes = 1, + .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10, + }, { + .name = "RAW12 (GRBG)", + .fourcc = V4L2_PIX_FMT_SGRBG12, + .depth = { 12 }, + .color = FIMC_FMT_RAW12, + .memplanes = 1, + .mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12, + }, +}; + +/** + * fimc_isp_find_format - lookup color format by fourcc or media bus code + * @pixelformat: fourcc to match, ignored if null + * @mbus_code: media bus code to match, ignored if null + * @index: index to the fimc_isp_formats array, ignored if negative + */ +const struct fimc_fmt *fimc_isp_find_format(const u32 *pixelformat, + const u32 *mbus_code, int index) +{ + const struct fimc_fmt *fmt, *def_fmt = NULL; + unsigned int i; + int id = 0; + + if (index >= (int)ARRAY_SIZE(fimc_isp_formats)) + return NULL; + + for (i = 0; i < ARRAY_SIZE(fimc_isp_formats); ++i) { + fmt = &fimc_isp_formats[i]; + if (pixelformat && fmt->fourcc == *pixelformat) + return fmt; + if (mbus_code && fmt->mbus_code == *mbus_code) + return fmt; + if (index == id) + def_fmt = fmt; + id++; + } + return def_fmt; +} + +void fimc_isp_irq_handler(struct fimc_is *is) +{ + is->i2h_cmd.args[0] = mcuctl_read(is, MCUCTL_REG_ISSR(20)); + is->i2h_cmd.args[1] = mcuctl_read(is, MCUCTL_REG_ISSR(21)); + + fimc_is_fw_clear_irq1(is, FIMC_IS_INT_FRAME_DONE_ISP); + + /* TODO: Complete ISP DMA interrupt handler */ + wake_up(&is->irq_queue); +} + +/* Capture subdev media entity operations */ +static int fimc_is_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + return 0; +} + +static const struct media_entity_operations fimc_is_subdev_media_ops = { + .link_setup = fimc_is_link_setup, +}; + +static int fimc_is_subdev_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + const struct fimc_fmt *fmt; + + fmt = fimc_isp_find_format(NULL, NULL, code->index); + if (!fmt) + return -EINVAL; + code->code = fmt->mbus_code; + return 0; +} + +static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct fimc_isp *isp = v4l2_get_subdevdata(sd); + struct fimc_is *is = fimc_isp_to_is(isp); + struct v4l2_mbus_framefmt *mf = &fmt->format; + struct v4l2_mbus_framefmt cur_fmt; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(fh, fmt->pad); + fmt->format = *mf; + return 0; + } + + mf->colorspace = V4L2_COLORSPACE_JPEG; + + mutex_lock(&isp->subdev_lock); + __is_get_frame_size(is, &cur_fmt); + + if (fmt->pad == FIMC_ISP_SD_PAD_SINK) { + /* full camera input frame size */ + mf->width = cur_fmt.width + FIMC_ISP_CAC_MARGIN_WIDTH; + mf->height = cur_fmt.height + FIMC_ISP_CAC_MARGIN_HEIGHT; + mf->code = V4L2_MBUS_FMT_SGRBG10_1X10; + } else { + /* crop size */ + mf->width = cur_fmt.width; + mf->height = cur_fmt.height; + mf->code = V4L2_MBUS_FMT_YUV10_1X30; + } + + mutex_unlock(&isp->subdev_lock); + + v4l2_dbg(1, debug, sd, "%s: pad%d: fmt: 0x%x, %dx%d\n", + __func__, fmt->pad, mf->code, mf->width, mf->height); + + return 0; +} + +static void __isp_subdev_try_format(struct fimc_isp *isp, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *mf = &fmt->format; + + if (fmt->pad == FIMC_ISP_SD_PAD_SINK) { + v4l_bound_align_image(&mf->width, FIMC_ISP_SINK_WIDTH_MIN, + FIMC_ISP_SINK_WIDTH_MAX, 0, + &mf->height, FIMC_ISP_SINK_HEIGHT_MIN, + FIMC_ISP_SINK_HEIGHT_MAX, 0, 0); + isp->subdev_fmt = *mf; + } else { + /* Allow changing format only on sink pad */ + mf->width = isp->subdev_fmt.width - FIMC_ISP_CAC_MARGIN_WIDTH; + mf->height = isp->subdev_fmt.height - FIMC_ISP_CAC_MARGIN_HEIGHT; + mf->code = isp->subdev_fmt.code; + } +} + +static int fimc_isp_subdev_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct fimc_isp *isp = v4l2_get_subdevdata(sd); + struct fimc_is *is = fimc_isp_to_is(isp); + struct v4l2_mbus_framefmt *mf = &fmt->format; + int ret = 0; + + v4l2_dbg(1, debug, sd, "%s: pad%d: code: 0x%x, %dx%d\n", + __func__, fmt->pad, mf->code, mf->width, mf->height); + + mf->colorspace = V4L2_COLORSPACE_JPEG; + + mutex_lock(&isp->subdev_lock); + __isp_subdev_try_format(isp, fmt); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(fh, fmt->pad); + *mf = fmt->format; + mutex_unlock(&isp->subdev_lock); + return 0; + } + + if (sd->entity.stream_count == 0) + __is_set_frame_size(is, mf); + else + ret = -EBUSY; + mutex_unlock(&isp->subdev_lock); + + return ret; +} + +static int fimc_isp_subdev_s_stream(struct v4l2_subdev *sd, int on) +{ + struct fimc_isp *isp = v4l2_get_subdevdata(sd); + struct fimc_is *is = fimc_isp_to_is(isp); + int ret; + + v4l2_dbg(1, debug, sd, "%s: on: %d\n", __func__, on); + + if (!test_bit(IS_ST_INIT_DONE, &is->state)) + return -EBUSY; + + fimc_is_mem_barrier(); + + if (on) { + if (atomic_read(&is->cfg_param[is->scenario_id].p_region_num)) + ret = fimc_is_itf_s_param(is, true); + + v4l2_dbg(1, debug, sd, "changing mode to %d\n", + is->scenario_id); + ret = fimc_is_itf_mode_change(is); + if (ret) + return -EINVAL; + + clear_bit(IS_ST_STREAM_ON, &is->state); + fimc_is_hw_stream_on(is); + ret = fimc_is_wait_event(is, IS_ST_STREAM_ON, 1, + FIMC_IS_CONFIG_TIMEOUT); + if (ret < 0) { + v4l2_err(sd, "stream on timeout\n"); + return ret; + } + } else { + clear_bit(IS_ST_STREAM_OFF, &is->state); + fimc_is_hw_stream_off(is); + ret = fimc_is_wait_event(is, IS_ST_STREAM_OFF, 1, + FIMC_IS_CONFIG_TIMEOUT); + if (ret < 0) { + v4l2_err(sd, "stream off timeout\n"); + return ret; + } + is->setfile.sub_index = 0; + } + + return 0; +} + +static int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on) +{ + struct fimc_isp *isp = v4l2_get_subdevdata(sd); + struct fimc_is *is = fimc_isp_to_is(isp); + int ret = 0; + + pr_debug("on: %d\n", on); + + if (on) { + ret = pm_runtime_get_sync(&is->pdev->dev); + if (ret < 0) + return ret; + set_bit(IS_ST_PWR_ON, &is->state); + + ret = fimc_is_start_firmware(is); + if (ret < 0) { + v4l2_err(sd, "firmware booting failed\n"); + pm_runtime_put(&is->pdev->dev); + return ret; + } + set_bit(IS_ST_PWR_SUBIP_ON, &is->state); + + ret = fimc_is_hw_initialize(is); + } else { + /* Close sensor */ + if (!test_bit(IS_ST_PWR_ON, &is->state)) { + fimc_is_hw_close_sensor(is, 0); + + ret = fimc_is_wait_event(is, IS_ST_OPEN_SENSOR, 0, + FIMC_IS_CONFIG_TIMEOUT); + if (ret < 0) { + v4l2_err(sd, "sensor close timeout\n"); + return ret; + } + } + + /* SUB IP power off */ + if (test_bit(IS_ST_PWR_SUBIP_ON, &is->state)) { + fimc_is_hw_subip_power_off(is); + ret = fimc_is_wait_event(is, IS_ST_PWR_SUBIP_ON, 0, + FIMC_IS_CONFIG_TIMEOUT); + if (ret < 0) { + v4l2_err(sd, "sub-IP power off timeout\n"); + return ret; + } + } + + fimc_is_cpu_set_power(is, 0); + pm_runtime_put_sync(&is->pdev->dev); + + clear_bit(IS_ST_PWR_ON, &is->state); + clear_bit(IS_ST_INIT_DONE, &is->state); + is->state = 0; + is->cfg_param[is->scenario_id].p_region_index1 = 0; + is->cfg_param[is->scenario_id].p_region_index2 = 0; + set_bit(IS_ST_IDLE, &is->state); + wmb(); + } + + return ret; +} + +static int fimc_isp_subdev_open(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt fmt; + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SINK); + + fmt.colorspace = V4L2_COLORSPACE_SRGB; + fmt.code = fimc_isp_formats[0].mbus_code; + fmt.width = DEFAULT_PREVIEW_STILL_WIDTH + FIMC_ISP_CAC_MARGIN_WIDTH; + fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT + FIMC_ISP_CAC_MARGIN_HEIGHT; + fmt.field = V4L2_FIELD_NONE; + *format = fmt; + + format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SRC_FIFO); + fmt.width = DEFAULT_PREVIEW_STILL_WIDTH; + fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT; + *format = fmt; + + format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SRC_DMA); + *format = fmt; + + return 0; +} + +static const struct v4l2_subdev_internal_ops fimc_is_subdev_internal_ops = { + .open = fimc_isp_subdev_open, +}; + +static const struct v4l2_subdev_pad_ops fimc_is_subdev_pad_ops = { + .enum_mbus_code = fimc_is_subdev_enum_mbus_code, + .get_fmt = fimc_isp_subdev_get_fmt, + .set_fmt = fimc_isp_subdev_set_fmt, +}; + +static const struct v4l2_subdev_video_ops fimc_is_subdev_video_ops = { + .s_stream = fimc_isp_subdev_s_stream, +}; + +static const struct v4l2_subdev_core_ops fimc_is_core_ops = { + .s_power = fimc_isp_subdev_s_power, +}; + +static struct v4l2_subdev_ops fimc_is_subdev_ops = { + .core = &fimc_is_core_ops, + .video = &fimc_is_subdev_video_ops, + .pad = &fimc_is_subdev_pad_ops, +}; + +static int __ctrl_set_white_balance(struct fimc_is *is, int value) +{ + switch (value) { + case V4L2_WHITE_BALANCE_AUTO: + __is_set_isp_awb(is, ISP_AWB_COMMAND_AUTO, 0); + break; + case V4L2_WHITE_BALANCE_DAYLIGHT: + __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION, + ISP_AWB_ILLUMINATION_DAYLIGHT); + break; + case V4L2_WHITE_BALANCE_CLOUDY: + __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION, + ISP_AWB_ILLUMINATION_CLOUDY); + break; + case V4L2_WHITE_BALANCE_INCANDESCENT: + __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION, + ISP_AWB_ILLUMINATION_TUNGSTEN); + break; + case V4L2_WHITE_BALANCE_FLUORESCENT: + __is_set_isp_awb(is, ISP_AWB_COMMAND_ILLUMINATION, + ISP_AWB_ILLUMINATION_FLUORESCENT); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int __ctrl_set_aewb_lock(struct fimc_is *is, + struct v4l2_ctrl *ctrl) +{ + bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE; + bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE; + struct isp_param *isp = &is->is_p_region->parameter.isp; + int cmd, ret; + + cmd = ae_lock ? ISP_AA_COMMAND_STOP : ISP_AA_COMMAND_START; + isp->aa.cmd = cmd; + isp->aa.target = ISP_AA_TARGET_AE; + fimc_is_set_param_bit(is, PARAM_ISP_AA); + fimc_is_inc_param_num(is); + is->af.ae_lock_state = ae_lock; + wmb(); + + ret = fimc_is_itf_s_param(is, false); + if (ret < 0) + return ret; + + cmd = awb_lock ? ISP_AA_COMMAND_STOP : ISP_AA_COMMAND_START; + isp->aa.cmd = cmd; + isp->aa.target = ISP_AA_TARGET_AE; + fimc_is_set_param_bit(is, PARAM_ISP_AA); + fimc_is_inc_param_num(is); + is->af.awb_lock_state = awb_lock; + wmb(); + + return fimc_is_itf_s_param(is, false); +} + +/* Supported manual ISO values */ +static const s64 iso_qmenu[] = { + 50, 100, 200, 400, 800, +}; + +static int __ctrl_set_iso(struct fimc_is *is, int value) +{ + unsigned int idx, iso; + + if (value == V4L2_ISO_SENSITIVITY_AUTO) { + __is_set_isp_iso(is, ISP_ISO_COMMAND_AUTO, 0); + return 0; + } + idx = is->isp.ctrls.iso->val; + if (idx >= ARRAY_SIZE(iso_qmenu)) + return -EINVAL; + + iso = iso_qmenu[idx]; + __is_set_isp_iso(is, ISP_ISO_COMMAND_MANUAL, iso); + return 0; +} + +static int __ctrl_set_metering(struct fimc_is *is, unsigned int value) +{ + unsigned int val; + + switch (value) { + case V4L2_EXPOSURE_METERING_AVERAGE: + val = ISP_METERING_COMMAND_AVERAGE; + break; + case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: + val = ISP_METERING_COMMAND_CENTER; + break; + case V4L2_EXPOSURE_METERING_SPOT: + val = ISP_METERING_COMMAND_SPOT; + break; + case V4L2_EXPOSURE_METERING_MATRIX: + val = ISP_METERING_COMMAND_MATRIX; + break; + default: + return -EINVAL; + }; + + __is_set_isp_metering(is, IS_METERING_CONFIG_CMD, val); + return 0; +} + +static int __ctrl_set_afc(struct fimc_is *is, int value) +{ + switch (value) { + case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: + __is_set_isp_afc(is, ISP_AFC_COMMAND_DISABLE, 0); + break; + case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: + __is_set_isp_afc(is, ISP_AFC_COMMAND_MANUAL, 50); + break; + case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: + __is_set_isp_afc(is, ISP_AFC_COMMAND_MANUAL, 60); + break; + case V4L2_CID_POWER_LINE_FREQUENCY_AUTO: + __is_set_isp_afc(is, ISP_AFC_COMMAND_AUTO, 0); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int __ctrl_set_image_effect(struct fimc_is *is, int value) +{ + static const u8 effects[][2] = { + { V4L2_COLORFX_NONE, ISP_IMAGE_EFFECT_DISABLE }, + { V4L2_COLORFX_BW, ISP_IMAGE_EFFECT_MONOCHROME }, + { V4L2_COLORFX_SEPIA, ISP_IMAGE_EFFECT_SEPIA }, + { V4L2_COLORFX_NEGATIVE, ISP_IMAGE_EFFECT_NEGATIVE_MONO }, + { 16 /* TODO */, ISP_IMAGE_EFFECT_NEGATIVE_COLOR }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(effects); i++) { + if (effects[i][0] != value) + continue; + + __is_set_isp_effect(is, effects[i][1]); + return 0; + } + + return -EINVAL; +} + +static int fimc_is_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct fimc_isp *isp = ctrl_to_fimc_isp(ctrl); + struct fimc_is *is = fimc_isp_to_is(isp); + bool set_param = true; + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_CONTRAST: + __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_CONTRAST, + ctrl->val); + break; + + case V4L2_CID_SATURATION: + __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SATURATION, + ctrl->val); + break; + + case V4L2_CID_SHARPNESS: + __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SHARPNESS, + ctrl->val); + break; + + case V4L2_CID_EXPOSURE_ABSOLUTE: + __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_EXPOSURE, + ctrl->val); + break; + + case V4L2_CID_BRIGHTNESS: + __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS, + ctrl->val); + break; + + case V4L2_CID_HUE: + __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_HUE, + ctrl->val); + break; + + case V4L2_CID_EXPOSURE_METERING: + ret = __ctrl_set_metering(is, ctrl->val); + break; + + case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: + ret = __ctrl_set_white_balance(is, ctrl->val); + break; + + case V4L2_CID_3A_LOCK: + ret = __ctrl_set_aewb_lock(is, ctrl); + set_param = false; + break; + + case V4L2_CID_ISO_SENSITIVITY_AUTO: + ret = __ctrl_set_iso(is, ctrl->val); + break; + + case V4L2_CID_POWER_LINE_FREQUENCY: + ret = __ctrl_set_afc(is, ctrl->val); + break; + + case V4L2_CID_COLORFX: + __ctrl_set_image_effect(is, ctrl->val); + break; + + default: + ret = -EINVAL; + break; + } + + if (ret < 0) { + v4l2_err(&isp->subdev, "Failed to set control: %s (%d)\n", + ctrl->name, ctrl->val); + return ret; + } + + if (set_param && test_bit(IS_ST_STREAM_ON, &is->state)) + return fimc_is_itf_s_param(is, true); + + return 0; +} + +static const struct v4l2_ctrl_ops fimc_isp_ctrl_ops = { + .s_ctrl = fimc_is_s_ctrl, +}; + +int fimc_isp_subdev_create(struct fimc_isp *isp) +{ + const struct v4l2_ctrl_ops *ops = &fimc_isp_ctrl_ops; + struct v4l2_ctrl_handler *handler = &isp->ctrls.handler; + struct v4l2_subdev *sd = &isp->subdev; + struct fimc_isp_ctrls *ctrls = &isp->ctrls; + int ret; + + mutex_init(&isp->subdev_lock); + + v4l2_subdev_init(sd, &fimc_is_subdev_ops); + sd->grp_id = GRP_ID_FIMC_IS; + sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(sd->name, sizeof(sd->name), "FIMC-IS-ISP"); + + isp->subdev_pads[FIMC_ISP_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_FIFO].flags = MEDIA_PAD_FL_SOURCE; + isp->subdev_pads[FIMC_ISP_SD_PAD_SRC_DMA].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_init(&sd->entity, FIMC_ISP_SD_PADS_NUM, + isp->subdev_pads, 0); + if (ret) + return ret; + + v4l2_ctrl_handler_init(handler, 20); + + ctrls->saturation = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SATURATION, + -2, 2, 1, 0); + ctrls->brightness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_BRIGHTNESS, + -4, 4, 1, 0); + ctrls->contrast = v4l2_ctrl_new_std(handler, ops, V4L2_CID_CONTRAST, + -2, 2, 1, 0); + ctrls->sharpness = v4l2_ctrl_new_std(handler, ops, V4L2_CID_SHARPNESS, + -2, 2, 1, 0); + ctrls->hue = v4l2_ctrl_new_std(handler, ops, V4L2_CID_HUE, + -2, 2, 1, 0); + + ctrls->auto_wb = v4l2_ctrl_new_std_menu(handler, ops, + V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, + 8, ~0x14e, V4L2_WHITE_BALANCE_AUTO); + + ctrls->exposure = v4l2_ctrl_new_std(handler, ops, + V4L2_CID_EXPOSURE_ABSOLUTE, + -4, 4, 1, 0); + + ctrls->exp_metering = v4l2_ctrl_new_std_menu(handler, ops, + V4L2_CID_EXPOSURE_METERING, 3, + ~0xf, V4L2_EXPOSURE_METERING_AVERAGE); + + v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, + V4L2_CID_POWER_LINE_FREQUENCY_AUTO); + /* ISO sensitivity */ + ctrls->auto_iso = v4l2_ctrl_new_std_menu(handler, ops, + V4L2_CID_ISO_SENSITIVITY_AUTO, 1, 0, + V4L2_ISO_SENSITIVITY_AUTO); + + ctrls->iso = v4l2_ctrl_new_int_menu(handler, ops, + V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1, + ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu); + + ctrls->aewb_lock = v4l2_ctrl_new_std(handler, ops, + V4L2_CID_3A_LOCK, 0, 0x3, 0, 0); + + /* TODO: Add support for NEGATIVE_COLOR option */ + ctrls->colorfx = v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_COLORFX, + V4L2_COLORFX_SET_CBCR + 1, ~0x1000f, V4L2_COLORFX_NONE); + + if (handler->error) { + media_entity_cleanup(&sd->entity); + return handler->error; + } + + v4l2_ctrl_auto_cluster(2, &ctrls->auto_iso, + V4L2_ISO_SENSITIVITY_MANUAL, false); + + sd->ctrl_handler = handler; + sd->internal_ops = &fimc_is_subdev_internal_ops; + sd->entity.ops = &fimc_is_subdev_media_ops; + v4l2_set_subdevdata(sd, isp); + + return 0; +} + +void fimc_isp_subdev_destroy(struct fimc_isp *isp) +{ + struct v4l2_subdev *sd = &isp->subdev; + + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(&isp->ctrls.handler); + v4l2_set_subdevdata(sd, NULL); +} diff --git a/drivers/media/platform/exynos4-is/fimc-isp.h b/drivers/media/platform/exynos4-is/fimc-isp.h new file mode 100644 index 000000000000..800aba7ab4a7 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-isp.h @@ -0,0 +1,181 @@ +/* + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * + * Authors: Sylwester Nawrocki + * Younghwan Joo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef FIMC_ISP_H_ +#define FIMC_ISP_H_ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* FIXME: revisit these constraints */ +#define FIMC_ISP_SINK_WIDTH_MIN (16 + 8) +#define FIMC_ISP_SINK_HEIGHT_MIN (12 + 8) +#define FIMC_ISP_SOURCE_WIDTH_MIN 8 +#define FIMC_ISP_SOURC_HEIGHT_MIN 8 +#define FIMC_ISP_CAC_MARGIN_WIDTH 16 +#define FIMC_ISP_CAC_MARGIN_HEIGHT 12 + +#define FIMC_ISP_SINK_WIDTH_MAX (4000 - 16) +#define FIMC_ISP_SINK_HEIGHT_MAX (4000 + 12) +#define FIMC_ISP_SOURCE_WIDTH_MAX 4000 +#define FIMC_ISP_SOURC_HEIGHT_MAX 4000 + +#define FIMC_ISP_NUM_FORMATS 3 +#define FIMC_ISP_REQ_BUFS_MIN 2 + +#define FIMC_ISP_SD_PAD_SINK 0 +#define FIMC_ISP_SD_PAD_SRC_FIFO 1 +#define FIMC_ISP_SD_PAD_SRC_DMA 2 +#define FIMC_ISP_SD_PADS_NUM 3 +#define FIMC_ISP_MAX_PLANES 1 + +/** + * struct fimc_isp_frame - source/target frame properties + * @width: full image width + * @height: full image height + * @rect: crop/composition rectangle + */ +struct fimc_isp_frame { + u16 width; + u16 height; + struct v4l2_rect rect; +}; + +struct fimc_isp_ctrls { + struct v4l2_ctrl_handler handler; + + /* Auto white balance */ + struct v4l2_ctrl *auto_wb; + /* Auto ISO control cluster */ + struct { + struct v4l2_ctrl *auto_iso; + struct v4l2_ctrl *iso; + }; + /* Adjust - contrast */ + struct v4l2_ctrl *contrast; + /* Adjust - saturation */ + struct v4l2_ctrl *saturation; + /* Adjust - sharpness */ + struct v4l2_ctrl *sharpness; + /* Adjust - brightness */ + struct v4l2_ctrl *brightness; + /* Adjust - hue */ + struct v4l2_ctrl *hue; + + /* Auto/manual exposure */ + struct v4l2_ctrl *auto_exp; + /* Manual exposure value */ + struct v4l2_ctrl *exposure; + /* AE/AWB lock/unlock */ + struct v4l2_ctrl *aewb_lock; + /* Exposure metering mode */ + struct v4l2_ctrl *exp_metering; + /* AFC */ + struct v4l2_ctrl *afc; + /* ISP image effect */ + struct v4l2_ctrl *colorfx; +}; + +/** + * struct fimc_is_video - fimc-is video device structure + * @vdev: video_device structure + * @type: video device type (CAPTURE/OUTPUT) + * @pad: video device media (sink) pad + * @pending_buf_q: pending buffers queue head + * @active_buf_q: a queue head of buffers scheduled in hardware + * @vb_queue: vb2 buffer queue + * @active_buf_count: number of video buffers scheduled in hardware + * @frame_count: counter of frames dequeued to user space + * @reqbufs_count: number of buffers requested with REQBUFS ioctl + * @format: current pixel format + */ +struct fimc_is_video { + struct video_device vdev; + enum v4l2_buf_type type; + struct media_pad pad; + struct list_head pending_buf_q; + struct list_head active_buf_q; + struct vb2_queue vb_queue; + unsigned int frame_count; + unsigned int reqbufs_count; + int streaming; + unsigned long payload[FIMC_ISP_MAX_PLANES]; + const struct fimc_fmt *format; +}; + +/** + * struct fimc_isp - FIMC-IS ISP data structure + * @pdev: pointer to FIMC-IS platform device + * @alloc_ctx: videobuf2 memory allocator context + * @subdev: ISP v4l2_subdev + * @subdev_pads: the ISP subdev media pads + * @ctrl_handler: v4l2 controls handler + * @test_pattern: test pattern controls + * @pipeline: video capture pipeline data structure + * @video_lock: mutex serializing video device and the subdev operations + * @fmt: pointer to color format description structure + * @payload: image size in bytes (w x h x bpp) + * @inp_frame: camera input frame structure + * @out_frame: DMA output frame structure + * @source_subdev_grp_id: group id of remote source subdev + * @cac_margin_x: horizontal CAC margin in pixels + * @cac_margin_y: vertical CAC margin in pixels + * @state: driver state flags + * @video_capture: the ISP block video capture device + */ +struct fimc_isp { + struct platform_device *pdev; + struct vb2_alloc_ctx *alloc_ctx; + struct v4l2_subdev subdev; + struct media_pad subdev_pads[FIMC_ISP_SD_PADS_NUM]; + struct v4l2_mbus_framefmt subdev_fmt; + struct v4l2_ctrl *test_pattern; + struct fimc_isp_ctrls ctrls; + + struct mutex video_lock; + struct mutex subdev_lock; + + struct fimc_isp_frame inp_frame; + struct fimc_isp_frame out_frame; + unsigned int source_subdev_grp_id; + + unsigned int cac_margin_x; + unsigned int cac_margin_y; + + unsigned long state; + + struct fimc_is_video video_capture; +}; + +#define ctrl_to_fimc_isp(_ctrl) \ + container_of(ctrl->handler, struct fimc_isp, ctrls.handler) + +struct fimc_is; + +int fimc_isp_subdev_create(struct fimc_isp *isp); +void fimc_isp_subdev_destroy(struct fimc_isp *isp); +void fimc_isp_irq_handler(struct fimc_is *is); +int fimc_is_create_controls(struct fimc_isp *isp); +int fimc_is_delete_controls(struct fimc_isp *isp); +const struct fimc_fmt *fimc_isp_find_format(const u32 *pixelformat, + const u32 *mbus_code, int index); +#endif /* FIMC_ISP_H_ */ -- cgit v1.2.3 From da114376d325298cce4a7271c4de9bd41c712266 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 11 Mar 2013 15:28:18 -0300 Subject: [media] exynos4-is: Add FIMC-IS ISP I2C bus driver This patch adds the ISP I2C bus controller driver files. Creating a standard I2C bus adapter, even if the driver doesn't actually communicate with the hardware and it is instead controlled by the ISP firmware running on the Cortex-A5, allows to use standard hardware description in the device tree. As the sensor would have actually had a standard V4L2 sub-device driver run on the host CPU. This approach allows to adapt the driver with a relatively small effort should the Imaging Subsystem architecture change so that the I2C bus is handled by the host's CPU OS, rather than the internal FIMC-IS ARM CPU firmware. The image sensor driver could be a standard I2C client driver, as in case of most existing image sensors. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is-i2c.c | 129 ++++++++++++++++++++++++ drivers/media/platform/exynos4-is/fimc-is-i2c.h | 15 +++ 2 files changed, 144 insertions(+) create mode 100644 drivers/media/platform/exynos4-is/fimc-is-i2c.c create mode 100644 drivers/media/platform/exynos4-is/fimc-is-i2c.h (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/exynos4-is/fimc-is-i2c.c new file mode 100644 index 000000000000..1ec6b3c6a62a --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.c @@ -0,0 +1,129 @@ +/* + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * + * Author: Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include "fimc-is-i2c.h" + +struct fimc_is_i2c { + struct i2c_adapter adapter; + struct clk *clock; +}; + +/* + * An empty algorithm is used as the actual I2C bus controller driver + * is implemented in the FIMC-IS subsystem firmware and the host CPU + * doesn't access the I2C bus controller. + */ +static const struct i2c_algorithm fimc_is_i2c_algorithm; + +static int fimc_is_i2c_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct fimc_is_i2c *isp_i2c; + struct i2c_adapter *i2c_adap; + int ret; + + isp_i2c = devm_kzalloc(&pdev->dev, sizeof(*isp_i2c), GFP_KERNEL); + if (!isp_i2c) + return -ENOMEM; + + isp_i2c->clock = devm_clk_get(&pdev->dev, "i2c_isp"); + if (IS_ERR(isp_i2c->clock)) { + dev_err(&pdev->dev, "failed to get the clock\n"); + return PTR_ERR(isp_i2c->clock); + } + + i2c_adap = &isp_i2c->adapter; + i2c_adap->dev.of_node = node; + i2c_adap->dev.parent = &pdev->dev; + strlcpy(i2c_adap->name, "exynos4x12-isp-i2c", sizeof(i2c_adap->name)); + i2c_adap->owner = THIS_MODULE; + i2c_adap->algo = &fimc_is_i2c_algorithm; + i2c_adap->class = I2C_CLASS_SPD; + + ret = i2c_add_adapter(i2c_adap); + if (ret < 0) { + dev_err(&pdev->dev, "failed to add I2C bus %s\n", + node->full_name); + return ret; + } + + platform_set_drvdata(pdev, isp_i2c); + + pm_runtime_enable(&pdev->dev); + pm_runtime_enable(&i2c_adap->dev); + + of_i2c_register_devices(i2c_adap); + + return 0; +} + +static int fimc_is_i2c_remove(struct platform_device *pdev) +{ + struct fimc_is_i2c *isp_i2c = platform_get_drvdata(pdev); + + pm_runtime_disable(&isp_i2c->adapter.dev); + pm_runtime_disable(&pdev->dev); + i2c_del_adapter(&isp_i2c->adapter); + + return 0; +} + +static int fimc_is_i2c_suspend(struct device *dev) +{ + struct fimc_is_i2c *isp_i2c = dev_get_drvdata(dev); + clk_disable_unprepare(isp_i2c->clock); + return 0; +} + +static int fimc_is_i2c_resume(struct device *dev) +{ + struct fimc_is_i2c *isp_i2c = dev_get_drvdata(dev); + return clk_prepare_enable(isp_i2c->clock); +} + +UNIVERSAL_DEV_PM_OPS(fimc_is_i2c_pm_ops, fimc_is_i2c_suspend, + fimc_is_i2c_resume, NULL); + +static const struct of_device_id fimc_is_i2c_of_match[] = { + { .compatible = FIMC_IS_I2C_COMPATIBLE }, + { }, +}; +MODULE_DEVICE_TABLE(of, fimc_is_i2c_of_match); + +static struct platform_driver fimc_is_i2c_driver = { + .probe = fimc_is_i2c_probe, + .remove = fimc_is_i2c_remove, + .driver = { + .of_match_table = fimc_is_i2c_of_match, + .name = "fimc-isp-i2c", + .owner = THIS_MODULE, + .pm = &fimc_is_i2c_pm_ops, + } +}; + +int fimc_is_register_i2c_driver(void) +{ + return platform_driver_register(&fimc_is_i2c_driver); +} +EXPORT_SYMBOL(fimc_is_register_i2c_driver); + +void fimc_is_unregister_i2c_driver(void) +{ + platform_driver_unregister(&fimc_is_i2c_driver); +} +EXPORT_SYMBOL(fimc_is_unregister_i2c_driver); diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.h b/drivers/media/platform/exynos4-is/fimc-is-i2c.h new file mode 100644 index 000000000000..0d38d6bb963b --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.h @@ -0,0 +1,15 @@ +/* + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define FIMC_IS_I2C_COMPATIBLE "samsung,exynos4212-i2c-isp" + +int fimc_is_register_i2c_driver(void); +void fimc_is_unregister_i2c_driver(void); -- cgit v1.2.3 From 294781db46155b8a64976649567538ada91131f8 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 11 Mar 2013 15:33:56 -0300 Subject: [media] exynos4-is: Add FIMC-IS parameter region definitions This patch adds the ISP processing parameters interface files. Signed-off-by: Younghwan Joo Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is-param.c | 955 +++++++++++++++++++ drivers/media/platform/exynos4-is/fimc-is-param.h | 1022 +++++++++++++++++++++ 2 files changed, 1977 insertions(+) create mode 100644 drivers/media/platform/exynos4-is/fimc-is-param.c create mode 100644 drivers/media/platform/exynos4-is/fimc-is-param.h (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c new file mode 100644 index 000000000000..37fd5fe68eef --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-is-param.c @@ -0,0 +1,955 @@ +/* + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * + * Authors: Younghwan Joo + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "fimc-is.h" +#include "fimc-is-command.h" +#include "fimc-is-errno.h" +#include "fimc-is-param.h" +#include "fimc-is-regs.h" +#include "fimc-is-sensor.h" + +static void __hw_param_copy(void *dst, void *src) +{ + memcpy(dst, src, FIMC_IS_PARAM_MAX_SIZE); +} + +void __fimc_is_hw_update_param_global_shotmode(struct fimc_is *is) +{ + struct param_global_shotmode *dst, *src; + + dst = &is->is_p_region->parameter.global.shotmode; + src = &is->cfg_param[is->scenario_id].global.shotmode; + __hw_param_copy(dst, src); +} + +void __fimc_is_hw_update_param_sensor_framerate(struct fimc_is *is) +{ + struct param_sensor_framerate *dst, *src; + + dst = &is->is_p_region->parameter.sensor.frame_rate; + src = &is->cfg_param[is->scenario_id].sensor.frame_rate; + __hw_param_copy(dst, src); +} + +int __fimc_is_hw_update_param(struct fimc_is *is, u32 offset) +{ + struct is_param_region *par = &is->is_p_region->parameter; + struct is_config_param *cfg = &is->cfg_param[is->scenario_id]; + + switch (offset) { + case PARAM_ISP_CONTROL: + __hw_param_copy(&par->isp.control, &cfg->isp.control); + break; + + case PARAM_ISP_OTF_INPUT: + __hw_param_copy(&par->isp.otf_input, &cfg->isp.otf_input); + break; + + case PARAM_ISP_DMA1_INPUT: + __hw_param_copy(&par->isp.dma1_input, &cfg->isp.dma1_input); + break; + + case PARAM_ISP_DMA2_INPUT: + __hw_param_copy(&par->isp.dma2_input, &cfg->isp.dma2_input); + break; + + case PARAM_ISP_AA: + __hw_param_copy(&par->isp.aa, &cfg->isp.aa); + break; + + case PARAM_ISP_FLASH: + __hw_param_copy(&par->isp.flash, &cfg->isp.flash); + break; + + case PARAM_ISP_AWB: + __hw_param_copy(&par->isp.awb, &cfg->isp.awb); + break; + + case PARAM_ISP_IMAGE_EFFECT: + __hw_param_copy(&par->isp.effect, &cfg->isp.effect); + break; + + case PARAM_ISP_ISO: + __hw_param_copy(&par->isp.iso, &cfg->isp.iso); + break; + + case PARAM_ISP_ADJUST: + __hw_param_copy(&par->isp.adjust, &cfg->isp.adjust); + break; + + case PARAM_ISP_METERING: + __hw_param_copy(&par->isp.metering, &cfg->isp.metering); + break; + + case PARAM_ISP_AFC: + __hw_param_copy(&par->isp.afc, &cfg->isp.afc); + break; + + case PARAM_ISP_OTF_OUTPUT: + __hw_param_copy(&par->isp.otf_output, &cfg->isp.otf_output); + break; + + case PARAM_ISP_DMA1_OUTPUT: + __hw_param_copy(&par->isp.dma1_output, &cfg->isp.dma1_output); + break; + + case PARAM_ISP_DMA2_OUTPUT: + __hw_param_copy(&par->isp.dma2_output, &cfg->isp.dma2_output); + break; + + case PARAM_DRC_CONTROL: + __hw_param_copy(&par->drc.control, &cfg->drc.control); + break; + + case PARAM_DRC_OTF_INPUT: + __hw_param_copy(&par->drc.otf_input, &cfg->drc.otf_input); + break; + + case PARAM_DRC_DMA_INPUT: + __hw_param_copy(&par->drc.dma_input, &cfg->drc.dma_input); + break; + + case PARAM_DRC_OTF_OUTPUT: + __hw_param_copy(&par->drc.otf_output, &cfg->drc.otf_output); + break; + + case PARAM_FD_CONTROL: + __hw_param_copy(&par->fd.control, &cfg->fd.control); + break; + + case PARAM_FD_OTF_INPUT: + __hw_param_copy(&par->fd.otf_input, &cfg->fd.otf_input); + break; + + case PARAM_FD_DMA_INPUT: + __hw_param_copy(&par->fd.dma_input, &cfg->fd.dma_input); + break; + + case PARAM_FD_CONFIG: + __hw_param_copy(&par->fd.config, &cfg->fd.config); + break; + + default: + return -EINVAL; + } + + return 0; +} + +int __is_hw_update_params(struct fimc_is *is) +{ + unsigned long *p_index1, *p_index2; + int i, id, ret = 0; + + id = is->scenario_id; + p_index1 = &is->cfg_param[id].p_region_index1; + p_index2 = &is->cfg_param[id].p_region_index2; + + if (test_bit(PARAM_GLOBAL_SHOTMODE, p_index1)) + __fimc_is_hw_update_param_global_shotmode(is); + + if (test_bit(PARAM_SENSOR_FRAME_RATE, p_index1)) + __fimc_is_hw_update_param_sensor_framerate(is); + + for (i = PARAM_ISP_CONTROL; i < PARAM_DRC_CONTROL; i++) { + if (test_bit(i, p_index1)) + ret = __fimc_is_hw_update_param(is, i); + } + + for (i = PARAM_DRC_CONTROL; i < PARAM_SCALERC_CONTROL; i++) { + if (test_bit(i, p_index1)) + ret = __fimc_is_hw_update_param(is, i); + } + + for (i = PARAM_FD_CONTROL; i <= PARAM_FD_CONFIG; i++) { + if (test_bit((i - 32), p_index2)) + ret = __fimc_is_hw_update_param(is, i); + } + + return ret; +} + +void __is_get_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf) +{ + struct isp_param *isp; + + isp = &is->cfg_param[is->scenario_id].isp; + mf->width = isp->otf_input.width; + mf->height = isp->otf_input.height; +} + +void __is_set_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf) +{ + struct isp_param *isp; + struct drc_param *drc; + struct fd_param *fd; + unsigned int mode; + + mode = is->scenario_id; + isp = &is->cfg_param[mode].isp; + drc = &is->cfg_param[mode].drc; + fd = &is->cfg_param[mode].fd; + + /* Update isp size info (OTF only) */ + isp->otf_input.width = mf->width; + isp->otf_input.height = mf->height; + isp->otf_output.width = mf->width; + isp->otf_output.height = mf->height; + /* Update drc size info (OTF only) */ + drc->otf_input.width = mf->width; + drc->otf_input.height = mf->height; + drc->otf_output.width = mf->width; + drc->otf_output.height = mf->height; + /* Update fd size info (OTF only) */ + fd->otf_input.width = mf->width; + fd->otf_input.height = mf->height; + + if (test_bit(PARAM_ISP_OTF_INPUT, + &is->cfg_param[mode].p_region_index1)) + return; + + /* Update field */ + fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT); + fimc_is_inc_param_num(is); + fimc_is_set_param_bit(is, PARAM_ISP_OTF_OUTPUT); + fimc_is_inc_param_num(is); + fimc_is_set_param_bit(is, PARAM_DRC_OTF_INPUT); + fimc_is_inc_param_num(is); + fimc_is_set_param_bit(is, PARAM_DRC_OTF_OUTPUT); + fimc_is_inc_param_num(is); + fimc_is_set_param_bit(is, PARAM_FD_OTF_INPUT); + fimc_is_inc_param_num(is); +} + +int fimc_is_hw_get_sensor_max_framerate(struct fimc_is *is) +{ + switch (is->sensor->drvdata->id) { + case FIMC_IS_SENSOR_ID_S5K6A3: + return 30; + default: + return 15; + } +} + +void __is_set_sensor(struct fimc_is *is, int fps) +{ + struct sensor_param *sensor; + struct isp_param *isp; + unsigned long *p_index, mode; + + mode = is->scenario_id; + p_index = &is->cfg_param[mode].p_region_index1; + sensor = &is->cfg_param[mode].sensor; + isp = &is->cfg_param[mode].isp; + + if (fps == 0) { + sensor->frame_rate.frame_rate = + fimc_is_hw_get_sensor_max_framerate(is); + isp->otf_input.frametime_min = 0; + isp->otf_input.frametime_max = 66666; + } else { + sensor->frame_rate.frame_rate = fps; + isp->otf_input.frametime_min = 0; + isp->otf_input.frametime_max = (u32)1000000 / fps; + } + + if (!test_bit(PARAM_SENSOR_FRAME_RATE, p_index)) { + fimc_is_set_param_bit(is, PARAM_SENSOR_FRAME_RATE); + fimc_is_inc_param_num(is); + } + if (!test_bit(PARAM_ISP_OTF_INPUT, p_index)) { + fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT); + fimc_is_inc_param_num(is); + } +} + +void __is_set_init_isp_aa(struct fimc_is *is) +{ + struct isp_param *isp; + + isp = &is->cfg_param[is->scenario_id].isp; + + isp->aa.cmd = ISP_AA_COMMAND_START; + isp->aa.target = ISP_AA_TARGET_AF | ISP_AA_TARGET_AE | + ISP_AA_TARGET_AWB; + isp->aa.mode = 0; + isp->aa.scene = 0; + isp->aa.sleep = 0; + isp->aa.face = 0; + isp->aa.touch_x = 0; + isp->aa.touch_y = 0; + isp->aa.manual_af_setting = 0; + isp->aa.err = ISP_AF_ERROR_NONE; + + fimc_is_set_param_bit(is, PARAM_ISP_AA); + fimc_is_inc_param_num(is); +} + +void __is_set_isp_flash(struct fimc_is *is, u32 cmd, u32 redeye) +{ + unsigned int mode = is->scenario_id; + struct is_config_param *cfg = &is->cfg_param[mode]; + struct isp_param *isp = &cfg->isp; + + isp->flash.cmd = cmd; + isp->flash.redeye = redeye; + isp->flash.err = ISP_FLASH_ERROR_NONE; + + if (!test_bit(PARAM_ISP_FLASH, &cfg->p_region_index1)) { + fimc_is_set_param_bit(is, PARAM_ISP_FLASH); + fimc_is_inc_param_num(is); + } +} + +void __is_set_isp_awb(struct fimc_is *is, u32 cmd, u32 val) +{ + unsigned int mode = is->scenario_id; + struct isp_param *isp; + unsigned long *p_index; + + p_index = &is->cfg_param[mode].p_region_index1; + isp = &is->cfg_param[mode].isp; + + isp->awb.cmd = cmd; + isp->awb.illumination = val; + isp->awb.err = ISP_AWB_ERROR_NONE; + + if (!test_bit(PARAM_ISP_AWB, p_index)) { + fimc_is_set_param_bit(is, PARAM_ISP_AWB); + fimc_is_inc_param_num(is); + } +} + +void __is_set_isp_effect(struct fimc_is *is, u32 cmd) +{ + unsigned int mode = is->scenario_id; + struct isp_param *isp; + unsigned long *p_index; + + p_index = &is->cfg_param[mode].p_region_index1; + isp = &is->cfg_param[mode].isp; + + isp->effect.cmd = cmd; + isp->effect.err = ISP_IMAGE_EFFECT_ERROR_NONE; + + if (!test_bit(PARAM_ISP_IMAGE_EFFECT, p_index)) { + fimc_is_set_param_bit(is, PARAM_ISP_IMAGE_EFFECT); + fimc_is_inc_param_num(is); + } +} + +void __is_set_isp_iso(struct fimc_is *is, u32 cmd, u32 val) +{ + unsigned int mode = is->scenario_id; + struct isp_param *isp; + unsigned long *p_index; + + p_index = &is->cfg_param[mode].p_region_index1; + isp = &is->cfg_param[mode].isp; + + isp->iso.cmd = cmd; + isp->iso.value = val; + isp->iso.err = ISP_ISO_ERROR_NONE; + + if (!test_bit(PARAM_ISP_ISO, p_index)) { + fimc_is_set_param_bit(is, PARAM_ISP_ISO); + fimc_is_inc_param_num(is); + } +} + +void __is_set_isp_adjust(struct fimc_is *is, u32 cmd, u32 val) +{ + unsigned int mode = is->scenario_id; + unsigned long *p_index; + struct isp_param *isp; + + p_index = &is->cfg_param[mode].p_region_index1; + isp = &is->cfg_param[mode].isp; + + switch (cmd) { + case ISP_ADJUST_COMMAND_MANUAL_CONTRAST: + isp->adjust.contrast = val; + break; + case ISP_ADJUST_COMMAND_MANUAL_SATURATION: + isp->adjust.saturation = val; + break; + case ISP_ADJUST_COMMAND_MANUAL_SHARPNESS: + isp->adjust.sharpness = val; + break; + case ISP_ADJUST_COMMAND_MANUAL_EXPOSURE: + isp->adjust.exposure = val; + break; + case ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS: + isp->adjust.brightness = val; + break; + case ISP_ADJUST_COMMAND_MANUAL_HUE: + isp->adjust.hue = val; + break; + case ISP_ADJUST_COMMAND_AUTO: + isp->adjust.contrast = 0; + isp->adjust.saturation = 0; + isp->adjust.sharpness = 0; + isp->adjust.exposure = 0; + isp->adjust.brightness = 0; + isp->adjust.hue = 0; + break; + } + + if (!test_bit(PARAM_ISP_ADJUST, p_index)) { + isp->adjust.cmd = cmd; + isp->adjust.err = ISP_ADJUST_ERROR_NONE; + fimc_is_set_param_bit(is, PARAM_ISP_ADJUST); + fimc_is_inc_param_num(is); + } else { + isp->adjust.cmd |= cmd; + } +} + +void __is_set_isp_metering(struct fimc_is *is, u32 id, u32 val) +{ + struct isp_param *isp; + unsigned long *p_index, mode; + + mode = is->scenario_id; + p_index = &is->cfg_param[mode].p_region_index1; + isp = &is->cfg_param[mode].isp; + + switch (id) { + case IS_METERING_CONFIG_CMD: + isp->metering.cmd = val; + break; + case IS_METERING_CONFIG_WIN_POS_X: + isp->metering.win_pos_x = val; + break; + case IS_METERING_CONFIG_WIN_POS_Y: + isp->metering.win_pos_y = val; + break; + case IS_METERING_CONFIG_WIN_WIDTH: + isp->metering.win_width = val; + break; + case IS_METERING_CONFIG_WIN_HEIGHT: + isp->metering.win_height = val; + break; + default: + return; + } + + if (!test_bit(PARAM_ISP_METERING, p_index)) { + isp->metering.err = ISP_METERING_ERROR_NONE; + fimc_is_set_param_bit(is, PARAM_ISP_METERING); + fimc_is_inc_param_num(is); + } +} + +void __is_set_isp_afc(struct fimc_is *is, u32 cmd, u32 val) +{ + struct isp_param *isp; + unsigned long *p_index, mode; + + mode = is->scenario_id; + p_index = &is->cfg_param[mode].p_region_index1; + isp = &is->cfg_param[mode].isp; + + isp->afc.cmd = cmd; + isp->afc.manual = val; + isp->afc.err = ISP_AFC_ERROR_NONE; + + if (!test_bit(PARAM_ISP_AFC, p_index)) { + fimc_is_set_param_bit(is, PARAM_ISP_AFC); + fimc_is_inc_param_num(is); + } +} + +void __is_set_drc_control(struct fimc_is *is, u32 val) +{ + struct drc_param *drc; + unsigned long *p_index, mode; + + mode = is->scenario_id; + p_index = &is->cfg_param[mode].p_region_index1; + drc = &is->cfg_param[mode].drc; + + drc->control.bypass = val; + + if (!test_bit(PARAM_DRC_CONTROL, p_index)) { + fimc_is_set_param_bit(is, PARAM_DRC_CONTROL); + fimc_is_inc_param_num(is); + } +} + +void __is_set_fd_control(struct fimc_is *is, u32 val) +{ + struct fd_param *fd; + unsigned long *p_index, mode; + + mode = is->scenario_id; + p_index = &is->cfg_param[mode].p_region_index2; + fd = &is->cfg_param[mode].fd; + + fd->control.cmd = val; + + if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) { + fimc_is_set_param_bit(is, PARAM_FD_CONTROL); + fimc_is_inc_param_num(is); + } +} + +void __is_set_fd_config_maxface(struct fimc_is *is, u32 val) +{ + struct fd_param *fd; + unsigned long *p_index, mode; + + mode = is->scenario_id; + p_index = &is->cfg_param[mode].p_region_index2; + fd = &is->cfg_param[mode].fd; + + fd->config.max_number = val; + + if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) { + fd->config.cmd = FD_CONFIG_COMMAND_MAXIMUM_NUMBER; + fd->config.err = ERROR_FD_NONE; + fimc_is_set_param_bit(is, PARAM_FD_CONFIG); + fimc_is_inc_param_num(is); + } else { + fd->config.cmd |= FD_CONFIG_COMMAND_MAXIMUM_NUMBER; + } +} + +void __is_set_fd_config_rollangle(struct fimc_is *is, u32 val) +{ + struct fd_param *fd; + unsigned long *p_index, mode; + + mode = is->scenario_id; + p_index = &is->cfg_param[mode].p_region_index2; + fd = &is->cfg_param[mode].fd; + + fd->config.roll_angle = val; + + if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) { + fd->config.cmd = FD_CONFIG_COMMAND_ROLL_ANGLE; + fd->config.err = ERROR_FD_NONE; + fimc_is_set_param_bit(is, PARAM_FD_CONFIG); + fimc_is_inc_param_num(is); + } else { + fd->config.cmd |= FD_CONFIG_COMMAND_ROLL_ANGLE; + } +} + +void __is_set_fd_config_yawangle(struct fimc_is *is, u32 val) +{ + struct fd_param *fd; + unsigned long *p_index, mode; + + mode = is->scenario_id; + p_index = &is->cfg_param[mode].p_region_index2; + fd = &is->cfg_param[mode].fd; + + fd->config.yaw_angle = val; + + if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) { + fd->config.cmd = FD_CONFIG_COMMAND_YAW_ANGLE; + fd->config.err = ERROR_FD_NONE; + fimc_is_set_param_bit(is, PARAM_FD_CONFIG); + fimc_is_inc_param_num(is); + } else { + fd->config.cmd |= FD_CONFIG_COMMAND_YAW_ANGLE; + } +} + +void __is_set_fd_config_smilemode(struct fimc_is *is, u32 val) +{ + struct fd_param *fd; + unsigned long *p_index, mode; + + mode = is->scenario_id; + p_index = &is->cfg_param[mode].p_region_index2; + fd = &is->cfg_param[mode].fd; + + fd->config.smile_mode = val; + + if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) { + fd->config.cmd = FD_CONFIG_COMMAND_SMILE_MODE; + fd->config.err = ERROR_FD_NONE; + fimc_is_set_param_bit(is, PARAM_FD_CONFIG); + fimc_is_inc_param_num(is); + } else { + fd->config.cmd |= FD_CONFIG_COMMAND_SMILE_MODE; + } +} + +void __is_set_fd_config_blinkmode(struct fimc_is *is, u32 val) +{ + struct fd_param *fd; + unsigned long *p_index, mode; + + mode = is->scenario_id; + p_index = &is->cfg_param[mode].p_region_index2; + fd = &is->cfg_param[mode].fd; + + fd->config.blink_mode = val; + + if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) { + fd->config.cmd = FD_CONFIG_COMMAND_BLINK_MODE; + fd->config.err = ERROR_FD_NONE; + fimc_is_set_param_bit(is, PARAM_FD_CONFIG); + fimc_is_inc_param_num(is); + } else { + fd->config.cmd |= FD_CONFIG_COMMAND_BLINK_MODE; + } +} + +void __is_set_fd_config_eyedetect(struct fimc_is *is, u32 val) +{ + struct fd_param *fd; + unsigned long *p_index, mode; + + mode = is->scenario_id; + p_index = &is->cfg_param[mode].p_region_index2; + fd = &is->cfg_param[mode].fd; + + fd->config.eye_detect = val; + + if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) { + fd->config.cmd = FD_CONFIG_COMMAND_EYES_DETECT; + fd->config.err = ERROR_FD_NONE; + fimc_is_set_param_bit(is, PARAM_FD_CONFIG); + fimc_is_inc_param_num(is); + } else { + fd->config.cmd |= FD_CONFIG_COMMAND_EYES_DETECT; + } +} + +void __is_set_fd_config_mouthdetect(struct fimc_is *is, u32 val) +{ + struct fd_param *fd; + unsigned long *p_index, mode; + + mode = is->scenario_id; + p_index = &is->cfg_param[mode].p_region_index2; + fd = &is->cfg_param[mode].fd; + + fd->config.mouth_detect = val; + + if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) { + fd->config.cmd = FD_CONFIG_COMMAND_MOUTH_DETECT; + fd->config.err = ERROR_FD_NONE; + fimc_is_set_param_bit(is, PARAM_FD_CONFIG); + fimc_is_inc_param_num(is); + } else { + fd->config.cmd |= FD_CONFIG_COMMAND_MOUTH_DETECT; + } +} + +void __is_set_fd_config_orientation(struct fimc_is *is, u32 val) +{ + struct fd_param *fd; + unsigned long *p_index, mode; + + mode = is->scenario_id; + p_index = &is->cfg_param[mode].p_region_index2; + fd = &is->cfg_param[mode].fd; + + fd->config.orientation = val; + + if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) { + fd->config.cmd = FD_CONFIG_COMMAND_ORIENTATION; + fd->config.err = ERROR_FD_NONE; + fimc_is_set_param_bit(is, PARAM_FD_CONFIG); + fimc_is_inc_param_num(is); + } else { + fd->config.cmd |= FD_CONFIG_COMMAND_ORIENTATION; + } +} + +void __is_set_fd_config_orientation_val(struct fimc_is *is, u32 val) +{ + struct fd_param *fd; + unsigned long *p_index, mode; + + mode = is->scenario_id; + p_index = &is->cfg_param[mode].p_region_index2; + fd = &is->cfg_param[mode].fd; + + fd->config.orientation_value = val; + + if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) { + fd->config.cmd = FD_CONFIG_COMMAND_ORIENTATION_VALUE; + fd->config.err = ERROR_FD_NONE; + fimc_is_set_param_bit(is, PARAM_FD_CONFIG); + fimc_is_inc_param_num(is); + } else { + fd->config.cmd |= FD_CONFIG_COMMAND_ORIENTATION_VALUE; + } +} + +void fimc_is_set_initial_params(struct fimc_is *is) +{ + struct global_param *global; + struct sensor_param *sensor; + struct isp_param *isp; + struct drc_param *drc; + struct fd_param *fd; + unsigned long *p_index1, *p_index2; + unsigned int mode; + + mode = is->scenario_id; + global = &is->cfg_param[mode].global; + sensor = &is->cfg_param[mode].sensor; + isp = &is->cfg_param[mode].isp; + drc = &is->cfg_param[mode].drc; + fd = &is->cfg_param[mode].fd; + p_index1 = &is->cfg_param[mode].p_region_index1; + p_index2 = &is->cfg_param[mode].p_region_index2; + + /* Global */ + global->shotmode.cmd = 1; + fimc_is_set_param_bit(is, PARAM_GLOBAL_SHOTMODE); + fimc_is_inc_param_num(is); + + /* ISP */ + isp->control.cmd = CONTROL_COMMAND_START; + isp->control.bypass = CONTROL_BYPASS_DISABLE; + isp->control.err = CONTROL_ERROR_NONE; + fimc_is_set_param_bit(is, PARAM_ISP_CONTROL); + fimc_is_inc_param_num(is); + + isp->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE; + if (!test_bit(PARAM_ISP_OTF_INPUT, p_index1)) { + isp->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH; + isp->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT; + fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT); + fimc_is_inc_param_num(is); + } + if (is->sensor->test_pattern) + isp->otf_input.format = OTF_INPUT_FORMAT_STRGEN_COLORBAR_BAYER; + else + isp->otf_input.format = OTF_INPUT_FORMAT_BAYER; + isp->otf_input.bitwidth = 10; + isp->otf_input.order = OTF_INPUT_ORDER_BAYER_GR_BG; + isp->otf_input.crop_offset_x = 0; + isp->otf_input.crop_offset_y = 0; + isp->otf_input.err = OTF_INPUT_ERROR_NONE; + + isp->dma1_input.cmd = DMA_INPUT_COMMAND_DISABLE; + isp->dma1_input.width = 0; + isp->dma1_input.height = 0; + isp->dma1_input.format = 0; + isp->dma1_input.bitwidth = 0; + isp->dma1_input.plane = 0; + isp->dma1_input.order = 0; + isp->dma1_input.buffer_number = 0; + isp->dma1_input.width = 0; + isp->dma1_input.err = DMA_INPUT_ERROR_NONE; + fimc_is_set_param_bit(is, PARAM_ISP_DMA1_INPUT); + fimc_is_inc_param_num(is); + + isp->dma2_input.cmd = DMA_INPUT_COMMAND_DISABLE; + isp->dma2_input.width = 0; + isp->dma2_input.height = 0; + isp->dma2_input.format = 0; + isp->dma2_input.bitwidth = 0; + isp->dma2_input.plane = 0; + isp->dma2_input.order = 0; + isp->dma2_input.buffer_number = 0; + isp->dma2_input.width = 0; + isp->dma2_input.err = DMA_INPUT_ERROR_NONE; + fimc_is_set_param_bit(is, PARAM_ISP_DMA2_INPUT); + fimc_is_inc_param_num(is); + + isp->aa.cmd = ISP_AA_COMMAND_START; + isp->aa.target = ISP_AA_TARGET_AE | ISP_AA_TARGET_AWB; + fimc_is_set_param_bit(is, PARAM_ISP_AA); + fimc_is_inc_param_num(is); + + if (!test_bit(PARAM_ISP_FLASH, p_index1)) + __is_set_isp_flash(is, ISP_FLASH_COMMAND_DISABLE, + ISP_FLASH_REDEYE_DISABLE); + + if (!test_bit(PARAM_ISP_AWB, p_index1)) + __is_set_isp_awb(is, ISP_AWB_COMMAND_AUTO, 0); + + if (!test_bit(PARAM_ISP_IMAGE_EFFECT, p_index1)) + __is_set_isp_effect(is, ISP_IMAGE_EFFECT_DISABLE); + + if (!test_bit(PARAM_ISP_ISO, p_index1)) + __is_set_isp_iso(is, ISP_ISO_COMMAND_AUTO, 0); + + if (!test_bit(PARAM_ISP_ADJUST, p_index1)) { + __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_CONTRAST, 0); + __is_set_isp_adjust(is, + ISP_ADJUST_COMMAND_MANUAL_SATURATION, 0); + __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_SHARPNESS, 0); + __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_EXPOSURE, 0); + __is_set_isp_adjust(is, + ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS, 0); + __is_set_isp_adjust(is, ISP_ADJUST_COMMAND_MANUAL_HUE, 0); + } + + if (!test_bit(PARAM_ISP_METERING, p_index1)) { + __is_set_isp_metering(is, 0, ISP_METERING_COMMAND_CENTER); + __is_set_isp_metering(is, 1, 0); + __is_set_isp_metering(is, 2, 0); + __is_set_isp_metering(is, 3, 0); + __is_set_isp_metering(is, 4, 0); + } + + if (!test_bit(PARAM_ISP_AFC, p_index1)) + __is_set_isp_afc(is, ISP_AFC_COMMAND_AUTO, 0); + + isp->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE; + if (!test_bit(PARAM_ISP_OTF_OUTPUT, p_index1)) { + isp->otf_output.width = DEFAULT_PREVIEW_STILL_WIDTH; + isp->otf_output.height = DEFAULT_PREVIEW_STILL_HEIGHT; + fimc_is_set_param_bit(is, PARAM_ISP_OTF_OUTPUT); + fimc_is_inc_param_num(is); + } + isp->otf_output.format = OTF_OUTPUT_FORMAT_YUV444; + isp->otf_output.bitwidth = 12; + isp->otf_output.order = 0; + isp->otf_output.err = OTF_OUTPUT_ERROR_NONE; + + if (!test_bit(PARAM_ISP_DMA1_OUTPUT, p_index1)) { + isp->dma1_output.cmd = DMA_OUTPUT_COMMAND_DISABLE; + isp->dma1_output.width = 0; + isp->dma1_output.height = 0; + isp->dma1_output.format = 0; + isp->dma1_output.bitwidth = 0; + isp->dma1_output.plane = 0; + isp->dma1_output.order = 0; + isp->dma1_output.buffer_number = 0; + isp->dma1_output.buffer_address = 0; + isp->dma1_output.notify_dma_done = 0; + isp->dma1_output.dma_out_mask = 0; + isp->dma1_output.err = DMA_OUTPUT_ERROR_NONE; + fimc_is_set_param_bit(is, PARAM_ISP_DMA1_OUTPUT); + fimc_is_inc_param_num(is); + } + + if (!test_bit(PARAM_ISP_DMA2_OUTPUT, p_index1)) { + isp->dma2_output.cmd = DMA_OUTPUT_COMMAND_DISABLE; + isp->dma2_output.width = 0; + isp->dma2_output.height = 0; + isp->dma2_output.format = 0; + isp->dma2_output.bitwidth = 0; + isp->dma2_output.plane = 0; + isp->dma2_output.order = 0; + isp->dma2_output.buffer_number = 0; + isp->dma2_output.buffer_address = 0; + isp->dma2_output.notify_dma_done = 0; + isp->dma2_output.dma_out_mask = 0; + isp->dma2_output.err = DMA_OUTPUT_ERROR_NONE; + fimc_is_set_param_bit(is, PARAM_ISP_DMA2_OUTPUT); + fimc_is_inc_param_num(is); + } + + /* Sensor */ + if (!test_bit(PARAM_SENSOR_FRAME_RATE, p_index1)) { + if (!mode) + __is_set_sensor(is, 0); + } + + /* DRC */ + drc->control.cmd = CONTROL_COMMAND_START; + __is_set_drc_control(is, CONTROL_BYPASS_ENABLE); + + drc->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE; + if (!test_bit(PARAM_DRC_OTF_INPUT, p_index1)) { + drc->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH; + drc->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT; + fimc_is_set_param_bit(is, PARAM_DRC_OTF_INPUT); + fimc_is_inc_param_num(is); + } + drc->otf_input.format = OTF_INPUT_FORMAT_YUV444; + drc->otf_input.bitwidth = 12; + drc->otf_input.order = 0; + drc->otf_input.err = OTF_INPUT_ERROR_NONE; + + drc->dma_input.cmd = DMA_INPUT_COMMAND_DISABLE; + drc->dma_input.width = 0; + drc->dma_input.height = 0; + drc->dma_input.format = 0; + drc->dma_input.bitwidth = 0; + drc->dma_input.plane = 0; + drc->dma_input.order = 0; + drc->dma_input.buffer_number = 0; + drc->dma_input.width = 0; + drc->dma_input.err = DMA_INPUT_ERROR_NONE; + fimc_is_set_param_bit(is, PARAM_DRC_DMA_INPUT); + fimc_is_inc_param_num(is); + + drc->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE; + if (!test_bit(PARAM_DRC_OTF_OUTPUT, p_index1)) { + drc->otf_output.width = DEFAULT_PREVIEW_STILL_WIDTH; + drc->otf_output.height = DEFAULT_PREVIEW_STILL_HEIGHT; + fimc_is_set_param_bit(is, PARAM_DRC_OTF_OUTPUT); + fimc_is_inc_param_num(is); + } + drc->otf_output.format = OTF_OUTPUT_FORMAT_YUV444; + drc->otf_output.bitwidth = 8; + drc->otf_output.order = 0; + drc->otf_output.err = OTF_OUTPUT_ERROR_NONE; + + /* FD */ + __is_set_fd_control(is, CONTROL_COMMAND_STOP); + fd->control.bypass = CONTROL_BYPASS_DISABLE; + + fd->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE; + if (!test_bit((PARAM_FD_OTF_INPUT - 32), p_index2)) { + fd->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH; + fd->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT; + fimc_is_set_param_bit(is, PARAM_FD_OTF_INPUT); + fimc_is_inc_param_num(is); + } + fd->otf_input.format = OTF_INPUT_FORMAT_YUV444; + fd->otf_input.bitwidth = 8; + fd->otf_input.order = 0; + fd->otf_input.err = OTF_INPUT_ERROR_NONE; + + fd->dma_input.cmd = DMA_INPUT_COMMAND_DISABLE; + fd->dma_input.width = 0; + fd->dma_input.height = 0; + fd->dma_input.format = 0; + fd->dma_input.bitwidth = 0; + fd->dma_input.plane = 0; + fd->dma_input.order = 0; + fd->dma_input.buffer_number = 0; + fd->dma_input.width = 0; + fd->dma_input.err = DMA_INPUT_ERROR_NONE; + fimc_is_set_param_bit(is, PARAM_FD_DMA_INPUT); + fimc_is_inc_param_num(is); + + __is_set_fd_config_maxface(is, 5); + __is_set_fd_config_rollangle(is, FD_CONFIG_ROLL_ANGLE_FULL); + __is_set_fd_config_yawangle(is, FD_CONFIG_YAW_ANGLE_45_90); + __is_set_fd_config_smilemode(is, FD_CONFIG_SMILE_MODE_DISABLE); + __is_set_fd_config_blinkmode(is, FD_CONFIG_BLINK_MODE_DISABLE); + __is_set_fd_config_eyedetect(is, FD_CONFIG_EYES_DETECT_ENABLE); + __is_set_fd_config_mouthdetect(is, FD_CONFIG_MOUTH_DETECT_DISABLE); + __is_set_fd_config_orientation(is, FD_CONFIG_ORIENTATION_DISABLE); + __is_set_fd_config_orientation_val(is, 0); +} diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.h b/drivers/media/platform/exynos4-is/fimc-is-param.h new file mode 100644 index 000000000000..71464a58b56b --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-is-param.h @@ -0,0 +1,1022 @@ +/* + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. + * + * Authors: Younghwan Joo + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef FIMC_IS_PARAM_H_ +#define FIMC_IS_PARAM_H_ + +#include + +#define FIMC_IS_CONFIG_TIMEOUT 3000 /* ms */ +#define IS_DEFAULT_WIDTH 1280 +#define IS_DEFAULT_HEIGHT 720 + +#define DEFAULT_PREVIEW_STILL_WIDTH IS_DEFAULT_WIDTH +#define DEFAULT_PREVIEW_STILL_HEIGHT IS_DEFAULT_HEIGHT +#define DEFAULT_CAPTURE_STILL_WIDTH IS_DEFAULT_WIDTH +#define DEFAULT_CAPTURE_STILL_HEIGHT IS_DEFAULT_HEIGHT +#define DEFAULT_PREVIEW_VIDEO_WIDTH IS_DEFAULT_WIDTH +#define DEFAULT_PREVIEW_VIDEO_HEIGHT IS_DEFAULT_HEIGHT +#define DEFAULT_CAPTURE_VIDEO_WIDTH IS_DEFAULT_WIDTH +#define DEFAULT_CAPTURE_VIDEO_HEIGHT IS_DEFAULT_HEIGHT + +#define DEFAULT_PREVIEW_STILL_FRAMERATE 30 +#define DEFAULT_CAPTURE_STILL_FRAMERATE 15 +#define DEFAULT_PREVIEW_VIDEO_FRAMERATE 30 +#define DEFAULT_CAPTURE_VIDEO_FRAMERATE 30 + +#define FIMC_IS_REGION_VER 124 /* IS REGION VERSION 1.24 */ +#define FIMC_IS_PARAM_SIZE (FIMC_IS_REGION_SIZE + 1) +#define FIMC_IS_MAGIC_NUMBER 0x01020304 +#define FIMC_IS_PARAM_MAX_SIZE 64 /* in bytes */ +#define FIMC_IS_PARAM_MAX_ENTRIES (FIMC_IS_PARAM_MAX_SIZE / 4) + +/* The parameter bitmask bit definitions. */ +enum is_param_bit { + PARAM_GLOBAL_SHOTMODE, + PARAM_SENSOR_CONTROL, + PARAM_SENSOR_OTF_OUTPUT, + PARAM_SENSOR_FRAME_RATE, + PARAM_BUFFER_CONTROL, + PARAM_BUFFER_OTF_INPUT, + PARAM_BUFFER_OTF_OUTPUT, + PARAM_ISP_CONTROL, + PARAM_ISP_OTF_INPUT, + PARAM_ISP_DMA1_INPUT, + /* 10 */ + PARAM_ISP_DMA2_INPUT, + PARAM_ISP_AA, + PARAM_ISP_FLASH, + PARAM_ISP_AWB, + PARAM_ISP_IMAGE_EFFECT, + PARAM_ISP_ISO, + PARAM_ISP_ADJUST, + PARAM_ISP_METERING, + PARAM_ISP_AFC, + PARAM_ISP_OTF_OUTPUT, + /* 20 */ + PARAM_ISP_DMA1_OUTPUT, + PARAM_ISP_DMA2_OUTPUT, + PARAM_DRC_CONTROL, + PARAM_DRC_OTF_INPUT, + PARAM_DRC_DMA_INPUT, + PARAM_DRC_OTF_OUTPUT, + PARAM_SCALERC_CONTROL, + PARAM_SCALERC_OTF_INPUT, + PARAM_SCALERC_IMAGE_EFFECT, + PARAM_SCALERC_INPUT_CROP, + /* 30 */ + PARAM_SCALERC_OUTPUT_CROP, + PARAM_SCALERC_OTF_OUTPUT, + PARAM_SCALERC_DMA_OUTPUT, + PARAM_ODC_CONTROL, + PARAM_ODC_OTF_INPUT, + PARAM_ODC_OTF_OUTPUT, + PARAM_DIS_CONTROL, + PARAM_DIS_OTF_INPUT, + PARAM_DIS_OTF_OUTPUT, + PARAM_TDNR_CONTROL, + /* 40 */ + PARAM_TDNR_OTF_INPUT, + PARAM_TDNR_1ST_FRAME, + PARAM_TDNR_OTF_OUTPUT, + PARAM_TDNR_DMA_OUTPUT, + PARAM_SCALERP_CONTROL, + PARAM_SCALERP_OTF_INPUT, + PARAM_SCALERP_IMAGE_EFFECT, + PARAM_SCALERP_INPUT_CROP, + PARAM_SCALERP_OUTPUT_CROP, + PARAM_SCALERP_ROTATION, + /* 50 */ + PARAM_SCALERP_FLIP, + PARAM_SCALERP_OTF_OUTPUT, + PARAM_SCALERP_DMA_OUTPUT, + PARAM_FD_CONTROL, + PARAM_FD_OTF_INPUT, + PARAM_FD_DMA_INPUT, + PARAM_FD_CONFIG, +}; + +/* Interrupt map */ +#define FIMC_IS_INT_GENERAL 0 +#define FIMC_IS_INT_FRAME_DONE_ISP 1 + +/* Input */ + +#define CONTROL_COMMAND_STOP 0 +#define CONTROL_COMMAND_START 1 + +#define CONTROL_BYPASS_DISABLE 0 +#define CONTROL_BYPASS_ENABLE 1 + +#define CONTROL_ERROR_NONE 0 + +/* OTF (On-The-Fly) input interface commands */ +#define OTF_INPUT_COMMAND_DISABLE 0 +#define OTF_INPUT_COMMAND_ENABLE 1 + +/* OTF input interface color formats */ +enum oft_input_fmt { + OTF_INPUT_FORMAT_BAYER = 0, /* 1 channel */ + OTF_INPUT_FORMAT_YUV444 = 1, /* 3 channels */ + OTF_INPUT_FORMAT_YUV422 = 2, /* 3 channels */ + OTF_INPUT_FORMAT_YUV420 = 3, /* 3 channels */ + OTF_INPUT_FORMAT_STRGEN_COLORBAR_BAYER = 10, + OTF_INPUT_FORMAT_BAYER_DMA = 11, +}; + +#define OTF_INPUT_ORDER_BAYER_GR_BG 0 + +/* OTF input error codes */ +#define OTF_INPUT_ERROR_NONE 0 /* Input setting is done */ + +/* DMA input commands */ +#define DMA_INPUT_COMMAND_DISABLE 0 +#define DMA_INPUT_COMMAND_ENABLE 1 + +/* DMA input color formats */ +enum dma_input_fmt { + DMA_INPUT_FORMAT_BAYER = 0, + DMA_INPUT_FORMAT_YUV444 = 1, + DMA_INPUT_FORMAT_YUV422 = 2, + DMA_INPUT_FORMAT_YUV420 = 3, +}; + +enum dma_input_order { + /* (for DMA_INPUT_PLANE_3) */ + DMA_INPUT_ORDER_NO = 0, + /* (only valid at DMA_INPUT_PLANE_2) */ + DMA_INPUT_ORDER_CBCR = 1, + /* (only valid at DMA_INPUT_PLANE_2) */ + DMA_INPUT_ORDER_CRCB = 2, + /* (only valid at DMA_INPUT_PLANE_1 & DMA_INPUT_FORMAT_YUV444) */ + DMA_INPUT_ORDER_YCBCR = 3, + /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */ + DMA_INPUT_ORDER_YYCBCR = 4, + /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */ + DMA_INPUT_ORDER_YCBYCR = 5, + /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */ + DMA_INPUT_ORDER_YCRYCB = 6, + /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */ + DMA_INPUT_ORDER_CBYCRY = 7, + /* (only valid at DMA_INPUT_FORMAT_YUV422 & DMA_INPUT_PLANE_1) */ + DMA_INPUT_ORDER_CRYCBY = 8, + /* (only valid at DMA_INPUT_FORMAT_BAYER) */ + DMA_INPUT_ORDER_GR_BG = 9 +}; + +#define DMA_INPUT_ERROR_NONE 0 /* DMA input setting + is done */ +/* + * Data output parameter definitions + */ +#define OTF_OUTPUT_CROP_DISABLE 0 +#define OTF_OUTPUT_CROP_ENABLE 1 + +#define OTF_OUTPUT_COMMAND_DISABLE 0 +#define OTF_OUTPUT_COMMAND_ENABLE 1 + +enum otf_output_fmt { + OTF_OUTPUT_FORMAT_YUV444 = 1, + OTF_OUTPUT_FORMAT_YUV422 = 2, + OTF_OUTPUT_FORMAT_YUV420 = 3, + OTF_OUTPUT_FORMAT_RGB = 4, +}; + +#define OTF_OUTPUT_ORDER_BAYER_GR_BG 0 + +#define OTF_OUTPUT_ERROR_NONE 0 /* Output Setting is done */ + +#define DMA_OUTPUT_COMMAND_DISABLE 0 +#define DMA_OUTPUT_COMMAND_ENABLE 1 + +enum dma_output_fmt { + DMA_OUTPUT_FORMAT_BAYER = 0, + DMA_OUTPUT_FORMAT_YUV444 = 1, + DMA_OUTPUT_FORMAT_YUV422 = 2, + DMA_OUTPUT_FORMAT_YUV420 = 3, + DMA_OUTPUT_FORMAT_RGB = 4, +}; + +enum dma_output_order { + DMA_OUTPUT_ORDER_NO = 0, + /* for DMA_OUTPUT_PLANE_3 */ + DMA_OUTPUT_ORDER_CBCR = 1, + /* only valid at DMA_INPUT_PLANE_2) */ + DMA_OUTPUT_ORDER_CRCB = 2, + /* only valid at DMA_OUTPUT_PLANE_2) */ + DMA_OUTPUT_ORDER_YYCBCR = 3, + /* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */ + DMA_OUTPUT_ORDER_YCBYCR = 4, + /* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */ + DMA_OUTPUT_ORDER_YCRYCB = 5, + /* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */ + DMA_OUTPUT_ORDER_CBYCRY = 6, + /* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */ + DMA_OUTPUT_ORDER_CRYCBY = 7, + /* only valid at DMA_OUTPUT_FORMAT_YUV422 & DMA_OUTPUT_PLANE_1 */ + DMA_OUTPUT_ORDER_YCBCR = 8, + /* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */ + DMA_OUTPUT_ORDER_CRYCB = 9, + /* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */ + DMA_OUTPUT_ORDER_CRCBY = 10, + /* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */ + DMA_OUTPUT_ORDER_CBYCR = 11, + /* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */ + DMA_OUTPUT_ORDER_YCRCB = 12, + /* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */ + DMA_OUTPUT_ORDER_CBCRY = 13, + /* only valid at DMA_OUTPUT_FORMAT_YUV444 & DMA_OUPUT_PLANE_1 */ + DMA_OUTPUT_ORDER_BGR = 14, + /* only valid at DMA_OUTPUT_FORMAT_RGB */ + DMA_OUTPUT_ORDER_GB_BG = 15 + /* only valid at DMA_OUTPUT_FORMAT_BAYER */ +}; + +/* enum dma_output_notify_dma_done */ +#define DMA_OUTPUT_NOTIFY_DMA_DONE_DISABLE 0 +#define DMA_OUTPUT_NOTIFY_DMA_DONE_ENABLE 1 + +/* DMA output error codes */ +#define DMA_OUTPUT_ERROR_NONE 0 /* DMA output setting + is done */ + +/* ---------------------- Global ----------------------------------- */ +#define GLOBAL_SHOTMODE_ERROR_NONE 0 /* shot-mode setting + is done */ +/* 3A lock commands */ +#define ISP_AA_COMMAND_START 0 +#define ISP_AA_COMMAND_STOP 1 + +/* 3A lock target */ +#define ISP_AA_TARGET_AF 1 +#define ISP_AA_TARGET_AE 2 +#define ISP_AA_TARGET_AWB 4 + +enum isp_af_mode { + ISP_AF_MODE_MANUAL = 0, + ISP_AF_MODE_SINGLE = 1, + ISP_AF_MODE_CONTINUOUS = 2, + ISP_AF_MODE_TOUCH = 3, + ISP_AF_MODE_SLEEP = 4, + ISP_AF_MODE_INIT = 5, + ISP_AF_MODE_SET_CENTER_WINDOW = 6, + ISP_AF_MODE_SET_TOUCH_WINDOW = 7 +}; + +/* Face AF commands */ +#define ISP_AF_FACE_DISABLE 0 +#define ISP_AF_FACE_ENABLE 1 + +/* AF range */ +#define ISP_AF_RANGE_NORMAL 0 +#define ISP_AF_RANGE_MACRO 1 + +/* AF sleep */ +#define ISP_AF_SLEEP_OFF 0 +#define ISP_AF_SLEEP_ON 1 + +/* Continuous AF commands */ +#define ISP_AF_CONTINUOUS_DISABLE 0 +#define ISP_AF_CONTINUOUS_ENABLE 1 + +/* ISP AF error codes */ +#define ISP_AF_ERROR_NONE 0 /* AF mode change is done */ +#define ISP_AF_ERROR_NONE_LOCK_DONE 1 /* AF lock is done */ + +/* Flash commands */ +#define ISP_FLASH_COMMAND_DISABLE 0 +#define ISP_FLASH_COMMAND_MANUAL_ON 1 /* (forced flash) */ +#define ISP_FLASH_COMMAND_AUTO 2 +#define ISP_FLASH_COMMAND_TORCH 3 /* 3 sec */ + +/* Flash red-eye commads */ +#define ISP_FLASH_REDEYE_DISABLE 0 +#define ISP_FLASH_REDEYE_ENABLE 1 + +/* Flash error codes */ +#define ISP_FLASH_ERROR_NONE 0 /* Flash setting is done */ + +/* -------------------------- AWB ------------------------------------ */ +enum isp_awb_command { + ISP_AWB_COMMAND_AUTO = 0, + ISP_AWB_COMMAND_ILLUMINATION = 1, + ISP_AWB_COMMAND_MANUAL = 2 +}; + +enum isp_awb_illumination { + ISP_AWB_ILLUMINATION_DAYLIGHT = 0, + ISP_AWB_ILLUMINATION_CLOUDY = 1, + ISP_AWB_ILLUMINATION_TUNGSTEN = 2, + ISP_AWB_ILLUMINATION_FLUORESCENT = 3 +}; + +/* ISP AWN error codes */ +#define ISP_AWB_ERROR_NONE 0 /* AWB setting is done */ + +/* -------------------------- Effect ----------------------------------- */ +enum isp_imageeffect_command { + ISP_IMAGE_EFFECT_DISABLE = 0, + ISP_IMAGE_EFFECT_MONOCHROME = 1, + ISP_IMAGE_EFFECT_NEGATIVE_MONO = 2, + ISP_IMAGE_EFFECT_NEGATIVE_COLOR = 3, + ISP_IMAGE_EFFECT_SEPIA = 4 +}; + +/* Image effect error codes */ +#define ISP_IMAGE_EFFECT_ERROR_NONE 0 /* Image effect setting + is done */ +/* ISO commands */ +#define ISP_ISO_COMMAND_AUTO 0 +#define ISP_ISO_COMMAND_MANUAL 1 + +/* ISO error codes */ +#define ISP_ISO_ERROR_NONE 0 /* ISO setting is done */ + +/* ISP adjust commands */ +#define ISP_ADJUST_COMMAND_AUTO (0 << 0) +#define ISP_ADJUST_COMMAND_MANUAL_CONTRAST (1 << 0) +#define ISP_ADJUST_COMMAND_MANUAL_SATURATION (1 << 1) +#define ISP_ADJUST_COMMAND_MANUAL_SHARPNESS (1 << 2) +#define ISP_ADJUST_COMMAND_MANUAL_EXPOSURE (1 << 3) +#define ISP_ADJUST_COMMAND_MANUAL_BRIGHTNESS (1 << 4) +#define ISP_ADJUST_COMMAND_MANUAL_HUE (1 << 5) +#define ISP_ADJUST_COMMAND_MANUAL_ALL 0x7f + +/* ISP adjustment error codes */ +#define ISP_ADJUST_ERROR_NONE 0 /* Adjust setting is done */ + +/* + * Exposure metering + */ +enum isp_metering_command { + ISP_METERING_COMMAND_AVERAGE = 0, + ISP_METERING_COMMAND_SPOT = 1, + ISP_METERING_COMMAND_MATRIX = 2, + ISP_METERING_COMMAND_CENTER = 3 +}; + +/* ISP metering error codes */ +#define ISP_METERING_ERROR_NONE 0 /* Metering setting is done */ + +/* + * AFC + */ +enum isp_afc_command { + ISP_AFC_COMMAND_DISABLE = 0, + ISP_AFC_COMMAND_AUTO = 1, + ISP_AFC_COMMAND_MANUAL = 2, +}; + +#define ISP_AFC_MANUAL_50HZ 50 +#define ISP_AFC_MANUAL_60HZ 60 + +/* ------------------------ SCENE MODE--------------------------------- */ +enum isp_scene_mode { + ISP_SCENE_NONE = 0, + ISP_SCENE_PORTRAIT = 1, + ISP_SCENE_LANDSCAPE = 2, + ISP_SCENE_SPORTS = 3, + ISP_SCENE_PARTYINDOOR = 4, + ISP_SCENE_BEACHSNOW = 5, + ISP_SCENE_SUNSET = 6, + ISP_SCENE_DAWN = 7, + ISP_SCENE_FALL = 8, + ISP_SCENE_NIGHT = 9, + ISP_SCENE_AGAINSTLIGHTWLIGHT = 10, + ISP_SCENE_AGAINSTLIGHTWOLIGHT = 11, + ISP_SCENE_FIRE = 12, + ISP_SCENE_TEXT = 13, + ISP_SCENE_CANDLE = 14 +}; + +/* AFC error codes */ +#define ISP_AFC_ERROR_NONE 0 /* AFC setting is done */ + +/* ---------------------------- FD ------------------------------------- */ +enum fd_config_command { + FD_CONFIG_COMMAND_MAXIMUM_NUMBER = 0x1, + FD_CONFIG_COMMAND_ROLL_ANGLE = 0x2, + FD_CONFIG_COMMAND_YAW_ANGLE = 0x4, + FD_CONFIG_COMMAND_SMILE_MODE = 0x8, + FD_CONFIG_COMMAND_BLINK_MODE = 0x10, + FD_CONFIG_COMMAND_EYES_DETECT = 0x20, + FD_CONFIG_COMMAND_MOUTH_DETECT = 0x40, + FD_CONFIG_COMMAND_ORIENTATION = 0x80, + FD_CONFIG_COMMAND_ORIENTATION_VALUE = 0x100 +}; + +enum fd_config_roll_angle { + FD_CONFIG_ROLL_ANGLE_BASIC = 0, + FD_CONFIG_ROLL_ANGLE_PRECISE_BASIC = 1, + FD_CONFIG_ROLL_ANGLE_SIDES = 2, + FD_CONFIG_ROLL_ANGLE_PRECISE_SIDES = 3, + FD_CONFIG_ROLL_ANGLE_FULL = 4, + FD_CONFIG_ROLL_ANGLE_PRECISE_FULL = 5, +}; + +enum fd_config_yaw_angle { + FD_CONFIG_YAW_ANGLE_0 = 0, + FD_CONFIG_YAW_ANGLE_45 = 1, + FD_CONFIG_YAW_ANGLE_90 = 2, + FD_CONFIG_YAW_ANGLE_45_90 = 3, +}; + +/* Smile mode configuration */ +#define FD_CONFIG_SMILE_MODE_DISABLE 0 +#define FD_CONFIG_SMILE_MODE_ENABLE 1 + +/* Blink mode configuration */ +#define FD_CONFIG_BLINK_MODE_DISABLE 0 +#define FD_CONFIG_BLINK_MODE_ENABLE 1 + +/* Eyes detection configuration */ +#define FD_CONFIG_EYES_DETECT_DISABLE 0 +#define FD_CONFIG_EYES_DETECT_ENABLE 1 + +/* Mouth detection configuration */ +#define FD_CONFIG_MOUTH_DETECT_DISABLE 0 +#define FD_CONFIG_MOUTH_DETECT_ENABLE 1 + +#define FD_CONFIG_ORIENTATION_DISABLE 0 +#define FD_CONFIG_ORIENTATION_ENABLE 1 + +struct param_control { + u32 cmd; + u32 bypass; + u32 buffer_address; + u32 buffer_size; + u32 skip_frames; /* only valid at ISP */ + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 6]; + u32 err; +}; + +struct param_otf_input { + u32 cmd; + u32 width; + u32 height; + u32 format; + u32 bitwidth; + u32 order; + u32 crop_offset_x; + u32 crop_offset_y; + u32 crop_width; + u32 crop_height; + u32 frametime_min; + u32 frametime_max; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 13]; + u32 err; +}; + +struct param_dma_input { + u32 cmd; + u32 width; + u32 height; + u32 format; + u32 bitwidth; + u32 plane; + u32 order; + u32 buffer_number; + u32 buffer_address; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 10]; + u32 err; +}; + +struct param_otf_output { + u32 cmd; + u32 width; + u32 height; + u32 format; + u32 bitwidth; + u32 order; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 7]; + u32 err; +}; + +struct param_dma_output { + u32 cmd; + u32 width; + u32 height; + u32 format; + u32 bitwidth; + u32 plane; + u32 order; + u32 buffer_number; + u32 buffer_address; + u32 notify_dma_done; + u32 dma_out_mask; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 12]; + u32 err; +}; + +struct param_global_shotmode { + u32 cmd; + u32 skip_frames; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3]; + u32 err; +}; + +struct param_sensor_framerate { + u32 frame_rate; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2]; + u32 err; +}; + +struct param_isp_aa { + u32 cmd; + u32 target; + u32 mode; + u32 scene; + u32 sleep; + u32 face; + u32 touch_x; + u32 touch_y; + u32 manual_af_setting; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 10]; + u32 err; +}; + +struct param_isp_flash { + u32 cmd; + u32 redeye; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3]; + u32 err; +}; + +struct param_isp_awb { + u32 cmd; + u32 illumination; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3]; + u32 err; +}; + +struct param_isp_imageeffect { + u32 cmd; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2]; + u32 err; +}; + +struct param_isp_iso { + u32 cmd; + u32 value; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3]; + u32 err; +}; + +struct param_isp_adjust { + u32 cmd; + s32 contrast; + s32 saturation; + s32 sharpness; + s32 exposure; + s32 brightness; + s32 hue; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 8]; + u32 err; +}; + +struct param_isp_metering { + u32 cmd; + u32 win_pos_x; + u32 win_pos_y; + u32 win_width; + u32 win_height; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 6]; + u32 err; +}; + +struct param_isp_afc { + u32 cmd; + u32 manual; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 3]; + u32 err; +}; + +struct param_scaler_imageeffect { + u32 cmd; + u32 arbitrary_cb; + u32 arbitrary_cr; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 4]; + u32 err; +}; + +struct param_scaler_input_crop { + u32 cmd; + u32 crop_offset_x; + u32 crop_offset_y; + u32 crop_width; + u32 crop_height; + u32 in_width; + u32 in_height; + u32 out_width; + u32 out_height; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 10]; + u32 err; +}; + +struct param_scaler_output_crop { + u32 cmd; + u32 crop_offset_x; + u32 crop_offset_y; + u32 crop_width; + u32 crop_height; + u32 out_format; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 7]; + u32 err; +}; + +struct param_scaler_rotation { + u32 cmd; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2]; + u32 err; +}; + +struct param_scaler_flip { + u32 cmd; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2]; + u32 err; +}; + +struct param_3dnr_1stframe { + u32 cmd; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 2]; + u32 err; +}; + +struct param_fd_config { + u32 cmd; + u32 max_number; + u32 roll_angle; + u32 yaw_angle; + u32 smile_mode; + u32 blink_mode; + u32 eye_detect; + u32 mouth_detect; + u32 orientation; + u32 orientation_value; + u32 reserved[FIMC_IS_PARAM_MAX_ENTRIES - 11]; + u32 err; +}; + +struct global_param { + struct param_global_shotmode shotmode; +}; + +struct sensor_param { + struct param_control control; + struct param_otf_output otf_output; + struct param_sensor_framerate frame_rate; +} __packed; + +struct buffer_param { + struct param_control control; + struct param_otf_input otf_input; + struct param_otf_output otf_output; +} __packed; + +struct isp_param { + struct param_control control; + struct param_otf_input otf_input; + struct param_dma_input dma1_input; + struct param_dma_input dma2_input; + struct param_isp_aa aa; + struct param_isp_flash flash; + struct param_isp_awb awb; + struct param_isp_imageeffect effect; + struct param_isp_iso iso; + struct param_isp_adjust adjust; + struct param_isp_metering metering; + struct param_isp_afc afc; + struct param_otf_output otf_output; + struct param_dma_output dma1_output; + struct param_dma_output dma2_output; +} __packed; + +struct drc_param { + struct param_control control; + struct param_otf_input otf_input; + struct param_dma_input dma_input; + struct param_otf_output otf_output; +} __packed; + +struct scalerc_param { + struct param_control control; + struct param_otf_input otf_input; + struct param_scaler_imageeffect effect; + struct param_scaler_input_crop input_crop; + struct param_scaler_output_crop output_crop; + struct param_otf_output otf_output; + struct param_dma_output dma_output; +} __packed; + +struct odc_param { + struct param_control control; + struct param_otf_input otf_input; + struct param_otf_output otf_output; +} __packed; + +struct dis_param { + struct param_control control; + struct param_otf_output otf_input; + struct param_otf_output otf_output; +} __packed; + +struct tdnr_param { + struct param_control control; + struct param_otf_input otf_input; + struct param_3dnr_1stframe frame; + struct param_otf_output otf_output; + struct param_dma_output dma_output; +} __packed; + +struct scalerp_param { + struct param_control control; + struct param_otf_input otf_input; + struct param_scaler_imageeffect effect; + struct param_scaler_input_crop input_crop; + struct param_scaler_output_crop output_crop; + struct param_scaler_rotation rotation; + struct param_scaler_flip flip; + struct param_otf_output otf_output; + struct param_dma_output dma_output; +} __packed; + +struct fd_param { + struct param_control control; + struct param_otf_input otf_input; + struct param_dma_input dma_input; + struct param_fd_config config; +} __packed; + +struct is_param_region { + struct global_param global; + struct sensor_param sensor; + struct buffer_param buf; + struct isp_param isp; + struct drc_param drc; + struct scalerc_param scalerc; + struct odc_param odc; + struct dis_param dis; + struct tdnr_param tdnr; + struct scalerp_param scalerp; + struct fd_param fd; +} __packed; + +#define NUMBER_OF_GAMMA_CURVE_POINTS 32 + +struct is_tune_sensor { + u32 exposure; + u32 analog_gain; + u32 frame_rate; + u32 actuator_position; +}; + +struct is_tune_gammacurve { + u32 num_pts_x[NUMBER_OF_GAMMA_CURVE_POINTS]; + u32 num_pts_y_r[NUMBER_OF_GAMMA_CURVE_POINTS]; + u32 num_pts_y_g[NUMBER_OF_GAMMA_CURVE_POINTS]; + u32 num_pts_y_b[NUMBER_OF_GAMMA_CURVE_POINTS]; +}; + +struct is_tune_isp { + /* Brightness level: range 0...100, default 7. */ + u32 brightness_level; + /* Contrast level: range -127...127, default 0. */ + s32 contrast_level; + /* Saturation level: range -127...127, default 0. */ + s32 saturation_level; + s32 gamma_level; + struct is_tune_gammacurve gamma_curve[4]; + /* Hue: range -127...127, default 0. */ + s32 hue; + /* Sharpness blur: range -127...127, default 0. */ + s32 sharpness_blur; + /* Despeckle : range -127~127, default : 0 */ + s32 despeckle; + /* Edge color supression: range -127...127, default 0. */ + s32 edge_color_supression; + /* Noise reduction: range -127...127, default 0. */ + s32 noise_reduction; + /* (32 * 4 + 9) * 4 = 548 bytes */ +} __packed; + +struct is_tune_region { + struct is_tune_sensor sensor; + struct is_tune_isp isp; +} __packed; + +struct rational { + u32 num; + u32 den; +}; + +struct srational { + s32 num; + s32 den; +}; + +#define FLASH_FIRED_SHIFT 0 +#define FLASH_NOT_FIRED 0 +#define FLASH_FIRED 1 + +#define FLASH_STROBE_SHIFT 1 +#define FLASH_STROBE_NO_DETECTION 0 +#define FLASH_STROBE_RESERVED 1 +#define FLASH_STROBE_RETURN_LIGHT_NOT_DETECTED 2 +#define FLASH_STROBE_RETURN_LIGHT_DETECTED 3 + +#define FLASH_MODE_SHIFT 3 +#define FLASH_MODE_UNKNOWN 0 +#define FLASH_MODE_COMPULSORY_FLASH_FIRING 1 +#define FLASH_MODE_COMPULSORY_FLASH_SUPPRESSION 2 +#define FLASH_MODE_AUTO_MODE 3 + +#define FLASH_FUNCTION_SHIFT 5 +#define FLASH_FUNCTION_PRESENT 0 +#define FLASH_FUNCTION_NONE 1 + +#define FLASH_RED_EYE_SHIFT 6 +#define FLASH_RED_EYE_DISABLED 0 +#define FLASH_RED_EYE_SUPPORTED 1 + +enum apex_aperture_value { + F1_0 = 0, + F1_4 = 1, + F2_0 = 2, + F2_8 = 3, + F4_0 = 4, + F5_6 = 5, + F8_9 = 6, + F11_0 = 7, + F16_0 = 8, + F22_0 = 9, + F32_0 = 10, +}; + +struct exif_attribute { + struct rational exposure_time; + struct srational shutter_speed; + u32 iso_speed_rating; + u32 flash; + struct srational brightness; +} __packed; + +struct is_frame_header { + u32 valid; + u32 bad_mark; + u32 captured; + u32 frame_number; + struct exif_attribute exif; +} __packed; + +struct is_fd_rect { + u32 offset_x; + u32 offset_y; + u32 width; + u32 height; +}; + +struct is_face_marker { + u32 frame_number; + struct is_fd_rect face; + struct is_fd_rect left_eye; + struct is_fd_rect right_eye; + struct is_fd_rect mouth; + u32 roll_angle; + u32 yaw_angle; + u32 confidence; + s32 smile_level; + s32 blink_level; +} __packed; + +#define MAX_FRAME_COUNT 8 +#define MAX_FRAME_COUNT_PREVIEW 4 +#define MAX_FRAME_COUNT_CAPTURE 1 +#define MAX_FACE_COUNT 16 +#define MAX_SHARED_COUNT 500 + +struct is_region { + struct is_param_region parameter; + struct is_tune_region tune; + struct is_frame_header header[MAX_FRAME_COUNT]; + struct is_face_marker face[MAX_FACE_COUNT]; + u32 shared[MAX_SHARED_COUNT]; +} __packed; + +struct is_debug_frame_descriptor { + u32 sensor_frame_time; + u32 sensor_exposure_time; + s32 sensor_analog_gain; + /* monitor for AA */ + u32 req_lei; + + u32 next_next_lei_exp; + u32 next_next_lei_a_gain; + u32 next_next_lei_d_gain; + u32 next_next_lei_statlei; + u32 next_next_lei_lei; + + u32 dummy0; +}; + +#define MAX_FRAMEDESCRIPTOR_CONTEXT_NUM (30*20) /* 600 frames */ +#define MAX_VERSION_DISPLAY_BUF 32 + +struct is_share_region { + u32 frame_time; + u32 exposure_time; + s32 analog_gain; + + u32 r_gain; + u32 g_gain; + u32 b_gain; + + u32 af_position; + u32 af_status; + /* 0 : SIRC_ISP_CAMERA_AUTOFOCUSMESSAGE_NOMESSAGE */ + /* 1 : SIRC_ISP_CAMERA_AUTOFOCUSMESSAGE_REACHED */ + /* 2 : SIRC_ISP_CAMERA_AUTOFOCUSMESSAGE_UNABLETOREACH */ + /* 3 : SIRC_ISP_CAMERA_AUTOFOCUSMESSAGE_LOST */ + /* default : unknown */ + u32 af_scene_type; + + u32 frame_descp_onoff_control; + u32 frame_descp_update_done; + u32 frame_descp_idx; + u32 frame_descp_max_idx; + struct is_debug_frame_descriptor + dbg_frame_descp_ctx[MAX_FRAMEDESCRIPTOR_CONTEXT_NUM]; + + u32 chip_id; + u32 chip_rev_no; + u8 isp_fw_ver_no[MAX_VERSION_DISPLAY_BUF]; + u8 isp_fw_ver_date[MAX_VERSION_DISPLAY_BUF]; + u8 sirc_sdk_ver_no[MAX_VERSION_DISPLAY_BUF]; + u8 sirc_sdk_rev_no[MAX_VERSION_DISPLAY_BUF]; + u8 sirc_sdk_rev_date[MAX_VERSION_DISPLAY_BUF]; +} __packed; + +struct is_debug_control { + u32 write_point; /* 0~ 500KB boundary */ + u32 assert_flag; /* 0: Not invoked, 1: Invoked */ + u32 pabort_flag; /* 0: Not invoked, 1: Invoked */ + u32 dabort_flag; /* 0: Not invoked, 1: Invoked */ +}; + +struct sensor_open_extended { + u32 actuator_type; + u32 mclk; + u32 mipi_lane_num; + u32 mipi_speed; + /* Skip setfile loading when fast_open_sensor is not 0 */ + u32 fast_open_sensor; + /* Activating sensor self calibration mode (6A3) */ + u32 self_calibration_mode; + /* This field is to adjust I2c clock based on ACLK200 */ + /* This value is varied in case of rev 0.2 */ + u32 i2c_sclk; +}; + +#define fimc_is_inc_param_num(is) \ + atomic_inc(&(is)->cfg_param[(is)->scenario_id].p_region_num) + +struct fimc_is; + +int fimc_is_hw_get_sensor_max_framerate(struct fimc_is *is); +void fimc_is_set_initial_params(struct fimc_is *is); + +int __is_hw_update_params(struct fimc_is *is); +void __is_get_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf); +void __is_set_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf); +void __is_set_sensor(struct fimc_is *is, int fps); +void __is_set_isp_aa_ae(struct fimc_is *is); +void __is_set_isp_flash(struct fimc_is *is, u32 cmd, u32 redeye); +void __is_set_isp_awb(struct fimc_is *is, u32 cmd, u32 val); +void __is_set_isp_effect(struct fimc_is *is, u32 cmd); +void __is_set_isp_iso(struct fimc_is *is, u32 cmd, u32 val); +void __is_set_isp_adjust(struct fimc_is *is, u32 cmd, u32 val); +void __is_set_isp_metering(struct fimc_is *is, u32 id, u32 val); +void __is_set_isp_afc(struct fimc_is *is, u32 cmd, u32 val); +void __is_set_drc_control(struct fimc_is *is, u32 val); +void __is_set_fd_control(struct fimc_is *is, u32 val); +void __is_set_fd_config_maxface(struct fimc_is *is, u32 val); +void __is_set_fd_config_rollangle(struct fimc_is *is, u32 val); +void __is_set_fd_config_yawangle(struct fimc_is *is, u32 val); +void __is_set_fd_config_smilemode(struct fimc_is *is, u32 val); +void __is_set_fd_config_blinkmode(struct fimc_is *is, u32 val); +void __is_set_fd_config_eyedetect(struct fimc_is *is, u32 val); +void __is_set_fd_config_mouthdetect(struct fimc_is *is, u32 val); +void __is_set_fd_config_orientation(struct fimc_is *is, u32 val); +void __is_set_fd_config_orientation_val(struct fimc_is *is, u32 val); +void __is_set_isp_aa_af_mode(struct fimc_is *is, int cmd); +void __is_set_isp_aa_af_start_stop(struct fimc_is *is, int cmd); + +#endif -- cgit v1.2.3 From b8d9834a1258460311a7b318cd851eb323dd63cd Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 11 Mar 2013 15:38:29 -0300 Subject: [media] exynos4-is: Add common FIMC-IS image sensor driver This patch adds a common image sensor driver and Makefile/Kconfig to enable compilation of the whole IS driver. The sensor subdev driver currently only handles an image sensor's power supplies and reset signal. There is no I2C communication as it is handled by the ISP's firmware. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/Kconfig | 12 + drivers/media/platform/exynos4-is/Makefile | 3 + drivers/media/platform/exynos4-is/fimc-is-sensor.c | 322 +++++++++++++++++++++ drivers/media/platform/exynos4-is/fimc-is-sensor.h | 83 ++++++ 4 files changed, 420 insertions(+) create mode 100644 drivers/media/platform/exynos4-is/fimc-is-sensor.c create mode 100644 drivers/media/platform/exynos4-is/fimc-is-sensor.h (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index ae579208565b..6ff99b5849f9 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -46,4 +46,16 @@ config VIDEO_EXYNOS_FIMC_LITE module will be called exynos-fimc-lite. endif +config VIDEO_EXYNOS4_FIMC_IS + tristate "EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver" + select VIDEOBUF2_DMA_CONTIG + depends on OF + select FW_LOADER + help + This is a V4L2 driver for Samsung EXYNOS4x12 SoC series + FIMC-IS (Imaging Subsystem). + + To compile this driver as a module, choose M here: the + module will be called exynos4-fimc-is. + endif # VIDEO_SAMSUNG_S5P_FIMC diff --git a/drivers/media/platform/exynos4-is/Makefile b/drivers/media/platform/exynos4-is/Makefile index 8c67441558f7..f25f46377399 100644 --- a/drivers/media/platform/exynos4-is/Makefile +++ b/drivers/media/platform/exynos4-is/Makefile @@ -1,7 +1,10 @@ s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-m2m.o fimc-capture.o media-dev.o exynos-fimc-lite-objs += fimc-lite-reg.o fimc-lite.o +exynos-fimc-is-objs := fimc-is.o fimc-isp.o fimc-is-sensor.o fimc-is-regs.o +exynos-fimc-is-objs += fimc-is-param.o fimc-is-errno.o fimc-is-i2c.o s5p-csis-objs := mipi-csis.o obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS) += s5p-csis.o obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE) += exynos-fimc-lite.o +obj-$(CONFIG_VIDEO_EXYNOS4_FIMC_IS) += exynos-fimc-is.o obj-$(CONFIG_VIDEO_S5P_FIMC) += s5p-fimc.o diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.c b/drivers/media/platform/exynos4-is/fimc-is-sensor.c new file mode 100644 index 000000000000..02b27190d2ae --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.c @@ -0,0 +1,322 @@ +/* + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * + * Author: Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fimc-is.h" +#include "fimc-is-sensor.h" + +#define DRIVER_NAME "FIMC-IS-SENSOR" + +static const char * const sensor_supply_names[] = { + "svdda", + "svddio", +}; + +static const struct v4l2_mbus_framefmt fimc_is_sensor_formats[] = { + { + .code = V4L2_MBUS_FMT_SGRBG10_1X10, + .colorspace = V4L2_COLORSPACE_SRGB, + .field = V4L2_FIELD_NONE, + } +}; + +static struct fimc_is_sensor *sd_to_fimc_is_sensor(struct v4l2_subdev *sd) +{ + return container_of(sd, struct fimc_is_sensor, subdev); +} + +static const struct v4l2_mbus_framefmt *find_sensor_format( + struct v4l2_mbus_framefmt *mf) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(fimc_is_sensor_formats); i++) + if (mf->code == fimc_is_sensor_formats[i].code) + return &fimc_is_sensor_formats[i]; + + return &fimc_is_sensor_formats[0]; +} + +static int fimc_is_sensor_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(fimc_is_sensor_formats)) + return -EINVAL; + + code->code = fimc_is_sensor_formats[code->index].code; + return 0; +} + +static void fimc_is_sensor_try_format(struct fimc_is_sensor *sensor, + struct v4l2_mbus_framefmt *mf) +{ + const struct sensor_drv_data *dd = sensor->drvdata; + const struct v4l2_mbus_framefmt *fmt; + + fmt = find_sensor_format(mf); + mf->code = fmt->code; + v4l_bound_align_image(&mf->width, 16 + 8, dd->width, 0, + &mf->height, 12 + 8, dd->height, 0, 0); +} + +static struct v4l2_mbus_framefmt *__fimc_is_sensor_get_format( + struct fimc_is_sensor *sensor, struct v4l2_subdev_fh *fh, + u32 pad, enum v4l2_subdev_format_whence which) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL; + + return &sensor->format; +} + +static int fimc_is_sensor_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd); + struct v4l2_mbus_framefmt *mf; + + fimc_is_sensor_try_format(sensor, &fmt->format); + + mf = __fimc_is_sensor_get_format(sensor, fh, fmt->pad, fmt->which); + if (mf) { + mutex_lock(&sensor->lock); + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) + *mf = fmt->format; + mutex_unlock(&sensor->lock); + } + return 0; +} + +static int fimc_is_sensor_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd); + struct v4l2_mbus_framefmt *mf; + + mf = __fimc_is_sensor_get_format(sensor, fh, fmt->pad, fmt->which); + + mutex_lock(&sensor->lock); + fmt->format = *mf; + mutex_unlock(&sensor->lock); + return 0; +} + +static struct v4l2_subdev_pad_ops fimc_is_sensor_pad_ops = { + .enum_mbus_code = fimc_is_sensor_enum_mbus_code, + .get_fmt = fimc_is_sensor_get_fmt, + .set_fmt = fimc_is_sensor_set_fmt, +}; + +static int fimc_is_sensor_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0); + + *format = fimc_is_sensor_formats[0]; + format->width = FIMC_IS_SENSOR_DEF_PIX_WIDTH; + format->height = FIMC_IS_SENSOR_DEF_PIX_HEIGHT; + + return 0; +} + +static const struct v4l2_subdev_internal_ops fimc_is_sensor_sd_internal_ops = { + .open = fimc_is_sensor_open, +}; + +static int fimc_is_sensor_s_power(struct v4l2_subdev *sd, int on) +{ + struct fimc_is_sensor *sensor = v4l2_get_subdevdata(sd); + int gpio = sensor->gpio_reset; + int ret; + + if (on) { + ret = pm_runtime_get(sensor->dev); + if (ret < 0) + return ret; + + ret = regulator_bulk_enable(SENSOR_NUM_SUPPLIES, + sensor->supplies); + if (ret < 0) { + pm_runtime_put(sensor->dev); + return ret; + } + if (gpio_is_valid(gpio)) { + gpio_set_value(gpio, 1); + usleep_range(600, 800); + gpio_set_value(gpio, 0); + usleep_range(10000, 11000); + gpio_set_value(gpio, 1); + } + + /* A delay needed for the sensor initialization. */ + msleep(20); + } else { + if (gpio_is_valid(gpio)) + gpio_set_value(gpio, 0); + + ret = regulator_bulk_disable(SENSOR_NUM_SUPPLIES, + sensor->supplies); + if (!ret) + pm_runtime_put(sensor->dev); + } + + pr_info("%s:%d: on: %d, ret: %d\n", __func__, __LINE__, on, ret); + + return ret; +} + +static struct v4l2_subdev_core_ops fimc_is_sensor_core_ops = { + .s_power = fimc_is_sensor_s_power, +}; + +static struct v4l2_subdev_ops fimc_is_sensor_subdev_ops = { + .core = &fimc_is_sensor_core_ops, + .pad = &fimc_is_sensor_pad_ops, +}; + +static const struct of_device_id fimc_is_sensor_of_match[]; + +static int fimc_is_sensor_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct fimc_is_sensor *sensor; + const struct of_device_id *of_id; + struct v4l2_subdev *sd; + int gpio, i, ret; + + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + mutex_init(&sensor->lock); + sensor->gpio_reset = -EINVAL; + + gpio = of_get_gpio_flags(dev->of_node, 0, NULL); + if (gpio_is_valid(gpio)) { + ret = gpio_request_one(gpio, GPIOF_OUT_INIT_LOW, DRIVER_NAME); + if (ret < 0) + return ret; + } + sensor->gpio_reset = gpio; + + for (i = 0; i < SENSOR_NUM_SUPPLIES; i++) + sensor->supplies[i].supply = sensor_supply_names[i]; + + ret = devm_regulator_bulk_get(&client->dev, SENSOR_NUM_SUPPLIES, + sensor->supplies); + if (ret < 0) + goto err_gpio; + + of_id = of_match_node(fimc_is_sensor_of_match, dev->of_node); + if (!of_id) { + ret = -ENODEV; + goto err_reg; + } + + sensor->drvdata = of_id->data; + sensor->dev = dev; + + sd = &sensor->subdev; + v4l2_i2c_subdev_init(sd, client, &fimc_is_sensor_subdev_ops); + snprintf(sd->name, sizeof(sd->name), sensor->drvdata->subdev_name); + sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + sensor->format.code = fimc_is_sensor_formats[0].code; + sensor->format.width = FIMC_IS_SENSOR_DEF_PIX_WIDTH; + sensor->format.height = FIMC_IS_SENSOR_DEF_PIX_HEIGHT; + + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_init(&sd->entity, 1, &sensor->pad, 0); + if (ret < 0) + goto err_reg; + + v4l2_set_subdevdata(sd, sensor); + pm_runtime_no_callbacks(dev); + pm_runtime_enable(dev); + + return 0; +err_reg: + regulator_bulk_free(SENSOR_NUM_SUPPLIES, sensor->supplies); +err_gpio: + if (gpio_is_valid(sensor->gpio_reset)) + gpio_free(sensor->gpio_reset); + return ret; +} + +static int fimc_is_sensor_remove(struct i2c_client *client) +{ + struct fimc_is_sensor *sensor; + + regulator_bulk_free(SENSOR_NUM_SUPPLIES, sensor->supplies); + media_entity_cleanup(&sensor->subdev.entity); + + return 0; +} + +static const struct i2c_device_id fimc_is_sensor_ids[] = { + { } +}; + +static const struct sensor_drv_data s5k6a3_drvdata = { + .id = FIMC_IS_SENSOR_ID_S5K6A3, + .subdev_name = "S5K6A3", + .width = S5K6A3_SENSOR_WIDTH, + .height = S5K6A3_SENSOR_HEIGHT, +}; + +static const struct of_device_id fimc_is_sensor_of_match[] = { + { + .compatible = "samsung,s5k6a3", + .data = &s5k6a3_drvdata, + }, + { } +}; +MODULE_DEVICE_TABLE(of, fimc_is_sensor_of_match); + +static struct i2c_driver fimc_is_sensor_driver = { + .driver = { + .of_match_table = fimc_is_sensor_of_match, + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = fimc_is_sensor_probe, + .remove = fimc_is_sensor_remove, + .id_table = fimc_is_sensor_ids, +}; + +int fimc_is_register_sensor_driver(void) +{ + return i2c_add_driver(&fimc_is_sensor_driver); +} + +void fimc_is_unregister_sensor_driver(void) +{ + i2c_del_driver(&fimc_is_sensor_driver); +} + +MODULE_AUTHOR("Sylwester Nawrocki "); +MODULE_DESCRIPTION("Exynos4x12 FIMC-IS image sensor subdev driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.h b/drivers/media/platform/exynos4-is/fimc-is-sensor.h new file mode 100644 index 000000000000..50b8e4d59d62 --- /dev/null +++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.h @@ -0,0 +1,83 @@ +/* + * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver + * + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * + * Authors: Sylwester Nawrocki + * Younghwan Joo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef FIMC_IS_SENSOR_H_ +#define FIMC_IS_SENSOR_H_ + +#include +#include +#include +#include +#include +#include +#include + +#define FIMC_IS_SENSOR_OPEN_TIMEOUT 2000 /* ms */ + +#define FIMC_IS_SENSOR_DEF_PIX_WIDTH 1296 +#define FIMC_IS_SENSOR_DEF_PIX_HEIGHT 732 + +#define S5K6A3_SENSOR_WIDTH 1392 +#define S5K6A3_SENSOR_HEIGHT 1392 + +#define SENSOR_NUM_SUPPLIES 2 + +enum fimc_is_sensor_id { + FIMC_IS_SENSOR_ID_S5K3H2 = 1, + FIMC_IS_SENSOR_ID_S5K6A3, + FIMC_IS_SENSOR_ID_S5K4E5, + FIMC_IS_SENSOR_ID_S5K3H7, + FIMC_IS_SENSOR_ID_CUSTOM, + FIMC_IS_SENSOR_ID_END +}; + +#define IS_SENSOR_CTRL_BUS_I2C0 0 +#define IS_SENSOR_CTRL_BUS_I2C1 1 + +struct sensor_drv_data { + enum fimc_is_sensor_id id; + const char * const subdev_name; + unsigned int width; + unsigned int height; +}; + +/** + * struct fimc_is_sensor - fimc-is sensor data structure + * @dev: pointer to this I2C client device structure + * @subdev: the image sensor's v4l2 subdev + * @pad: subdev media source pad + * @supplies: image sensor's voltage regulator supplies + * @gpio_reset: GPIO connected to the sensor's reset pin + * @drvdata: a pointer to the sensor's parameters data structure + * @i2c_bus: ISP I2C bus index (0...1) + * @test_pattern: true to enable video test pattern + * @lock: mutex protecting the structure's members below + * @format: media bus format at the sensor's source pad + */ +struct fimc_is_sensor { + struct device *dev; + struct v4l2_subdev subdev; + struct media_pad pad; + struct regulator_bulk_data supplies[SENSOR_NUM_SUPPLIES]; + int gpio_reset; + const struct sensor_drv_data *drvdata; + unsigned int i2c_bus; + bool test_pattern; + + struct mutex lock; + struct v4l2_mbus_framefmt format; +}; + +int fimc_is_register_sensor_driver(void); +void fimc_is_unregister_sensor_driver(void); + +#endif /* FIMC_IS_SENSOR_H_ */ -- cgit v1.2.3 From e781bbe3fecf05ab8f3c05fd0b693bebb5e489d5 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 21 Mar 2013 14:49:16 -0300 Subject: [media] exynos4-is: Add fimc-is subdevs registration This patch adds support for registration of the FIMC-IS device represented by the FIMC-IS-ISP subdev to the top level media device driver. The FIMC-IS subsystem is available on Exynos4x12 SoCs which support only device tree based booting. Signed-off-by: Sylwester Nawrocki Signed-off-by: Andrzej Hajda Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/media-dev.c | 37 ++++++++++++++++++++++++--- drivers/media/platform/exynos4-is/media-dev.h | 13 ++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index a0fd8cce18df..597648e2bd76 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -32,6 +32,7 @@ #include "media-dev.h" #include "fimc-core.h" +#include "fimc-is.h" #include "fimc-lite.h" #include "mipi-csis.h" @@ -85,9 +86,11 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p, case GRP_ID_FIMC: /* No need to control FIMC subdev through subdev ops */ break; + case GRP_ID_FIMC_IS: + p->subdevs[IDX_IS_ISP] = sd; + break; default: - pr_warn("%s: Unknown subdev grp_id: %#x\n", - __func__, sd->grp_id); + break; } me = &sd->entity; if (me->num_pads == 1) @@ -322,6 +325,7 @@ static void fimc_md_unregister_sensor(struct v4l2_subdev *sd) if (!client) return; + v4l2_device_unregister_subdev(sd); if (!client->dev.of_node) { @@ -372,7 +376,11 @@ static int fimc_md_of_add_sensor(struct fimc_md *fmd, goto mod_put; v4l2_set_subdev_hostdata(sd, si); - sd->grp_id = GRP_ID_SENSOR; + if (si->pdata.fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) + sd->grp_id = GRP_ID_FIMC_IS_SENSOR; + else + sd->grp_id = GRP_ID_SENSOR; + si->subdev = sd; v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice: %s (%d)\n", sd->name, fmd->num_sensors); @@ -652,6 +660,22 @@ static int register_csis_entity(struct fimc_md *fmd, return ret; } +static int register_fimc_is_entity(struct fimc_md *fmd, struct fimc_is *is) +{ + struct v4l2_subdev *sd = &is->isp.subdev; + int ret; + + ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); + if (ret) { + v4l2_err(&fmd->v4l2_dev, + "Failed to register FIMC-ISP (%d)\n", ret); + return ret; + } + + fmd->fimc_is = is; + return 0; +} + static int fimc_md_register_platform_entity(struct fimc_md *fmd, struct platform_device *pdev, int plat_entity) @@ -679,6 +703,9 @@ static int fimc_md_register_platform_entity(struct fimc_md *fmd, case IDX_CSIS: ret = register_csis_entity(fmd, pdev, drvdata); break; + case IDX_IS_ISP: + ret = register_fimc_is_entity(fmd, drvdata); + break; default: ret = -ENODEV; } @@ -742,6 +769,8 @@ static int fimc_md_register_of_platform_entities(struct fimc_md *fmd, /* If driver of any entity isn't ready try all again later. */ if (!strcmp(node->name, CSIS_OF_NODE_NAME)) plat_entity = IDX_CSIS; + else if (!strcmp(node->name, FIMC_IS_OF_NODE_NAME)) + plat_entity = IDX_IS_ISP; else if (!strcmp(node->name, FIMC_LITE_OF_NODE_NAME)) plat_entity = IDX_FLITE; else if (!strcmp(node->name, FIMC_OF_NODE_NAME) && @@ -1308,6 +1337,8 @@ static int fimc_md_probe(struct platform_device *pdev) v4l2_dev->notify = fimc_sensor_notify; strlcpy(v4l2_dev->name, "s5p-fimc-md", sizeof(v4l2_dev->name)); + fmd->use_isp = fimc_md_is_isp_available(dev->of_node); + ret = v4l2_device_register(dev, &fmd->v4l2_dev); if (ret < 0) { v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret); diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h index 1d5cea5a6bbe..0b14cd575747 100644 --- a/drivers/media/platform/exynos4-is/media-dev.h +++ b/drivers/media/platform/exynos4-is/media-dev.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,7 @@ struct fimc_sensor_info { * @num_sensors: actual number of registered sensors * @camclk: external sensor clock information * @fimc: array of registered fimc devices + * @fimc_is: fimc-is data structure * @use_isp: set to true when FIMC-IS subsystem is used * @pmf: handle to the CAMCLK clock control FIMC helper device * @media_dev: top level media device @@ -99,6 +101,7 @@ struct fimc_md { struct clk *wbclk[FIMC_MAX_WBCLKS]; struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS]; struct fimc_dev *fimc[FIMC_MAX_DEVS]; + struct fimc_is *fimc_is; bool use_isp; struct device *pmf; struct media_device media_dev; @@ -139,4 +142,14 @@ static inline void fimc_md_graph_unlock(struct fimc_dev *fimc) int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on); +#ifdef CONFIG_OF +static inline bool fimc_md_is_isp_available(struct device_node *node) +{ + node = of_get_child_by_name(node, FIMC_IS_OF_NODE_NAME); + return node ? of_device_is_available(node) : false; +} +#else +#define fimc_md_is_isp_available(node) (false) +#endif /* CONFIG_OF */ + #endif -- cgit v1.2.3 From f998bb7ba9a8f91b76830944fdf7b3e54eebb639 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 27 Nov 2012 13:29:48 -0300 Subject: [media] exynos4-is: Create media links for the FIMC-IS entities Create disabled links from the FIMC-LITE subdevs to the FIMC-IS-ISP subdev and from FIMC-IS-ISP to all FIMC subdevs. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/media-dev.c | 79 ++++++++++++++++++++------- 1 file changed, 60 insertions(+), 19 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 597648e2bd76..44d6c1d5bf4b 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -838,12 +838,19 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, struct v4l2_subdev *sensor, int pad, int link_mask) { - struct fimc_sensor_info *s_info = NULL; + struct fimc_sensor_info *si = NULL; struct media_entity *sink; unsigned int flags = 0; - int ret, i; + int i, ret = 0; - for (i = 0; i < FIMC_MAX_DEVS; i++) { + if (sensor) { + si = v4l2_get_subdev_hostdata(sensor); + /* Skip direct FIMC links in the logical FIMC-IS sensor path */ + if (si && si->pdata.fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) + ret = 1; + } + + for (i = 0; !ret && i < FIMC_MAX_DEVS; i++) { if (!fmd->fimc[i]) continue; /* @@ -872,11 +879,11 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, if (flags == 0 || sensor == NULL) continue; - s_info = v4l2_get_subdev_hostdata(sensor); - if (!WARN_ON(s_info == NULL)) { + + if (!WARN_ON(si == NULL)) { unsigned long irq_flags; spin_lock_irqsave(&fmd->slock, irq_flags); - s_info->host = fmd->fimc[i]; + si->host = fmd->fimc[i]; spin_unlock_irqrestore(&fmd->slock, irq_flags); } } @@ -885,25 +892,20 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, if (!fmd->fimc_lite[i]) continue; - if (link_mask & (1 << (i + FIMC_MAX_DEVS))) - flags = MEDIA_LNK_FL_ENABLED; - else - flags = 0; - sink = &fmd->fimc_lite[i]->subdev.entity; ret = media_entity_create_link(source, pad, sink, - FLITE_SD_PAD_SINK, flags); + FLITE_SD_PAD_SINK, 0); if (ret) return ret; /* Notify FIMC-LITE subdev entity */ ret = media_entity_call(sink, link_setup, &sink->pads[0], - &source->pads[pad], flags); + &source->pads[pad], 0); if (ret) break; - v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]\n", - source->name, flags ? '=' : '-', sink->name); + v4l2_info(&fmd->v4l2_dev, "created link [%s] -> [%s]\n", + source->name, sink->name); } return 0; } @@ -912,21 +914,50 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, static int __fimc_md_create_flite_source_links(struct fimc_md *fmd) { struct media_entity *source, *sink; - unsigned int flags = MEDIA_LNK_FL_ENABLED; int i, ret = 0; for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) { struct fimc_lite *fimc = fmd->fimc_lite[i]; + if (fimc == NULL) continue; + source = &fimc->subdev.entity; sink = &fimc->vfd.entity; /* FIMC-LITE's subdev and video node */ ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_DMA, - sink, 0, flags); + sink, 0, 0); + if (ret) + break; + /* Link from FIMC-LITE to IS-ISP subdev */ + sink = &fmd->fimc_is->isp.subdev.entity; + ret = media_entity_create_link(source, FLITE_SD_PAD_SOURCE_ISP, + sink, 0, 0); if (ret) break; - /* TODO: create links to other entities */ + } + + return ret; +} + +/* Create FIMC-IS links */ +static int __fimc_md_create_fimc_is_links(struct fimc_md *fmd) +{ + struct media_entity *source, *sink; + int i, ret; + + source = &fmd->fimc_is->isp.subdev.entity; + + for (i = 0; i < FIMC_MAX_DEVS; i++) { + if (fmd->fimc[i] == NULL) + continue; + + /* Link from IS-ISP subdev to FIMC */ + sink = &fmd->fimc[i]->vid_cap.subdev.entity; + ret = media_entity_create_link(source, FIMC_ISP_SD_PAD_SRC_FIFO, + sink, FIMC_SD_PAD_SINK_FIFO, 0); + if (ret) + return ret; } return ret; @@ -1014,6 +1045,7 @@ static int fimc_md_create_links(struct fimc_md *fmd) for (i = 0; i < CSIS_MAX_ENTITIES; i++) { if (fmd->csis[i].sd == NULL) continue; + source = &fmd->csis[i].sd->entity; pad = CSIS_PAD_SOURCE; sensor = csi_sensors[i]; @@ -1028,15 +1060,24 @@ static int fimc_md_create_links(struct fimc_md *fmd) for (i = 0; i < FIMC_MAX_DEVS; i++) { if (!fmd->fimc[i]) continue; + source = &fmd->fimc[i]->vid_cap.subdev.entity; sink = &fmd->fimc[i]->vid_cap.vfd.entity; + ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE, sink, 0, flags); if (ret) break; } - return __fimc_md_create_flite_source_links(fmd); + ret = __fimc_md_create_flite_source_links(fmd); + if (ret < 0) + return ret; + + if (fmd->use_isp) + ret = __fimc_md_create_fimc_is_links(fmd); + + return ret; } /* -- cgit v1.2.3 From 8cec74c60be850c33882a0cec16154082a551a26 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Sun, 24 Feb 2013 18:29:21 -0300 Subject: [media] exynos4-is: Remove static driver data for Exynos4210 FIMC variants The Exynos platform will support only device tree based booting from v3.10. The FIMC variant data will be parsed directly from the device tree, hence the now unused static data can be removed. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-core.c | 35 --------------------------- 1 file changed, 35 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index 6b4a244132fb..90d907e1a5f8 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -1142,14 +1142,6 @@ static const struct fimc_pix_limit s5p_pix_limit[4] = { .out_rot_en_w = 1280, .out_rot_dis_w = 1920, }, - [3] = { - .scaler_en_w = 1920, - .scaler_dis_w = 8192, - .in_rot_en_h = 1366, - .in_rot_dis_w = 8192, - .out_rot_en_w = 1366, - .out_rot_dis_w = 1920, - }, }; static const struct fimc_variant fimc0_variant_s5p = { @@ -1204,27 +1196,6 @@ static const struct fimc_variant fimc2_variant_s5pv210 = { .pix_limit = &s5p_pix_limit[2], }; -static const struct fimc_variant fimc0_variant_exynos4210 = { - .has_inp_rot = 1, - .has_out_rot = 1, - .has_cam_if = 1, - .has_mainscaler_ext = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 2, - .min_vsize_align = 1, - .pix_limit = &s5p_pix_limit[1], -}; - -static const struct fimc_variant fimc3_variant_exynos4210 = { - .has_mainscaler_ext = 1, - .min_inp_pixsize = 16, - .min_out_pixsize = 16, - .hor_offs_align = 2, - .min_vsize_align = 1, - .pix_limit = &s5p_pix_limit[3], -}; - /* S5PC100 */ static const struct fimc_drvdata fimc_drvdata_s5p = { .variant = { @@ -1252,12 +1223,6 @@ static const struct fimc_drvdata fimc_drvdata_s5pv210 = { /* EXYNOS4210, S5PV310, S5PC210 */ static const struct fimc_drvdata fimc_drvdata_exynos4210 = { - .variant = { - [0] = &fimc0_variant_exynos4210, - [1] = &fimc0_variant_exynos4210, - [2] = &fimc0_variant_exynos4210, - [3] = &fimc3_variant_exynos4210, - }, .num_entities = 4, .lclk_frequency = 166000000UL, .dma_pix_hoff = 1, -- cgit v1.2.3 From 9c8399c86cbfce767fb32459f8e0eb33e087f910 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Sat, 16 Mar 2013 17:35:10 -0300 Subject: [media] exynos4-is: Use common driver data for all FIMC-LITE IP instances There is no need to use separate variant data structure for each FIMC-LITE IP instance. According to my knowledge there are no differences across them on Exynos4 as well as Exynos5 SoCs. Drop flite_variant data structure and use struct flite_drvdata instead. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-lite.c | 35 +++++++++++---------------- drivers/media/platform/exynos4-is/fimc-lite.h | 10 +++----- 2 files changed, 17 insertions(+), 28 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 70c0cc2ad3e5..ba35328aaec5 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -528,7 +528,7 @@ static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc, u32 *width, u32 *height, u32 *code, u32 *fourcc, int pad) { - struct flite_variant *variant = fimc->variant; + struct flite_drvdata *dd = fimc->dd; const struct fimc_fmt *fmt; fmt = fimc_lite_find_format(fourcc, code, 0); @@ -541,12 +541,12 @@ static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc, *fourcc = fmt->fourcc; if (pad == FLITE_SD_PAD_SINK) { - v4l_bound_align_image(width, 8, variant->max_width, - ffs(variant->out_width_align) - 1, - height, 0, variant->max_height, 0, 0); + v4l_bound_align_image(width, 8, dd->max_width, + ffs(dd->out_width_align) - 1, + height, 0, dd->max_height, 0, 0); } else { v4l_bound_align_image(width, 8, fimc->inp_frame.rect.width, - ffs(variant->out_width_align) - 1, + ffs(dd->out_width_align) - 1, height, 0, fimc->inp_frame.rect.height, 0, 0); } @@ -566,7 +566,7 @@ static void fimc_lite_try_crop(struct fimc_lite *fimc, struct v4l2_rect *r) /* Adjust left/top if cropping rectangle got out of bounds */ r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width); - r->left = round_down(r->left, fimc->variant->win_hor_offs_align); + r->left = round_down(r->left, fimc->dd->win_hor_offs_align); r->top = clamp_t(u32, r->top, 0, frame->f_height - r->height); v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, sink fmt: %dx%d\n", @@ -586,7 +586,7 @@ static void fimc_lite_try_compose(struct fimc_lite *fimc, struct v4l2_rect *r) /* Adjust left/top if the composing rectangle got out of bounds */ r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width); - r->left = round_down(r->left, fimc->variant->out_hor_offs_align); + r->left = round_down(r->left, fimc->dd->out_hor_offs_align); r->top = clamp_t(u32, r->top, 0, fimc->out_frame.f_height - r->height); v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, source fmt: %dx%d\n", @@ -647,8 +647,8 @@ static int fimc_lite_try_fmt(struct fimc_lite *fimc, struct v4l2_pix_format_mplane *pixm, const struct fimc_fmt **ffmt) { - struct flite_variant *variant = fimc->variant; u32 bpl = pixm->plane_fmt[0].bytesperline; + struct flite_drvdata *dd = fimc->dd; const struct fimc_fmt *fmt; fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0); @@ -656,9 +656,9 @@ static int fimc_lite_try_fmt(struct fimc_lite *fimc, return -EINVAL; if (ffmt) *ffmt = fmt; - v4l_bound_align_image(&pixm->width, 8, variant->max_width, - ffs(variant->out_width_align) - 1, - &pixm->height, 0, variant->max_height, 0, 0); + v4l_bound_align_image(&pixm->width, 8, dd->max_width, + ffs(dd->out_width_align) - 1, + &pixm->height, 0, dd->max_height, 0, 0); if ((bpl == 0 || ((bpl * 8) / fmt->depth[0]) < pixm->width)) pixm->plane_fmt[0].bytesperline = (pixm->width * @@ -1429,7 +1429,7 @@ static int fimc_lite_probe(struct platform_device *pdev) if (!drv_data || fimc->index < 0 || fimc->index >= FIMC_LITE_MAX_DEVS) return -EINVAL; - fimc->variant = drv_data->variant[fimc->index]; + fimc->dd = drv_data; fimc->pdev = pdev; init_waitqueue_head(&fimc->irq_queue); @@ -1577,7 +1577,8 @@ static const struct dev_pm_ops fimc_lite_pm_ops = { NULL) }; -static struct flite_variant fimc_lite0_variant_exynos4 = { +/* EXYNOS4212, EXYNOS4412 */ +static struct flite_drvdata fimc_lite_drvdata_exynos4 = { .max_width = 8192, .max_height = 8192, .out_width_align = 8, @@ -1585,14 +1586,6 @@ static struct flite_variant fimc_lite0_variant_exynos4 = { .out_hor_offs_align = 8, }; -/* EXYNOS4212, EXYNOS4412 */ -static struct flite_drvdata fimc_lite_drvdata_exynos4 = { - .variant = { - [0] = &fimc_lite0_variant_exynos4, - [1] = &fimc_lite0_variant_exynos4, - }, -}; - static struct platform_device_id fimc_lite_driver_ids[] = { { .name = "exynos-fimc-lite", diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index 4c2345086366..0b6380bb5c8a 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -48,7 +48,7 @@ enum { #define FLITE_SD_PAD_SOURCE_ISP 2 #define FLITE_SD_PADS_NUM 3 -struct flite_variant { +struct flite_drvdata { unsigned short max_width; unsigned short max_height; unsigned short out_width_align; @@ -56,10 +56,6 @@ struct flite_variant { unsigned short out_hor_offs_align; }; -struct flite_drvdata { - struct flite_variant *variant[FIMC_LITE_MAX_DEVS]; -}; - #define fimc_lite_get_drvdata(_pdev) \ ((struct flite_drvdata *) platform_get_device_id(_pdev)->driver_data) @@ -96,7 +92,7 @@ struct flite_buffer { /** * struct fimc_lite - fimc lite structure * @pdev: pointer to FIMC-LITE platform device - * @variant: variant information for this IP + * @dd: SoC specific driver data structure * @v4l2_dev: pointer to top the level v4l2_device * @vfd: video device node * @fh: v4l2 file handle @@ -132,7 +128,7 @@ struct flite_buffer { */ struct fimc_lite { struct platform_device *pdev; - struct flite_variant *variant; + struct flite_drvdata *dd; struct v4l2_device *v4l2_dev; struct video_device vfd; struct v4l2_fh fh; -- cgit v1.2.3 From e90ad659cde4d11ccbc935adcfe018799afcc22d Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 20 Mar 2013 15:31:03 -0300 Subject: [media] exynos4-is: Allow colorspace conversion at FIMC-LITE The FIMC-LITE output DMA allows to configure different YUV order than the order at the camera input interface. Thus there is some limited colorspace conversion possible. This patch makes the color format variable be per FIMC-LITE input/output, rather than a global per device. This also fixes incorrect behavior where color format at the FIMC-LITE.N subdev's source pad is modified by VIDIOC_S_FMT ioctl on the related video node. YUV order definitions are corrected so that we use notation: | byte3 | byte2 | byte1 | byte0 -------+-------+-------+-------+------ YCBYCR | CR | Y | CB | Y YCRYCB | CB | Y | CR | Y CBYCRY | Y | CR | Y | CB CRYCBY | Y | CB | Y | CR Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-lite-reg.c | 4 +- drivers/media/platform/exynos4-is/fimc-lite-reg.h | 8 +-- drivers/media/platform/exynos4-is/fimc-lite.c | 76 +++++++++++++++-------- drivers/media/platform/exynos4-is/fimc-lite.h | 4 +- include/media/s5p_fimc.h | 2 + 5 files changed, 61 insertions(+), 33 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c index ac9663ce2a49..8cc0d39a2fea 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c @@ -127,7 +127,7 @@ static const u32 src_pixfmt_map[8][3] = { /* Set camera input pixel format and resolution */ void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f) { - enum v4l2_mbus_pixelcode pixelcode = dev->fmt->mbus_code; + enum v4l2_mbus_pixelcode pixelcode = f->fmt->mbus_code; int i = ARRAY_SIZE(src_pixfmt_map); u32 cfg; @@ -227,7 +227,7 @@ static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f) int i = ARRAY_SIZE(pixcode); while (--i >= 0) - if (pixcode[i][0] == dev->fmt->mbus_code) + if (pixcode[i][0] == f->fmt->mbus_code) break; cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK; writel(cfg | pixcode[i][1], dev->regs + FLITE_REG_CIODMAFMT); diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.h b/drivers/media/platform/exynos4-is/fimc-lite-reg.h index 0e345844c13a..390383941c19 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite-reg.h +++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.h @@ -72,10 +72,10 @@ #define FLITE_REG_CIODMAFMT 0x18 #define FLITE_REG_CIODMAFMT_RAW_CON (1 << 15) #define FLITE_REG_CIODMAFMT_PACK12 (1 << 14) -#define FLITE_REG_CIODMAFMT_CRYCBY (0 << 4) -#define FLITE_REG_CIODMAFMT_CBYCRY (1 << 4) -#define FLITE_REG_CIODMAFMT_YCRYCB (2 << 4) -#define FLITE_REG_CIODMAFMT_YCBYCR (3 << 4) +#define FLITE_REG_CIODMAFMT_YCBYCR (0 << 4) +#define FLITE_REG_CIODMAFMT_YCRYCB (1 << 4) +#define FLITE_REG_CIODMAFMT_CBYCRY (2 << 4) +#define FLITE_REG_CIODMAFMT_CRYCBY (3 << 4) #define FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK (0x3 << 4) /* Camera Output Canvas */ diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index ba35328aaec5..b11e3583b9fa 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -46,6 +46,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .color = FIMC_FMT_YCBYCR422, .memplanes = 1, .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8, + .flags = FMT_FLAGS_YUV, }, { .name = "YUV 4:2:2 packed, CbYCrY", .fourcc = V4L2_PIX_FMT_UYVY, @@ -53,6 +54,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .color = FIMC_FMT_CBYCRY422, .memplanes = 1, .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8, + .flags = FMT_FLAGS_YUV, }, { .name = "YUV 4:2:2 packed, CrYCbY", .fourcc = V4L2_PIX_FMT_VYUY, @@ -60,6 +62,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .color = FIMC_FMT_CRYCBY422, .memplanes = 1, .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8, + .flags = FMT_FLAGS_YUV, }, { .name = "YUV 4:2:2 packed, YCrYCb", .fourcc = V4L2_PIX_FMT_YVYU, @@ -67,6 +70,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .color = FIMC_FMT_YCRYCB422, .memplanes = 1, .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8, + .flags = FMT_FLAGS_YUV, }, { .name = "RAW8 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG8, @@ -74,6 +78,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .color = FIMC_FMT_RAW8, .memplanes = 1, .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8, + .flags = FMT_FLAGS_RAW_BAYER, }, { .name = "RAW10 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG10, @@ -81,6 +86,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .color = FIMC_FMT_RAW10, .memplanes = 1, .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10, + .flags = FMT_FLAGS_RAW_BAYER, }, { .name = "RAW12 (GRBG)", .fourcc = V4L2_PIX_FMT_SGRBG12, @@ -88,6 +94,7 @@ static const struct fimc_fmt fimc_lite_formats[] = { .color = FIMC_FMT_RAW12, .memplanes = 1, .mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12, + .flags = FMT_FLAGS_RAW_BAYER, }, }; @@ -95,10 +102,11 @@ static const struct fimc_fmt fimc_lite_formats[] = { * fimc_lite_find_format - lookup fimc color format by fourcc or media bus code * @pixelformat: fourcc to match, ignored if null * @mbus_code: media bus code to match, ignored if null + * @mask: the color format flags to match * @index: index to the fimc_lite_formats array, ignored if negative */ static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat, - const u32 *mbus_code, int index) + const u32 *mbus_code, unsigned int mask, int index) { const struct fimc_fmt *fmt, *def_fmt = NULL; unsigned int i; @@ -109,6 +117,8 @@ static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat, for (i = 0; i < ARRAY_SIZE(fimc_lite_formats); ++i) { fmt = &fimc_lite_formats[i]; + if (mask && !(fmt->flags & mask)) + continue; if (pixelformat && fmt->fourcc == *pixelformat) return fmt; if (mbus_code && fmt->mbus_code == *mbus_code) @@ -132,7 +142,7 @@ static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output) if (sensor == NULL) return -ENXIO; - if (fimc->fmt == NULL) + if (fimc->inp_frame.fmt == NULL || fimc->out_frame.fmt == NULL) return -EINVAL; /* Get sensor configuration data from the sensor subdev */ @@ -339,13 +349,13 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, const struct v4l2_pix_format_mplane *pixm = NULL; struct fimc_lite *fimc = vq->drv_priv; struct flite_frame *frame = &fimc->out_frame; - const struct fimc_fmt *fmt = fimc->fmt; + const struct fimc_fmt *fmt = frame->fmt; unsigned long wh; int i; if (pfmt) { pixm = &pfmt->fmt.pix_mp; - fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, -1); + fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0, -1); wh = pixm->width * pixm->height; } else { wh = frame->f_width * frame->f_height; @@ -374,10 +384,10 @@ static int buffer_prepare(struct vb2_buffer *vb) struct fimc_lite *fimc = vq->drv_priv; int i; - if (fimc->fmt == NULL) + if (fimc->out_frame.fmt == NULL) return -EINVAL; - for (i = 0; i < fimc->fmt->memplanes; i++) { + for (i = 0; i < fimc->out_frame.fmt->memplanes; i++) { unsigned long size = fimc->payload[i]; if (vb2_plane_size(vb, i) < size) { @@ -530,15 +540,7 @@ static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc, { struct flite_drvdata *dd = fimc->dd; const struct fimc_fmt *fmt; - - fmt = fimc_lite_find_format(fourcc, code, 0); - if (WARN_ON(!fmt)) - return NULL; - - if (code) - *code = fmt->mbus_code; - if (fourcc) - *fourcc = fmt->fourcc; + unsigned int flags = 0; if (pad == FLITE_SD_PAD_SINK) { v4l_bound_align_image(width, 8, dd->max_width, @@ -549,8 +551,18 @@ static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc, ffs(dd->out_width_align) - 1, height, 0, fimc->inp_frame.rect.height, 0, 0); + flags = fimc->inp_frame.fmt->flags; } + fmt = fimc_lite_find_format(fourcc, code, flags, 0); + if (WARN_ON(!fmt)) + return NULL; + + if (code) + *code = fmt->mbus_code; + if (fourcc) + *fourcc = fmt->fourcc; + v4l2_dbg(1, debug, &fimc->subdev, "code: 0x%x, %dx%d\n", code ? *code : 0, *width, *height); @@ -629,7 +641,7 @@ static int fimc_lite_g_fmt_mplane(struct file *file, void *fh, struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; struct v4l2_plane_pix_format *plane_fmt = &pixm->plane_fmt[0]; struct flite_frame *frame = &fimc->out_frame; - const struct fimc_fmt *fmt = fimc->fmt; + const struct fimc_fmt *fmt = frame->fmt; plane_fmt->bytesperline = (frame->f_width * fmt->depth[0]) / 8; plane_fmt->sizeimage = plane_fmt->bytesperline * frame->f_height; @@ -649,9 +661,22 @@ static int fimc_lite_try_fmt(struct fimc_lite *fimc, { u32 bpl = pixm->plane_fmt[0].bytesperline; struct flite_drvdata *dd = fimc->dd; + const struct fimc_fmt *inp_fmt = fimc->inp_frame.fmt; const struct fimc_fmt *fmt; - fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0); + if (WARN_ON(inp_fmt == NULL)) + return -EINVAL; + /* + * We allow some flexibility only for YUV formats. In case of raw + * raw Bayer the FIMC-LITE's output format must match its camera + * interface input format. + */ + if (inp_fmt->flags & FMT_FLAGS_YUV) + fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, + inp_fmt->flags, 0); + else + fmt = inp_fmt; + if (WARN_ON(fmt == NULL)) return -EINVAL; if (ffmt) @@ -697,7 +722,7 @@ static int fimc_lite_s_fmt_mplane(struct file *file, void *priv, if (ret < 0) return ret; - fimc->fmt = fmt; + frame->fmt = fmt; fimc->payload[0] = max((pixm->width * pixm->height * fmt->depth[0]) / 8, pixm->plane_fmt[0].sizeimage); frame->f_width = pixm->width; @@ -723,7 +748,7 @@ static int fimc_pipeline_validate(struct fimc_lite *fimc) struct flite_frame *ff = &fimc->out_frame; sink_fmt.format.width = ff->f_width; sink_fmt.format.height = ff->f_height; - sink_fmt.format.code = fimc->fmt->mbus_code; + sink_fmt.format.code = fimc->inp_frame.fmt->mbus_code; } else { sink_fmt.pad = pad->index; sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; @@ -991,7 +1016,7 @@ static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd, { const struct fimc_fmt *fmt; - fmt = fimc_lite_find_format(NULL, NULL, code->index); + fmt = fimc_lite_find_format(NULL, NULL, 0, code->index); if (!fmt) return -EINVAL; code->code = fmt->mbus_code; @@ -1004,7 +1029,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, { struct fimc_lite *fimc = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf = &fmt->format; - struct flite_frame *f = &fimc->out_frame; + struct flite_frame *f = &fimc->inp_frame; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { mf = v4l2_subdev_get_try_format(fh, fmt->pad); @@ -1014,7 +1039,7 @@ static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd, mf->colorspace = V4L2_COLORSPACE_JPEG; mutex_lock(&fimc->lock); - mf->code = fimc->fmt->mbus_code; + mf->code = f->fmt->mbus_code; if (fmt->pad == FLITE_SD_PAD_SINK) { /* full camera input frame size */ @@ -1066,7 +1091,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, if (fmt->pad == FLITE_SD_PAD_SINK) { sink->f_width = mf->width; sink->f_height = mf->height; - fimc->fmt = ffmt; + sink->fmt = ffmt; /* Set sink crop rectangle */ sink->rect.width = mf->width; sink->rect.height = mf->height; @@ -1078,7 +1103,7 @@ static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd, source->f_height = mf->height; } else { /* Allow changing format only on sink pad */ - mf->code = fimc->fmt->mbus_code; + mf->code = sink->fmt->mbus_code; mf->width = sink->rect.width; mf->height = sink->rect.height; } @@ -1219,7 +1244,8 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) memset(vfd, 0, sizeof(*vfd)); - fimc->fmt = &fimc_lite_formats[0]; + fimc->inp_frame.fmt = &fimc_lite_formats[0]; + fimc->out_frame.fmt = &fimc_lite_formats[0]; atomic_set(&fimc->out_path, FIMC_IO_DMA); snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture", diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index 0b6380bb5c8a..8a8d26f58344 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -70,11 +70,13 @@ struct fimc_lite_events { * @f_width: full pixel width * @f_height: full pixel height * @rect: crop/composition rectangle + * @fmt: pointer to pixel format description data structure */ struct flite_frame { u16 f_width; u16 f_height; struct v4l2_rect rect; + const struct fimc_fmt *fmt; }; /** @@ -111,7 +113,6 @@ struct flite_buffer { * @clock: FIMC-LITE gate clock * @regs: memory mapped io registers * @irq_queue: interrupt handler waitqueue - * @fmt: pointer to color format description structure * @payload: image size in bytes (w x h x bpp) * @inp_frame: camera input frame structure * @out_frame: DMA output frame structure @@ -150,7 +151,6 @@ struct fimc_lite { void __iomem *regs; wait_queue_head_t irq_queue; - const struct fimc_fmt *fmt; unsigned long payload[FLITE_MAX_PLANES]; struct flite_frame inp_frame; struct flite_frame out_frame; diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index 2363aff24df7..e316d15896f9 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -125,6 +125,8 @@ struct fimc_fmt { #define FMT_HAS_ALPHA (1 << 3) #define FMT_FLAGS_COMPRESSED (1 << 4) #define FMT_FLAGS_WRITEBACK (1 << 5) +#define FMT_FLAGS_RAW_BAYER (1 << 6) +#define FMT_FLAGS_YUV (1 << 7) }; enum fimc_subdev_index { -- cgit v1.2.3 From 439797980af4bddfc2b86a44ddb573c5e48a1fcc Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 21 Mar 2013 14:22:34 -0300 Subject: [media] exynos4-is: Correct input DMA YUV order configuration This patch fixes erroneous setup of the YUV order caused by not clearing FIMC_REG_MSCTRL_ORDER422_MASK bit field before setting proper FIMC_REG_MSCTRL_ORDER422 bits. This resulted in false colors for YUYV, YVYU, UYVY, VYUY color formats, depending in what sequence those were configured by user space. YUV order definitions are corrected so that following convention is used: | byte3 | byte2 | byte1 | byte0 -------+-------+-------+-------+------ YCBYCR | CR | Y | CB | Y YCRYCB | CB | Y | CR | Y CBYCRY | Y | CR | Y | CB CRYCBY | Y | CB | Y | CR Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-core.c | 16 ++++++++-------- drivers/media/platform/exynos4-is/fimc-reg.c | 3 ++- drivers/media/platform/exynos4-is/fimc-reg.h | 16 ++++++++-------- 3 files changed, 18 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index 90d907e1a5f8..f25807d7bc8a 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -412,34 +412,34 @@ void fimc_set_yuv_order(struct fimc_ctx *ctx) /* Set order for 1 plane input formats. */ switch (ctx->s_frame.fmt->color) { case FIMC_FMT_YCRYCB422: - ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CBYCRY; + ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCRYCB; break; case FIMC_FMT_CBYCRY422: - ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCRYCB; + ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CBYCRY; break; case FIMC_FMT_CRYCBY422: - ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCBYCR; + ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CRYCBY; break; case FIMC_FMT_YCBYCR422: default: - ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CRYCBY; + ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCBYCR; break; } dbg("ctx->in_order_1p= %d", ctx->in_order_1p); switch (ctx->d_frame.fmt->color) { case FIMC_FMT_YCRYCB422: - ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CBYCRY; + ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCRYCB; break; case FIMC_FMT_CBYCRY422: - ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCRYCB; + ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CBYCRY; break; case FIMC_FMT_CRYCBY422: - ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCBYCR; + ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CRYCBY; break; case FIMC_FMT_YCBYCR422: default: - ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CRYCBY; + ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCBYCR; break; } dbg("ctx->out_order_1p= %d", ctx->out_order_1p); diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c index c82e9bdaae94..f079f36099de 100644 --- a/drivers/media/platform/exynos4-is/fimc-reg.c +++ b/drivers/media/platform/exynos4-is/fimc-reg.c @@ -449,7 +449,8 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx) | FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK | FIMC_REG_MSCTRL_INPUT_MASK | FIMC_REG_MSCTRL_C_INT_IN_MASK - | FIMC_REG_MSCTRL_2P_IN_ORDER_MASK); + | FIMC_REG_MSCTRL_2P_IN_ORDER_MASK + | FIMC_REG_MSCTRL_ORDER422_MASK); cfg |= (FIMC_REG_MSCTRL_IN_BURST_COUNT(4) | FIMC_REG_MSCTRL_INPUT_MEMORY diff --git a/drivers/media/platform/exynos4-is/fimc-reg.h b/drivers/media/platform/exynos4-is/fimc-reg.h index 01da7f3622bf..6c97798c75a5 100644 --- a/drivers/media/platform/exynos4-is/fimc-reg.h +++ b/drivers/media/platform/exynos4-is/fimc-reg.h @@ -95,10 +95,10 @@ /* Output DMA control */ #define FIMC_REG_CIOCTRL 0x4c #define FIMC_REG_CIOCTRL_ORDER422_MASK (3 << 0) -#define FIMC_REG_CIOCTRL_ORDER422_CRYCBY (0 << 0) -#define FIMC_REG_CIOCTRL_ORDER422_CBYCRY (1 << 0) -#define FIMC_REG_CIOCTRL_ORDER422_YCRYCB (2 << 0) -#define FIMC_REG_CIOCTRL_ORDER422_YCBYCR (3 << 0) +#define FIMC_REG_CIOCTRL_ORDER422_YCBYCR (0 << 0) +#define FIMC_REG_CIOCTRL_ORDER422_YCRYCB (1 << 0) +#define FIMC_REG_CIOCTRL_ORDER422_CBYCRY (2 << 0) +#define FIMC_REG_CIOCTRL_ORDER422_CRYCBY (3 << 0) #define FIMC_REG_CIOCTRL_LASTIRQ_ENABLE (1 << 2) #define FIMC_REG_CIOCTRL_YCBCR_3PLANE (0 << 3) #define FIMC_REG_CIOCTRL_YCBCR_2PLANE (1 << 3) @@ -220,10 +220,10 @@ #define FIMC_REG_MSCTRL_FLIP_180 (3 << 13) #define FIMC_REG_MSCTRL_FIFO_CTRL_FULL (1 << 12) #define FIMC_REG_MSCTRL_ORDER422_SHIFT 4 -#define FIMC_REG_MSCTRL_ORDER422_YCBYCR (0 << 4) -#define FIMC_REG_MSCTRL_ORDER422_CBYCRY (1 << 4) -#define FIMC_REG_MSCTRL_ORDER422_YCRYCB (2 << 4) -#define FIMC_REG_MSCTRL_ORDER422_CRYCBY (3 << 4) +#define FIMC_REG_MSCTRL_ORDER422_CRYCBY (0 << 4) +#define FIMC_REG_MSCTRL_ORDER422_YCRYCB (1 << 4) +#define FIMC_REG_MSCTRL_ORDER422_CBYCRY (2 << 4) +#define FIMC_REG_MSCTRL_ORDER422_YCBYCR (3 << 4) #define FIMC_REG_MSCTRL_ORDER422_MASK (3 << 4) #define FIMC_REG_MSCTRL_INPUT_EXTCAM (0 << 3) #define FIMC_REG_MSCTRL_INPUT_MEMORY (1 << 3) -- cgit v1.2.3 From 9ea89e2b62c70f3986c89363818a89c8c11c96c4 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 25 Mar 2013 16:50:50 -0300 Subject: [media] exynos4-is: Ensure proper media pipeline state on device close Make sure media_entity_pipeline_stop() is called on video device close in cases where there was VIDIOC_STREAMON ioctl and no VIDIOC_STREAMOFF. This patch fixes media entities stream_count state which could prevent links from being disconnected, due to non-zero stream_count. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-capture.c | 18 +++++++++++++----- drivers/media/platform/exynos4-is/fimc-core.h | 1 + drivers/media/platform/exynos4-is/fimc-lite.c | 18 ++++++++++++++---- drivers/media/platform/exynos4-is/fimc-lite.h | 1 + 4 files changed, 29 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 965b07f36e3c..28c6b26f6ff5 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -551,6 +551,7 @@ unlock: static int fimc_capture_release(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); + struct fimc_vid_cap *vc = &fimc->vid_cap; int ret; dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); @@ -558,6 +559,10 @@ static int fimc_capture_release(struct file *file) mutex_lock(&fimc->lock); if (v4l2_fh_is_singular_file(file)) { + if (vc->streaming) { + media_entity_pipeline_stop(&vc->vfd.entity); + vc->streaming = false; + } clear_bit(ST_CAPT_BUSY, &fimc->state); fimc_stop_capture(fimc, false); fimc_pipeline_call(fimc, close, &fimc->pipeline); @@ -1243,8 +1248,10 @@ static int fimc_cap_streamon(struct file *file, void *priv, } ret = vb2_ioctl_streamon(file, priv, type); - if (!ret) + if (!ret) { + vc->streaming = true; return ret; + } err_p_stop: media_entity_pipeline_stop(entity); @@ -1258,11 +1265,12 @@ static int fimc_cap_streamoff(struct file *file, void *priv, int ret; ret = vb2_ioctl_streamoff(file, priv, type); + if (ret < 0) + return ret; - if (ret == 0) - media_entity_pipeline_stop(&fimc->vid_cap.vfd.entity); - - return ret; + media_entity_pipeline_stop(&fimc->vid_cap.vfd.entity); + fimc->vid_cap.streaming = false; + return 0; } static int fimc_cap_reqbufs(struct file *file, void *priv, diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h index 7d361b24dfd7..d2fe162485a3 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.h +++ b/drivers/media/platform/exynos4-is/fimc-core.h @@ -319,6 +319,7 @@ struct fimc_vid_cap { int buf_index; unsigned int frame_count; unsigned int reqbufs_count; + bool streaming; int input_index; int refcnt; u32 input; diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index b11e3583b9fa..cb196b85a858 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -507,6 +507,10 @@ static int fimc_lite_release(struct file *file) if (v4l2_fh_is_singular_file(file) && atomic_read(&fimc->out_path) == FIMC_IO_DMA) { + if (fimc->streaming) { + media_entity_pipeline_stop(&fimc->vfd.entity); + fimc->streaming = false; + } clear_bit(ST_FLITE_IN_USE, &fimc->state); fimc_lite_stop_capture(fimc, false); fimc_pipeline_call(fimc, close, &fimc->pipeline); @@ -798,8 +802,11 @@ static int fimc_lite_streamon(struct file *file, void *priv, goto err_p_stop; ret = vb2_ioctl_streamon(file, priv, type); - if (!ret) + if (!ret) { + fimc->streaming = true; return ret; + } + err_p_stop: media_entity_pipeline_stop(entity); return 0; @@ -812,9 +819,12 @@ static int fimc_lite_streamoff(struct file *file, void *priv, int ret; ret = vb2_ioctl_streamoff(file, priv, type); - if (ret == 0) - media_entity_pipeline_stop(&fimc->vfd.entity); - return ret; + if (ret < 0) + return ret; + + media_entity_pipeline_stop(&fimc->vfd.entity); + fimc->streaming = false; + return 0; } static int fimc_lite_reqbufs(struct file *file, void *priv, diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index 8a8d26f58344..71fed5129e30 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -166,6 +166,7 @@ struct fimc_lite { int ref_count; struct fimc_lite_events events; + bool streaming; }; static inline bool fimc_lite_active(struct fimc_lite *fimc) -- cgit v1.2.3 From fde04ab95d43e55959f12b92711b0ca4fed40637 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 4 Apr 2013 13:25:30 -0300 Subject: [media] demux.h: Remove duplicated enum "enum dmx_ts_pes" and "typedef enum dmx_pes_type_t" are just the same enum declared twice, since Kernel (2.6.12). There's no reason to duplicate it there, and sparse complains about that: drivers/media/dvb-core/dmxdev.c:600:55: warning: mixing different enum types So, remove the internal define, keeping just the external one. Internally, use only "enum dmx_ts_pes", as it is too late to drop dmx_pes_type_t from the userspace API. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/demux.h | 39 ----------------------- drivers/media/dvb-core/dmxdev.c | 2 +- drivers/media/dvb-core/dvb_demux.c | 6 ++-- drivers/media/dvb-core/dvb_demux.h | 4 +-- drivers/media/dvb-core/dvb_net.c | 2 +- drivers/media/firewire/firedtv-dvb.c | 14 ++++---- drivers/media/pci/ttpci/av7110.c | 6 ++-- drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c | 10 +++--- drivers/media/usb/ttusb-dec/ttusb_dec.c | 20 ++++++------ include/uapi/linux/dvb/dmx.h | 2 +- 10 files changed, 33 insertions(+), 72 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h index eb91fd808c16..833191bcd810 100644 --- a/drivers/media/dvb-core/demux.h +++ b/drivers/media/dvb-core/demux.h @@ -83,45 +83,6 @@ enum dmx_success { #define TS_DEMUX 8 /* in case TS_PACKET is set, send the TS to the demux device, not to the dvr device */ -/* PES type for filters which write to built-in decoder */ -/* these should be kept identical to the types in dmx.h */ - -enum dmx_ts_pes -{ /* also send packets to decoder (if it exists) */ - DMX_TS_PES_AUDIO0, - DMX_TS_PES_VIDEO0, - DMX_TS_PES_TELETEXT0, - DMX_TS_PES_SUBTITLE0, - DMX_TS_PES_PCR0, - - DMX_TS_PES_AUDIO1, - DMX_TS_PES_VIDEO1, - DMX_TS_PES_TELETEXT1, - DMX_TS_PES_SUBTITLE1, - DMX_TS_PES_PCR1, - - DMX_TS_PES_AUDIO2, - DMX_TS_PES_VIDEO2, - DMX_TS_PES_TELETEXT2, - DMX_TS_PES_SUBTITLE2, - DMX_TS_PES_PCR2, - - DMX_TS_PES_AUDIO3, - DMX_TS_PES_VIDEO3, - DMX_TS_PES_TELETEXT3, - DMX_TS_PES_SUBTITLE3, - DMX_TS_PES_PCR3, - - DMX_TS_PES_OTHER -}; - -#define DMX_TS_PES_AUDIO DMX_TS_PES_AUDIO0 -#define DMX_TS_PES_VIDEO DMX_TS_PES_VIDEO0 -#define DMX_TS_PES_TELETEXT DMX_TS_PES_TELETEXT0 -#define DMX_TS_PES_SUBTITLE DMX_TS_PES_SUBTITLE0 -#define DMX_TS_PES_PCR DMX_TS_PES_PCR0 - - struct dmx_ts_feed { int is_filtering; /* Set to non-zero when filtering in progress */ struct dmx_demux *parent; /* Back-pointer */ diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 8896993e631f..a1a3a5159d71 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -569,7 +569,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, dmx_output_t otype; int ret; int ts_type; - dmx_pes_type_t ts_pes; + enum dmx_ts_pes ts_pes; struct dmx_ts_feed *tsfeed; feed->ts = NULL; diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 71641b2dde6b..3485655fa082 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -674,7 +674,7 @@ static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, return -ERESTARTSYS; if (ts_type & TS_DECODER) { - if (pes_type >= DMX_TS_PES_OTHER) { + if (pes_type >= DMX_PES_OTHER) { mutex_unlock(&demux->mutex); return -EINVAL; } @@ -846,7 +846,7 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, feed->pid = 0xffff; - if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER) + if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_PES_OTHER) demux->pesfilter[feed->pes_type] = NULL; mutex_unlock(&demux->mutex); @@ -1268,7 +1268,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) INIT_LIST_HEAD(&dvbdemux->frontend_list); - for (i = 0; i < DMX_TS_PES_OTHER; i++) { + for (i = 0; i < DMX_PES_OTHER; i++) { dvbdemux->pesfilter[i] = NULL; dvbdemux->pids[i] = 0xffff; } diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index fa7188a253aa..ae7fc33c3231 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -119,8 +119,8 @@ struct dvb_demux { struct list_head frontend_list; - struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER]; - u16 pids[DMX_TS_PES_OTHER]; + struct dvb_demux_feed *pesfilter[DMX_PES_OTHER]; + u16 pids[DMX_PES_OTHER]; int playing; int recording; diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index 44225b186f6d..e17cb85d3ecf 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -1044,7 +1044,7 @@ static int dvb_net_feed_start(struct net_device *dev) ret = priv->tsfeed->set(priv->tsfeed, priv->pid, /* pid */ TS_PACKET, /* type */ - DMX_TS_PES_OTHER, /* pes type */ + DMX_PES_OTHER, /* pes type */ 32768, /* circular buffer size */ timeout /* timeout */ ); diff --git a/drivers/media/firewire/firedtv-dvb.c b/drivers/media/firewire/firedtv-dvb.c index eb7496eab130..f710e17953e3 100644 --- a/drivers/media/firewire/firedtv-dvb.c +++ b/drivers/media/firewire/firedtv-dvb.c @@ -71,11 +71,11 @@ int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed) if (dvbdmxfeed->type == DMX_TYPE_TS) { switch (dvbdmxfeed->pes_type) { - case DMX_TS_PES_VIDEO: - case DMX_TS_PES_AUDIO: - case DMX_TS_PES_TELETEXT: - case DMX_TS_PES_PCR: - case DMX_TS_PES_OTHER: + case DMX_PES_VIDEO: + case DMX_PES_AUDIO: + case DMX_PES_TELETEXT: + case DMX_PES_PCR: + case DMX_PES_OTHER: c = alloc_channel(fdtv); break; default: @@ -132,7 +132,7 @@ int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) (demux->dmx.frontend->source != DMX_MEMORY_FE))) { if (dvbdmxfeed->ts_type & TS_DECODER) { - if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER || + if (dvbdmxfeed->pes_type >= DMX_PES_OTHER || !demux->pesfilter[dvbdmxfeed->pes_type]) return -EINVAL; @@ -141,7 +141,7 @@ int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed) } if (!(dvbdmxfeed->ts_type & TS_DECODER && - dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) + dvbdmxfeed->pes_type < DMX_PES_OTHER)) return 0; } diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index 3dc7aa9b6f40..f38329d29daa 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -990,7 +990,7 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) if (feed->type == DMX_TYPE_TS) { if ((feed->ts_type & TS_DECODER) && - (feed->pes_type <= DMX_TS_PES_PCR)) { + (feed->pes_type <= DMX_PES_PCR)) { switch (demux->dmx.frontend->source) { case DMX_MEMORY_FE: if (feed->ts_type & TS_DECODER) @@ -1051,14 +1051,14 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed) if (feed->type == DMX_TYPE_TS) { if (feed->ts_type & TS_DECODER) { - if (feed->pes_type >= DMX_TS_PES_OTHER || + if (feed->pes_type >= DMX_PES_OTHER || !demux->pesfilter[feed->pes_type]) return -EINVAL; demux->pids[feed->pes_type] |= 0x8000; demux->pesfilter[feed->pes_type] = NULL; } if (feed->ts_type & TS_DECODER && - feed->pes_type < DMX_TS_PES_OTHER) { + feed->pes_type < DMX_PES_OTHER) { ret = dvb_feed_stop_pid(feed); } else if ((feed->ts_type & TS_PACKET) && diff --git a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c index e40718552850..21b9049c7b3f 100644 --- a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c @@ -930,11 +930,11 @@ static int ttusb_start_feed(struct dvb_demux_feed *dvbdmxfeed) if (dvbdmxfeed->type == DMX_TYPE_TS) { switch (dvbdmxfeed->pes_type) { - case DMX_TS_PES_VIDEO: - case DMX_TS_PES_AUDIO: - case DMX_TS_PES_TELETEXT: - case DMX_TS_PES_PCR: - case DMX_TS_PES_OTHER: + case DMX_PES_VIDEO: + case DMX_PES_AUDIO: + case DMX_PES_TELETEXT: + case DMX_PES_PCR: + case DMX_PES_OTHER: break; default: return -EINVAL; diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 504c81230339..e52c3b97f304 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -951,34 +951,34 @@ static int ttusb_dec_start_ts_feed(struct dvb_demux_feed *dvbdmxfeed) switch (dvbdmxfeed->pes_type) { - case DMX_TS_PES_VIDEO: - dprintk(" pes_type: DMX_TS_PES_VIDEO\n"); + case DMX_PES_VIDEO: + dprintk(" pes_type: DMX_PES_VIDEO\n"); dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; dec->pid[DMX_PES_VIDEO] = dvbdmxfeed->pid; dec->video_filter = dvbdmxfeed->filter; ttusb_dec_set_pids(dec); break; - case DMX_TS_PES_AUDIO: - dprintk(" pes_type: DMX_TS_PES_AUDIO\n"); + case DMX_PES_AUDIO: + dprintk(" pes_type: DMX_PES_AUDIO\n"); dec->pid[DMX_PES_AUDIO] = dvbdmxfeed->pid; dec->audio_filter = dvbdmxfeed->filter; ttusb_dec_set_pids(dec); break; - case DMX_TS_PES_TELETEXT: + case DMX_PES_TELETEXT: dec->pid[DMX_PES_TELETEXT] = dvbdmxfeed->pid; - dprintk(" pes_type: DMX_TS_PES_TELETEXT(not supported)\n"); + dprintk(" pes_type: DMX_PES_TELETEXT(not supported)\n"); return -ENOSYS; - case DMX_TS_PES_PCR: - dprintk(" pes_type: DMX_TS_PES_PCR\n"); + case DMX_PES_PCR: + dprintk(" pes_type: DMX_PES_PCR\n"); dec->pid[DMX_PES_PCR] = dvbdmxfeed->pid; ttusb_dec_set_pids(dec); break; - case DMX_TS_PES_OTHER: - dprintk(" pes_type: DMX_TS_PES_OTHER(not supported)\n"); + case DMX_PES_OTHER: + dprintk(" pes_type: DMX_PES_OTHER(not supported)\n"); return -ENOSYS; default: diff --git a/include/uapi/linux/dvb/dmx.h b/include/uapi/linux/dvb/dmx.h index b2a9ad8cafdc..b4fb650d9d4f 100644 --- a/include/uapi/linux/dvb/dmx.h +++ b/include/uapi/linux/dvb/dmx.h @@ -51,7 +51,7 @@ typedef enum } dmx_input_t; -typedef enum +typedef enum dmx_ts_pes { DMX_PES_AUDIO0, DMX_PES_VIDEO0, -- cgit v1.2.3 From a9bd87c232b87014b20fdf52416f80c5c1e869fc Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 4 Apr 2013 16:32:09 -0300 Subject: [media] MEDIA: ttusbir, fix double free rc_unregister_device already calls rc_free_device to free the passed device. But in one of ttusbir's probe fail paths, we call rc_unregister_device _and_ rc_free_device. This is wrong and results in a double free. Instead, set rc to NULL resulting in rc_free_device being a noop. Signed-off-by: Jiri Slaby Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ttusbir.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c index cf0d47f57fb2..891762d167ed 100644 --- a/drivers/media/rc/ttusbir.c +++ b/drivers/media/rc/ttusbir.c @@ -347,6 +347,7 @@ static int ttusbir_probe(struct usb_interface *intf, return 0; out3: rc_unregister_device(rc); + rc = NULL; out2: led_classdev_unregister(&tt->led); out: -- cgit v1.2.3 From 48a8a03b5806179f12dd6994a6957f797c13675f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 5 Apr 2013 12:18:54 -0300 Subject: [media] cx88: kernel bz#9476: Fix tone setting for Nova-S+ model 92001 Hauppauge Nova-S-Plus DVB-S model 92001 does not lock on horizontal polarisation. According with the info provided at the BZ, model 92002 does. The difference is that, on model 92001, the tone select is done via isl6421, while, on other devices, this is done via cx24123 code. This patch adds a way to override the demod's set_tone at isl6421 driver. In order to avoid regressions, the override is enabled only for cx88 Nova S plus model 92001. For all other models and devices, the set_tone is provided by the demod driver. Patch originally proposed at bz@9476[1] by Michel Meyers and John Donoghue but applying the original patch would break support for all other devices based on isl6421. [1] https://bugzilla.kernel.org/show_bug.cgi?id=9476 Tested-by: Adam Sampson Tested-by: Hans-Peter Jansen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/b2c2/flexcop-fe-tuner.c | 4 ++-- drivers/media/dvb-frontends/isl6421.c | 28 +++++++++++++++++++++++++++- drivers/media/dvb-frontends/isl6421.h | 4 ++-- drivers/media/pci/cx88/cx88-cards.c | 1 + drivers/media/pci/cx88/cx88-dvb.c | 16 ++++++++++++---- drivers/media/pci/cx88/cx88.h | 1 + drivers/media/pci/saa7134/saa7134-dvb.c | 8 +++++--- 7 files changed, 50 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/b2c2/flexcop-fe-tuner.c b/drivers/media/common/b2c2/flexcop-fe-tuner.c index 850a6c606750..7e14e90d2922 100644 --- a/drivers/media/common/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/common/b2c2/flexcop-fe-tuner.c @@ -325,7 +325,7 @@ static int skystar2_rev27_attach(struct flexcop_device *fc, /* enable no_base_addr - no repeated start when reading */ fc->fc_i2c_adap[2].no_base_addr = 1; if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, - 0x08, 1, 1)) { + 0x08, 1, 1, false)) { err("ISL6421 could NOT be attached"); goto fail_isl; } @@ -391,7 +391,7 @@ static int skystar2_rev28_attach(struct flexcop_device *fc, fc->fc_i2c_adap[2].no_base_addr = 1; if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, - 0x08, 0, 0)) { + 0x08, 0, 0, false)) { err("ISL6421 could NOT be attached"); fc->fc_i2c_adap[2].no_base_addr = 0; return 0; diff --git a/drivers/media/dvb-frontends/isl6421.c b/drivers/media/dvb-frontends/isl6421.c index 0cb3f0f74c9c..c77002fcc8e2 100644 --- a/drivers/media/dvb-frontends/isl6421.c +++ b/drivers/media/dvb-frontends/isl6421.c @@ -89,6 +89,30 @@ static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO; } +static int isl6421_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv; + struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0, + .buf = &isl6421->config, + .len = sizeof(isl6421->config) }; + + switch (tone) { + case SEC_TONE_ON: + isl6421->config |= ISL6421_ENT1; + break; + case SEC_TONE_OFF: + isl6421->config &= ~ISL6421_ENT1; + break; + default: + return -EINVAL; + } + + isl6421->config |= isl6421->override_or; + isl6421->config &= isl6421->override_and; + + return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + static void isl6421_release(struct dvb_frontend *fe) { /* power off */ @@ -100,7 +124,7 @@ static void isl6421_release(struct dvb_frontend *fe) } struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, - u8 override_set, u8 override_clear) + u8 override_set, u8 override_clear, bool override_tone) { struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL); if (!isl6421) @@ -131,6 +155,8 @@ struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter /* override frontend ops */ fe->ops.set_voltage = isl6421_set_voltage; fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage; + if (override_tone) + fe->ops.set_tone = isl6421_set_tone; return fe; } diff --git a/drivers/media/dvb-frontends/isl6421.h b/drivers/media/dvb-frontends/isl6421.h index e7ca7d12b50a..630e7f8a150e 100644 --- a/drivers/media/dvb-frontends/isl6421.h +++ b/drivers/media/dvb-frontends/isl6421.h @@ -42,10 +42,10 @@ #if IS_ENABLED(CONFIG_DVB_ISL6421) /* override_set and override_clear control which system register bits (above) to always set & clear */ extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, - u8 override_set, u8 override_clear); + u8 override_set, u8 override_clear, bool override_tone); #else static inline struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, - u8 override_set, u8 override_clear) + u8 override_set, u8 override_clear, bool override_tone) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index e2e0b8faf7a4..07b700a9ed7f 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c @@ -2855,6 +2855,7 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) core->board.tuner_type = tv.tuner_type; core->tuner_formats = tv.tuner_formats; core->board.radio.type = tv.has_radio ? CX88_RADIO : 0; + core->model = tv.model; /* Make sure we support the board model */ switch (tv.model) diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index 672b267a2d3e..053ed1ba1d85 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -1042,7 +1042,7 @@ static int dvb_register(struct cx8802_dev *dev) if (!dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->core->i2c_adap, - 0x08, ISL6421_DCL, 0x00)) + 0x08, ISL6421_DCL, 0x00, false)) goto frontend_detach; } /* MFE frontend 2 */ @@ -1279,8 +1279,16 @@ static int dvb_register(struct cx8802_dev *dev) &hauppauge_novas_config, &core->i2c_adap); if (fe0->dvb.frontend) { + bool override_tone; + + if (core->model == 92001) + override_tone = true; + else + override_tone = false; + if (!dvb_attach(isl6421_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x08, ISL6421_DCL, 0x00)) + &core->i2c_adap, 0x08, ISL6421_DCL, 0x00, + override_tone)) goto frontend_detach; } break; @@ -1403,7 +1411,7 @@ static int dvb_register(struct cx8802_dev *dev) if (!dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->core->i2c_adap, - 0x08, ISL6421_DCL, 0x00)) + 0x08, ISL6421_DCL, 0x00, false)) goto frontend_detach; } /* MFE frontend 2 */ @@ -1431,7 +1439,7 @@ static int dvb_register(struct cx8802_dev *dev) if (!dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->core->i2c_adap, - 0x08, ISL6421_DCL, 0x00)) + 0x08, ISL6421_DCL, 0x00, false)) goto frontend_detach; } break; diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index eca02c2435de..4e29c9deb684 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -334,6 +334,7 @@ struct cx88_core { /* board name */ int nr; char name[32]; + u32 model; /* pci stuff */ int pci_bus; diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c index 27915e501db9..45271390d7fb 100644 --- a/drivers/media/pci/saa7134/saa7134-dvb.c +++ b/drivers/media/pci/saa7134/saa7134-dvb.c @@ -1391,8 +1391,9 @@ static int dvb_init(struct saa7134_dev *dev) wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__); goto detach_frontend; } - if (dvb_attach(isl6421_attach, fe0->dvb.frontend, &dev->i2c_adap, - 0x08, 0, 0) == NULL) { + if (dvb_attach(isl6421_attach, fe0->dvb.frontend, + &dev->i2c_adap, + 0x08, 0, 0, false) == NULL) { wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__); goto detach_frontend; } @@ -1509,7 +1510,8 @@ static int dvb_init(struct saa7134_dev *dev) goto detach_frontend; } if (dvb_attach(isl6421_attach, fe0->dvb.frontend, - &dev->i2c_adap, 0x08, 0, 0) == NULL) { + &dev->i2c_adap, + 0x08, 0, 0, false) == NULL) { wprintk("%s: No ISL6421 found!\n", __func__); goto detach_frontend; } -- cgit v1.2.3 From 2f719f7a9aa599bc9e1516190336a4ac5c59b18a Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sun, 3 Feb 2013 22:47:38 -0300 Subject: [media] tda8290: Allow disabling I2C gate Allow disabling I2C gate handling by external configuration. This is required by cards that have all devices on a single I2C bus, like AverMedia A706. Signed-off-by: Ondrej Zary Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tda8290.c | 49 +++++++++++++++++++++++++----------------- drivers/media/tuners/tda8290.h | 1 + 2 files changed, 30 insertions(+), 20 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c index 8c4852114eeb..a2b7a9fbd344 100644 --- a/drivers/media/tuners/tda8290.c +++ b/drivers/media/tuners/tda8290.c @@ -233,7 +233,8 @@ static void tda8290_set_params(struct dvb_frontend *fe, } - tda8290_i2c_bridge(fe, 1); + if (fe->ops.analog_ops.i2c_gate_ctrl) + fe->ops.analog_ops.i2c_gate_ctrl(fe, 1); if (fe->ops.tuner_ops.set_analog_params) fe->ops.tuner_ops.set_analog_params(fe, params); @@ -302,7 +303,8 @@ static void tda8290_set_params(struct dvb_frontend *fe, } } - tda8290_i2c_bridge(fe, 0); + if (fe->ops.analog_ops.i2c_gate_ctrl) + fe->ops.analog_ops.i2c_gate_ctrl(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); } @@ -424,7 +426,8 @@ static void tda8295_set_params(struct dvb_frontend *fe, tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); msleep(20); - tda8295_i2c_bridge(fe, 1); + if (fe->ops.analog_ops.i2c_gate_ctrl) + fe->ops.analog_ops.i2c_gate_ctrl(fe, 1); if (fe->ops.tuner_ops.set_analog_params) fe->ops.tuner_ops.set_analog_params(fe, params); @@ -437,7 +440,8 @@ static void tda8295_set_params(struct dvb_frontend *fe, else tuner_dbg("tda8295 not locked, no signal?\n"); - tda8295_i2c_bridge(fe, 0); + if (fe->ops.analog_ops.i2c_gate_ctrl) + fe->ops.analog_ops.i2c_gate_ctrl(fe, 0); } /*---------------------------------------------------------------------*/ @@ -465,11 +469,13 @@ static void tda8290_standby(struct dvb_frontend *fe) unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; - tda8290_i2c_bridge(fe, 1); + if (fe->ops.analog_ops.i2c_gate_ctrl) + fe->ops.analog_ops.i2c_gate_ctrl(fe, 1); if (priv->ver & TDA8275A) cb1[1] = 0x90; i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(fe, 0); + if (fe->ops.analog_ops.i2c_gate_ctrl) + fe->ops.analog_ops.i2c_gate_ctrl(fe, 0); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); } @@ -537,9 +543,11 @@ static void tda8290_init_tuner(struct dvb_frontend *fe) if (priv->ver & TDA8275A) msg.buf = tda8275a_init; - tda8290_i2c_bridge(fe, 1); + if (fe->ops.analog_ops.i2c_gate_ctrl) + fe->ops.analog_ops.i2c_gate_ctrl(fe, 1); i2c_transfer(priv->i2c_props.adap, &msg, 1); - tda8290_i2c_bridge(fe, 0); + if (fe->ops.analog_ops.i2c_gate_ctrl) + fe->ops.analog_ops.i2c_gate_ctrl(fe, 0); } /*---------------------------------------------------------------------*/ @@ -565,19 +573,13 @@ static struct tda18271_config tda829x_tda18271_config = { static int tda829x_find_tuner(struct dvb_frontend *fe) { struct tda8290_priv *priv = fe->analog_demod_priv; - struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; int i, ret, tuners_found; u32 tuner_addrs; u8 data; struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; - if (!analog_ops->i2c_gate_ctrl) { - printk(KERN_ERR "tda8290: no gate control were provided!\n"); - - return -EINVAL; - } - - analog_ops->i2c_gate_ctrl(fe, 1); + if (fe->ops.analog_ops.i2c_gate_ctrl) + fe->ops.analog_ops.i2c_gate_ctrl(fe, 1); /* probe for tuner chip */ tuners_found = 0; @@ -595,7 +597,8 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) give a response now */ - analog_ops->i2c_gate_ctrl(fe, 0); + if (fe->ops.analog_ops.i2c_gate_ctrl) + fe->ops.analog_ops.i2c_gate_ctrl(fe, 0); if (tuners_found > 1) for (i = 0; i < tuners_found; i++) { @@ -618,12 +621,14 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) priv->tda827x_addr = tuner_addrs; msg.addr = tuner_addrs; - analog_ops->i2c_gate_ctrl(fe, 1); + if (fe->ops.analog_ops.i2c_gate_ctrl) + fe->ops.analog_ops.i2c_gate_ctrl(fe, 1); ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); if (ret != 1) { tuner_warn("tuner access failed!\n"); - analog_ops->i2c_gate_ctrl(fe, 0); + if (fe->ops.analog_ops.i2c_gate_ctrl) + fe->ops.analog_ops.i2c_gate_ctrl(fe, 0); return -EREMOTEIO; } @@ -648,7 +653,8 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) if (fe->ops.tuner_ops.sleep) fe->ops.tuner_ops.sleep(fe); - analog_ops->i2c_gate_ctrl(fe, 0); + if (fe->ops.analog_ops.i2c_gate_ctrl) + fe->ops.analog_ops.i2c_gate_ctrl(fe, 0); return 0; } @@ -755,6 +761,9 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, sizeof(struct analog_demod_ops)); } + if (cfg && cfg->no_i2c_gate) + fe->ops.analog_ops.i2c_gate_ctrl = NULL; + if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) { tda8295_power(fe, 1); if (tda829x_find_tuner(fe) < 0) diff --git a/drivers/media/tuners/tda8290.h b/drivers/media/tuners/tda8290.h index e12ecbaa35a4..b5b51a947747 100644 --- a/drivers/media/tuners/tda8290.h +++ b/drivers/media/tuners/tda8290.h @@ -26,6 +26,7 @@ struct tda829x_config { unsigned int probe_tuner:1; #define TDA829X_PROBE_TUNER 0 #define TDA829X_DONT_PROBE 1 + unsigned int no_i2c_gate:1; }; #if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA8290) -- cgit v1.2.3 From 5b0e5350cecb5a370ecdaa71ac113728e36e1d55 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sun, 3 Feb 2013 22:48:56 -0300 Subject: [media] tda8290: Allow custom std_map for tda18271 Allow specifying a custom std_map for tda18271 by external configuration. This is required by cards that require custom std_map for analog TV or radio, like AverMedia A706. Signed-off-by: Ondrej Zary Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tda8290.c | 8 ++++++-- drivers/media/tuners/tda8290.h | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c index a2b7a9fbd344..c1ade88d1fa8 100644 --- a/drivers/media/tuners/tda8290.c +++ b/drivers/media/tuners/tda8290.c @@ -54,6 +54,7 @@ struct tda8290_priv { #define TDA18271 16 struct tda827x_config cfg; + struct tda18271_std_map *tda18271_std_map; }; /*---------------------------------------------------------------------*/ @@ -635,6 +636,7 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) if ((data == 0x83) || (data == 0x84)) { priv->ver |= TDA18271; tda829x_tda18271_config.config = priv->cfg.config; + tda829x_tda18271_config.std_map = priv->tda18271_std_map; dvb_attach(tda18271_attach, fe, priv->tda827x_addr, priv->i2c_props.adap, &tda829x_tda18271_config); } else { @@ -746,8 +748,10 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, priv->i2c_props.addr = i2c_addr; priv->i2c_props.adap = i2c_adap; priv->i2c_props.name = "tda829x"; - if (cfg) - priv->cfg.config = cfg->lna_cfg; + if (cfg) { + priv->cfg.config = cfg->lna_cfg; + priv->tda18271_std_map = cfg->tda18271_std_map; + } if (tda8290_probe(&priv->i2c_props) == 0) { priv->ver = TDA8290; diff --git a/drivers/media/tuners/tda8290.h b/drivers/media/tuners/tda8290.h index b5b51a947747..97f1d0f848ef 100644 --- a/drivers/media/tuners/tda8290.h +++ b/drivers/media/tuners/tda8290.h @@ -19,6 +19,7 @@ #include #include "dvb_frontend.h" +#include "tda18271.h" struct tda829x_config { unsigned int lna_cfg; @@ -27,6 +28,7 @@ struct tda829x_config { #define TDA829X_PROBE_TUNER 0 #define TDA829X_DONT_PROBE 1 unsigned int no_i2c_gate:1; + struct tda18271_std_map *tda18271_std_map; }; #if IS_ENABLED(CONFIG_MEDIA_TUNER_TDA8290) -- cgit v1.2.3 From cdcd141c95f0c2b88e0b0869028c320cd031a23b Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sat, 6 Apr 2013 14:21:36 -0300 Subject: [media] tuner-core: Change config from unsigned int to void * config looks like a hack that was added to tuner-core to allow some configuration of TDA8290 tuner (it's not used by any other driver). But with the new configuration options of tda8290 driver (no_i2c_gate and std_map), it's no longer sufficient. Change config to be void * instead, which allows passing tuner-dependent config struct to drivers. Also update saa7134 driver to reflect this change (no other driver uses this). Signed-off-by: Ondrej Zary Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-cards.c | 40 +++++++++++++++---------------- drivers/media/pci/saa7134/saa7134.h | 3 ++- drivers/media/v4l2-core/tuner-core.c | 20 ++++++---------- include/media/tuner.h | 2 +- 4 files changed, 30 insertions(+), 35 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index dc68cf1070f7..29fb7a9ac2a4 100644 --- a/drivers/media/pci/saa7134/saa7134-cards.c +++ b/drivers/media/pci/saa7134/saa7134-cards.c @@ -2760,7 +2760,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 0, + .tda829x_conf = { .lna_cfg = 0 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = {{ @@ -3291,7 +3291,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 1, + .tda829x_conf = { .lna_cfg = 1 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x000200000, .inputs = {{ @@ -3395,7 +3395,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 1, + .tda829x_conf = { .lna_cfg = 1 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200100, .inputs = {{ @@ -3426,7 +3426,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 3, + .tda829x_conf = { .lna_cfg = 3 }, .mpeg = SAA7134_MPEG_DVB, .ts_type = SAA7134_MPEG_TS_SERIAL, .ts_force_val = 1, @@ -3459,7 +3459,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 3, + .tda829x_conf = { .lna_cfg = 3 }, .mpeg = SAA7134_MPEG_DVB, .ts_type = SAA7134_MPEG_TS_SERIAL, .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */ @@ -3683,7 +3683,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = {{ @@ -3736,7 +3736,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = {{ @@ -3754,7 +3754,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .gpiomask = 1 << 21, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ @@ -3887,7 +3887,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 0, + .tda829x_conf = { .lna_cfg = 0 }, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_tv, /* FIXME: analog tv untested */ @@ -3903,7 +3903,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .gpiomask = 0x020200000, .inputs = {{ .name = name_tv, @@ -3937,7 +3937,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 0, + .tda829x_conf = { .lna_cfg = 0 }, .gpiomask = 0x020200000, .inputs = {{ .name = name_tv, @@ -4737,7 +4737,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = {{ @@ -4823,7 +4823,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 0, + .tda829x_conf = { .lna_cfg = 0 }, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_tv, @@ -4847,7 +4847,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = { { @@ -5057,7 +5057,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .gpiomask = 1 << 21, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ @@ -5087,7 +5087,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 2, + .tda829x_conf = { .lna_cfg = 2 }, .gpiomask = 1 << 21, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ @@ -5176,7 +5176,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 0, + .tda829x_conf = { .lna_cfg = 0 }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = { { @@ -5406,7 +5406,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tuner_config = 0, + .tda829x_conf = { .lna_cfg = 0 }, .mpeg = SAA7134_MPEG_DVB, .ts_type = SAA7134_MPEG_TS_PARALLEL, .inputs = {{ @@ -5629,7 +5629,7 @@ struct saa7134_board saa7134_boards[] = { .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, - .tuner_config = 3, + .tda829x_conf = { .lna_cfg = 3 }, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .gpiomask = 0x02050000, @@ -7633,7 +7633,7 @@ static void saa7134_tuner_setup(struct saa7134_dev *dev) if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type != UNSET)) { tun_setup.type = dev->tuner_type; tun_setup.addr = dev->tuner_addr; - tun_setup.config = saa7134_boards[dev->board].tuner_config; + tun_setup.config = &saa7134_boards[dev->board].tda829x_conf; tun_setup.tuner_callback = saa7134_tuner_callback; tun_setup.mode_mask = mode_mask; diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index 62169dd74c6a..b90b48821104 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -45,6 +45,7 @@ #if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB) #include #endif +#include "tda8290.h" #define UNSET (-1U) @@ -390,7 +391,7 @@ struct saa7134_board { unsigned char rds_addr; unsigned int tda9887_conf; - unsigned int tuner_config; + struct tda829x_config tda829x_conf; /* peripheral I/O */ enum saa7134_video_out video_out; diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index cf9a9af90322..7d60c5d38ca0 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -132,7 +132,7 @@ struct tuner { bool standby; /* Standby mode */ unsigned int type; /* chip type id */ - unsigned int config; + void *config; const char *name; }; @@ -270,9 +270,8 @@ static const struct analog_demod_ops tuner_analog_ops = { * @c: i2c_client descriptoy * @type: type of the tuner (e. g. tuner number) * @new_mode_mask: Indicates if tuner supports TV and/or Radio - * @new_config: an optional parameter ranging from 0-255 used by - a few tuners to adjust an internal parameter, - like LNA mode + * @new_config: an optional parameter used by a few tuners to adjust + internal parameters, like LNA mode * @tuner_callback: an optional function to be called when switching * to analog mode * @@ -280,7 +279,7 @@ static const struct analog_demod_ops tuner_analog_ops = { * by tun_setup structure. It contains several per-tuner initialization "magic" */ static void set_type(struct i2c_client *c, unsigned int type, - unsigned int new_mode_mask, unsigned int new_config, + unsigned int new_mode_mask, void *new_config, int (*tuner_callback) (void *dev, int component, int cmd, int arg)) { struct tuner *t = to_tuner(i2c_get_clientdata(c)); @@ -295,8 +294,7 @@ static void set_type(struct i2c_client *c, unsigned int type, } t->type = type; - /* prevent invalid config values */ - t->config = new_config < 256 ? new_config : 0; + t->config = new_config; if (tuner_callback != NULL) { tuner_dbg("defining GPIO callback\n"); t->fe.callback = tuner_callback; @@ -314,11 +312,8 @@ static void set_type(struct i2c_client *c, unsigned int type, break; case TUNER_PHILIPS_TDA8290: { - struct tda829x_config cfg = { - .lna_cfg = t->config, - }; if (!dvb_attach(tda829x_attach, &t->fe, t->i2c->adapter, - t->i2c->addr, &cfg)) + t->i2c->addr, t->config)) goto attach_failed; break; } @@ -407,7 +402,6 @@ static void set_type(struct i2c_client *c, unsigned int type, case TUNER_NXP_TDA18271: { struct tda18271_config cfg = { - .config = t->config, .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, }; @@ -509,7 +503,7 @@ static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner *t = to_tuner(sd); struct i2c_client *c = v4l2_get_subdevdata(sd); - tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=0x%02x\n", + tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=%p\n", tun_setup->type, tun_setup->addr, tun_setup->mode_mask, diff --git a/include/media/tuner.h b/include/media/tuner.h index 24eaafe461bd..b46ebb48fe74 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -192,7 +192,7 @@ struct tuner_setup { unsigned short addr; /* I2C address */ unsigned int type; /* Tuner type */ unsigned int mode_mask; /* Allowed tuner modes */ - unsigned int config; /* configuraion for more complex tuners */ + void *config; /* configuraion for more complex tuners */ int (*tuner_callback) (void *dev, int component, int cmd, int arg); }; -- cgit v1.2.3 From 34fe2784b4aabeec6d2afbd132d070b20abea132 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sat, 6 Apr 2013 14:28:16 -0300 Subject: [media] saa7134: Add AverMedia A706 AverTV Satellite Hybrid+FM Add AverMedia AverTV Satellite Hybrid+FM (A706) card to saa7134 driver. Working: analog inputs, TV, FM radio and IR remote control. Untested: DVB-S. Signed-off-by: Ondrej Zary Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ir-kbd-i2c.c | 13 ++++++- drivers/media/pci/saa7134/saa7134-cards.c | 53 +++++++++++++++++++++++++++++ drivers/media/pci/saa7134/saa7134-dvb.c | 23 +++++++++++++ drivers/media/pci/saa7134/saa7134-i2c.c | 1 + drivers/media/pci/saa7134/saa7134-input.c | 3 ++ drivers/media/pci/saa7134/saa7134-tvaudio.c | 1 + drivers/media/pci/saa7134/saa7134.h | 1 + 7 files changed, 94 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 2586e46f14b5..8e2f79cb045e 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -230,7 +230,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, return 0; dprintk(1, "read key 0x%02x/0x%02x\n", key, keygroup); - if (keygroup < 2 || keygroup > 3) { + if (keygroup < 2 || keygroup > 4) { /* Only a warning */ dprintk(1, "warning: invalid key group 0x%02x for key 0x%02x\n", keygroup, key); @@ -239,6 +239,10 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, *ir_key = key; *ir_raw = key; + if (!strcmp(ir->ir_codes, RC_MAP_AVERMEDIA_M733A_RM_K6)) { + *ir_key |= keygroup << 8; + *ir_raw |= keygroup << 8; + } return 1; } @@ -332,6 +336,13 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) rc_type = RC_BIT_OTHER; ir_codes = RC_MAP_AVERMEDIA_CARDBUS; break; + case 0x41: + name = "AVerMedia EM78P153"; + ir->get_key = get_key_avermedia_cardbus; + rc_type = RC_BIT_OTHER; + /* RM-KV remote, seems to be same as RM-K6 */ + ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6; + break; case 0x71: name = "Hauppauge/Zilog Z8"; ir->get_key = get_key_haup_xvr; diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index 29fb7a9ac2a4..67e06e178e98 100644 --- a/drivers/media/pci/saa7134/saa7134-cards.c +++ b/drivers/media/pci/saa7134/saa7134-cards.c @@ -50,6 +50,11 @@ static char name_svideo[] = "S-Video"; /* ------------------------------------------------------------------ */ /* board config info */ +static struct tda18271_std_map aver_a706_std_map = { + .fm_radio = { .if_freq = 5500, .fm_rfn = 0, .agc_mode = 3, .std = 0, + .if_lvl = 0, .rfagc_top = 0x2c, }, +}; + /* If radio_type !=UNSET, radio_addr should be specified */ @@ -5790,6 +5795,37 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x6010000, } }, }, + [SAA7134_BOARD_AVERMEDIA_A706] = { + .name = "AverMedia AverTV Satellite Hybrid+FM A706", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda829x_conf = { .lna_cfg = 0, .no_i2c_gate = 1, + .tda18271_std_map = &aver_a706_std_map }, + .gpiomask = 1 << 11, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + }, { + .name = name_comp, + .vmux = 4, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x0000800, + }, + }, }; @@ -7036,6 +7072,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x6000, .subdevice = 0x0911, .driver_data = SAA7134_BOARD_SENSORAY811_911, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0x2055, /* AverTV Satellite Hybrid+FM A706 */ + .driver_data = SAA7134_BOARD_AVERMEDIA_A706, }, { /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -7585,6 +7627,17 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100); saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100); break; + case SAA7134_BOARD_AVERMEDIA_A706: + /* radio antenna select: tristate both as in Windows driver */ + saa7134_set_gpio(dev, 12, 3); /* TV antenna */ + saa7134_set_gpio(dev, 13, 3); /* FM antenna */ + dev->has_remote = SAA7134_REMOTE_I2C; + /* + * Disable CE5039 DVB-S tuner now (SLEEP pin high) to prevent + * it from interfering with analog tuner detection + */ + saa7134_set_gpio(dev, 23, 1); + break; case SAA7134_BOARD_VIDEOMATE_S350: dev->has_remote = SAA7134_REMOTE_GPIO; saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0000C000, 0x0000C000); diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c index 45271390d7fb..4a08ae31df2e 100644 --- a/drivers/media/pci/saa7134/saa7134-dvb.c +++ b/drivers/media/pci/saa7134/saa7134-dvb.c @@ -1073,6 +1073,10 @@ static struct mt312_config zl10313_compro_s350_config = { .demod_address = 0x0e, }; +static struct mt312_config zl10313_avermedia_a706_config = { + .demod_address = 0x0e, +}; + static struct lgdt3305_config hcw_lgdt3305_config = { .i2c_addr = 0x0e, .mpeg_mode = LGDT3305_MPEG_SERIAL, @@ -1822,6 +1826,25 @@ static int dvb_init(struct saa7134_dev *dev) &prohdtv_pro2_tda18271_config); } break; + case SAA7134_BOARD_AVERMEDIA_A706: + /* Enable all DVB-S devices now */ + /* CE5039 DVB-S tuner SLEEP pin low */ + saa7134_set_gpio(dev, 23, 0); + /* CE6313 DVB-S demod SLEEP pin low */ + saa7134_set_gpio(dev, 9, 0); + /* CE6313 DVB-S demod RESET# pin high */ + saa7134_set_gpio(dev, 25, 1); + msleep(1); + fe0->dvb.frontend = dvb_attach(mt312_attach, + &zl10313_avermedia_a706_config, &dev->i2c_adap); + if (fe0->dvb.frontend) { + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; + if (dvb_attach(zl10039_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_adap) == NULL) + wprintk("%s: No zl10039 found!\n", + __func__); + } + break; default: wprintk("Huh? unknown DVB card?\n"); break; diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c index a176ec3285e0..c68169d75804 100644 --- a/drivers/media/pci/saa7134/saa7134-i2c.c +++ b/drivers/media/pci/saa7134/saa7134-i2c.c @@ -256,6 +256,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, addr |= 1; if (i > 0 && msgs[i].flags & I2C_M_RD && msgs[i].addr != 0x40 && + msgs[i].addr != 0x41 && msgs[i].addr != 0x19) { /* workaround for a saa7134 i2c bug * needed to talk to the mt352 demux diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c index e761262f7475..6f4312663bdf 100644 --- a/drivers/media/pci/saa7134/saa7134-input.c +++ b/drivers/media/pci/saa7134/saa7134-input.c @@ -997,6 +997,9 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: info.addr = 0x40; break; + case SAA7134_BOARD_AVERMEDIA_A706: + info.addr = 0x41; + break; case SAA7134_BOARD_FLYDVB_TRIO: dev->init_data.name = "FlyDVB Trio"; dev->init_data.get_key = get_key_flydvb_trio; diff --git a/drivers/media/pci/saa7134/saa7134-tvaudio.c b/drivers/media/pci/saa7134/saa7134-tvaudio.c index b7a99bee2f98..0f34e09d98dc 100644 --- a/drivers/media/pci/saa7134/saa7134-tvaudio.c +++ b/drivers/media/pci/saa7134/saa7134-tvaudio.c @@ -796,6 +796,7 @@ static int tvaudio_thread_ddep(void *data) dprintk("FM Radio\n"); if (dev->tuner_type == TUNER_PHILIPS_TDA8290) { norms = (0x11 << 2) | 0x01; + /* set IF frequency to 5.5 MHz */ saa_dsp_writel(dev, 0x42c >> 2, 0x729555); } else { norms = (0x0f << 2) | 0x01; diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index b90b48821104..1f6c41ed2a07 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -335,6 +335,7 @@ struct saa7134_card_ir { #define SAA7134_BOARD_KWORLD_PC150U 189 #define SAA7134_BOARD_ASUSTeK_PS3_100 190 #define SAA7134_BOARD_HAWELL_HW_9004V1 191 +#define SAA7134_BOARD_AVERMEDIA_A706 192 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.3 From 1bacb2df3bc999dcad21e9aab6bdb60d6dc7bc02 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Sat, 6 Apr 2013 14:29:29 -0300 Subject: [media] tda8290: change magic LNA config values to enum Use enum instead of magic values for LNA config in tda8290. Update tda827x, tda18271 and saa7134 to use the enum too. Signed-off-by: Ondrej Zary Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-cards.c | 41 ++++++++++++++++--------------- drivers/media/tuners/tda18271-fe.c | 9 ++++--- drivers/media/tuners/tda827x.c | 10 ++++---- drivers/media/tuners/tda827x.h | 3 ++- drivers/media/tuners/tda8290.c | 3 ++- drivers/media/tuners/tda8290.h | 9 ++++++- 6 files changed, 43 insertions(+), 32 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index 67e06e178e98..d45e7f6ff332 100644 --- a/drivers/media/pci/saa7134/saa7134-cards.c +++ b/drivers/media/pci/saa7134/saa7134-cards.c @@ -2765,7 +2765,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 0 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = {{ @@ -3296,7 +3296,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 1 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_ON }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x000200000, .inputs = {{ @@ -3400,7 +3400,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 1 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_ON }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200100, .inputs = {{ @@ -3431,7 +3431,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 3 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_ON_BRIDGE }, .mpeg = SAA7134_MPEG_DVB, .ts_type = SAA7134_MPEG_TS_SERIAL, .ts_force_val = 1, @@ -3464,7 +3464,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 3 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_ON_BRIDGE }, .mpeg = SAA7134_MPEG_DVB, .ts_type = SAA7134_MPEG_TS_SERIAL, .gpiomask = 0x0800100, /* GPIO 21 is an INPUT */ @@ -3688,7 +3688,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 2 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = {{ @@ -3741,7 +3741,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 2 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = {{ @@ -3759,7 +3759,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 2 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF }, .gpiomask = 1 << 21, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ @@ -3892,7 +3892,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 0 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF }, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_tv, /* FIXME: analog tv untested */ @@ -3908,7 +3908,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 2 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF }, .gpiomask = 0x020200000, .inputs = {{ .name = name_tv, @@ -3942,7 +3942,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 0 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF }, .gpiomask = 0x020200000, .inputs = {{ .name = name_tv, @@ -4742,7 +4742,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 2 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = {{ @@ -4828,7 +4828,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 0 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF }, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_tv, @@ -4852,7 +4852,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 2 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = { { @@ -5062,7 +5062,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 2 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF }, .gpiomask = 1 << 21, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ @@ -5092,7 +5092,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 2 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_GP0_HIGH_OFF }, .gpiomask = 1 << 21, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ @@ -5181,7 +5181,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 0 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF }, .mpeg = SAA7134_MPEG_DVB, .gpiomask = 0x0200000, .inputs = { { @@ -5411,7 +5411,7 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 0 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF }, .mpeg = SAA7134_MPEG_DVB, .ts_type = SAA7134_MPEG_TS_PARALLEL, .inputs = {{ @@ -5634,7 +5634,7 @@ struct saa7134_board saa7134_boards[] = { .audio_clock = 0x00187de7, .tuner_type = TUNER_PHILIPS_TDA8290, .radio_type = UNSET, - .tda829x_conf = { .lna_cfg = 3 }, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_ON_BRIDGE }, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .gpiomask = 0x02050000, @@ -5802,7 +5802,8 @@ struct saa7134_board saa7134_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .tda829x_conf = { .lna_cfg = 0, .no_i2c_gate = 1, + .tda829x_conf = { .lna_cfg = TDA8290_LNA_OFF, + .no_i2c_gate = 1, .tda18271_std_map = &aver_a706_std_map }, .gpiomask = 1 << 11, .mpeg = SAA7134_MPEG_DVB, diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c index e7786862dab2..4995b890c164 100644 --- a/drivers/media/tuners/tda18271-fe.c +++ b/drivers/media/tuners/tda18271-fe.c @@ -21,6 +21,7 @@ #include #include #include "tda18271-priv.h" +#include "tda8290.h" int tda18271_debug; module_param_named(debug, tda18271_debug, int, 0644); @@ -867,12 +868,12 @@ static int tda18271_agc(struct dvb_frontend *fe) int ret = 0; switch (priv->config) { - case 0: + case TDA8290_LNA_OFF: /* no external agc configuration required */ if (tda18271_debug & DBG_ADV) tda_dbg("no agc configuration provided\n"); break; - case 3: + case TDA8290_LNA_ON_BRIDGE: /* switch with GPIO of saa713x */ tda_dbg("invoking callback\n"); if (fe->callback) @@ -881,8 +882,8 @@ static int tda18271_agc(struct dvb_frontend *fe) TDA18271_CALLBACK_CMD_AGC_ENABLE, priv->mode); break; - case 1: - case 2: + case TDA8290_LNA_GP0_HIGH_ON: + case TDA8290_LNA_GP0_HIGH_OFF: default: /* n/a - currently not supported */ tda_err("unsupported configuration: %d\n", priv->config); diff --git a/drivers/media/tuners/tda827x.c b/drivers/media/tuners/tda827x.c index a0d176267470..73453a255cdc 100644 --- a/drivers/media/tuners/tda827x.c +++ b/drivers/media/tuners/tda827x.c @@ -479,10 +479,10 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, dprintk("setting LNA to low gain\n"); } switch (priv->cfg->config) { - case 0: /* no LNA */ + case TDA8290_LNA_OFF: /* no LNA */ break; - case 1: /* switch is GPIO 0 of tda8290 */ - case 2: + case TDA8290_LNA_GP0_HIGH_ON: /* switch is GPIO 0 of tda8290 */ + case TDA8290_LNA_GP0_HIGH_OFF: if (params == NULL) { gp_func = 0; arg = 0; @@ -499,11 +499,11 @@ static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, DVB_FRONTEND_COMPONENT_TUNER, gp_func, arg); buf[1] = high ? 0 : 1; - if (priv->cfg->config == 2) + if (priv->cfg->config == TDA8290_LNA_GP0_HIGH_OFF) buf[1] = high ? 1 : 0; tuner_transfer(fe, &msg, 1); break; - case 3: /* switch with GPIO of saa713x */ + case TDA8290_LNA_ON_BRIDGE: /* switch with GPIO of saa713x */ if (fe->callback) fe->callback(priv->i2c_adap->algo_data, DVB_FRONTEND_COMPONENT_TUNER, 0, high); diff --git a/drivers/media/tuners/tda827x.h b/drivers/media/tuners/tda827x.h index 9432b5b6121b..b64292152baf 100644 --- a/drivers/media/tuners/tda827x.h +++ b/drivers/media/tuners/tda827x.h @@ -26,6 +26,7 @@ #include #include "dvb_frontend.h" +#include "tda8290.h" struct tda827x_config { @@ -34,7 +35,7 @@ struct tda827x_config int (*sleep) (struct dvb_frontend *fe); /* interface to tda829x driver */ - unsigned int config; + enum tda8290_lna config; int switch_addr; void (*agcf)(struct dvb_frontend *fe); diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c index c1ade88d1fa8..20cc7dad6b4e 100644 --- a/drivers/media/tuners/tda8290.c +++ b/drivers/media/tuners/tda8290.c @@ -496,7 +496,8 @@ static void tda8290_init_if(struct dvb_frontend *fe) unsigned char set_GP00_CF[] = { 0x20, 0x01 }; unsigned char set_GP01_CF[] = { 0x20, 0x0B }; - if ((priv->cfg.config == 1) || (priv->cfg.config == 2)) + if ((priv->cfg.config == TDA8290_LNA_GP0_HIGH_ON) || + (priv->cfg.config == TDA8290_LNA_GP0_HIGH_OFF)) tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); else tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); diff --git a/drivers/media/tuners/tda8290.h b/drivers/media/tuners/tda8290.h index 97f1d0f848ef..cf96e585785e 100644 --- a/drivers/media/tuners/tda8290.h +++ b/drivers/media/tuners/tda8290.h @@ -21,8 +21,15 @@ #include "dvb_frontend.h" #include "tda18271.h" +enum tda8290_lna { + TDA8290_LNA_OFF = 0, + TDA8290_LNA_GP0_HIGH_ON = 1, + TDA8290_LNA_GP0_HIGH_OFF = 2, + TDA8290_LNA_ON_BRIDGE = 3, +}; + struct tda829x_config { - unsigned int lna_cfg; + enum tda8290_lna lna_cfg; unsigned int probe_tuner:1; #define TDA829X_PROBE_TUNER 0 -- cgit v1.2.3 From 4f62a20dfbdf46825dea707a033f941874e34930 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 7 Apr 2013 20:50:34 -0300 Subject: [media] mb86a20s: Use a macro for the number of layers Instead of using the magic number "3", use NUM_LAYERS macro on all places that are related to the ISDB-T layers. This makes the source code a little more readable. No functional changes. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index d04b52e3f4cc..80a8ee090c80 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -20,6 +20,8 @@ #include "dvb_frontend.h" #include "mb86a20s.h" +#define NUM_LAYERS 3 + static int debug = 1; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); @@ -48,7 +50,7 @@ struct mb86a20s_state { bool inversion; u32 subchannel; - u32 estimated_rate[3]; + u32 estimated_rate[NUM_LAYERS]; unsigned long get_strength_time; bool need_init; @@ -666,7 +668,7 @@ static int mb86a20s_get_frontend(struct dvb_frontend *fe) /* Get per-layer data */ - for (i = 0; i < 3; i++) { + for (i = 0; i < NUM_LAYERS; i++) { dev_dbg(&state->i2c->dev, "%s: getting data for layer %c.\n", __func__, 'A' + i); @@ -828,7 +830,7 @@ static int mb86a20s_get_pre_ber(struct dvb_frontend *fe, dev_dbg(&state->i2c->dev, "%s called.\n", __func__); - if (layer >= 3) + if (layer >= NUM_LAYERS) return -EINVAL; /* Check if the BER measures are already available */ @@ -962,7 +964,7 @@ static int mb86a20s_get_post_ber(struct dvb_frontend *fe, dev_dbg(&state->i2c->dev, "%s called.\n", __func__); - if (layer >= 3) + if (layer >= NUM_LAYERS) return -EINVAL; /* Check if the BER measures are already available */ @@ -1089,7 +1091,7 @@ static int mb86a20s_get_blk_error(struct dvb_frontend *fe, u32 collect_rate; dev_dbg(&state->i2c->dev, "%s called.\n", __func__); - if (layer >= 3) + if (layer >= NUM_LAYERS) return -EINVAL; /* Check if the PER measures are already available */ @@ -1476,7 +1478,7 @@ static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe) } /* Read all layers */ - for (i = 0; i < 3; i++) { + for (i = 0; i < NUM_LAYERS; i++) { if (!(c->isdbt_layer_enabled & (1 << i))) { c->cnr.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE; continue; @@ -1565,20 +1567,20 @@ static void mb86a20s_stats_not_ready(struct dvb_frontend *fe) c->strength.len = 1; /* Per-layer stats - 3 layers + global */ - c->cnr.len = 4; - c->pre_bit_error.len = 4; - c->pre_bit_count.len = 4; - c->post_bit_error.len = 4; - c->post_bit_count.len = 4; - c->block_error.len = 4; - c->block_count.len = 4; + c->cnr.len = NUM_LAYERS + 1; + c->pre_bit_error.len = NUM_LAYERS + 1; + c->pre_bit_count.len = NUM_LAYERS + 1; + c->post_bit_error.len = NUM_LAYERS + 1; + c->post_bit_count.len = NUM_LAYERS + 1; + c->block_error.len = NUM_LAYERS + 1; + c->block_count.len = NUM_LAYERS + 1; /* Signal is always available */ c->strength.stat[0].scale = FE_SCALE_RELATIVE; c->strength.stat[0].uvalue = 0; /* Put all of them at FE_SCALE_NOT_AVAILABLE */ - for (i = 0; i < 4; i++) { + for (i = 0; i < NUM_LAYERS + 1; i++) { c->cnr.stat[i].scale = FE_SCALE_NOT_AVAILABLE; c->pre_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; c->pre_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; @@ -1617,7 +1619,7 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe, int status_nr) if (status_nr < 9) return 0; - for (i = 0; i < 3; i++) { + for (i = 0; i < NUM_LAYERS; i++) { if (c->isdbt_layer_enabled & (1 << i)) { /* Layer is active and has rc segments */ active_layers++; -- cgit v1.2.3 From 41c6e9dd0915741051e813cafa14f2e7f88b71d9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 7 Apr 2013 20:51:32 -0300 Subject: [media] mb86a20s: fix audio sub-channel check As reported by Dan Carpenter FYI, there are new smatch warnings show up in: tree: git://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next master head: da17d7bda957ae4697b6abc0793f74fb9b50b58f commit: 04fa725e7b1c22c583dd71a8cd85b8d997edfce3 [media] mb86a20s: Implement set_frontend cache logic New smatch warnings: drivers/media/dvb-frontends/mb86a20s.c:1897 mb86a20s_set_frontend() error: buffer overflow 'mb86a20s_subchannel' 8 <= 8 04fa725e Mauro Carvalho Chehab 2013-03-04 1894 if (c->isdbt_sb_subchannel > ARRAY_SIZE(mb86a20s_subchannel)) 04fa725e Mauro Carvalho Chehab 2013-03-04 1895 c->isdbt_sb_subchannel = 0; 04fa725e Mauro Carvalho Chehab 2013-03-04 1896 04fa725e Mauro Carvalho Chehab 2013-03-04 @1897 state->subchannel = mb86a20s_subchannel[c->isdbt_sb_subchannel]; Reported-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 80a8ee090c80..70158aae1886 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -1915,7 +1915,7 @@ static int mb86a20s_set_frontend(struct dvb_frontend *fe) if (!c->isdbt_sb_mode) { state->subchannel = 0; } else { - if (c->isdbt_sb_subchannel > ARRAY_SIZE(mb86a20s_subchannel)) + if (c->isdbt_sb_subchannel >= ARRAY_SIZE(mb86a20s_subchannel)) c->isdbt_sb_subchannel = 0; state->subchannel = mb86a20s_subchannel[c->isdbt_sb_subchannel]; -- cgit v1.2.3 From 5cb88ca84aa8dc4efcabd8482fff6002774c7f03 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 7 Apr 2013 20:52:16 -0300 Subject: [media] mb86a20s: Use 'layer' instead of 'i' on all places We're using the anonymous 'i' to indicate the layer number on several places on the driver. That's not good, as some cut-and-paste type of change might be doing the wrong thing. So, call it as "layer" everywhere. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 148 ++++++++++++++++----------------- 1 file changed, 74 insertions(+), 74 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 70158aae1886..f2565896ce42 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -650,7 +650,7 @@ static int mb86a20s_get_frontend(struct dvb_frontend *fe) { struct mb86a20s_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int i, rc; + int layer, rc; dev_dbg(&state->i2c->dev, "%s called.\n", __func__); @@ -668,43 +668,43 @@ static int mb86a20s_get_frontend(struct dvb_frontend *fe) /* Get per-layer data */ - for (i = 0; i < NUM_LAYERS; i++) { + for (layer = 0; layer < NUM_LAYERS; layer++) { dev_dbg(&state->i2c->dev, "%s: getting data for layer %c.\n", - __func__, 'A' + i); + __func__, 'A' + layer); - rc = mb86a20s_get_segment_count(state, i); + rc = mb86a20s_get_segment_count(state, layer); if (rc < 0) goto noperlayer_error; if (rc >= 0 && rc < 14) { - c->layer[i].segment_count = rc; + c->layer[layer].segment_count = rc; } else { - c->layer[i].segment_count = 0; - state->estimated_rate[i] = 0; + c->layer[layer].segment_count = 0; + state->estimated_rate[layer] = 0; continue; } - c->isdbt_layer_enabled |= 1 << i; - rc = mb86a20s_get_modulation(state, i); + c->isdbt_layer_enabled |= 1 << layer; + rc = mb86a20s_get_modulation(state, layer); if (rc < 0) goto noperlayer_error; dev_dbg(&state->i2c->dev, "%s: modulation %d.\n", __func__, rc); - c->layer[i].modulation = rc; - rc = mb86a20s_get_fec(state, i); + c->layer[layer].modulation = rc; + rc = mb86a20s_get_fec(state, layer); if (rc < 0) goto noperlayer_error; dev_dbg(&state->i2c->dev, "%s: FEC %d.\n", __func__, rc); - c->layer[i].fec = rc; - rc = mb86a20s_get_interleaving(state, i); + c->layer[layer].fec = rc; + rc = mb86a20s_get_interleaving(state, layer); if (rc < 0) goto noperlayer_error; dev_dbg(&state->i2c->dev, "%s: interleaving %d.\n", __func__, rc); - c->layer[i].interleaving = rc; - mb86a20s_layer_bitrate(fe, i, c->layer[i].modulation, - c->layer[i].fec, - c->layer[i].interleaving, - c->layer[i].segment_count); + c->layer[layer].interleaving = rc; + mb86a20s_layer_bitrate(fe, layer, c->layer[layer].modulation, + c->layer[layer].fec, + c->layer[layer].interleaving, + c->layer[layer].segment_count); } rc = mb86a20s_writereg(state, 0x6d, 0x84); @@ -1456,7 +1456,7 @@ static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe) struct mb86a20s_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 mer, cnr; - int rc, val, i; + int rc, val, layer; struct linear_segments *segs; unsigned segs_len; @@ -1478,27 +1478,27 @@ static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe) } /* Read all layers */ - for (i = 0; i < NUM_LAYERS; i++) { - if (!(c->isdbt_layer_enabled & (1 << i))) { - c->cnr.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE; + for (layer = 0; layer < NUM_LAYERS; layer++) { + if (!(c->isdbt_layer_enabled & (1 << layer))) { + c->cnr.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; continue; } - rc = mb86a20s_writereg(state, 0x50, 0x52 + i * 3); + rc = mb86a20s_writereg(state, 0x50, 0x52 + layer * 3); if (rc < 0) return rc; rc = mb86a20s_readreg(state, 0x51); if (rc < 0) return rc; mer = rc << 16; - rc = mb86a20s_writereg(state, 0x50, 0x53 + i * 3); + rc = mb86a20s_writereg(state, 0x50, 0x53 + layer * 3); if (rc < 0) return rc; rc = mb86a20s_readreg(state, 0x51); if (rc < 0) return rc; mer |= rc << 8; - rc = mb86a20s_writereg(state, 0x50, 0x54 + i * 3); + rc = mb86a20s_writereg(state, 0x50, 0x54 + layer * 3); if (rc < 0) return rc; rc = mb86a20s_readreg(state, 0x51); @@ -1506,7 +1506,7 @@ static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe) return rc; mer |= rc; - switch (c->layer[i].modulation) { + switch (c->layer[layer].modulation) { case DQPSK: case QPSK: segs = cnr_qpsk_table; @@ -1524,12 +1524,12 @@ static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe) } cnr = interpolate_value(mer, segs, segs_len); - c->cnr.stat[1 + i].scale = FE_SCALE_DECIBEL; - c->cnr.stat[1 + i].svalue = cnr; + c->cnr.stat[1 + layer].scale = FE_SCALE_DECIBEL; + c->cnr.stat[1 + layer].svalue = cnr; dev_dbg(&state->i2c->dev, "%s: CNR for layer %c is %d.%03d dB (MER = %d).\n", - __func__, 'A' + i, cnr / 1000, cnr % 1000, mer); + __func__, 'A' + layer, cnr / 1000, cnr % 1000, mer); } @@ -1557,7 +1557,7 @@ static void mb86a20s_stats_not_ready(struct dvb_frontend *fe) { struct mb86a20s_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int i; + int layer; dev_dbg(&state->i2c->dev, "%s called.\n", __func__); @@ -1580,14 +1580,14 @@ static void mb86a20s_stats_not_ready(struct dvb_frontend *fe) c->strength.stat[0].uvalue = 0; /* Put all of them at FE_SCALE_NOT_AVAILABLE */ - for (i = 0; i < NUM_LAYERS + 1; i++) { - c->cnr.stat[i].scale = FE_SCALE_NOT_AVAILABLE; - c->pre_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; - c->pre_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; - c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; - c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; - c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE; - c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE; + for (layer = 0; layer < NUM_LAYERS + 1; layer++) { + c->cnr.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_error.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_count.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[layer].scale = FE_SCALE_NOT_AVAILABLE; } } @@ -1595,7 +1595,7 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe, int status_nr) { struct mb86a20s_state *state = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int rc = 0, i; + int rc = 0, layer; u32 bit_error = 0, bit_count = 0; u32 t_pre_bit_error = 0, t_pre_bit_count = 0; u32 t_post_bit_error = 0, t_post_bit_count = 0; @@ -1619,90 +1619,90 @@ static int mb86a20s_get_stats(struct dvb_frontend *fe, int status_nr) if (status_nr < 9) return 0; - for (i = 0; i < NUM_LAYERS; i++) { - if (c->isdbt_layer_enabled & (1 << i)) { + for (layer = 0; layer < NUM_LAYERS; layer++) { + if (c->isdbt_layer_enabled & (1 << layer)) { /* Layer is active and has rc segments */ active_layers++; /* Handle BER before vterbi */ - rc = mb86a20s_get_pre_ber(fe, i, + rc = mb86a20s_get_pre_ber(fe, layer, &bit_error, &bit_count); if (rc >= 0) { - c->pre_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER; - c->pre_bit_error.stat[1 + i].uvalue += bit_error; - c->pre_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER; - c->pre_bit_count.stat[1 + i].uvalue += bit_count; + c->pre_bit_error.stat[1 + layer].scale = FE_SCALE_COUNTER; + c->pre_bit_error.stat[1 + layer].uvalue += bit_error; + c->pre_bit_count.stat[1 + layer].scale = FE_SCALE_COUNTER; + c->pre_bit_count.stat[1 + layer].uvalue += bit_count; } else if (rc != -EBUSY) { /* * If an I/O error happened, * measures are now unavailable */ - c->pre_bit_error.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE; - c->pre_bit_count.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_error.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; + c->pre_bit_count.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; dev_err(&state->i2c->dev, "%s: Can't get BER for layer %c (error %d).\n", - __func__, 'A' + i, rc); + __func__, 'A' + layer, rc); } - if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE) + if (c->block_error.stat[1 + layer].scale != FE_SCALE_NOT_AVAILABLE) pre_ber_layers++; /* Handle BER post vterbi */ - rc = mb86a20s_get_post_ber(fe, i, + rc = mb86a20s_get_post_ber(fe, layer, &bit_error, &bit_count); if (rc >= 0) { - c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[1 + i].uvalue += bit_error; - c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER; - c->post_bit_count.stat[1 + i].uvalue += bit_count; + c->post_bit_error.stat[1 + layer].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[1 + layer].uvalue += bit_error; + c->post_bit_count.stat[1 + layer].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[1 + layer].uvalue += bit_count; } else if (rc != -EBUSY) { /* * If an I/O error happened, * measures are now unavailable */ - c->post_bit_error.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE; - c->post_bit_count.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; dev_err(&state->i2c->dev, "%s: Can't get BER for layer %c (error %d).\n", - __func__, 'A' + i, rc); + __func__, 'A' + layer, rc); } - if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE) + if (c->block_error.stat[1 + layer].scale != FE_SCALE_NOT_AVAILABLE) post_ber_layers++; /* Handle Block errors for PER/UCB reports */ - rc = mb86a20s_get_blk_error(fe, i, + rc = mb86a20s_get_blk_error(fe, layer, &block_error, &block_count); if (rc >= 0) { - c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER; - c->block_error.stat[1 + i].uvalue += block_error; - c->block_count.stat[1 + i].scale = FE_SCALE_COUNTER; - c->block_count.stat[1 + i].uvalue += block_count; + c->block_error.stat[1 + layer].scale = FE_SCALE_COUNTER; + c->block_error.stat[1 + layer].uvalue += block_error; + c->block_count.stat[1 + layer].scale = FE_SCALE_COUNTER; + c->block_count.stat[1 + layer].uvalue += block_count; } else if (rc != -EBUSY) { /* * If an I/O error happened, * measures are now unavailable */ - c->block_error.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE; - c->block_count.stat[1 + i].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[1 + layer].scale = FE_SCALE_NOT_AVAILABLE; dev_err(&state->i2c->dev, "%s: Can't get PER for layer %c (error %d).\n", - __func__, 'A' + i, rc); + __func__, 'A' + layer, rc); } - if (c->block_error.stat[1 + i].scale != FE_SCALE_NOT_AVAILABLE) + if (c->block_error.stat[1 + layer].scale != FE_SCALE_NOT_AVAILABLE) per_layers++; /* Update total preBER */ - t_pre_bit_error += c->pre_bit_error.stat[1 + i].uvalue; - t_pre_bit_count += c->pre_bit_count.stat[1 + i].uvalue; + t_pre_bit_error += c->pre_bit_error.stat[1 + layer].uvalue; + t_pre_bit_count += c->pre_bit_count.stat[1 + layer].uvalue; /* Update total postBER */ - t_post_bit_error += c->post_bit_error.stat[1 + i].uvalue; - t_post_bit_count += c->post_bit_count.stat[1 + i].uvalue; + t_post_bit_error += c->post_bit_error.stat[1 + layer].uvalue; + t_post_bit_count += c->post_bit_count.stat[1 + layer].uvalue; /* Update total PER */ - t_block_error += c->block_error.stat[1 + i].uvalue; - t_block_count += c->block_count.stat[1 + i].uvalue; + t_block_error += c->block_error.stat[1 + layer].uvalue; + t_block_count += c->block_count.stat[1 + layer].uvalue; } } -- cgit v1.2.3 From b1f89331190820c42397156063fe5e39bc514e3b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 7 Apr 2013 21:06:12 -0300 Subject: [media] mb86a20s: Fix estimate_rate setting As reported by Dan Carpenter : Smatch warnings: drivers/media/dvb-frontends/mb86a20s.c:644 mb86a20s_layer_bitrate() error: buffer overflow 'state->estimated_rate' 3 <= 3 What happens there is that estimate_rate index should be the layer number, and not the guard interval. Reported-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index f2565896ce42..d25df75ed404 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -642,7 +642,7 @@ static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer, __func__, 'A' + layer, segment * isdbt_rate[m][f][i]/1000, rate, rate); - state->estimated_rate[i] = rate; + state->estimated_rate[layer] = rate; } -- cgit v1.2.3 From 0562aef296c251e50b0934e6af113c511349dd9c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 7 Apr 2013 21:07:47 -0300 Subject: [media] mb86a20s: better name temp vars at mb86a20s_layer_bitrate() Using 'i' for the guard interval temporary var is a bad idea, as 'i' is generally used by "anonymous" indexes. Let's rename modulation, fec and guard interval temp vars with a meaningful name, as that makes easier to understand the code and avoids cut-and-paste types of error. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 37 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index d25df75ed404..856374bd3676 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -566,12 +566,13 @@ static u32 isdbt_rate[3][5][4] = { }; static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer, - u32 modulation, u32 fec, u32 interleaving, + u32 modulation, u32 forward_error_correction, + u32 interleaving, u32 segment) { struct mb86a20s_state *state = fe->demodulator_priv; u32 rate; - int m, f, i; + int mod, fec, guard; /* * If modulation/fec/interleaving is not detected, the default is @@ -582,54 +583,54 @@ static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer, case DQPSK: case QPSK: default: - m = 0; + mod = 0; break; case QAM_16: - m = 1; + mod = 1; break; case QAM_64: - m = 2; + mod = 2; break; } - switch (fec) { + switch (forward_error_correction) { default: case FEC_1_2: case FEC_AUTO: - f = 0; + fec = 0; break; case FEC_2_3: - f = 1; + fec = 1; break; case FEC_3_4: - f = 2; + fec = 2; break; case FEC_5_6: - f = 3; + fec = 3; break; case FEC_7_8: - f = 4; + fec = 4; break; } switch (interleaving) { default: case GUARD_INTERVAL_1_4: - i = 0; + guard = 0; break; case GUARD_INTERVAL_1_8: - i = 1; + guard = 1; break; case GUARD_INTERVAL_1_16: - i = 2; + guard = 2; break; case GUARD_INTERVAL_1_32: - i = 3; + guard = 3; break; } /* Samples BER at BER_SAMPLING_RATE seconds */ - rate = isdbt_rate[m][f][i] * segment * BER_SAMPLING_RATE; + rate = isdbt_rate[mod][fec][guard] * segment * BER_SAMPLING_RATE; /* Avoids sampling too quickly or to overflow the register */ if (rate < 256) @@ -639,13 +640,13 @@ static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer, dev_dbg(&state->i2c->dev, "%s: layer %c bitrate: %d kbps; counter = %d (0x%06x)\n", - __func__, 'A' + layer, segment * isdbt_rate[m][f][i]/1000, + __func__, 'A' + layer, + segment * isdbt_rate[mod][fec][guard]/1000, rate, rate); state->estimated_rate[layer] = rate; } - static int mb86a20s_get_frontend(struct dvb_frontend *fe) { struct mb86a20s_state *state = fe->demodulator_priv; -- cgit v1.2.3 From 752a62b2ec9c21931dce869f2ae2c921c83a1164 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 7 Apr 2013 21:11:53 -0300 Subject: [media] cx24123: improve precision when calculating symbol rate ratio Symbol rate ratio were using a rough calculus, as the code was limited to 32 bits arithmetic. Change it to 64 bits, in order to better estimate the bandwidth low-pass filter on the demod. This should reduce the noise and improve reception. Reported-by: Hans-Peter Jansen Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cx24123.c | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c index 68c88ab58e71..a771da3e9f99 100644 --- a/drivers/media/dvb-frontends/cx24123.c +++ b/drivers/media/dvb-frontends/cx24123.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "dvb_frontend.h" #include "cx24123.h" @@ -452,7 +453,8 @@ static u32 cx24123_int_log2(u32 a, u32 b) static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate) { - u32 tmp, sample_rate, ratio, sample_gain; + u64 tmp; + u32 sample_rate, ratio, sample_gain; u8 pll_mult; /* check if symbol rate is within limits */ @@ -482,27 +484,11 @@ static int cx24123_set_symbolrate(struct cx24123_state *state, u32 srate) sample_rate = pll_mult * XTAL; - /* - SYSSymbolRate[21:0] = (srate << 23) / sample_rate - - We have to use 32 bit unsigned arithmetic without precision loss. - The maximum srate is 45000000 or 0x02AEA540. This number has - only 6 clear bits on top, hence we can shift it left only 6 bits - at a time. Borrowed from cx24110.c - */ - - tmp = srate << 6; - ratio = tmp / sample_rate; - - tmp = (tmp % sample_rate) << 6; - ratio = (ratio << 6) + (tmp / sample_rate); - - tmp = (tmp % sample_rate) << 6; - ratio = (ratio << 6) + (tmp / sample_rate); - - tmp = (tmp % sample_rate) << 5; - ratio = (ratio << 5) + (tmp / sample_rate); + /* SYSSymbolRate[21:0] = (srate << 23) / sample_rate */ + tmp = ((u64)srate) << 23; + do_div(tmp, sample_rate); + ratio = (u32) tmp; cx24123_writereg(state, 0x01, pll_mult * 6); -- cgit v1.2.3 From 4a74772e6d2869b34b33f1072420c6891ce865ad Mon Sep 17 00:00:00 2001 From: Evgeny Plehov Date: Sun, 7 Apr 2013 23:56:46 -0300 Subject: [media] cxd2820r_t2: Multistream support (MultiPLP) MultiPLP filtering support for CXD2820r. Signed-off-by: Evgeny Plehov Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2820r_core.c | 3 ++- drivers/media/dvb-frontends/cxd2820r_t2.c | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 9b658c1cf39a..7ca5c69dd200 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -660,7 +660,8 @@ static const struct dvb_frontend_ops cxd2820r_ops = { FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | FE_CAN_MUTE_TS | - FE_CAN_2G_MODULATION + FE_CAN_2G_MODULATION | + FE_CAN_MULTISTREAM }, .release = cxd2820r_release, diff --git a/drivers/media/dvb-frontends/cxd2820r_t2.c b/drivers/media/dvb-frontends/cxd2820r_t2.c index e82d82a7a2eb..c2bfea7551e9 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t2.c +++ b/drivers/media/dvb-frontends/cxd2820r_t2.c @@ -124,6 +124,23 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe) buf[1] = ((if_ctl >> 8) & 0xff); buf[2] = ((if_ctl >> 0) & 0xff); + /* PLP filtering */ + if (c->stream_id < 0 || c->stream_id > 255) { + dev_dbg(&priv->i2c->dev, "%s: Disable PLP filtering\n", __func__); + ret = cxd2820r_wr_reg(priv, 0x023ad , 0); + if (ret) + goto error; + } else { + dev_dbg(&priv->i2c->dev, "%s: Enable PLP filtering = %d\n", __func__, + c->stream_id); + ret = cxd2820r_wr_reg(priv, 0x023af , c->stream_id & 0xFF); + if (ret) + goto error; + ret = cxd2820r_wr_reg(priv, 0x023ad , 1); + if (ret) + goto error; + } + ret = cxd2820r_wr_regs(priv, 0x020b6, buf, 3); if (ret) goto error; -- cgit v1.2.3 From 81e096c8ac6a064854c2157e0bf802dc4906678c Mon Sep 17 00:00:00 2001 From: Peter Wiese Date: Thu, 4 Apr 2013 17:36:12 -0300 Subject: [media] budget: Add support for Philips Semi Sylt PCI ref. design Add support for Philips Semiconductor (now NXP) SAA7146 reference design DVB Sat card, using ALPS BSRU6 tuner. [mchehab@redhat.com: Merge conflicts fix; email whitespacing unmangling] Signed-off-by: Peter Wiese Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/budget.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c index 7e6e43ae5c51..6ccc48833fd8 100644 --- a/drivers/media/pci/ttpci/budget.c +++ b/drivers/media/pci/ttpci/budget.c @@ -537,6 +537,16 @@ static void frontend_init(struct budget *budget) } break; + case 0x4f52: /* Cards based on Philips Semi Sylt PCI ref. design */ + budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + printk(KERN_INFO "budget: tuner ALPS BSRU6 in Philips Semi. Sylt detected\n"); + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + break; + } + break; + case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */ { int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67); @@ -818,6 +828,7 @@ MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps front MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY); MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY); MAKE_BUDGET_INFO(omicom, "Omicom S2 PCI", BUDGET_TT); +MAKE_BUDGET_INFO(sylt, "Philips Semi Sylt PCI", BUDGET_TT_HW_DISEQC); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), @@ -832,6 +843,7 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60), MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61), MAKE_EXTENSION_PCI(omicom, 0x14c4, 0x1020), + MAKE_EXTENSION_PCI(sylt, 0x1131, 0x4f52), { .vendor = 0, } -- cgit v1.2.3 From a34026e75bd1e6fdfbe8b59c320bb7d31c84b3da Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Fri, 11 Jan 2013 12:29:33 -0300 Subject: [media] s5p-mfc: Add support for EOS command and EOS event in video decoder Add support for V4L2_DEC_CMD_STOP command which will instruct MFC device to finish decoding and release all remaining frames kept for reference to the user. After dequeueing last decoded frame the driver will generate an V4L2_EVENT_EOS event. Signed-off-by: Kamil Debski Signed-off-by: Kyngmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 + drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 76 +++++++++++++++++++++++-- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 9 +++ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 10 +++- 4 files changed, 92 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 7379dc6dbebe..f608b7761be7 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -386,6 +386,8 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, } else { mfc_debug(2, "MFC needs next buffer\n"); ctx->consumed_stream = 0; + if (src_buf->flags & MFC_BUF_FLAG_EOS) + ctx->state = MFCINST_FINISHING; list_del(&src_buf->list); ctx->src_queue_cnt--; if (s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) > 0) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 4582473978ca..4af53bd2f182 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" @@ -623,17 +624,27 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) /* Dequeue a buffer */ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { + const struct v4l2_event ev = { + .type = V4L2_EVENT_EOS + }; struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + int ret; if (ctx->state == MFCINST_ERROR) { mfc_err("Call on DQBUF after unrecoverable error\n"); return -EIO; } if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); - else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); - return -EINVAL; + ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); + else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); + if (ret == 0 && ctx->state == MFCINST_FINISHED && + list_empty(&ctx->vq_dst.done_list)) + v4l2_event_queue_fh(&ctx->fh, &ev); + } else { + ret = -EINVAL; + } + return ret; } /* Export DMA buffer */ @@ -809,6 +820,59 @@ static int vidioc_g_crop(struct file *file, void *priv, return 0; } +int vidioc_decoder_cmd(struct file *file, void *priv, + struct v4l2_decoder_cmd *cmd) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *buf; + unsigned long flags; + + switch (cmd->cmd) { + case V4L2_ENC_CMD_STOP: + if (cmd->flags != 0) + return -EINVAL; + + if (!ctx->vq_src.streaming) + return -EINVAL; + + spin_lock_irqsave(&dev->irqlock, flags); + if (list_empty(&ctx->src_queue)) { + mfc_err("EOS: empty src queue, entering finishing state"); + ctx->state = MFCINST_FINISHING; + if (s5p_mfc_ctx_ready(ctx)) + set_work_bit_irqsave(ctx); + spin_unlock_irqrestore(&dev->irqlock, flags); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + } else { + mfc_err("EOS: marking last buffer of stream"); + buf = list_entry(ctx->src_queue.prev, + struct s5p_mfc_buf, list); + if (buf->flags & MFC_BUF_FLAG_USED) + ctx->state = MFCINST_FINISHING; + else + buf->flags |= MFC_BUF_FLAG_EOS; + spin_unlock_irqrestore(&dev->irqlock, flags); + } + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 2, NULL); + default: + return -EINVAL; + } +} + + /* v4l2_ioctl_ops */ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { .vidioc_querycap = vidioc_querycap, @@ -830,6 +894,9 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_g_crop = vidioc_g_crop, + .vidioc_decoder_cmd = vidioc_decoder_cmd, + .vidioc_subscribe_event = vidioc_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static int s5p_mfc_queue_setup(struct vb2_queue *vq, @@ -1147,3 +1214,4 @@ void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx) mfc_debug(2, "Default src_fmt is %x, dest_fmt is %x\n", (unsigned int)ctx->src_fmt, (unsigned int)ctx->dst_fmt); } + diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index c7ad329ca889..0af05a2d1cd4 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -1188,6 +1188,15 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) unsigned long flags; unsigned int index; + if (ctx->state == MFCINST_FINISHING) { + last_frame = MFC_DEC_LAST_FRAME; + s5p_mfc_set_dec_stream_buffer_v5(ctx, 0, 0, 0); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_decode_one_frame_v5(ctx, last_frame); + return 0; + } + spin_lock_irqsave(&dev->irqlock, flags); /* Frames are being decoded */ if (list_empty(&ctx->src_queue)) { diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 33de88b8e9d0..db57f2539f2d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -1363,8 +1363,16 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx) unsigned long flags; int last_frame = 0; - spin_lock_irqsave(&dev->irqlock, flags); + if (ctx->state == MFCINST_FINISHING) { + last_frame = MFC_DEC_LAST_FRAME; + s5p_mfc_set_dec_stream_buffer_v6(ctx, 0, 0, 0); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_decode_one_frame_v6(ctx, last_frame); + return 0; + } + spin_lock_irqsave(&dev->irqlock, flags); /* Frames are being decoded */ if (list_empty(&ctx->src_queue)) { mfc_debug(2, "No src buffers.\n"); -- cgit v1.2.3 From abd50853d9fff98e4277b0bc23e5cee23b058b9f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 8 Apr 2013 05:10:34 -0300 Subject: [media] s5c73m3: Fix s5c73m3-core.c compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix for this compiler warning: CC [M] drivers/media/i2c/s5c73m3/s5c73m3-core.o drivers/media/i2c/s5c73m3/s5c73m3-core.c: In function ‘s5c73m3_load_fw’: drivers/media/i2c/s5c73m3/s5c73m3-core.c:360:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘size_t’ [-Wformat] Signed-off-by: Hans Verkuil Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/s5c73m3/s5c73m3-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index 5dbb65e1f6b7..b353c50a6881 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -357,7 +357,7 @@ static int s5c73m3_load_fw(struct v4l2_subdev *sd) return -EINVAL; } - v4l2_info(sd, "Loading firmware (%s, %d B)\n", fw_name, fw->size); + v4l2_info(sd, "Loading firmware (%s, %zu B)\n", fw_name, fw->size); ret = s5c73m3_spi_write(state, fw->data, fw->size, 64); -- cgit v1.2.3 From 65fccab560922d8a1a1e7d3c9711c309126d636f Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 10 Apr 2013 07:17:52 -0300 Subject: [media] s5p-mfc: Remove potential uninitialized variable usage Make sure mem_info[] array is not used uninitialized. This prevents following compiler warning: drivers/media/platform/s5p-mfc/s5p_mfc.c: In function s5p_mfc_probe: drivers/media/platform/s5p-mfc/s5p_mfc.c:1032:33: warning: mem_info[0] may be used uninitialized in this function [-Wuninitialized] drivers/media/platform/s5p-mfc/s5p_mfc.c:1021:15: note: mem_info[0] was declared here drivers/media/platform/s5p-mfc/s5p_mfc.c:1032:33: warning: mem_info[1] may be used uninitialized in this function [-Wuninitialized] drivers/media/platform/s5p-mfc/s5p_mfc.c:1021:15: note: mem_info[1] was declared here Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index f608b7761be7..e810b1abf40e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1020,7 +1020,7 @@ static void *mfc_get_drv_data(struct platform_device *pdev); static int s5p_mfc_alloc_memdevs(struct s5p_mfc_dev *dev) { - unsigned int mem_info[2]; + unsigned int mem_info[2] = { }; dev->mem_dev_l = devm_kzalloc(&dev->plat_dev->dev, sizeof(struct device), GFP_KERNEL); -- cgit v1.2.3 From 488f29d00e819b178f9060fa08028b73d5f8d916 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 9 Apr 2013 07:19:27 -0300 Subject: [media] exynos4-is: Move the subdev group ID definitions to public header Move the sub-device group ID definitions to the driver's public header so they are available to other media drivers that need to share modules found in exynos4-is. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/media-dev.h | 9 --------- include/media/s5p_fimc.h | 11 +++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h index 0b14cd575747..7f126c3adacf 100644 --- a/drivers/media/platform/exynos4-is/media-dev.h +++ b/drivers/media/platform/exynos4-is/media-dev.h @@ -30,15 +30,6 @@ #define PINCTRL_STATE_IDLE "idle" -/* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */ -#define GRP_ID_SENSOR (1 << 8) -#define GRP_ID_FIMC_IS_SENSOR (1 << 9) -#define GRP_ID_WRITEBACK (1 << 10) -#define GRP_ID_CSIS (1 << 11) -#define GRP_ID_FIMC (1 << 12) -#define GRP_ID_FLITE (1 << 13) -#define GRP_ID_FIMC_IS (1 << 14) - #define FIMC_MAX_SENSORS 8 #define FIMC_MAX_CAMCLKS 2 diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h index e316d15896f9..f50969025ef3 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -49,6 +49,17 @@ enum fimc_bus_type { #define fimc_input_is_parallel(x) ((x) == 1 || (x) == 2) #define fimc_input_is_mipi_csi(x) ((x) == 3 || (x) == 4) +/* + * The subdevices' group IDs. + */ +#define GRP_ID_SENSOR (1 << 8) +#define GRP_ID_FIMC_IS_SENSOR (1 << 9) +#define GRP_ID_WRITEBACK (1 << 10) +#define GRP_ID_CSIS (1 << 11) +#define GRP_ID_FIMC (1 << 12) +#define GRP_ID_FLITE (1 << 13) +#define GRP_ID_FIMC_IS (1 << 14) + struct i2c_board_info; /** -- cgit v1.2.3 From 756e6e14484b3249dad9663ed1398711b62676a3 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 8 Apr 2013 13:17:36 -0300 Subject: [media] exynos4-is: Make fimc-lite independent of the pipeline->subdevs array Get the sensor subdev by walking media graph in both cases: when the device is used as a subdev only and through video node. This allows to not dereference the pipeline->subdevs[] array and makes the module more generic and easier to re-use in other media driver. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-lite.c | 57 +++++++++++++-------------- 1 file changed, 28 insertions(+), 29 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index cb196b85a858..3ea4fc7beaf7 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -130,23 +130,43 @@ static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat, return def_fmt; } +/* Called with the media graph mutex held or @me stream_count > 0. */ +static struct v4l2_subdev *__find_remote_sensor(struct media_entity *me) +{ + struct media_pad *pad = &me->pads[0]; + struct v4l2_subdev *sd; + + while (pad->flags & MEDIA_PAD_FL_SINK) { + /* source pad */ + pad = media_entity_remote_source(pad); + if (pad == NULL || + media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + break; + + sd = media_entity_to_v4l2_subdev(pad->entity); + + if (sd->grp_id == GRP_ID_FIMC_IS_SENSOR || + sd->grp_id == GRP_ID_SENSOR) + return sd; + /* sink pad */ + pad = &sd->entity.pads[0]; + } + return NULL; +} + static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output) { - struct fimc_pipeline *pipeline = &fimc->pipeline; - struct v4l2_subdev *sensor; struct fimc_sensor_info *si; unsigned long flags; - sensor = isp_output ? fimc->sensor : pipeline->subdevs[IDX_SENSOR]; - - if (sensor == NULL) + if (fimc->sensor == NULL) return -ENXIO; if (fimc->inp_frame.fmt == NULL || fimc->out_frame.fmt == NULL) return -EINVAL; /* Get sensor configuration data from the sensor subdev */ - si = v4l2_get_subdev_hostdata(sensor); + si = v4l2_get_subdev_hostdata(fimc->sensor); spin_lock_irqsave(&fimc->slock, flags); flite_hw_set_camera_bus(fimc, &si->pdata); @@ -801,6 +821,8 @@ static int fimc_lite_streamon(struct file *file, void *priv, if (ret < 0) goto err_p_stop; + fimc->sensor = __find_remote_sensor(&fimc->subdev.entity); + ret = vb2_ioctl_streamon(file, priv, type); if (!ret) { fimc->streaming = true; @@ -929,29 +951,6 @@ static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = { .vidioc_streamoff = fimc_lite_streamoff, }; -/* Called with the media graph mutex held */ -static struct v4l2_subdev *__find_remote_sensor(struct media_entity *me) -{ - struct media_pad *pad = &me->pads[0]; - struct v4l2_subdev *sd; - - while (pad->flags & MEDIA_PAD_FL_SINK) { - /* source pad */ - pad = media_entity_remote_source(pad); - if (pad == NULL || - media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) - break; - - sd = media_entity_to_v4l2_subdev(pad->entity); - - if (sd->grp_id == GRP_ID_FIMC_IS_SENSOR) - return sd; - /* sink pad */ - pad = &sd->entity.pads[0]; - } - return NULL; -} - /* Capture subdev media entity operations */ static int fimc_lite_link_setup(struct media_entity *entity, const struct media_pad *local, -- cgit v1.2.3 From 4c8f0629f53bb198ed00c2c54cf80cc2be95acab Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 9 Apr 2013 11:11:58 -0300 Subject: [media] exynos4-is: Make fimc-lite independent of struct fimc_sensor_info Make the sensor subdevs host_data hold a pointer to struct fimc_source_info, which is defined in the driver's public header, rather than a pointer to struct fimc_sensor_info which is specific to exynos4-is media device driver. The purpose of this change is to allow easier reuse of the fimc-lite module in the exynos5-is driver, which should similarly store a pointer to struct fimc_source_info instance in the sensor's subdev host_data. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-capture.c | 7 ++- drivers/media/platform/exynos4-is/fimc-lite.c | 10 +++- drivers/media/platform/exynos4-is/media-dev.c | 74 ++++++++++++------------ drivers/media/platform/exynos4-is/media-dev.h | 6 ++ 4 files changed, 54 insertions(+), 43 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 28c6b26f6ff5..72c516af40f6 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -1450,7 +1450,7 @@ static const struct media_entity_operations fimc_sd_media_ops = { void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification, void *arg) { - struct fimc_sensor_info *sensor; + struct fimc_source_info *si; struct fimc_vid_buffer *buf; struct fimc_md *fmd; struct fimc_dev *fimc; @@ -1459,11 +1459,12 @@ void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification, if (sd == NULL) return; - sensor = v4l2_get_subdev_hostdata(sd); + si = v4l2_get_subdev_hostdata(sd); fmd = entity_to_fimc_mdev(&sd->entity); spin_lock_irqsave(&fmd->slock, flags); - fimc = sensor ? sensor->host : NULL; + + fimc = si ? source_to_sensor_info(si)->host : NULL; if (fimc && arg && notification == S5P_FIMC_TX_END_NOTIFY && test_bit(ST_CAPT_PEND, &fimc->state)) { diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 3ea4fc7beaf7..661d0d148cb5 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -11,6 +11,7 @@ #define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ #include +#include #include #include #include @@ -31,7 +32,7 @@ #include #include -#include "media-dev.h" +#include "fimc-core.h" #include "fimc-lite.h" #include "fimc-lite-reg.h" @@ -156,7 +157,7 @@ static struct v4l2_subdev *__find_remote_sensor(struct media_entity *me) static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output) { - struct fimc_sensor_info *si; + struct fimc_source_info *si; unsigned long flags; if (fimc->sensor == NULL) @@ -167,9 +168,12 @@ static int fimc_lite_hw_init(struct fimc_lite *fimc, bool isp_output) /* Get sensor configuration data from the sensor subdev */ si = v4l2_get_subdev_hostdata(fimc->sensor); + if (!si) + return -EINVAL; + spin_lock_irqsave(&fimc->slock, flags); - flite_hw_set_camera_bus(fimc, &si->pdata); + flite_hw_set_camera_bus(fimc, si); flite_hw_set_source_format(fimc, &fimc->inp_frame); flite_hw_set_window_offset(fimc, &fimc->inp_frame); flite_hw_set_output_dma(fimc, &fimc->out_frame, !isp_output); diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 44d6c1d5bf4b..1dbd55422706 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -37,7 +37,7 @@ #include "mipi-csis.h" static int __fimc_md_set_camclk(struct fimc_md *fmd, - struct fimc_sensor_info *s_info, + struct fimc_source_info *si, bool on); /** * fimc_pipeline_prepare - update pipeline information with subdevice pointers @@ -281,36 +281,36 @@ static const struct fimc_pipeline_ops fimc_pipeline_ops = { * Sensor subdevice helper functions */ static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd, - struct fimc_sensor_info *s_info) + struct fimc_source_info *si) { struct i2c_adapter *adapter; struct v4l2_subdev *sd = NULL; - if (!s_info || !fmd) + if (!si || !fmd) return NULL; /* * If FIMC bus type is not Writeback FIFO assume it is same * as sensor_bus_type. */ - s_info->pdata.fimc_bus_type = s_info->pdata.sensor_bus_type; + si->fimc_bus_type = si->sensor_bus_type; - adapter = i2c_get_adapter(s_info->pdata.i2c_bus_num); + adapter = i2c_get_adapter(si->i2c_bus_num); if (!adapter) { v4l2_warn(&fmd->v4l2_dev, "Failed to get I2C adapter %d, deferring probe\n", - s_info->pdata.i2c_bus_num); + si->i2c_bus_num); return ERR_PTR(-EPROBE_DEFER); } sd = v4l2_i2c_new_subdev_board(&fmd->v4l2_dev, adapter, - s_info->pdata.board_info, NULL); + si->board_info, NULL); if (IS_ERR_OR_NULL(sd)) { i2c_put_adapter(adapter); v4l2_warn(&fmd->v4l2_dev, "Failed to acquire subdev %s, deferring probe\n", - s_info->pdata.board_info->type); + si->board_info->type); return ERR_PTR(-EPROBE_DEFER); } - v4l2_set_subdev_hostdata(sd, s_info); + v4l2_set_subdev_hostdata(sd, si); sd->grp_id = GRP_ID_SENSOR; v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice %s\n", @@ -365,17 +365,17 @@ static int fimc_md_of_add_sensor(struct fimc_md *fmd, } /* Enable sensor's master clock */ - ret = __fimc_md_set_camclk(fmd, si, true); + ret = __fimc_md_set_camclk(fmd, &si->pdata, true); if (ret < 0) goto mod_put; sd = i2c_get_clientdata(client); ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); - __fimc_md_set_camclk(fmd, si, false); + __fimc_md_set_camclk(fmd, &si->pdata, false); if (ret < 0) goto mod_put; - v4l2_set_subdev_hostdata(sd, si); + v4l2_set_subdev_hostdata(sd, &si->pdata); if (si->pdata.fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) sd->grp_id = GRP_ID_FIMC_IS_SENSOR; else @@ -559,21 +559,22 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) fmd->num_sensors = num_clients; for (i = 0; i < num_clients; i++) { + struct fimc_sensor_info *si = &fmd->sensor[i]; struct v4l2_subdev *sd; - fmd->sensor[i].pdata = pdata->source_info[i]; - ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], true); + si->pdata = pdata->source_info[i]; + ret = __fimc_md_set_camclk(fmd, &si->pdata, true); if (ret) break; - sd = fimc_md_register_sensor(fmd, &fmd->sensor[i]); - ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], false); + sd = fimc_md_register_sensor(fmd, &si->pdata); + ret = __fimc_md_set_camclk(fmd, &si->pdata, false); if (IS_ERR(sd)) { - fmd->sensor[i].subdev = NULL; + si->subdev = NULL; ret = PTR_ERR(sd); break; } - fmd->sensor[i].subdev = sd; + si->subdev = sd; if (ret) break; } @@ -838,7 +839,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, struct v4l2_subdev *sensor, int pad, int link_mask) { - struct fimc_sensor_info *si = NULL; + struct fimc_source_info *si = NULL; struct media_entity *sink; unsigned int flags = 0; int i, ret = 0; @@ -846,7 +847,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, if (sensor) { si = v4l2_get_subdev_hostdata(sensor); /* Skip direct FIMC links in the logical FIMC-IS sensor path */ - if (si && si->pdata.fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) + if (si && si->fimc_bus_type == FIMC_BUS_TYPE_ISP_WRITEBACK) ret = 1; } @@ -882,8 +883,10 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, if (!WARN_ON(si == NULL)) { unsigned long irq_flags; + struct fimc_sensor_info *inf = source_to_sensor_info(si); + spin_lock_irqsave(&fmd->slock, irq_flags); - si->host = fmd->fimc[i]; + inf->host = fmd->fimc[i]; spin_unlock_irqrestore(&fmd->slock, irq_flags); } } @@ -980,7 +983,6 @@ static int fimc_md_create_links(struct fimc_md *fmd) struct v4l2_subdev *csi_sensors[CSIS_MAX_ENTITIES] = { NULL }; struct v4l2_subdev *sensor, *csis; struct fimc_source_info *pdata; - struct fimc_sensor_info *s_info; struct media_entity *source, *sink; int i, pad, fimc_id = 0, ret = 0; u32 flags, link_mask = 0; @@ -990,12 +992,11 @@ static int fimc_md_create_links(struct fimc_md *fmd) continue; sensor = fmd->sensor[i].subdev; - s_info = v4l2_get_subdev_hostdata(sensor); - if (!s_info) + pdata = v4l2_get_subdev_hostdata(sensor); + if (!pdata) continue; source = NULL; - pdata = &s_info->pdata; switch (pdata->sensor_bus_type) { case FIMC_BUS_TYPE_MIPI_CSI2: @@ -1164,34 +1165,33 @@ static int fimc_md_get_clocks(struct fimc_md *fmd) } static int __fimc_md_set_camclk(struct fimc_md *fmd, - struct fimc_sensor_info *s_info, + struct fimc_source_info *si, bool on) { - struct fimc_source_info *pdata = &s_info->pdata; struct fimc_camclk_info *camclk; int ret = 0; - if (WARN_ON(pdata->clk_id >= FIMC_MAX_CAMCLKS) || !fmd || !fmd->pmf) + if (WARN_ON(si->clk_id >= FIMC_MAX_CAMCLKS) || !fmd || !fmd->pmf) return -EINVAL; - camclk = &fmd->camclk[pdata->clk_id]; + camclk = &fmd->camclk[si->clk_id]; dbg("camclk %d, f: %lu, use_count: %d, on: %d", - pdata->clk_id, pdata->clk_frequency, camclk->use_count, on); + si->clk_id, si->clk_frequency, camclk->use_count, on); if (on) { if (camclk->use_count > 0 && - camclk->frequency != pdata->clk_frequency) + camclk->frequency != si->clk_frequency) return -EINVAL; if (camclk->use_count++ == 0) { - clk_set_rate(camclk->clock, pdata->clk_frequency); - camclk->frequency = pdata->clk_frequency; + clk_set_rate(camclk->clock, si->clk_frequency); + camclk->frequency = si->clk_frequency; ret = pm_runtime_get_sync(fmd->pmf); if (ret < 0) return ret; ret = clk_enable(camclk->clock); - dbg("Enabled camclk %d: f: %lu", pdata->clk_id, + dbg("Enabled camclk %d: f: %lu", si->clk_id, clk_get_rate(camclk->clock)); } return ret; @@ -1203,7 +1203,7 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd, if (--camclk->use_count == 0) { clk_disable(camclk->clock); pm_runtime_put(fmd->pmf); - dbg("Disabled camclk %d", pdata->clk_id); + dbg("Disabled camclk %d", si->clk_id); } return ret; } @@ -1222,10 +1222,10 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd, */ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on) { - struct fimc_sensor_info *s_info = v4l2_get_subdev_hostdata(sd); + struct fimc_source_info *si = v4l2_get_subdev_hostdata(sd); struct fimc_md *fmd = entity_to_fimc_mdev(&sd->entity); - return __fimc_md_set_camclk(fmd, s_info, on); + return __fimc_md_set_camclk(fmd, si, on); } static int fimc_md_link_notify(struct media_pad *source, diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h index 7f126c3adacf..44d86b61d660 100644 --- a/drivers/media/platform/exynos4-is/media-dev.h +++ b/drivers/media/platform/exynos4-is/media-dev.h @@ -115,6 +115,12 @@ struct fimc_md { #define subdev_has_devnode(__sd) (__sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE) +static inline +struct fimc_sensor_info *source_to_sensor_info(struct fimc_source_info *si) +{ + return container_of(si, struct fimc_sensor_info, pdata); +} + static inline struct fimc_md *entity_to_fimc_mdev(struct media_entity *me) { return me->parent == NULL ? NULL : -- cgit v1.2.3 From a6f5635e63ffa02c30a22ea4af21f3daa1e98cdf Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 10 Apr 2013 06:23:05 -0300 Subject: [media] exynos4-is: Improve the ISP chain parameter count calculation Instead of incrementing p_region_num field each time we set a bit in the parameter mask calculate the number of bits set only when this information is needed. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is-param.c | 86 +++++++---------------- drivers/media/platform/exynos4-is/fimc-is-param.h | 4 +- drivers/media/platform/exynos4-is/fimc-is-regs.c | 3 +- drivers/media/platform/exynos4-is/fimc-is.c | 2 - drivers/media/platform/exynos4-is/fimc-is.h | 1 - drivers/media/platform/exynos4-is/fimc-isp.c | 7 +- 6 files changed, 34 insertions(+), 69 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c index 37fd5fe68eef..58123e3e1b62 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-param.c +++ b/drivers/media/platform/exynos4-is/fimc-is-param.c @@ -12,14 +12,15 @@ */ #define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ +#include #include #include #include #include #include -#include #include #include +#include #include #include @@ -160,6 +161,20 @@ int __fimc_is_hw_update_param(struct fimc_is *is, u32 offset) return 0; } +unsigned int __get_pending_param_count(struct fimc_is *is) +{ + struct is_config_param *config = &is->cfg_param[is->scenario_id]; + unsigned long flags; + unsigned int count; + + spin_lock_irqsave(&is->slock, flags); + count = hweight32(config->p_region_index1); + count += hweight32(config->p_region_index2); + spin_unlock_irqrestore(&is->slock, flags); + + return count; +} + int __is_hw_update_params(struct fimc_is *is) { unsigned long *p_index1, *p_index2; @@ -234,15 +249,10 @@ void __is_set_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf) /* Update field */ fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT); - fimc_is_inc_param_num(is); fimc_is_set_param_bit(is, PARAM_ISP_OTF_OUTPUT); - fimc_is_inc_param_num(is); fimc_is_set_param_bit(is, PARAM_DRC_OTF_INPUT); - fimc_is_inc_param_num(is); fimc_is_set_param_bit(is, PARAM_DRC_OTF_OUTPUT); - fimc_is_inc_param_num(is); fimc_is_set_param_bit(is, PARAM_FD_OTF_INPUT); - fimc_is_inc_param_num(is); } int fimc_is_hw_get_sensor_max_framerate(struct fimc_is *is) @@ -277,14 +287,11 @@ void __is_set_sensor(struct fimc_is *is, int fps) isp->otf_input.frametime_max = (u32)1000000 / fps; } - if (!test_bit(PARAM_SENSOR_FRAME_RATE, p_index)) { + if (!test_bit(PARAM_SENSOR_FRAME_RATE, p_index)) fimc_is_set_param_bit(is, PARAM_SENSOR_FRAME_RATE); - fimc_is_inc_param_num(is); - } - if (!test_bit(PARAM_ISP_OTF_INPUT, p_index)) { + + if (!test_bit(PARAM_ISP_OTF_INPUT, p_index)) fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT); - fimc_is_inc_param_num(is); - } } void __is_set_init_isp_aa(struct fimc_is *is) @@ -306,7 +313,6 @@ void __is_set_init_isp_aa(struct fimc_is *is) isp->aa.err = ISP_AF_ERROR_NONE; fimc_is_set_param_bit(is, PARAM_ISP_AA); - fimc_is_inc_param_num(is); } void __is_set_isp_flash(struct fimc_is *is, u32 cmd, u32 redeye) @@ -319,10 +325,8 @@ void __is_set_isp_flash(struct fimc_is *is, u32 cmd, u32 redeye) isp->flash.redeye = redeye; isp->flash.err = ISP_FLASH_ERROR_NONE; - if (!test_bit(PARAM_ISP_FLASH, &cfg->p_region_index1)) { + if (!test_bit(PARAM_ISP_FLASH, &cfg->p_region_index1)) fimc_is_set_param_bit(is, PARAM_ISP_FLASH); - fimc_is_inc_param_num(is); - } } void __is_set_isp_awb(struct fimc_is *is, u32 cmd, u32 val) @@ -338,10 +342,8 @@ void __is_set_isp_awb(struct fimc_is *is, u32 cmd, u32 val) isp->awb.illumination = val; isp->awb.err = ISP_AWB_ERROR_NONE; - if (!test_bit(PARAM_ISP_AWB, p_index)) { + if (!test_bit(PARAM_ISP_AWB, p_index)) fimc_is_set_param_bit(is, PARAM_ISP_AWB); - fimc_is_inc_param_num(is); - } } void __is_set_isp_effect(struct fimc_is *is, u32 cmd) @@ -356,10 +358,8 @@ void __is_set_isp_effect(struct fimc_is *is, u32 cmd) isp->effect.cmd = cmd; isp->effect.err = ISP_IMAGE_EFFECT_ERROR_NONE; - if (!test_bit(PARAM_ISP_IMAGE_EFFECT, p_index)) { + if (!test_bit(PARAM_ISP_IMAGE_EFFECT, p_index)) fimc_is_set_param_bit(is, PARAM_ISP_IMAGE_EFFECT); - fimc_is_inc_param_num(is); - } } void __is_set_isp_iso(struct fimc_is *is, u32 cmd, u32 val) @@ -375,10 +375,8 @@ void __is_set_isp_iso(struct fimc_is *is, u32 cmd, u32 val) isp->iso.value = val; isp->iso.err = ISP_ISO_ERROR_NONE; - if (!test_bit(PARAM_ISP_ISO, p_index)) { + if (!test_bit(PARAM_ISP_ISO, p_index)) fimc_is_set_param_bit(is, PARAM_ISP_ISO); - fimc_is_inc_param_num(is); - } } void __is_set_isp_adjust(struct fimc_is *is, u32 cmd, u32 val) @@ -423,7 +421,6 @@ void __is_set_isp_adjust(struct fimc_is *is, u32 cmd, u32 val) isp->adjust.cmd = cmd; isp->adjust.err = ISP_ADJUST_ERROR_NONE; fimc_is_set_param_bit(is, PARAM_ISP_ADJUST); - fimc_is_inc_param_num(is); } else { isp->adjust.cmd |= cmd; } @@ -461,7 +458,6 @@ void __is_set_isp_metering(struct fimc_is *is, u32 id, u32 val) if (!test_bit(PARAM_ISP_METERING, p_index)) { isp->metering.err = ISP_METERING_ERROR_NONE; fimc_is_set_param_bit(is, PARAM_ISP_METERING); - fimc_is_inc_param_num(is); } } @@ -478,10 +474,8 @@ void __is_set_isp_afc(struct fimc_is *is, u32 cmd, u32 val) isp->afc.manual = val; isp->afc.err = ISP_AFC_ERROR_NONE; - if (!test_bit(PARAM_ISP_AFC, p_index)) { + if (!test_bit(PARAM_ISP_AFC, p_index)) fimc_is_set_param_bit(is, PARAM_ISP_AFC); - fimc_is_inc_param_num(is); - } } void __is_set_drc_control(struct fimc_is *is, u32 val) @@ -495,10 +489,8 @@ void __is_set_drc_control(struct fimc_is *is, u32 val) drc->control.bypass = val; - if (!test_bit(PARAM_DRC_CONTROL, p_index)) { + if (!test_bit(PARAM_DRC_CONTROL, p_index)) fimc_is_set_param_bit(is, PARAM_DRC_CONTROL); - fimc_is_inc_param_num(is); - } } void __is_set_fd_control(struct fimc_is *is, u32 val) @@ -512,10 +504,8 @@ void __is_set_fd_control(struct fimc_is *is, u32 val) fd->control.cmd = val; - if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) { + if (!test_bit((PARAM_FD_CONFIG - 32), p_index)) fimc_is_set_param_bit(is, PARAM_FD_CONTROL); - fimc_is_inc_param_num(is); - } } void __is_set_fd_config_maxface(struct fimc_is *is, u32 val) @@ -533,7 +523,6 @@ void __is_set_fd_config_maxface(struct fimc_is *is, u32 val) fd->config.cmd = FD_CONFIG_COMMAND_MAXIMUM_NUMBER; fd->config.err = ERROR_FD_NONE; fimc_is_set_param_bit(is, PARAM_FD_CONFIG); - fimc_is_inc_param_num(is); } else { fd->config.cmd |= FD_CONFIG_COMMAND_MAXIMUM_NUMBER; } @@ -554,7 +543,6 @@ void __is_set_fd_config_rollangle(struct fimc_is *is, u32 val) fd->config.cmd = FD_CONFIG_COMMAND_ROLL_ANGLE; fd->config.err = ERROR_FD_NONE; fimc_is_set_param_bit(is, PARAM_FD_CONFIG); - fimc_is_inc_param_num(is); } else { fd->config.cmd |= FD_CONFIG_COMMAND_ROLL_ANGLE; } @@ -575,7 +563,6 @@ void __is_set_fd_config_yawangle(struct fimc_is *is, u32 val) fd->config.cmd = FD_CONFIG_COMMAND_YAW_ANGLE; fd->config.err = ERROR_FD_NONE; fimc_is_set_param_bit(is, PARAM_FD_CONFIG); - fimc_is_inc_param_num(is); } else { fd->config.cmd |= FD_CONFIG_COMMAND_YAW_ANGLE; } @@ -596,7 +583,6 @@ void __is_set_fd_config_smilemode(struct fimc_is *is, u32 val) fd->config.cmd = FD_CONFIG_COMMAND_SMILE_MODE; fd->config.err = ERROR_FD_NONE; fimc_is_set_param_bit(is, PARAM_FD_CONFIG); - fimc_is_inc_param_num(is); } else { fd->config.cmd |= FD_CONFIG_COMMAND_SMILE_MODE; } @@ -617,7 +603,6 @@ void __is_set_fd_config_blinkmode(struct fimc_is *is, u32 val) fd->config.cmd = FD_CONFIG_COMMAND_BLINK_MODE; fd->config.err = ERROR_FD_NONE; fimc_is_set_param_bit(is, PARAM_FD_CONFIG); - fimc_is_inc_param_num(is); } else { fd->config.cmd |= FD_CONFIG_COMMAND_BLINK_MODE; } @@ -638,7 +623,6 @@ void __is_set_fd_config_eyedetect(struct fimc_is *is, u32 val) fd->config.cmd = FD_CONFIG_COMMAND_EYES_DETECT; fd->config.err = ERROR_FD_NONE; fimc_is_set_param_bit(is, PARAM_FD_CONFIG); - fimc_is_inc_param_num(is); } else { fd->config.cmd |= FD_CONFIG_COMMAND_EYES_DETECT; } @@ -659,7 +643,6 @@ void __is_set_fd_config_mouthdetect(struct fimc_is *is, u32 val) fd->config.cmd = FD_CONFIG_COMMAND_MOUTH_DETECT; fd->config.err = ERROR_FD_NONE; fimc_is_set_param_bit(is, PARAM_FD_CONFIG); - fimc_is_inc_param_num(is); } else { fd->config.cmd |= FD_CONFIG_COMMAND_MOUTH_DETECT; } @@ -680,7 +663,6 @@ void __is_set_fd_config_orientation(struct fimc_is *is, u32 val) fd->config.cmd = FD_CONFIG_COMMAND_ORIENTATION; fd->config.err = ERROR_FD_NONE; fimc_is_set_param_bit(is, PARAM_FD_CONFIG); - fimc_is_inc_param_num(is); } else { fd->config.cmd |= FD_CONFIG_COMMAND_ORIENTATION; } @@ -701,7 +683,6 @@ void __is_set_fd_config_orientation_val(struct fimc_is *is, u32 val) fd->config.cmd = FD_CONFIG_COMMAND_ORIENTATION_VALUE; fd->config.err = ERROR_FD_NONE; fimc_is_set_param_bit(is, PARAM_FD_CONFIG); - fimc_is_inc_param_num(is); } else { fd->config.cmd |= FD_CONFIG_COMMAND_ORIENTATION_VALUE; } @@ -729,21 +710,18 @@ void fimc_is_set_initial_params(struct fimc_is *is) /* Global */ global->shotmode.cmd = 1; fimc_is_set_param_bit(is, PARAM_GLOBAL_SHOTMODE); - fimc_is_inc_param_num(is); /* ISP */ isp->control.cmd = CONTROL_COMMAND_START; isp->control.bypass = CONTROL_BYPASS_DISABLE; isp->control.err = CONTROL_ERROR_NONE; fimc_is_set_param_bit(is, PARAM_ISP_CONTROL); - fimc_is_inc_param_num(is); isp->otf_input.cmd = OTF_INPUT_COMMAND_ENABLE; if (!test_bit(PARAM_ISP_OTF_INPUT, p_index1)) { isp->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH; isp->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT; fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT); - fimc_is_inc_param_num(is); } if (is->sensor->test_pattern) isp->otf_input.format = OTF_INPUT_FORMAT_STRGEN_COLORBAR_BAYER; @@ -766,7 +744,6 @@ void fimc_is_set_initial_params(struct fimc_is *is) isp->dma1_input.width = 0; isp->dma1_input.err = DMA_INPUT_ERROR_NONE; fimc_is_set_param_bit(is, PARAM_ISP_DMA1_INPUT); - fimc_is_inc_param_num(is); isp->dma2_input.cmd = DMA_INPUT_COMMAND_DISABLE; isp->dma2_input.width = 0; @@ -779,12 +756,10 @@ void fimc_is_set_initial_params(struct fimc_is *is) isp->dma2_input.width = 0; isp->dma2_input.err = DMA_INPUT_ERROR_NONE; fimc_is_set_param_bit(is, PARAM_ISP_DMA2_INPUT); - fimc_is_inc_param_num(is); isp->aa.cmd = ISP_AA_COMMAND_START; isp->aa.target = ISP_AA_TARGET_AE | ISP_AA_TARGET_AWB; fimc_is_set_param_bit(is, PARAM_ISP_AA); - fimc_is_inc_param_num(is); if (!test_bit(PARAM_ISP_FLASH, p_index1)) __is_set_isp_flash(is, ISP_FLASH_COMMAND_DISABLE, @@ -826,7 +801,6 @@ void fimc_is_set_initial_params(struct fimc_is *is) isp->otf_output.width = DEFAULT_PREVIEW_STILL_WIDTH; isp->otf_output.height = DEFAULT_PREVIEW_STILL_HEIGHT; fimc_is_set_param_bit(is, PARAM_ISP_OTF_OUTPUT); - fimc_is_inc_param_num(is); } isp->otf_output.format = OTF_OUTPUT_FORMAT_YUV444; isp->otf_output.bitwidth = 12; @@ -847,7 +821,6 @@ void fimc_is_set_initial_params(struct fimc_is *is) isp->dma1_output.dma_out_mask = 0; isp->dma1_output.err = DMA_OUTPUT_ERROR_NONE; fimc_is_set_param_bit(is, PARAM_ISP_DMA1_OUTPUT); - fimc_is_inc_param_num(is); } if (!test_bit(PARAM_ISP_DMA2_OUTPUT, p_index1)) { @@ -864,7 +837,6 @@ void fimc_is_set_initial_params(struct fimc_is *is) isp->dma2_output.dma_out_mask = 0; isp->dma2_output.err = DMA_OUTPUT_ERROR_NONE; fimc_is_set_param_bit(is, PARAM_ISP_DMA2_OUTPUT); - fimc_is_inc_param_num(is); } /* Sensor */ @@ -882,7 +854,6 @@ void fimc_is_set_initial_params(struct fimc_is *is) drc->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH; drc->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT; fimc_is_set_param_bit(is, PARAM_DRC_OTF_INPUT); - fimc_is_inc_param_num(is); } drc->otf_input.format = OTF_INPUT_FORMAT_YUV444; drc->otf_input.bitwidth = 12; @@ -900,14 +871,12 @@ void fimc_is_set_initial_params(struct fimc_is *is) drc->dma_input.width = 0; drc->dma_input.err = DMA_INPUT_ERROR_NONE; fimc_is_set_param_bit(is, PARAM_DRC_DMA_INPUT); - fimc_is_inc_param_num(is); drc->otf_output.cmd = OTF_OUTPUT_COMMAND_ENABLE; if (!test_bit(PARAM_DRC_OTF_OUTPUT, p_index1)) { drc->otf_output.width = DEFAULT_PREVIEW_STILL_WIDTH; drc->otf_output.height = DEFAULT_PREVIEW_STILL_HEIGHT; fimc_is_set_param_bit(is, PARAM_DRC_OTF_OUTPUT); - fimc_is_inc_param_num(is); } drc->otf_output.format = OTF_OUTPUT_FORMAT_YUV444; drc->otf_output.bitwidth = 8; @@ -923,8 +892,8 @@ void fimc_is_set_initial_params(struct fimc_is *is) fd->otf_input.width = DEFAULT_PREVIEW_STILL_WIDTH; fd->otf_input.height = DEFAULT_PREVIEW_STILL_HEIGHT; fimc_is_set_param_bit(is, PARAM_FD_OTF_INPUT); - fimc_is_inc_param_num(is); } + fd->otf_input.format = OTF_INPUT_FORMAT_YUV444; fd->otf_input.bitwidth = 8; fd->otf_input.order = 0; @@ -941,7 +910,6 @@ void fimc_is_set_initial_params(struct fimc_is *is) fd->dma_input.width = 0; fd->dma_input.err = DMA_INPUT_ERROR_NONE; fimc_is_set_param_bit(is, PARAM_FD_DMA_INPUT); - fimc_is_inc_param_num(is); __is_set_fd_config_maxface(is, 5); __is_set_fd_config_rollangle(is, FD_CONFIG_ROLL_ANGLE_FULL); diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.h b/drivers/media/platform/exynos4-is/fimc-is-param.h index 71464a58b56b..f9358c27ae2d 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-param.h +++ b/drivers/media/platform/exynos4-is/fimc-is-param.h @@ -985,13 +985,11 @@ struct sensor_open_extended { u32 i2c_sclk; }; -#define fimc_is_inc_param_num(is) \ - atomic_inc(&(is)->cfg_param[(is)->scenario_id].p_region_num) - struct fimc_is; int fimc_is_hw_get_sensor_max_framerate(struct fimc_is *is); void fimc_is_set_initial_params(struct fimc_is *is); +unsigned int __get_pending_param_count(struct fimc_is *is); int __is_hw_update_params(struct fimc_is *is); void __is_get_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf); diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c index efb9da06052c..f59a289c530d 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-regs.c +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c @@ -80,6 +80,7 @@ int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is) int fimc_is_hw_set_param(struct fimc_is *is) { struct is_config_param *cfg = &is->cfg_param[is->scenario_id]; + unsigned int param_count = __get_pending_param_count(is); fimc_is_hw_wait_intmsr0_intmsd0(is); @@ -87,7 +88,7 @@ int fimc_is_hw_set_param(struct fimc_is *is) mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); mcuctl_write(is->scenario_id, is, MCUCTL_REG_ISSR(2)); - mcuctl_write(atomic_read(&cfg->p_region_num), is, MCUCTL_REG_ISSR(3)); + mcuctl_write(param_count, is, MCUCTL_REG_ISSR(3)); mcuctl_write(cfg->p_region_index1, is, MCUCTL_REG_ISSR(4)); mcuctl_write(cfg->p_region_index2, is, MCUCTL_REG_ISSR(5)); diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index c5e4c5380f24..10ec173d1254 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -532,7 +532,6 @@ static void fimc_is_general_irq_handler(struct fimc_is *is) case HIC_SET_PARAMETER: is->cfg_param[is->scenario_id].p_region_index1 = 0; is->cfg_param[is->scenario_id].p_region_index2 = 0; - atomic_set(&is->cfg_param[is->scenario_id].p_region_num, 0); set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state); pr_debug("HIC_SET_PARAMETER\n"); break; @@ -593,7 +592,6 @@ static void fimc_is_general_irq_handler(struct fimc_is *is) case HIC_SET_PARAMETER: is->cfg_param[is->scenario_id].p_region_index1 = 0; is->cfg_param[is->scenario_id].p_region_index2 = 0; - atomic_set(&is->cfg_param[is->scenario_id].p_region_num, 0); set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state); break; } diff --git a/drivers/media/platform/exynos4-is/fimc-is.h b/drivers/media/platform/exynos4-is/fimc-is.h index 936e2ca5c1d2..9406894f306d 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.h +++ b/drivers/media/platform/exynos4-is/fimc-is.h @@ -226,7 +226,6 @@ struct is_config_param { struct drc_param drc; struct fd_param fd; - atomic_t p_region_num; unsigned long p_region_index1; unsigned long p_region_index2; }; diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index 59502b111a8b..b11c001ad388 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -229,8 +229,11 @@ static int fimc_isp_subdev_s_stream(struct v4l2_subdev *sd, int on) fimc_is_mem_barrier(); if (on) { - if (atomic_read(&is->cfg_param[is->scenario_id].p_region_num)) + if (__get_pending_param_count(is)) { ret = fimc_is_itf_s_param(is, true); + if (ret < 0) + return ret; + } v4l2_dbg(1, debug, sd, "changing mode to %d\n", is->scenario_id); @@ -414,7 +417,6 @@ static int __ctrl_set_aewb_lock(struct fimc_is *is, isp->aa.cmd = cmd; isp->aa.target = ISP_AA_TARGET_AE; fimc_is_set_param_bit(is, PARAM_ISP_AA); - fimc_is_inc_param_num(is); is->af.ae_lock_state = ae_lock; wmb(); @@ -426,7 +428,6 @@ static int __ctrl_set_aewb_lock(struct fimc_is *is, isp->aa.cmd = cmd; isp->aa.target = ISP_AA_TARGET_AE; fimc_is_set_param_bit(is, PARAM_ISP_AA); - fimc_is_inc_param_num(is); is->af.awb_lock_state = awb_lock; wmb(); -- cgit v1.2.3 From 3530ef0a6ea56636b23b5a15ff645632f7596c04 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 10 Apr 2013 06:24:46 -0300 Subject: [media] exynos4-is: Rename the ISP chain configuration data structure More appropriate names for the ISP chain data structure. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is-param.c | 191 +++++++++++----------- drivers/media/platform/exynos4-is/fimc-is-regs.c | 14 +- drivers/media/platform/exynos4-is/fimc-is.c | 22 +-- drivers/media/platform/exynos4-is/fimc-is.h | 9 +- drivers/media/platform/exynos4-is/fimc-isp.c | 6 +- 5 files changed, 121 insertions(+), 121 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c index 58123e3e1b62..254740f5e418 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-param.c +++ b/drivers/media/platform/exynos4-is/fimc-is-param.c @@ -43,7 +43,7 @@ void __fimc_is_hw_update_param_global_shotmode(struct fimc_is *is) struct param_global_shotmode *dst, *src; dst = &is->is_p_region->parameter.global.shotmode; - src = &is->cfg_param[is->scenario_id].global.shotmode; + src = &is->config[is->config_index].global.shotmode; __hw_param_copy(dst, src); } @@ -52,14 +52,14 @@ void __fimc_is_hw_update_param_sensor_framerate(struct fimc_is *is) struct param_sensor_framerate *dst, *src; dst = &is->is_p_region->parameter.sensor.frame_rate; - src = &is->cfg_param[is->scenario_id].sensor.frame_rate; + src = &is->config[is->config_index].sensor.frame_rate; __hw_param_copy(dst, src); } int __fimc_is_hw_update_param(struct fimc_is *is, u32 offset) { struct is_param_region *par = &is->is_p_region->parameter; - struct is_config_param *cfg = &is->cfg_param[is->scenario_id]; + struct chain_config *cfg = &is->config[is->config_index]; switch (offset) { case PARAM_ISP_CONTROL: @@ -163,7 +163,7 @@ int __fimc_is_hw_update_param(struct fimc_is *is, u32 offset) unsigned int __get_pending_param_count(struct fimc_is *is) { - struct is_config_param *config = &is->cfg_param[is->scenario_id]; + struct chain_config *config = &is->config[is->config_index]; unsigned long flags; unsigned int count; @@ -180,9 +180,9 @@ int __is_hw_update_params(struct fimc_is *is) unsigned long *p_index1, *p_index2; int i, id, ret = 0; - id = is->scenario_id; - p_index1 = &is->cfg_param[id].p_region_index1; - p_index2 = &is->cfg_param[id].p_region_index2; + id = is->config_index; + p_index1 = &is->config[id].p_region_index1; + p_index2 = &is->config[id].p_region_index2; if (test_bit(PARAM_GLOBAL_SHOTMODE, p_index1)) __fimc_is_hw_update_param_global_shotmode(is); @@ -212,22 +212,21 @@ void __is_get_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf) { struct isp_param *isp; - isp = &is->cfg_param[is->scenario_id].isp; + isp = &is->config[is->config_index].isp; mf->width = isp->otf_input.width; mf->height = isp->otf_input.height; } void __is_set_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf) { + unsigned int index = is->config_index; struct isp_param *isp; struct drc_param *drc; struct fd_param *fd; - unsigned int mode; - mode = is->scenario_id; - isp = &is->cfg_param[mode].isp; - drc = &is->cfg_param[mode].drc; - fd = &is->cfg_param[mode].fd; + isp = &is->config[index].isp; + drc = &is->config[index].drc; + fd = &is->config[index].fd; /* Update isp size info (OTF only) */ isp->otf_input.width = mf->width; @@ -244,7 +243,7 @@ void __is_set_frame_size(struct fimc_is *is, struct v4l2_mbus_framefmt *mf) fd->otf_input.height = mf->height; if (test_bit(PARAM_ISP_OTF_INPUT, - &is->cfg_param[mode].p_region_index1)) + &is->config[index].p_region_index1)) return; /* Update field */ @@ -267,14 +266,14 @@ int fimc_is_hw_get_sensor_max_framerate(struct fimc_is *is) void __is_set_sensor(struct fimc_is *is, int fps) { + unsigned int index = is->config_index; struct sensor_param *sensor; struct isp_param *isp; - unsigned long *p_index, mode; + unsigned long *p_index; - mode = is->scenario_id; - p_index = &is->cfg_param[mode].p_region_index1; - sensor = &is->cfg_param[mode].sensor; - isp = &is->cfg_param[mode].isp; + p_index = &is->config[index].p_region_index1; + sensor = &is->config[index].sensor; + isp = &is->config[index].isp; if (fps == 0) { sensor->frame_rate.frame_rate = @@ -298,7 +297,7 @@ void __is_set_init_isp_aa(struct fimc_is *is) { struct isp_param *isp; - isp = &is->cfg_param[is->scenario_id].isp; + isp = &is->config[is->config_index].isp; isp->aa.cmd = ISP_AA_COMMAND_START; isp->aa.target = ISP_AA_TARGET_AF | ISP_AA_TARGET_AE | @@ -317,8 +316,8 @@ void __is_set_init_isp_aa(struct fimc_is *is) void __is_set_isp_flash(struct fimc_is *is, u32 cmd, u32 redeye) { - unsigned int mode = is->scenario_id; - struct is_config_param *cfg = &is->cfg_param[mode]; + unsigned int index = is->config_index; + struct chain_config *cfg = &is->config[index]; struct isp_param *isp = &cfg->isp; isp->flash.cmd = cmd; @@ -331,12 +330,12 @@ void __is_set_isp_flash(struct fimc_is *is, u32 cmd, u32 redeye) void __is_set_isp_awb(struct fimc_is *is, u32 cmd, u32 val) { - unsigned int mode = is->scenario_id; + unsigned int index = is->config_index; struct isp_param *isp; unsigned long *p_index; - p_index = &is->cfg_param[mode].p_region_index1; - isp = &is->cfg_param[mode].isp; + p_index = &is->config[index].p_region_index1; + isp = &is->config[index].isp; isp->awb.cmd = cmd; isp->awb.illumination = val; @@ -348,12 +347,12 @@ void __is_set_isp_awb(struct fimc_is *is, u32 cmd, u32 val) void __is_set_isp_effect(struct fimc_is *is, u32 cmd) { - unsigned int mode = is->scenario_id; + unsigned int index = is->config_index; struct isp_param *isp; unsigned long *p_index; - p_index = &is->cfg_param[mode].p_region_index1; - isp = &is->cfg_param[mode].isp; + p_index = &is->config[index].p_region_index1; + isp = &is->config[index].isp; isp->effect.cmd = cmd; isp->effect.err = ISP_IMAGE_EFFECT_ERROR_NONE; @@ -364,12 +363,12 @@ void __is_set_isp_effect(struct fimc_is *is, u32 cmd) void __is_set_isp_iso(struct fimc_is *is, u32 cmd, u32 val) { - unsigned int mode = is->scenario_id; + unsigned int index = is->config_index; struct isp_param *isp; unsigned long *p_index; - p_index = &is->cfg_param[mode].p_region_index1; - isp = &is->cfg_param[mode].isp; + p_index = &is->config[index].p_region_index1; + isp = &is->config[index].isp; isp->iso.cmd = cmd; isp->iso.value = val; @@ -381,12 +380,12 @@ void __is_set_isp_iso(struct fimc_is *is, u32 cmd, u32 val) void __is_set_isp_adjust(struct fimc_is *is, u32 cmd, u32 val) { - unsigned int mode = is->scenario_id; + unsigned int index = is->config_index; unsigned long *p_index; struct isp_param *isp; - p_index = &is->cfg_param[mode].p_region_index1; - isp = &is->cfg_param[mode].isp; + p_index = &is->config[index].p_region_index1; + isp = &is->config[index].isp; switch (cmd) { case ISP_ADJUST_COMMAND_MANUAL_CONTRAST: @@ -428,12 +427,12 @@ void __is_set_isp_adjust(struct fimc_is *is, u32 cmd, u32 val) void __is_set_isp_metering(struct fimc_is *is, u32 id, u32 val) { + unsigned int index = is->config_index; struct isp_param *isp; - unsigned long *p_index, mode; + unsigned long *p_index; - mode = is->scenario_id; - p_index = &is->cfg_param[mode].p_region_index1; - isp = &is->cfg_param[mode].isp; + p_index = &is->config[index].p_region_index1; + isp = &is->config[index].isp; switch (id) { case IS_METERING_CONFIG_CMD: @@ -463,12 +462,12 @@ void __is_set_isp_metering(struct fimc_is *is, u32 id, u32 val) void __is_set_isp_afc(struct fimc_is *is, u32 cmd, u32 val) { + unsigned int index = is->config_index; struct isp_param *isp; - unsigned long *p_index, mode; + unsigned long *p_index; - mode = is->scenario_id; - p_index = &is->cfg_param[mode].p_region_index1; - isp = &is->cfg_param[mode].isp; + p_index = &is->config[index].p_region_index1; + isp = &is->config[index].isp; isp->afc.cmd = cmd; isp->afc.manual = val; @@ -480,12 +479,12 @@ void __is_set_isp_afc(struct fimc_is *is, u32 cmd, u32 val) void __is_set_drc_control(struct fimc_is *is, u32 val) { + unsigned int index = is->config_index; struct drc_param *drc; - unsigned long *p_index, mode; + unsigned long *p_index; - mode = is->scenario_id; - p_index = &is->cfg_param[mode].p_region_index1; - drc = &is->cfg_param[mode].drc; + p_index = &is->config[index].p_region_index1; + drc = &is->config[index].drc; drc->control.bypass = val; @@ -495,12 +494,12 @@ void __is_set_drc_control(struct fimc_is *is, u32 val) void __is_set_fd_control(struct fimc_is *is, u32 val) { + unsigned int index = is->config_index; struct fd_param *fd; - unsigned long *p_index, mode; + unsigned long *p_index; - mode = is->scenario_id; - p_index = &is->cfg_param[mode].p_region_index2; - fd = &is->cfg_param[mode].fd; + p_index = &is->config[index].p_region_index2; + fd = &is->config[index].fd; fd->control.cmd = val; @@ -510,12 +509,12 @@ void __is_set_fd_control(struct fimc_is *is, u32 val) void __is_set_fd_config_maxface(struct fimc_is *is, u32 val) { + unsigned int index = is->config_index; struct fd_param *fd; - unsigned long *p_index, mode; + unsigned long *p_index; - mode = is->scenario_id; - p_index = &is->cfg_param[mode].p_region_index2; - fd = &is->cfg_param[mode].fd; + p_index = &is->config[index].p_region_index2; + fd = &is->config[index].fd; fd->config.max_number = val; @@ -530,12 +529,12 @@ void __is_set_fd_config_maxface(struct fimc_is *is, u32 val) void __is_set_fd_config_rollangle(struct fimc_is *is, u32 val) { + unsigned int index = is->config_index; struct fd_param *fd; - unsigned long *p_index, mode; + unsigned long *p_index; - mode = is->scenario_id; - p_index = &is->cfg_param[mode].p_region_index2; - fd = &is->cfg_param[mode].fd; + p_index = &is->config[index].p_region_index2; + fd = &is->config[index].fd; fd->config.roll_angle = val; @@ -550,12 +549,12 @@ void __is_set_fd_config_rollangle(struct fimc_is *is, u32 val) void __is_set_fd_config_yawangle(struct fimc_is *is, u32 val) { + unsigned int index = is->config_index; struct fd_param *fd; - unsigned long *p_index, mode; + unsigned long *p_index; - mode = is->scenario_id; - p_index = &is->cfg_param[mode].p_region_index2; - fd = &is->cfg_param[mode].fd; + p_index = &is->config[index].p_region_index2; + fd = &is->config[index].fd; fd->config.yaw_angle = val; @@ -570,12 +569,12 @@ void __is_set_fd_config_yawangle(struct fimc_is *is, u32 val) void __is_set_fd_config_smilemode(struct fimc_is *is, u32 val) { + unsigned int index = is->config_index; struct fd_param *fd; - unsigned long *p_index, mode; + unsigned long *p_index; - mode = is->scenario_id; - p_index = &is->cfg_param[mode].p_region_index2; - fd = &is->cfg_param[mode].fd; + p_index = &is->config[index].p_region_index2; + fd = &is->config[index].fd; fd->config.smile_mode = val; @@ -590,12 +589,12 @@ void __is_set_fd_config_smilemode(struct fimc_is *is, u32 val) void __is_set_fd_config_blinkmode(struct fimc_is *is, u32 val) { + unsigned int index = is->config_index; struct fd_param *fd; - unsigned long *p_index, mode; + unsigned long *p_index; - mode = is->scenario_id; - p_index = &is->cfg_param[mode].p_region_index2; - fd = &is->cfg_param[mode].fd; + p_index = &is->config[index].p_region_index2; + fd = &is->config[index].fd; fd->config.blink_mode = val; @@ -610,12 +609,12 @@ void __is_set_fd_config_blinkmode(struct fimc_is *is, u32 val) void __is_set_fd_config_eyedetect(struct fimc_is *is, u32 val) { + unsigned int index = is->config_index; struct fd_param *fd; - unsigned long *p_index, mode; + unsigned long *p_index; - mode = is->scenario_id; - p_index = &is->cfg_param[mode].p_region_index2; - fd = &is->cfg_param[mode].fd; + p_index = &is->config[index].p_region_index2; + fd = &is->config[index].fd; fd->config.eye_detect = val; @@ -630,12 +629,12 @@ void __is_set_fd_config_eyedetect(struct fimc_is *is, u32 val) void __is_set_fd_config_mouthdetect(struct fimc_is *is, u32 val) { + unsigned int index = is->config_index; struct fd_param *fd; - unsigned long *p_index, mode; + unsigned long *p_index; - mode = is->scenario_id; - p_index = &is->cfg_param[mode].p_region_index2; - fd = &is->cfg_param[mode].fd; + p_index = &is->config[index].p_region_index2; + fd = &is->config[index].fd; fd->config.mouth_detect = val; @@ -650,12 +649,12 @@ void __is_set_fd_config_mouthdetect(struct fimc_is *is, u32 val) void __is_set_fd_config_orientation(struct fimc_is *is, u32 val) { + unsigned int index = is->config_index; struct fd_param *fd; - unsigned long *p_index, mode; + unsigned long *p_index; - mode = is->scenario_id; - p_index = &is->cfg_param[mode].p_region_index2; - fd = &is->cfg_param[mode].fd; + p_index = &is->config[index].p_region_index2; + fd = &is->config[index].fd; fd->config.orientation = val; @@ -670,12 +669,12 @@ void __is_set_fd_config_orientation(struct fimc_is *is, u32 val) void __is_set_fd_config_orientation_val(struct fimc_is *is, u32 val) { + unsigned int index = is->config_index; struct fd_param *fd; - unsigned long *p_index, mode; + unsigned long *p_index; - mode = is->scenario_id; - p_index = &is->cfg_param[mode].p_region_index2; - fd = &is->cfg_param[mode].fd; + p_index = &is->config[index].p_region_index2; + fd = &is->config[index].fd; fd->config.orientation_value = val; @@ -696,16 +695,16 @@ void fimc_is_set_initial_params(struct fimc_is *is) struct drc_param *drc; struct fd_param *fd; unsigned long *p_index1, *p_index2; - unsigned int mode; + unsigned int index; - mode = is->scenario_id; - global = &is->cfg_param[mode].global; - sensor = &is->cfg_param[mode].sensor; - isp = &is->cfg_param[mode].isp; - drc = &is->cfg_param[mode].drc; - fd = &is->cfg_param[mode].fd; - p_index1 = &is->cfg_param[mode].p_region_index1; - p_index2 = &is->cfg_param[mode].p_region_index2; + index = is->config_index; + global = &is->config[index].global; + sensor = &is->config[index].sensor; + isp = &is->config[index].isp; + drc = &is->config[index].drc; + fd = &is->config[index].fd; + p_index1 = &is->config[index].p_region_index1; + p_index2 = &is->config[index].p_region_index2; /* Global */ global->shotmode.cmd = 1; @@ -841,7 +840,7 @@ void fimc_is_set_initial_params(struct fimc_is *is) /* Sensor */ if (!test_bit(PARAM_SENSOR_FRAME_RATE, p_index1)) { - if (!mode) + if (is->config_index == 0) __is_set_sensor(is, 0); } diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c index f59a289c530d..b0ff67bc1b05 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-regs.c +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c @@ -79,18 +79,18 @@ int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is) int fimc_is_hw_set_param(struct fimc_is *is) { - struct is_config_param *cfg = &is->cfg_param[is->scenario_id]; + struct chain_config *config = &is->config[is->config_index]; unsigned int param_count = __get_pending_param_count(is); fimc_is_hw_wait_intmsr0_intmsd0(is); mcuctl_write(HIC_SET_PARAMETER, is, MCUCTL_REG_ISSR(0)); mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); - mcuctl_write(is->scenario_id, is, MCUCTL_REG_ISSR(2)); + mcuctl_write(is->config_index, is, MCUCTL_REG_ISSR(2)); mcuctl_write(param_count, is, MCUCTL_REG_ISSR(3)); - mcuctl_write(cfg->p_region_index1, is, MCUCTL_REG_ISSR(4)); - mcuctl_write(cfg->p_region_index2, is, MCUCTL_REG_ISSR(5)); + mcuctl_write(config->p_region_index1, is, MCUCTL_REG_ISSR(4)); + mcuctl_write(config->p_region_index2, is, MCUCTL_REG_ISSR(5)); fimc_is_hw_set_intgr0_gd0(is); return 0; @@ -174,10 +174,10 @@ int fimc_is_hw_change_mode(struct fimc_is *is) HIC_CAPTURE_STILL, HIC_CAPTURE_VIDEO, }; - if (WARN_ON(is->scenario_id > ARRAY_SIZE(cmd))) + if (WARN_ON(is->config_index > ARRAY_SIZE(cmd))) return -EINVAL; - mcuctl_write(cmd[is->scenario_id], is, MCUCTL_REG_ISSR(0)); + mcuctl_write(cmd[is->config_index], is, MCUCTL_REG_ISSR(0)); mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); mcuctl_write(is->setfile.sub_index, is, MCUCTL_REG_ISSR(2)); fimc_is_hw_set_intgr0_gd0(is); @@ -238,6 +238,6 @@ int fimc_is_itf_mode_change(struct fimc_is *is) FIMC_IS_CONFIG_TIMEOUT); if (!ret < 0) dev_err(&is->pdev->dev, "%s(): mode change (%d) timeout\n", - __func__, is->scenario_id); + __func__, is->config_index); return ret; } diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 10ec173d1254..3c81c882bfd1 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -530,8 +530,8 @@ static void fimc_is_general_irq_handler(struct fimc_is *is) break; case HIC_SET_PARAMETER: - is->cfg_param[is->scenario_id].p_region_index1 = 0; - is->cfg_param[is->scenario_id].p_region_index2 = 0; + is->config[is->config_index].p_region_index1 = 0; + is->config[is->config_index].p_region_index2 = 0; set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state); pr_debug("HIC_SET_PARAMETER\n"); break; @@ -590,8 +590,8 @@ static void fimc_is_general_irq_handler(struct fimc_is *is) switch (is->i2h_cmd.args[0]) { case HIC_SET_PARAMETER: - is->cfg_param[is->scenario_id].p_region_index1 = 0; - is->cfg_param[is->scenario_id].p_region_index2 = 0; + is->config[is->config_index].p_region_index1 = 0; + is->config[is->config_index].p_region_index2 = 0; set_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state); break; } @@ -656,7 +656,7 @@ static int fimc_is_hw_open_sensor(struct fimc_is *is, int fimc_is_hw_initialize(struct fimc_is *is) { - const int scenario_ids[] = { + const int config_ids[] = { IS_SC_PREVIEW_STILL, IS_SC_PREVIEW_VIDEO, IS_SC_CAPTURE_STILL, IS_SC_CAPTURE_VIDEO }; @@ -718,23 +718,23 @@ int fimc_is_hw_initialize(struct fimc_is *is) } /* Preserve previous mode. */ - prev_id = is->scenario_id; + prev_id = is->config_index; /* Set initial parameter values. */ - for (i = 0; i < ARRAY_SIZE(scenario_ids); i++) { - is->scenario_id = scenario_ids[i]; + for (i = 0; i < ARRAY_SIZE(config_ids); i++) { + is->config_index = config_ids[i]; fimc_is_set_initial_params(is); ret = fimc_is_itf_s_param(is, true); if (ret < 0) { - is->scenario_id = prev_id; + is->config_index = prev_id; return ret; } } - is->scenario_id = prev_id; + is->config_index = prev_id; set_bit(IS_ST_INIT_DONE, &is->state); dev_info(dev, "initialization sequence completed (%d)\n", - is->scenario_id); + is->config_index); return 0; } diff --git a/drivers/media/platform/exynos4-is/fimc-is.h b/drivers/media/platform/exynos4-is/fimc-is.h index 9406894f306d..f5275a5b0156 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.h +++ b/drivers/media/platform/exynos4-is/fimc-is.h @@ -219,7 +219,7 @@ struct fimc_is_setfile { u32 base; }; -struct is_config_param { +struct chain_config { struct global_param global; struct sensor_param sensor; struct isp_param isp; @@ -279,12 +279,13 @@ struct fimc_is { struct h2i_cmd h2i_cmd; struct is_fd_result_header fd_header; - struct is_config_param cfg_param[IS_SC_MAX]; + struct chain_config config[IS_SC_MAX]; + unsigned config_index; + struct is_region *is_p_region; dma_addr_t is_dma_p_region; struct is_share_region *is_shared_region; struct is_af_info af; - u32 scenario_id; struct dentry *debugfs_entry; }; @@ -301,7 +302,7 @@ static inline void fimc_is_mem_barrier(void) static inline void fimc_is_set_param_bit(struct fimc_is *is, int num) { - struct is_config_param *cfg = &is->cfg_param[is->scenario_id]; + struct chain_config *cfg = &is->config[is->config_index]; if (num >= 32) set_bit(num - 32, &cfg->p_region_index2); diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index b11c001ad388..7b8fbabe3556 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -236,7 +236,7 @@ static int fimc_isp_subdev_s_stream(struct v4l2_subdev *sd, int on) } v4l2_dbg(1, debug, sd, "changing mode to %d\n", - is->scenario_id); + is->config_index); ret = fimc_is_itf_mode_change(is); if (ret) return -EINVAL; @@ -317,8 +317,8 @@ static int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on) clear_bit(IS_ST_PWR_ON, &is->state); clear_bit(IS_ST_INIT_DONE, &is->state); is->state = 0; - is->cfg_param[is->scenario_id].p_region_index1 = 0; - is->cfg_param[is->scenario_id].p_region_index2 = 0; + is->config[is->config_index].p_region_index1 = 0; + is->config[is->config_index].p_region_index2 = 0; set_bit(IS_ST_IDLE, &is->state); wmb(); } -- cgit v1.2.3 From 03385b8e9d7a9f361c178ea33fa76b39793f85b2 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 10 Apr 2013 06:27:22 -0300 Subject: [media] exynos4-is: Remove meaningless test before bit setting There is no need to check same bit before setting it, since we always end up with a bit set. Remove some of the tests and make set unconditional, in every place where all that needs to be done is just setting a bit. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is-param.c | 40 +++++------------------ 1 file changed, 9 insertions(+), 31 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c index 254740f5e418..53fe2a2b4db3 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-param.c +++ b/drivers/media/platform/exynos4-is/fimc-is-param.c @@ -269,9 +269,7 @@ void __is_set_sensor(struct fimc_is *is, int fps) unsigned int index = is->config_index; struct sensor_param *sensor; struct isp_param *isp; - unsigned long *p_index; - p_index = &is->config[index].p_region_index1; sensor = &is->config[index].sensor; isp = &is->config[index].isp; @@ -286,11 +284,8 @@ void __is_set_sensor(struct fimc_is *is, int fps) isp->otf_input.frametime_max = (u32)1000000 / fps; } - if (!test_bit(PARAM_SENSOR_FRAME_RATE, p_index)) - fimc_is_set_param_bit(is, PARAM_SENSOR_FRAME_RATE); - - if (!test_bit(PARAM_ISP_OTF_INPUT, p_index)) - fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT); + fimc_is_set_param_bit(is, PARAM_SENSOR_FRAME_RATE); + fimc_is_set_param_bit(is, PARAM_ISP_OTF_INPUT); } void __is_set_init_isp_aa(struct fimc_is *is) @@ -317,65 +312,54 @@ void __is_set_init_isp_aa(struct fimc_is *is) void __is_set_isp_flash(struct fimc_is *is, u32 cmd, u32 redeye) { unsigned int index = is->config_index; - struct chain_config *cfg = &is->config[index]; - struct isp_param *isp = &cfg->isp; + struct isp_param *isp = &is->config[index].isp; isp->flash.cmd = cmd; isp->flash.redeye = redeye; isp->flash.err = ISP_FLASH_ERROR_NONE; - if (!test_bit(PARAM_ISP_FLASH, &cfg->p_region_index1)) - fimc_is_set_param_bit(is, PARAM_ISP_FLASH); + fimc_is_set_param_bit(is, PARAM_ISP_FLASH); } void __is_set_isp_awb(struct fimc_is *is, u32 cmd, u32 val) { unsigned int index = is->config_index; struct isp_param *isp; - unsigned long *p_index; - p_index = &is->config[index].p_region_index1; isp = &is->config[index].isp; isp->awb.cmd = cmd; isp->awb.illumination = val; isp->awb.err = ISP_AWB_ERROR_NONE; - if (!test_bit(PARAM_ISP_AWB, p_index)) - fimc_is_set_param_bit(is, PARAM_ISP_AWB); + fimc_is_set_param_bit(is, PARAM_ISP_AWB); } void __is_set_isp_effect(struct fimc_is *is, u32 cmd) { unsigned int index = is->config_index; struct isp_param *isp; - unsigned long *p_index; - p_index = &is->config[index].p_region_index1; isp = &is->config[index].isp; isp->effect.cmd = cmd; isp->effect.err = ISP_IMAGE_EFFECT_ERROR_NONE; - if (!test_bit(PARAM_ISP_IMAGE_EFFECT, p_index)) - fimc_is_set_param_bit(is, PARAM_ISP_IMAGE_EFFECT); + fimc_is_set_param_bit(is, PARAM_ISP_IMAGE_EFFECT); } void __is_set_isp_iso(struct fimc_is *is, u32 cmd, u32 val) { unsigned int index = is->config_index; struct isp_param *isp; - unsigned long *p_index; - p_index = &is->config[index].p_region_index1; isp = &is->config[index].isp; isp->iso.cmd = cmd; isp->iso.value = val; isp->iso.err = ISP_ISO_ERROR_NONE; - if (!test_bit(PARAM_ISP_ISO, p_index)) - fimc_is_set_param_bit(is, PARAM_ISP_ISO); + fimc_is_set_param_bit(is, PARAM_ISP_ISO); } void __is_set_isp_adjust(struct fimc_is *is, u32 cmd, u32 val) @@ -464,32 +448,26 @@ void __is_set_isp_afc(struct fimc_is *is, u32 cmd, u32 val) { unsigned int index = is->config_index; struct isp_param *isp; - unsigned long *p_index; - p_index = &is->config[index].p_region_index1; isp = &is->config[index].isp; isp->afc.cmd = cmd; isp->afc.manual = val; isp->afc.err = ISP_AFC_ERROR_NONE; - if (!test_bit(PARAM_ISP_AFC, p_index)) - fimc_is_set_param_bit(is, PARAM_ISP_AFC); + fimc_is_set_param_bit(is, PARAM_ISP_AFC); } void __is_set_drc_control(struct fimc_is *is, u32 val) { unsigned int index = is->config_index; struct drc_param *drc; - unsigned long *p_index; - p_index = &is->config[index].p_region_index1; drc = &is->config[index].drc; drc->control.bypass = val; - if (!test_bit(PARAM_DRC_CONTROL, p_index)) - fimc_is_set_param_bit(is, PARAM_DRC_CONTROL); + fimc_is_set_param_bit(is, PARAM_DRC_CONTROL); } void __is_set_fd_control(struct fimc_is *is, u32 val) -- cgit v1.2.3 From b54373c5491249dbdd8fcbe35d450fef18d8a10a Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 10 Apr 2013 06:42:44 -0300 Subject: [media] exynos4-is: Disable debug trace by default in fimc-isp.c Make sure the debug level is properly set initially so any debug information is not printed to the kernel log without explicitly enabling it. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-isp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index 7b8fbabe3556..3b9a6642a491 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -30,7 +30,7 @@ #include "fimc-is-regs.h" #include "fimc-is.h" -static int debug = 10; +static int debug; module_param_named(debug_isp, debug, int, S_IRUGO | S_IWUSR); static const struct fimc_fmt fimc_isp_formats[FIMC_ISP_NUM_FORMATS] = { -- cgit v1.2.3 From a54b80b17ab1fa33e58c5461f63fe3d8755d7e83 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 25 Sep 2012 10:46:34 -0300 Subject: [media] mt9m032: Fix PLL setup The MT9M032 PLL was assumed to be identical to the MT9P031 PLL but differs significantly. Update the registers definitions and PLL limits according to the datasheet. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9m032.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c index 2526b66b91fd..2f40a35b3ddb 100644 --- a/drivers/media/i2c/mt9m032.c +++ b/drivers/media/i2c/mt9m032.c @@ -87,7 +87,7 @@ #define MT9M032_RESTART 0x0b #define MT9M032_RESET 0x0d #define MT9M032_PLL_CONFIG1 0x11 -#define MT9M032_PLL_CONFIG1_OUTDIV_MASK 0x3f +#define MT9M032_PLL_CONFIG1_PREDIV_MASK 0x3f #define MT9M032_PLL_CONFIG1_MUL_SHIFT 8 #define MT9M032_READ_MODE1 0x1e #define MT9M032_READ_MODE2 0x20 @@ -106,6 +106,8 @@ #define MT9M032_GAIN_AMUL_SHIFT 6 #define MT9M032_GAIN_ANALOG_MASK 0x3f #define MT9M032_FORMATTER1 0x9e +#define MT9M032_FORMATTER1_PLL_P1_6 (1 << 8) +#define MT9M032_FORMATTER1_PARALLEL (1 << 12) #define MT9M032_FORMATTER2 0x9f #define MT9M032_FORMATTER2_DOUT_EN 0x1000 #define MT9M032_FORMATTER2_PIXCLK_EN 0x2000 @@ -121,8 +123,6 @@ #define MT9P031_PLL_CONTROL_PWROFF 0x0050 #define MT9P031_PLL_CONTROL_PWRON 0x0051 #define MT9P031_PLL_CONTROL_USEPLL 0x0052 -#define MT9P031_PLL_CONFIG2 0x11 -#define MT9P031_PLL_CONFIG2_P1_DIV_MASK 0x1f struct mt9m032 { struct v4l2_subdev subdev; @@ -255,13 +255,14 @@ static int mt9m032_setup_pll(struct mt9m032 *sensor) .n_max = 64, .m_min = 16, .m_max = 255, - .p1_min = 1, - .p1_max = 128, + .p1_min = 6, + .p1_max = 7, }; struct i2c_client *client = v4l2_get_subdevdata(&sensor->subdev); struct mt9m032_platform_data *pdata = sensor->pdata; struct aptina_pll pll; + u16 reg_val; int ret; pll.ext_clock = pdata->ext_clock; @@ -274,18 +275,19 @@ static int mt9m032_setup_pll(struct mt9m032 *sensor) sensor->pix_clock = pdata->pix_clock; ret = mt9m032_write(client, MT9M032_PLL_CONFIG1, - (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT) - | (pll.p1 - 1)); - if (!ret) - ret = mt9m032_write(client, MT9P031_PLL_CONFIG2, pll.n - 1); + (pll.m << MT9M032_PLL_CONFIG1_MUL_SHIFT) | + ((pll.n - 1) & MT9M032_PLL_CONFIG1_PREDIV_MASK)); if (!ret) ret = mt9m032_write(client, MT9P031_PLL_CONTROL, MT9P031_PLL_CONTROL_PWRON | MT9P031_PLL_CONTROL_USEPLL); if (!ret) /* more reserved, Continuous, Master Mode */ ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8006); - if (!ret) /* Set 14-bit mode, select 7 divider */ - ret = mt9m032_write(client, MT9M032_FORMATTER1, 0x111e); + if (!ret) { + reg_val = (pll.p1 == 6 ? MT9M032_FORMATTER1_PLL_P1_6 : 0) + | MT9M032_FORMATTER1_PARALLEL | 0x001e; /* 14-bit */ + ret = mt9m032_write(client, MT9M032_FORMATTER1, reg_val); + } return ret; } -- cgit v1.2.3 From 73254c30db7116c4bae1adffab0dd2ac68486933 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 26 Sep 2012 05:54:17 -0300 Subject: [media] mt9m032: Define MT9M032_READ_MODE1 bits Replace hardcoded values with #define's. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9m032.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c index 2f40a35b3ddb..8edb3d8f7b90 100644 --- a/drivers/media/i2c/mt9m032.c +++ b/drivers/media/i2c/mt9m032.c @@ -90,6 +90,24 @@ #define MT9M032_PLL_CONFIG1_PREDIV_MASK 0x3f #define MT9M032_PLL_CONFIG1_MUL_SHIFT 8 #define MT9M032_READ_MODE1 0x1e +#define MT9M032_READ_MODE1_OUTPUT_BAD_FRAMES (1 << 13) +#define MT9M032_READ_MODE1_MAINTAIN_FRAME_RATE (1 << 12) +#define MT9M032_READ_MODE1_XOR_LINE_VALID (1 << 11) +#define MT9M032_READ_MODE1_CONT_LINE_VALID (1 << 10) +#define MT9M032_READ_MODE1_INVERT_TRIGGER (1 << 9) +#define MT9M032_READ_MODE1_SNAPSHOT (1 << 8) +#define MT9M032_READ_MODE1_GLOBAL_RESET (1 << 7) +#define MT9M032_READ_MODE1_BULB_EXPOSURE (1 << 6) +#define MT9M032_READ_MODE1_INVERT_STROBE (1 << 5) +#define MT9M032_READ_MODE1_STROBE_ENABLE (1 << 4) +#define MT9M032_READ_MODE1_STROBE_START_TRIG1 (0 << 2) +#define MT9M032_READ_MODE1_STROBE_START_EXP (1 << 2) +#define MT9M032_READ_MODE1_STROBE_START_SHUTTER (2 << 2) +#define MT9M032_READ_MODE1_STROBE_START_TRIG2 (3 << 2) +#define MT9M032_READ_MODE1_STROBE_END_TRIG1 (0 << 0) +#define MT9M032_READ_MODE1_STROBE_END_EXP (1 << 0) +#define MT9M032_READ_MODE1_STROBE_END_SHUTTER (2 << 0) +#define MT9M032_READ_MODE1_STROBE_END_TRIG2 (3 << 0) #define MT9M032_READ_MODE2 0x20 #define MT9M032_READ_MODE2_VFLIP_SHIFT 15 #define MT9M032_READ_MODE2_HFLIP_SHIFT 14 @@ -282,7 +300,9 @@ static int mt9m032_setup_pll(struct mt9m032 *sensor) MT9P031_PLL_CONTROL_PWRON | MT9P031_PLL_CONTROL_USEPLL); if (!ret) /* more reserved, Continuous, Master Mode */ - ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8006); + ret = mt9m032_write(client, MT9M032_READ_MODE1, 0x8000 | + MT9M032_READ_MODE1_STROBE_START_EXP | + MT9M032_READ_MODE1_STROBE_END_SHUTTER); if (!ret) { reg_val = (pll.p1 == 6 ? MT9M032_FORMATTER1_PLL_P1_6 : 0) | MT9M032_FORMATTER1_PARALLEL | 0x001e; /* 14-bit */ -- cgit v1.2.3 From 37b9f2117f3b4b554315b0e7b357bfabb58a0204 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 21 Dec 2012 16:34:06 -0300 Subject: [media] mt9p031: Use devm_* managed helpers Replace kzalloc and gpio_request_one by their managed equivalents. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9p031.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index e32833262d32..e0bad594c8da 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -927,7 +927,7 @@ static int mt9p031_probe(struct i2c_client *client, return -EIO; } - mt9p031 = kzalloc(sizeof(*mt9p031), GFP_KERNEL); + mt9p031 = devm_kzalloc(&client->dev, sizeof(*mt9p031), GFP_KERNEL); if (mt9p031 == NULL) return -ENOMEM; @@ -1001,8 +1001,8 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB; if (pdata->reset != -1) { - ret = gpio_request_one(pdata->reset, GPIOF_OUT_INIT_LOW, - "mt9p031_rst"); + ret = devm_gpio_request_one(&client->dev, pdata->reset, + GPIOF_OUT_INIT_LOW, "mt9p031_rst"); if (ret < 0) goto done; @@ -1013,12 +1013,8 @@ static int mt9p031_probe(struct i2c_client *client, done: if (ret < 0) { - if (mt9p031->reset != -1) - gpio_free(mt9p031->reset); - v4l2_ctrl_handler_free(&mt9p031->ctrls); media_entity_cleanup(&mt9p031->subdev.entity); - kfree(mt9p031); } return ret; @@ -1032,9 +1028,6 @@ static int mt9p031_remove(struct i2c_client *client) v4l2_ctrl_handler_free(&mt9p031->ctrls); v4l2_device_unregister_subdev(subdev); media_entity_cleanup(&subdev->entity); - if (mt9p031->reset != -1) - gpio_free(mt9p031->reset); - kfree(mt9p031); return 0; } -- cgit v1.2.3 From 97f212767a4d0fbddbf4786ccedacb47fc210548 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 8 May 2012 10:10:36 -0300 Subject: [media] mt9p031: Add support for regulators Enable the regulators when powering the sensor up, and disable them when powering it down. The regulators are mandatory. Boards that don't allow controlling the sensor power lines must provide fixed voltage regulators. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9p031.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index e0bad594c8da..ecf4492c6b8e 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -121,6 +122,10 @@ struct mt9p031 { struct mutex power_lock; /* lock to protect power_count */ int power_count; + struct regulator *vaa; + struct regulator *vdd; + struct regulator *vdd_io; + enum mt9p031_model model; struct aptina_pll pll; int reset; @@ -264,6 +269,11 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031) usleep_range(1000, 2000); } + /* Bring up the supplies */ + regulator_enable(mt9p031->vdd); + regulator_enable(mt9p031->vdd_io); + regulator_enable(mt9p031->vaa); + /* Emable clock */ if (mt9p031->pdata->set_xclk) mt9p031->pdata->set_xclk(&mt9p031->subdev, @@ -285,6 +295,10 @@ static void mt9p031_power_off(struct mt9p031 *mt9p031) usleep_range(1000, 2000); } + regulator_disable(mt9p031->vaa); + regulator_disable(mt9p031->vdd_io); + regulator_disable(mt9p031->vdd); + if (mt9p031->pdata->set_xclk) mt9p031->pdata->set_xclk(&mt9p031->subdev, 0); } @@ -937,6 +951,16 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->model = did->driver_data; mt9p031->reset = -1; + mt9p031->vaa = devm_regulator_get(&client->dev, "vaa"); + mt9p031->vdd = devm_regulator_get(&client->dev, "vdd"); + mt9p031->vdd_io = devm_regulator_get(&client->dev, "vdd_io"); + + if (IS_ERR(mt9p031->vaa) || IS_ERR(mt9p031->vdd) || + IS_ERR(mt9p031->vdd_io)) { + dev_err(&client->dev, "Unable to get regulators\n"); + return -ENODEV; + } + v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 6); v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops, -- cgit v1.2.3 From d67492585d8308a22a841956f1e629ef3b7d0315 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 21 Dec 2012 16:11:55 -0300 Subject: [media] mt9p031: Use the common clock framework Configure the device external clock using the common clock framework instead of a board code callback function. Signed-off-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9p031.c | 21 ++++++++++++++------- include/media/mt9p031.h | 2 -- 2 files changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index ecf4492c6b8e..28cf95b37285 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -12,6 +12,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -122,6 +123,7 @@ struct mt9p031 { struct mutex power_lock; /* lock to protect power_count */ int power_count; + struct clk *clk; struct regulator *vaa; struct regulator *vdd; struct regulator *vdd_io; @@ -200,7 +202,7 @@ static int mt9p031_reset(struct mt9p031 *mt9p031) 0); } -static int mt9p031_pll_setup(struct mt9p031 *mt9p031) +static int mt9p031_clk_setup(struct mt9p031 *mt9p031) { static const struct aptina_pll_limits limits = { .ext_clock_min = 6000000, @@ -221,6 +223,12 @@ static int mt9p031_pll_setup(struct mt9p031 *mt9p031) struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev); struct mt9p031_platform_data *pdata = mt9p031->pdata; + mt9p031->clk = devm_clk_get(&client->dev, NULL); + if (IS_ERR(mt9p031->clk)) + return PTR_ERR(mt9p031->clk); + + clk_set_rate(mt9p031->clk, pdata->ext_freq); + mt9p031->pll.ext_clock = pdata->ext_freq; mt9p031->pll.pix_clock = pdata->target_freq; @@ -275,9 +283,8 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031) regulator_enable(mt9p031->vaa); /* Emable clock */ - if (mt9p031->pdata->set_xclk) - mt9p031->pdata->set_xclk(&mt9p031->subdev, - mt9p031->pdata->ext_freq); + if (mt9p031->clk) + clk_prepare_enable(mt9p031->clk); /* Now RESET_BAR must be high */ if (mt9p031->reset != -1) { @@ -299,8 +306,8 @@ static void mt9p031_power_off(struct mt9p031 *mt9p031) regulator_disable(mt9p031->vdd_io); regulator_disable(mt9p031->vdd); - if (mt9p031->pdata->set_xclk) - mt9p031->pdata->set_xclk(&mt9p031->subdev, 0); + if (mt9p031->clk) + clk_disable_unprepare(mt9p031->clk); } static int __mt9p031_set_power(struct mt9p031 *mt9p031, bool on) @@ -1033,7 +1040,7 @@ static int mt9p031_probe(struct i2c_client *client, mt9p031->reset = pdata->reset; } - ret = mt9p031_pll_setup(mt9p031); + ret = mt9p031_clk_setup(mt9p031); done: if (ret < 0) { diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h index 0c97b19af293..b1e63f2b72bd 100644 --- a/include/media/mt9p031.h +++ b/include/media/mt9p031.h @@ -5,13 +5,11 @@ struct v4l2_subdev; /* * struct mt9p031_platform_data - MT9P031 platform data - * @set_xclk: Clock frequency set callback * @reset: Chip reset GPIO (set to -1 if not used) * @ext_freq: Input clock frequency * @target_freq: Pixel clock frequency */ struct mt9p031_platform_data { - int (*set_xclk)(struct v4l2_subdev *subdev, int hz); int reset; int ext_freq; int target_freq; -- cgit v1.2.3 From c3b3e0c5fd5ccacecf454d60c8fdc5caa96ba862 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Fri, 1 Feb 2013 20:01:14 -0300 Subject: [media] saa7134: v4l2-compliance: implement V4L2_CAP_DEVICE_CAPS Make saa7134 driver more V4L2 compliant: implement V4L2_CAP_DEVICE_CAPS support and fix all capabilities problems reported by v4l2-compliance. Signed-off-by: Ondrej Zary Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-video.c | 58 ++++++++++++++++++------------- 1 file changed, 34 insertions(+), 24 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 1363e97ccda4..88e84c31c7d7 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1805,6 +1805,8 @@ static int saa7134_querycap(struct file *file, void *priv, { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; + struct video_device *vdev = video_devdata(file); + u32 radio_caps, video_caps, vbi_caps; unsigned int tuner_type = dev->tuner_type; @@ -1812,19 +1814,40 @@ static int saa7134_querycap(struct file *file, void *priv, strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_TUNER; + + cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + if ((tuner_type != TUNER_ABSENT) && (tuner_type != UNSET)) + cap->device_caps |= V4L2_CAP_TUNER; + + radio_caps = V4L2_CAP_RADIO; if (dev->has_rds) - cap->capabilities |= V4L2_CAP_RDS_CAPTURE; + radio_caps |= V4L2_CAP_RDS_CAPTURE; + + video_caps = V4L2_CAP_VIDEO_CAPTURE; if (saa7134_no_overlay <= 0) - cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; + video_caps |= V4L2_CAP_VIDEO_OVERLAY; + + vbi_caps = V4L2_CAP_VBI_CAPTURE; + + switch (vdev->vfl_type) { + case VFL_TYPE_RADIO: + cap->device_caps |= radio_caps; + break; + case VFL_TYPE_GRABBER: + cap->device_caps |= video_caps; + break; + case VFL_TYPE_VBI: + cap->device_caps |= vbi_caps; + break; + } + cap->capabilities = radio_caps | video_caps | vbi_caps | + cap->device_caps | V4L2_CAP_DEVICE_CAPS; + if (vdev->vfl_type == VFL_TYPE_RADIO) { + cap->device_caps &= ~V4L2_CAP_STREAMING; + if (!dev->has_rds) + cap->device_caps &= ~V4L2_CAP_READWRITE; + } - if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) - cap->capabilities &= ~V4L2_CAP_TUNER; return 0; } @@ -2312,19 +2335,6 @@ static int vidioc_s_register (struct file *file, void *priv, } #endif -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct saa7134_fh *fh = file->private_data; - struct saa7134_dev *dev = fh->dev; - - strcpy(cap->driver, "saa7134"); - strlcpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->capabilities = V4L2_CAP_TUNER; - return 0; -} - static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { @@ -2486,7 +2496,7 @@ static const struct v4l2_file_operations radio_fops = { }; static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = radio_querycap, + .vidioc_querycap = saa7134_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_enum_input = radio_enum_input, .vidioc_g_audio = radio_g_audio, -- cgit v1.2.3 From 82456708389d6d9eb81a4479d54efa0bf7dd8bf3 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Fri, 1 Feb 2013 20:01:15 -0300 Subject: [media] saa7134: v4l2-compliance: don't report invalid audio modes for radio Make saa7134 driver more V4L2 compliant: filter audio modes that came from tuner - keep only MONO/STEREO in radio mode Signed-off-by: Ondrej Zary Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-video.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 88e84c31c7d7..0f2d3bd4896a 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -2349,6 +2349,7 @@ static int radio_g_tuner(struct file *file, void *priv, t->type = V4L2_TUNER_RADIO; saa_call_all(dev, tuner, g_tuner, t); + t->audmode &= V4L2_TUNER_MODE_MONO | V4L2_TUNER_MODE_STEREO; if (dev->input->amux == TV) { t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11); t->rxsubchans = (saa_readb(0x529) & 0x08) ? -- cgit v1.2.3 From 3bbaa3a60175ed120c8ab8937c21425fd744c7b7 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Fri, 1 Feb 2013 20:01:16 -0300 Subject: [media] saa7134: v4l2-compliance: use v4l2_fh to fix priority handling Make saa7134 driver more V4L2 compliant: remove broken priority handling and use v4l2_fh instead Signed-off-by: Ondrej Zary [hans.verkuil@cisco.com: fixed a merge conflict in saa7134.h] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-core.c | 3 +- drivers/media/pci/saa7134/saa7134-video.c | 61 ++++--------------------------- drivers/media/pci/saa7134/saa7134.h | 4 +- 3 files changed, 10 insertions(+), 58 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index 8fd24e7c9403..45f0aca597ae 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -805,6 +805,7 @@ static struct video_device *vdev_init(struct saa7134_dev *dev, vfd->debug = video_debug; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, saa7134_boards[dev->board].name); + set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); video_set_drvdata(vfd, dev); return vfd; } @@ -1028,8 +1029,6 @@ static int saa7134_initdev(struct pci_dev *pci_dev, } } - v4l2_prio_init(&dev->prio); - mutex_lock(&saa7134_devlist_lock); list_for_each_entry(mops, &mops_list, next) mpeg_ops_attach(mops, dev); diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 0f2d3bd4896a..941e2ebab41d 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1176,14 +1176,6 @@ int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, str int restart_overlay = 0; int err; - /* When called from the empress code fh == NULL. - That needs to be fixed somehow, but for now this is - good enough. */ - if (fh) { - err = v4l2_prio_check(&dev->prio, fh->prio); - if (0 != err) - return err; - } err = -EINVAL; mutex_lock(&dev->lock); @@ -1352,6 +1344,7 @@ static int video_open(struct file *file) if (NULL == fh) return -ENOMEM; + v4l2_fh_init(&fh->fh, vdev); file->private_data = fh; fh->dev = dev; fh->radio = radio; @@ -1359,7 +1352,6 @@ static int video_open(struct file *file) fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); fh->width = 720; fh->height = 576; - v4l2_prio_open(&dev->prio, &fh->prio); videobuf_queue_sg_init(&fh->cap, &video_qops, &dev->pci->dev, &dev->slock, @@ -1384,6 +1376,8 @@ static int video_open(struct file *file) /* switch to video/vbi mode */ video_mux(dev,dev->ctl_input); } + v4l2_fh_add(&fh->fh); + return 0; } @@ -1504,7 +1498,8 @@ static int video_release(struct file *file) saa7134_pgtable_free(dev->pci,&fh->pt_cap); saa7134_pgtable_free(dev->pci,&fh->pt_vbi); - v4l2_prio_close(&dev->prio, fh->prio); + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); file->private_data = NULL; kfree(fh); return 0; @@ -1784,11 +1779,6 @@ static int saa7134_s_input(struct file *file, void *priv, unsigned int i) { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; - int err; - - err = v4l2_prio_check(&dev->prio, fh->prio); - if (0 != err) - return err; if (i >= SAA7134_INPUT_MAX) return -EINVAL; @@ -1856,16 +1846,8 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_ unsigned long flags; unsigned int i; v4l2_std_id fixup; - int err; - /* When called from the empress code fh == NULL. - That needs to be fixed somehow, but for now this is - good enough. */ - if (fh) { - err = v4l2_prio_check(&dev->prio, fh->prio); - if (0 != err) - return err; - } else if (res_locked(dev, RESOURCE_OVERLAY)) { + if (!fh && res_locked(dev, RESOURCE_OVERLAY)) { /* Don't change the std from the mpeg device if overlay is active. */ return -EBUSY; @@ -2050,11 +2032,7 @@ static int saa7134_s_tuner(struct file *file, void *priv, { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; - int rx, mode, err; - - err = v4l2_prio_check(&dev->prio, fh->prio); - if (0 != err) - return err; + int rx, mode; mode = dev->thread.mode; if (UNSET == mode) { @@ -2084,11 +2062,6 @@ static int saa7134_s_frequency(struct file *file, void *priv, { struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; - int err; - - err = v4l2_prio_check(&dev->prio, fh->prio); - if (0 != err) - return err; if (0 != f->tuner) return -EINVAL; @@ -2117,24 +2090,6 @@ static int saa7134_s_audio(struct file *file, void *priv, const struct v4l2_audi return 0; } -static int saa7134_g_priority(struct file *file, void *f, enum v4l2_priority *p) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; - - *p = v4l2_prio_max(&dev->prio); - return 0; -} - -static int saa7134_s_priority(struct file *file, void *f, - enum v4l2_priority prio) -{ - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; - - return v4l2_prio_change(&dev->prio, &fh->prio, prio); -} - static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { @@ -2476,8 +2431,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_fbuf = saa7134_g_fbuf, .vidioc_s_fbuf = saa7134_s_fbuf, .vidioc_overlay = saa7134_overlay, - .vidioc_g_priority = saa7134_g_priority, - .vidioc_s_priority = saa7134_s_priority, .vidioc_g_parm = saa7134_g_parm, .vidioc_g_frequency = saa7134_g_frequency, .vidioc_s_frequency = saa7134_s_frequency, diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index 1f6c41ed2a07..fc07b19ed536 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -468,11 +469,11 @@ struct saa7134_dmaqueue { /* video filehandle status */ struct saa7134_fh { + struct v4l2_fh fh; struct saa7134_dev *dev; unsigned int radio; enum v4l2_buf_type type; unsigned int resources; - enum v4l2_priority prio; struct pm_qos_request qos_request; /* video overlay */ @@ -544,7 +545,6 @@ struct saa7134_dev { struct list_head devlist; struct mutex lock; spinlock_t slock; - struct v4l2_prio_state prio; struct v4l2_device v4l2_dev; /* workstruct for loading modules */ struct work_struct request_module_wk; -- cgit v1.2.3 From 0a5ea88b31bed56350939c6a99c4cd58904baa66 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Fri, 1 Feb 2013 20:01:17 -0300 Subject: [media] saa7134: v4l2-compliance: return real frequency Make saa7134 driver more V4L2 compliant: don't cache frequency in s_frequency/g_frequency but return real one instead Signed-off-by: Ondrej Zary Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-video.c | 6 ++++-- drivers/media/pci/saa7134/saa7134.h | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 941e2ebab41d..506a9f401db7 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -2051,8 +2051,11 @@ static int saa7134_g_frequency(struct file *file, void *priv, struct saa7134_fh *fh = priv; struct saa7134_dev *dev = fh->dev; + if (0 != f->tuner) + return -EINVAL; + f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->ctl_freq; + saa_call_all(dev, tuner, g_frequency, f); return 0; } @@ -2070,7 +2073,6 @@ static int saa7134_s_frequency(struct file *file, void *priv, if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) return -EINVAL; mutex_lock(&dev->lock); - dev->ctl_freq = f->frequency; saa_call_all(dev, tuner, s_frequency, f); diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index fc07b19ed536..d2ad16c1569a 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -607,7 +607,6 @@ struct saa7134_dev { int ctl_contrast; int ctl_hue; int ctl_saturation; - int ctl_freq; int ctl_mute; /* audio */ int ctl_volume; int ctl_invert; /* private */ -- cgit v1.2.3 From ce5bdd52629ebb50f65db03e6dfa9c96697d0d40 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Fri, 1 Feb 2013 20:01:18 -0300 Subject: [media] saa7134: v4l2-compliance: fix g_tuner/s_tuner Make saa7134 driver more V4L2 compliant: return real frequency range in g_tuner and fail in s_tuner for non-zero tuner Signed-off-by: Ondrej Zary Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-video.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 506a9f401db7..b832684b940a 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -2014,11 +2014,11 @@ static int saa7134_g_tuner(struct file *file, void *priv, if (NULL != card_in(dev, n).name) { strcpy(t->name, "Television"); t->type = V4L2_TUNER_ANALOG_TV; + saa_call_all(dev, tuner, g_tuner, t); t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; - t->rangehigh = 0xffffffffUL; t->rxsubchans = saa7134_tvaudio_getstereo(dev); t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans); } @@ -2034,6 +2034,9 @@ static int saa7134_s_tuner(struct file *file, void *priv, struct saa7134_dev *dev = fh->dev; int rx, mode; + if (0 != t->index) + return -EINVAL; + mode = dev->thread.mode; if (UNSET == mode) { rx = saa7134_tvaudio_getstereo(dev); -- cgit v1.2.3 From 90a60e90749b844502bca1a7cd76755caf6f4548 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Fri, 1 Feb 2013 20:01:19 -0300 Subject: [media] saa7134: v4l2-compliance: remove bogus audio input support Make saa7134 driver more V4L2 compliant: remove empty g_audio and s_audio functions and don't set audioset in enum_input Signed-off-by: Ondrej Zary Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-video.c | 30 ------------------------------ 1 file changed, 30 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index b832684b940a..40245e42d431 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1750,7 +1750,6 @@ static int saa7134_enum_input(struct file *file, void *priv, strcpy(i->name, card_in(dev, n).name); if (card_in(dev, n).tv) i->type = V4L2_INPUT_TYPE_TUNER; - i->audioset = 1; if (n == dev->ctl_input) { int v1 = saa_readb(SAA7134_STATUS_VIDEO1); int v2 = saa_readb(SAA7134_STATUS_VIDEO2); @@ -2084,17 +2083,6 @@ static int saa7134_s_frequency(struct file *file, void *priv, return 0; } -static int saa7134_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - strcpy(a->name, "audio"); - return 0; -} - -static int saa7134_s_audio(struct file *file, void *priv, const struct v4l2_audio *a) -{ - return 0; -} - static int saa7134_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { @@ -2348,20 +2336,6 @@ static int radio_g_input(struct file *filp, void *priv, unsigned int *i) return 0; } -static int radio_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - memset(a, 0, sizeof(*a)); - strcpy(a->name, "Radio"); - return 0; -} - -static int radio_s_audio(struct file *file, void *priv, - const struct v4l2_audio *a) -{ - return 0; -} - static int radio_s_input(struct file *filp, void *priv, unsigned int i) { return 0; @@ -2412,8 +2386,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, .vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, .vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap, - .vidioc_g_audio = saa7134_g_audio, - .vidioc_s_audio = saa7134_s_audio, .vidioc_cropcap = saa7134_cropcap, .vidioc_reqbufs = saa7134_reqbufs, .vidioc_querybuf = saa7134_querybuf, @@ -2458,9 +2430,7 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_querycap = saa7134_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, .vidioc_s_input = radio_s_input, .vidioc_s_std = radio_s_std, .vidioc_queryctrl = radio_queryctrl, -- cgit v1.2.3 From 9cf21c47ca2e983a0c69d0871cf20d81657d4099 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Fri, 1 Feb 2013 20:01:20 -0300 Subject: [media] saa7134: v4l2-compliance: remove bogus g_parm Make saa7134 driver more V4L2 compliant: remove empty g_parm function Signed-off-by: Ondrej Zary Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-video.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 40245e42d431..3a2649f5485c 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -2250,12 +2250,6 @@ static int saa7134_streamoff(struct file *file, void *priv, return 0; } -static int saa7134_g_parm(struct file *file, void *fh, - struct v4l2_streamparm *parm) -{ - return 0; -} - #ifdef CONFIG_VIDEO_ADV_DEBUG static int vidioc_g_register (struct file *file, void *priv, struct v4l2_dbg_register *reg) @@ -2408,7 +2402,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_fbuf = saa7134_g_fbuf, .vidioc_s_fbuf = saa7134_s_fbuf, .vidioc_overlay = saa7134_overlay, - .vidioc_g_parm = saa7134_g_parm, .vidioc_g_frequency = saa7134_g_frequency, .vidioc_s_frequency = saa7134_s_frequency, #ifdef CONFIG_VIDEO_ADV_DEBUG -- cgit v1.2.3 From d047795c590f63d42160b84ac778b09af297d914 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Fri, 1 Feb 2013 20:01:21 -0300 Subject: [media] saa7134: v4l2-compliance: clear reserved part of VBI structure Make saa7134 driver more V4L2 compliant: clear reserved space of VBI structure to make sure no garbage is left there Signed-off-by: Ondrej Zary Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-video.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 3a2649f5485c..cc409380ee16 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1552,6 +1552,7 @@ static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv, struct saa7134_dev *dev = fh->dev; struct saa7134_tvnorm *norm = dev->tvnorm; + memset(&f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved)); f->fmt.vbi.sampling_rate = 6750000 * 4; f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */; f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; -- cgit v1.2.3 From a2192cf47f593681cd65798880853c5224066c81 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 6 Apr 2013 04:35:27 -0300 Subject: [media] tuner-core/tda9887: get_afc can be tuner mode specific The get_afc op in tda9887 is valid only for the radio mode. But due to the way get_afc in analog_demod_ops was designed it would overwrite the afc value with a bogus value when in TV mode. Pass a pointer to the afc value instead, and when not in radio mode leave it alone in the tda9887. This broke a long time ago in 2.6.19 when the get_afc op was introduced. Before that the afc was only set for radio mode in the tda9887. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.h | 2 +- drivers/media/tuners/tda9887.c | 14 +++++++------- drivers/media/v4l2-core/tuner-core.c | 14 ++------------ 3 files changed, 10 insertions(+), 20 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index b34922a08156..44fad1cbcb09 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -246,7 +246,7 @@ struct analog_demod_ops { void (*set_params)(struct dvb_frontend *fe, struct analog_parameters *params); int (*has_signal)(struct dvb_frontend *fe); - int (*get_afc)(struct dvb_frontend *fe); + int (*get_afc)(struct dvb_frontend *fe, s32 *afc); void (*tuner_status)(struct dvb_frontend *fe); void (*standby)(struct dvb_frontend *fe); void (*release)(struct dvb_frontend *fe); diff --git a/drivers/media/tuners/tda9887.c b/drivers/media/tuners/tda9887.c index cdb645d57438..300005c535ba 100644 --- a/drivers/media/tuners/tda9887.c +++ b/drivers/media/tuners/tda9887.c @@ -596,22 +596,22 @@ static void tda9887_tuner_status(struct dvb_frontend *fe) priv->data[1], priv->data[2], priv->data[3]); } -static int tda9887_get_afc(struct dvb_frontend *fe) +static int tda9887_get_afc(struct dvb_frontend *fe, s32 *afc) { struct tda9887_priv *priv = fe->analog_demod_priv; - static int AFC_BITS_2_kHz[] = { + static const int AFC_BITS_2_kHz[] = { -12500, -37500, -62500, -97500, -112500, -137500, -162500, -187500, 187500, 162500, 137500, 112500, 97500 , 62500, 37500 , 12500 }; - int afc=0; __u8 reg = 0; - if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,®,1)) - afc = AFC_BITS_2_kHz[(reg>>1)&0x0f]; - - return afc; + if (priv->mode != V4L2_TUNER_RADIO) + return 0; + if (1 == tuner_i2c_xfer_recv(&priv->i2c_props, ®, 1)) + *afc = AFC_BITS_2_kHz[(reg >> 1) & 0x0f]; + return 0; } static void tda9887_standby(struct dvb_frontend *fe) diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index 7d60c5d38ca0..a0b10e6b55ed 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -228,16 +228,6 @@ static int fe_has_signal(struct dvb_frontend *fe) return strength; } -static int fe_get_afc(struct dvb_frontend *fe) -{ - s32 afc; - - if (fe->ops.tuner_ops.get_afc(fe, &afc) < 0) - return 0; - - return afc; -} - static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg) { struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; @@ -448,7 +438,7 @@ static void set_type(struct i2c_client *c, unsigned int type, if (fe_tuner_ops->get_rf_strength) analog_ops->has_signal = fe_has_signal; if (fe_tuner_ops->get_afc) - analog_ops->get_afc = fe_get_afc; + analog_ops->get_afc = fe_tuner_ops->get_afc; } else { t->name = analog_ops->info.name; @@ -1190,7 +1180,7 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) if (check_mode(t, vt->type) == -EINVAL) return 0; if (vt->type == t->mode && analog_ops->get_afc) - vt->afc = analog_ops->get_afc(&t->fe); + analog_ops->get_afc(&t->fe, &vt->afc); if (analog_ops->has_signal) vt->signal = analog_ops->has_signal(&t->fe); if (vt->type != V4L2_TUNER_RADIO) { -- cgit v1.2.3 From dfc2e12df02d49a1567bc90989ceef870cf5b147 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 6 Apr 2013 04:41:29 -0300 Subject: [media] tuner-core/simple: get_rf_strength can be tuner mode specific The get_rf_strength op in tuner-simple is valid only for the radio mode. But due to the way get_signal in analog_demod_ops was designed it would overwrite the signal value with a bogus value when in TV mode. Pass a pointer to the signal value instead, and when not in radio mode leave it alone in the tuner-simple. This broke in commit 030755bde42bbed133182b0ece7c7a9c759478e8 (tuner-core: call has_signal for both TV and radio) in kernel 3.6. Before that this was working correctly. That commit did the right thing, but what wasn't realized at the time was that tuner-simple should have been updated as well to restrict setting the signal strength to the radio mode only. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.h | 2 +- drivers/media/tuners/tda8290.c | 15 +++++++++------ drivers/media/tuners/tuner-simple.c | 5 ++++- drivers/media/v4l2-core/tuner-core.c | 29 +++++++++++++---------------- 4 files changed, 27 insertions(+), 24 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 44fad1cbcb09..371b6caf486c 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -245,7 +245,7 @@ struct analog_demod_ops { void (*set_params)(struct dvb_frontend *fe, struct analog_parameters *params); - int (*has_signal)(struct dvb_frontend *fe); + int (*has_signal)(struct dvb_frontend *fe, u16 *signal); int (*get_afc)(struct dvb_frontend *fe, s32 *afc); void (*tuner_status)(struct dvb_frontend *fe); void (*standby)(struct dvb_frontend *fe); diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c index 20cc7dad6b4e..ab4106c17b4c 100644 --- a/drivers/media/tuners/tda8290.c +++ b/drivers/media/tuners/tda8290.c @@ -391,7 +391,7 @@ static void tda8295_agc2_out(struct dvb_frontend *fe, int enable) tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); } -static int tda8295_has_signal(struct dvb_frontend *fe) +static int tda8295_has_signal(struct dvb_frontend *fe, u16 *signal) { struct tda8290_priv *priv = fe->analog_demod_priv; @@ -399,7 +399,8 @@ static int tda8295_has_signal(struct dvb_frontend *fe) unsigned char ret; tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1); - return (ret & 0x01) ? 65535 : 0; + *signal = (ret & 0x01) ? 65535 : 0; + return 0; } /*---------------------------------------------------------------------*/ @@ -408,7 +409,7 @@ static void tda8295_set_params(struct dvb_frontend *fe, struct analog_parameters *params) { struct tda8290_priv *priv = fe->analog_demod_priv; - + u16 signal = 0; unsigned char blanking_mode[] = { 0x1d, 0x00 }; set_audio(fe, params); @@ -436,7 +437,8 @@ static void tda8295_set_params(struct dvb_frontend *fe, if (priv->cfg.agcf) priv->cfg.agcf(fe); - if (tda8295_has_signal(fe)) + tda8295_has_signal(fe, &signal); + if (signal) tuner_dbg("tda8295 is locked\n"); else tuner_dbg("tda8295 not locked, no signal?\n"); @@ -447,7 +449,7 @@ static void tda8295_set_params(struct dvb_frontend *fe, /*---------------------------------------------------------------------*/ -static int tda8290_has_signal(struct dvb_frontend *fe) +static int tda8290_has_signal(struct dvb_frontend *fe, u16 *signal) { struct tda8290_priv *priv = fe->analog_demod_priv; @@ -456,7 +458,8 @@ static int tda8290_has_signal(struct dvb_frontend *fe) tuner_i2c_xfer_send_recv(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1); - return (afc & 0x80)? 65535:0; + *signal = (afc & 0x80) ? 65535 : 0; + return 0; } /*---------------------------------------------------------------------*/ diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c index 39e7e583c8c0..ca274c2d8c70 100644 --- a/drivers/media/tuners/tuner-simple.c +++ b/drivers/media/tuners/tuner-simple.c @@ -115,6 +115,7 @@ struct tuner_simple_priv { u32 frequency; u32 bandwidth; + bool radio_mode; }; /* ---------------------------------------------------------------------- */ @@ -189,7 +190,7 @@ static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength) struct tuner_simple_priv *priv = fe->tuner_priv; int signal; - if (priv->i2c_props.adap == NULL) + if (priv->i2c_props.adap == NULL || !priv->radio_mode) return -EINVAL; signal = tuner_signal(tuner_read_status(fe)); @@ -776,11 +777,13 @@ static int simple_set_params(struct dvb_frontend *fe, switch (params->mode) { case V4L2_TUNER_RADIO: + priv->radio_mode = true; ret = simple_set_radio_freq(fe, params); priv->frequency = params->frequency * 125 / 2; break; case V4L2_TUNER_ANALOG_TV: case V4L2_TUNER_DIGITAL_TV: + priv->radio_mode = false; ret = simple_set_tv_freq(fe, params); priv->frequency = params->frequency * 62500; break; diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index a0b10e6b55ed..ddc9379eb276 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -218,16 +218,6 @@ static void fe_standby(struct dvb_frontend *fe) fe_tuner_ops->sleep(fe); } -static int fe_has_signal(struct dvb_frontend *fe) -{ - u16 strength; - - if (fe->ops.tuner_ops.get_rf_strength(fe, &strength) < 0) - return 0; - - return strength; -} - static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg) { struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; @@ -436,7 +426,7 @@ static void set_type(struct i2c_client *c, unsigned int type, sizeof(struct analog_demod_ops)); if (fe_tuner_ops->get_rf_strength) - analog_ops->has_signal = fe_has_signal; + analog_ops->has_signal = fe_tuner_ops->get_rf_strength; if (fe_tuner_ops->get_afc) analog_ops->get_afc = fe_tuner_ops->get_afc; @@ -1060,9 +1050,12 @@ static void tuner_status(struct dvb_frontend *fe) if (tuner_status & TUNER_STATUS_STEREO) tuner_info("Stereo: yes\n"); } - if (analog_ops->has_signal) - tuner_info("Signal strength: %d\n", - analog_ops->has_signal(fe)); + if (analog_ops->has_signal) { + u16 signal; + + if (!analog_ops->has_signal(fe, &signal)) + tuner_info("Signal strength: %hu\n", signal); + } } /* @@ -1181,8 +1174,12 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) return 0; if (vt->type == t->mode && analog_ops->get_afc) analog_ops->get_afc(&t->fe, &vt->afc); - if (analog_ops->has_signal) - vt->signal = analog_ops->has_signal(&t->fe); + if (vt->type == t->mode && analog_ops->has_signal) { + u16 signal = (u16)vt->signal; + + if (!analog_ops->has_signal(&t->fe, &signal)) + vt->signal = signal; + } if (vt->type != V4L2_TUNER_RADIO) { vt->capability |= V4L2_TUNER_CAP_NORM; vt->rangelow = tv_range[0] * 16; -- cgit v1.2.3 From cd634f1bfc182e564f33809fdca33027bb99fceb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 27 Mar 2013 08:04:23 -0300 Subject: [media] v4l2: put VIDIOC_DBG_G_CHIP_NAME under ADV_DEBUG Only enable this ioctl if the VIDEO_ADV_DEBUG config option is set. This prevents abuse from both userspace and kernelspace (some bridge drivers abuse DBG_G_CHIP_IDENT, lets prevent that from happening again with this ioctl). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml | 3 +++ drivers/media/usb/em28xx/em28xx-video.c | 4 ++-- drivers/media/v4l2-core/v4l2-dev.c | 2 +- drivers/media/v4l2-core/v4l2-ioctl.c | 8 ++++---- include/media/v4l2-ioctl.h | 6 +++--- 5 files changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml index 4921346fabd7..5fce8d84288e 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml @@ -63,6 +63,9 @@ card. Regular applications must not use it. When you found a chip specific bug, please contact the linux-media mailing list (&v4l-ml;) so it can be fixed. + Additionally the Linux kernel must be compiled with the +CONFIG_VIDEO_ADV_DEBUG option to enable this ioctl. + To query the driver applications must initialize the match.type and match.addr or match.name diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 792ead1025d7..39951f5731e1 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1331,6 +1331,7 @@ static int vidioc_g_chip_ident(struct file *file, void *priv, return 0; } +#ifdef CONFIG_VIDEO_ADV_DEBUG static int vidioc_g_chip_name(struct file *file, void *priv, struct v4l2_dbg_chip_name *chip) { @@ -1346,7 +1347,6 @@ static int vidioc_g_chip_name(struct file *file, void *priv, return 0; } -#ifdef CONFIG_VIDEO_ADV_DEBUG static int em28xx_reg_len(int reg) { switch (reg) { @@ -1796,8 +1796,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_g_chip_ident = vidioc_g_chip_ident, - .vidioc_g_chip_name = vidioc_g_chip_name, #ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_chip_name = vidioc_g_chip_name, .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 670b9ca8ecbe..1c3b43cf773d 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -591,8 +591,8 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency); SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency); SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status); - set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_NAME), valid_ioctls); #ifdef CONFIG_VIDEO_ADV_DEBUG + set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_NAME), valid_ioctls); set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls); set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls); #endif diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 336ed2dd607c..feac07e50293 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1873,6 +1873,7 @@ static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops, static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { +#ifdef CONFIG_VIDEO_ADV_DEBUG struct video_device *vfd = video_devdata(file); struct v4l2_dbg_chip_name *p = arg; struct v4l2_subdev *sd; @@ -1880,12 +1881,10 @@ static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, switch (p->match.type) { case V4L2_CHIP_MATCH_BRIDGE: -#ifdef CONFIG_VIDEO_ADV_DEBUG if (ops->vidioc_s_register) p->flags |= V4L2_CHIP_FL_WRITABLE; if (ops->vidioc_g_register) p->flags |= V4L2_CHIP_FL_READABLE; -#endif if (ops->vidioc_g_chip_name) return ops->vidioc_g_chip_name(file, fh, arg); if (p->match.addr) @@ -1904,12 +1903,10 @@ static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, break; v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { if (v4l_dbg_found_match(&p->match, sd, idx++)) { -#ifdef CONFIG_VIDEO_ADV_DEBUG if (sd->ops->core && sd->ops->core->s_register) p->flags |= V4L2_CHIP_FL_WRITABLE; if (sd->ops->core && sd->ops->core->g_register) p->flags |= V4L2_CHIP_FL_READABLE; -#endif strlcpy(p->name, sd->name, sizeof(p->name)); return 0; } @@ -1917,6 +1914,9 @@ static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, break; } return -EINVAL; +#else + return -ENOTTY; +#endif } static int v4l_dqevent(const struct v4l2_ioctl_ops *ops, diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index b273f0e81818..6b917d69e408 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -243,12 +243,12 @@ struct v4l2_ioctl_ops { struct v4l2_dbg_register *reg); int (*vidioc_s_register) (struct file *file, void *fh, const struct v4l2_dbg_register *reg); -#endif - int (*vidioc_g_chip_ident) (struct file *file, void *fh, - struct v4l2_dbg_chip_ident *chip); int (*vidioc_g_chip_name) (struct file *file, void *fh, struct v4l2_dbg_chip_name *chip); +#endif + int (*vidioc_g_chip_ident) (struct file *file, void *fh, + struct v4l2_dbg_chip_ident *chip); int (*vidioc_enum_framesizes) (struct file *file, void *fh, struct v4l2_frmsizeenum *fsize); -- cgit v1.2.3 From 3eef25107cab65a1158b11ba373fb9b4fc25b4b8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 3 Apr 2013 04:08:19 -0300 Subject: [media] v4l2: drop V4L2_CHIP_MATCH_SUBDEV_NAME After using the new VIDIOC_DBG_G_CHIP_NAME ioctl I realized that the matching by name possibility is useless. Just drop it and rename MATCH_SUBDEV_IDX to just MATCH_SUBDEV. The v4l2-dbg utility is much better placed to match by name by just enumerating all bridge and subdev devices until chip_name.name matches. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml | 7 +-- .../DocBook/media/v4l/vidioc-dbg-g-chip-name.xml | 18 +------ .../DocBook/media/v4l/vidioc-dbg-g-register.xml | 17 +------ drivers/media/v4l2-core/v4l2-common.c | 3 +- drivers/media/v4l2-core/v4l2-ioctl.c | 55 ++++++++-------------- include/uapi/linux/videodev2.h | 3 +- 6 files changed, 26 insertions(+), 77 deletions(-) (limited to 'drivers/media') diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml index 82e43c6c72b8..921e18550d26 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml @@ -221,13 +221,8 @@ the values from . Match the nth anciliary AC97 chip. - V4L2_CHIP_MATCH_SUBDEV_NAME + V4L2_CHIP_MATCH_SUBDEV 4 - Match the sub-device by name. Can't be used with this ioctl. - - - V4L2_CHIP_MATCH_SUBDEV_IDX - 5 Match the nth sub-device. Can't be used with this ioctl. diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml index 5fce8d84288e..fa3bd42ab167 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml @@ -87,16 +87,7 @@ connected to the PCI or USB bus. Non-zero numbers identify specific parts of the bridge chip such as an AC97 register block. When match.type is -V4L2_CHIP_MATCH_SUBDEV_NAME, -match.name contains the name of a sub-device. -For instance -"saa7127 6-0044" will match the saa7127 sub-device -at the given i2c bus. This match type is not very useful for this ioctl -and is here only for consistency. - - - When match.type is -V4L2_CHIP_MATCH_SUBDEV_IDX, +V4L2_CHIP_MATCH_SUBDEV, match.addr selects the nth sub-device. This allows you to enumerate over all sub-devices. @@ -207,13 +198,8 @@ is set, then the driver supports reading registers from the device. If Match the nth anciliary AC97 chip. Can't be used with this ioctl. - V4L2_CHIP_MATCH_SUBDEV_NAME + V4L2_CHIP_MATCH_SUBDEV 4 - Match the sub-device by name. - - - V4L2_CHIP_MATCH_SUBDEV_IDX - 5 Match the nth sub-device. diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml index 3082b4149dbe..db7844f2439f 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml @@ -123,15 +123,7 @@ bus address. on the TV card. When match.type is -V4L2_CHIP_MATCH_SUBDEV_NAME, -match.name contains the sub-device name. -For instance -"saa7127 6-0044" will match this specific saa7127 -sub-device. Again with the &VIDIOC-DBG-G-CHIP-NAME; ioctl you can find -out which sub-devices are present. - - When match.type is -V4L2_CHIP_MATCH_SUBDEV_IDX, +V4L2_CHIP_MATCH_SUBDEV, match.addr selects the nth sub-device. @@ -250,13 +242,8 @@ register. Match the nth anciliary AC97 chip. - V4L2_CHIP_MATCH_SUBDEV_NAME + V4L2_CHIP_MATCH_SUBDEV 4 - Match the sub-device by name. - - - V4L2_CHIP_MATCH_SUBDEV_IDX - 5 Match the nth sub-device. diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index f8fac9cefc3c..3fed63f4e026 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -254,8 +254,7 @@ int v4l2_chip_match_i2c_client(struct i2c_client *c, const struct v4l2_dbg_match return len && !strncmp(c->driver->driver.name, match->name, len); case V4L2_CHIP_MATCH_I2C_ADDR: return c->addr == match->addr; - case V4L2_CHIP_MATCH_SUBDEV_IDX: - case V4L2_CHIP_MATCH_SUBDEV_NAME: + case V4L2_CHIP_MATCH_SUBDEV: return 1; default: return 0; diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index feac07e50293..7a96162f544f 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -629,8 +629,7 @@ static void v4l_print_dbg_chip_ident(const void *arg, bool write_only) const struct v4l2_dbg_chip_ident *p = arg; pr_cont("type=%u, ", p->match.type); - if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || - p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) pr_cont("name=%.*s, ", (int)sizeof(p->match.name), p->match.name); else @@ -644,8 +643,7 @@ static void v4l_print_dbg_chip_name(const void *arg, bool write_only) const struct v4l2_dbg_chip_name *p = arg; pr_cont("type=%u, ", p->match.type); - if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || - p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) pr_cont("name=%.*s, ", (int)sizeof(p->match.name), p->match.name); else @@ -658,8 +656,7 @@ static void v4l_print_dbg_register(const void *arg, bool write_only) const struct v4l2_dbg_register *p = arg; pr_cont("type=%u, ", p->match.type); - if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER || - p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) + if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) pr_cont("name=%.*s, ", (int)sizeof(p->match.name), p->match.name); else @@ -1791,14 +1788,6 @@ static int v4l_log_status(const struct v4l2_ioctl_ops *ops, return ret; } -static bool v4l_dbg_found_match(const struct v4l2_dbg_match *match, - struct v4l2_subdev *sd, int idx) -{ - if (match->type == V4L2_CHIP_MATCH_SUBDEV_IDX) - return match->addr == idx; - return !strcmp(match->name, sd->name); -} - static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { @@ -1810,14 +1799,12 @@ static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (p->match.type == V4L2_CHIP_MATCH_SUBDEV_IDX || - p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) { + if (p->match.type == V4L2_CHIP_MATCH_SUBDEV) { if (vfd->v4l2_dev == NULL) return -EINVAL; - v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { - if (v4l_dbg_found_match(&p->match, sd, idx++)) + v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) + if (p->match.addr == idx++) return v4l2_subdev_call(sd, core, g_register, p); - } return -EINVAL; } if (ops->vidioc_g_register) @@ -1839,14 +1826,12 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (p->match.type == V4L2_CHIP_MATCH_SUBDEV_IDX || - p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME) { + if (p->match.type == V4L2_CHIP_MATCH_SUBDEV) { if (vfd->v4l2_dev == NULL) return -EINVAL; - v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { - if (v4l_dbg_found_match(&p->match, sd, idx++)) + v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) + if (p->match.addr == idx++) return v4l2_subdev_call(sd, core, s_register, p); - } return -EINVAL; } if (ops->vidioc_s_register) @@ -1864,8 +1849,7 @@ static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops, p->ident = V4L2_IDENT_NONE; p->revision = 0; - if (p->match.type == V4L2_CHIP_MATCH_SUBDEV_NAME || - p->match.type == V4L2_CHIP_MATCH_SUBDEV_IDX) + if (p->match.type == V4L2_CHIP_MATCH_SUBDEV) return -EINVAL; return ops->vidioc_g_chip_ident(file, fh, p); } @@ -1897,19 +1881,18 @@ static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, strlcpy(p->name, "bridge", sizeof(p->name)); return 0; - case V4L2_CHIP_MATCH_SUBDEV_IDX: - case V4L2_CHIP_MATCH_SUBDEV_NAME: + case V4L2_CHIP_MATCH_SUBDEV: if (vfd->v4l2_dev == NULL) break; v4l2_device_for_each_subdev(sd, vfd->v4l2_dev) { - if (v4l_dbg_found_match(&p->match, sd, idx++)) { - if (sd->ops->core && sd->ops->core->s_register) - p->flags |= V4L2_CHIP_FL_WRITABLE; - if (sd->ops->core && sd->ops->core->g_register) - p->flags |= V4L2_CHIP_FL_READABLE; - strlcpy(p->name, sd->name, sizeof(p->name)); - return 0; - } + if (p->match.addr != idx++) + continue; + if (sd->ops->core && sd->ops->core->s_register) + p->flags |= V4L2_CHIP_FL_WRITABLE; + if (sd->ops->core && sd->ops->core->g_register) + p->flags |= V4L2_CHIP_FL_READABLE; + strlcpy(p->name, sd->name, sizeof(p->name)); + return 0; } break; } diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index e9c49c5e6416..4c941c103c44 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1812,8 +1812,7 @@ struct v4l2_event_subscription { #define V4L2_CHIP_MATCH_I2C_DRIVER 1 /* Match against I2C driver name */ #define V4L2_CHIP_MATCH_I2C_ADDR 2 /* Match against I2C 7-bit address */ #define V4L2_CHIP_MATCH_AC97 3 /* Match against anciliary AC97 chip */ -#define V4L2_CHIP_MATCH_SUBDEV_NAME 4 /* Match against subdev name */ -#define V4L2_CHIP_MATCH_SUBDEV_IDX 5 /* Match against subdev index */ +#define V4L2_CHIP_MATCH_SUBDEV 4 /* Match against subdev index */ struct v4l2_dbg_match { __u32 type; /* Match type */ -- cgit v1.2.3 From 0f0fe4b9f6f32b90c82345b97da2977b84e14414 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 6 Apr 2013 06:06:13 -0300 Subject: [media] v4l2-ioctl: fill in name before calling vidioc_g_chip_name That way drivers do not need to fill in the name themselves for bridge address 0. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 7a96162f544f..c48d0acd8bb9 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1869,16 +1869,16 @@ static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, p->flags |= V4L2_CHIP_FL_WRITABLE; if (ops->vidioc_g_register) p->flags |= V4L2_CHIP_FL_READABLE; - if (ops->vidioc_g_chip_name) - return ops->vidioc_g_chip_name(file, fh, arg); - if (p->match.addr) - return -EINVAL; if (vfd->v4l2_dev) strlcpy(p->name, vfd->v4l2_dev->name, sizeof(p->name)); else if (vfd->parent) strlcpy(p->name, vfd->parent->driver->name, sizeof(p->name)); else strlcpy(p->name, "bridge", sizeof(p->name)); + if (ops->vidioc_g_chip_name) + return ops->vidioc_g_chip_name(file, fh, arg); + if (p->match.addr) + return -EINVAL; return 0; case V4L2_CHIP_MATCH_SUBDEV: -- cgit v1.2.3 From 96b03d2a3078d5e95a8b106634faa7cea88ebe5e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 6 Apr 2013 06:16:58 -0300 Subject: [media] v4l2: rename VIDIOC_DBG_G_CHIP_NAME to _CHIP_INFO This ioctl will be extended to return more information than just the name. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/compat.xml | 2 +- Documentation/DocBook/media/v4l/v4l2.xml | 4 +- .../DocBook/media/v4l/vidioc-dbg-g-chip-info.xml | 223 +++++++++++++++++++++ .../DocBook/media/v4l/vidioc-dbg-g-chip-name.xml | 223 --------------------- .../DocBook/media/v4l/vidioc-dbg-g-register.xml | 10 +- drivers/media/usb/em28xx/em28xx-video.c | 8 +- drivers/media/v4l2-core/v4l2-dev.c | 2 +- drivers/media/v4l2-core/v4l2-ioctl.c | 14 +- include/media/v4l2-ioctl.h | 4 +- include/uapi/linux/videodev2.h | 8 +- 10 files changed, 249 insertions(+), 249 deletions(-) create mode 100644 Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml delete mode 100644 Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml (limited to 'drivers/media') diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index e44161ffdd07..f43542ae2981 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2507,7 +2507,7 @@ that used it. It was originally scheduled for removal in 2.6.35. - Added new debugging ioctl &VIDIOC-DBG-G-CHIP-NAME;. + Added new debugging ioctl &VIDIOC-DBG-G-CHIP-INFO;. diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index c1f334084213..bfc93cdcf696 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -147,7 +147,7 @@ applications. --> Remove obsolete and unused DV_PRESET ioctls: VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET, VIDIOC_QUERY_DV_PRESET and VIDIOC_ENUM_DV_PRESET. Remove the related v4l2_input/output capability - flags V4L2_IN_CAP_PRESETS and V4L2_OUT_CAP_PRESETS. Added VIDIOC_DBG_G_CHIP_NAME. + flags V4L2_IN_CAP_PRESETS and V4L2_OUT_CAP_PRESETS. Added VIDIOC_DBG_G_CHIP_INFO. @@ -548,7 +548,7 @@ and discussions on the V4L mailing list. &sub-create-bufs; &sub-cropcap; &sub-dbg-g-chip-ident; - &sub-dbg-g-chip-name; + &sub-dbg-g-chip-info; &sub-dbg-g-register; &sub-decoder-cmd; &sub-dqevent; diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml new file mode 100644 index 000000000000..e1cece6c5de1 --- /dev/null +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml @@ -0,0 +1,223 @@ + + + ioctl VIDIOC_DBG_G_CHIP_INFO + &manvol; + + + + VIDIOC_DBG_G_CHIP_INFO + Identify the chips on a TV card + + + + + + int ioctl + int fd + int request + struct v4l2_dbg_chip_info +*argp + + + + + + Arguments + + + + fd + + &fd; + + + + request + + VIDIOC_DBG_G_CHIP_INFO + + + + argp + + + + + + + + + Description + + + Experimental + + This is an experimental interface and may change in +the future. + + + For driver debugging purposes this ioctl allows test +applications to query the driver about the chips present on the TV +card. Regular applications must not use it. When you found a chip +specific bug, please contact the linux-media mailing list (&v4l-ml;) +so it can be fixed. + + Additionally the Linux kernel must be compiled with the +CONFIG_VIDEO_ADV_DEBUG option to enable this ioctl. + + To query the driver applications must initialize the +match.type and +match.addr or match.name +fields of a &v4l2-dbg-chip-info; +and call VIDIOC_DBG_G_CHIP_INFO with a pointer to +this structure. On success the driver stores information about the +selected chip in the name and +flags fields. On failure the structure +remains unchanged. + + When match.type is +V4L2_CHIP_MATCH_BRIDGE, +match.addr selects the nth bridge 'chip' +on the TV card. You can enumerate all chips by starting at zero and +incrementing match.addr by one until +VIDIOC_DBG_G_CHIP_INFO fails with an &EINVAL;. +The number zero always selects the bridge chip itself, ⪚ the chip +connected to the PCI or USB bus. Non-zero numbers identify specific +parts of the bridge chip such as an AC97 register block. + + When match.type is +V4L2_CHIP_MATCH_SUBDEV, +match.addr selects the nth sub-device. This +allows you to enumerate over all sub-devices. + + On success, the name field will +contain a chip name and the flags field will +contain V4L2_CHIP_FL_READABLE if the driver supports +reading registers from the device or V4L2_CHIP_FL_WRITABLE +if the driver supports writing registers to the device. + + We recommended the v4l2-dbg +utility over calling this ioctl directly. It is available from the +LinuxTV v4l-dvb repository; see http://linuxtv.org/repo/ for +access instructions. + + +
+ struct <structname>v4l2_dbg_match</structname> + + &cs-ustr; + + + __u32 + type + See for a list of +possible types. + + + union + (anonymous) + + + + __u32 + addr + Match a chip by this number, interpreted according +to the type field. + + + + char + name[32] + Match a chip by this name, interpreted according +to the type field. + + + +
+ + + struct <structname>v4l2_dbg_chip_info</structname> + + &cs-str; + + + struct v4l2_dbg_match + match + How to match the chip, see . + + + char + name[32] + The name of the chip. + + + __u32 + flags + Set by the driver. If V4L2_CHIP_FL_READABLE +is set, then the driver supports reading registers from the device. If +V4L2_CHIP_FL_WRITABLE is set, then it supports writing registers. + + + __u32 + reserved[8] + Reserved fields, both application and driver must set these to 0. + + + +
+ + + + Chip Match Types + + &cs-def; + + + V4L2_CHIP_MATCH_BRIDGE + 0 + Match the nth chip on the card, zero for the + bridge chip. Does not match sub-devices. + + + V4L2_CHIP_MATCH_I2C_DRIVER + 1 + Match an &i2c; chip by its driver name. Can't be used with this ioctl. + + + V4L2_CHIP_MATCH_I2C_ADDR + 2 + Match a chip by its 7 bit &i2c; bus address. Can't be used with this ioctl. + + + V4L2_CHIP_MATCH_AC97 + 3 + Match the nth anciliary AC97 chip. Can't be used with this ioctl. + + + V4L2_CHIP_MATCH_SUBDEV + 4 + Match the nth sub-device. + + + +
+ + + + &return-value; + + + + EINVAL + + The match_type is invalid or +no device could be matched. + + + + + diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml deleted file mode 100644 index fa3bd42ab167..000000000000 --- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml +++ /dev/null @@ -1,223 +0,0 @@ - - - ioctl VIDIOC_DBG_G_CHIP_NAME - &manvol; - - - - VIDIOC_DBG_G_CHIP_NAME - Identify the chips on a TV card - - - - - - int ioctl - int fd - int request - struct v4l2_dbg_chip_name -*argp - - - - - - Arguments - - - - fd - - &fd; - - - - request - - VIDIOC_DBG_G_CHIP_NAME - - - - argp - - - - - - - - - Description - - - Experimental - - This is an experimental interface and may change in -the future. - - - For driver debugging purposes this ioctl allows test -applications to query the driver about the chips present on the TV -card. Regular applications must not use it. When you found a chip -specific bug, please contact the linux-media mailing list (&v4l-ml;) -so it can be fixed. - - Additionally the Linux kernel must be compiled with the -CONFIG_VIDEO_ADV_DEBUG option to enable this ioctl. - - To query the driver applications must initialize the -match.type and -match.addr or match.name -fields of a &v4l2-dbg-chip-name; -and call VIDIOC_DBG_G_CHIP_NAME with a pointer to -this structure. On success the driver stores information about the -selected chip in the name and -flags fields. On failure the structure -remains unchanged. - - When match.type is -V4L2_CHIP_MATCH_BRIDGE, -match.addr selects the nth bridge 'chip' -on the TV card. You can enumerate all chips by starting at zero and -incrementing match.addr by one until -VIDIOC_DBG_G_CHIP_NAME fails with an &EINVAL;. -The number zero always selects the bridge chip itself, ⪚ the chip -connected to the PCI or USB bus. Non-zero numbers identify specific -parts of the bridge chip such as an AC97 register block. - - When match.type is -V4L2_CHIP_MATCH_SUBDEV, -match.addr selects the nth sub-device. This -allows you to enumerate over all sub-devices. - - On success, the name field will -contain a chip name and the flags field will -contain V4L2_CHIP_FL_READABLE if the driver supports -reading registers from the device or V4L2_CHIP_FL_WRITABLE -if the driver supports writing registers to the device. - - We recommended the v4l2-dbg -utility over calling this ioctl directly. It is available from the -LinuxTV v4l-dvb repository; see http://linuxtv.org/repo/ for -access instructions. - - - - struct <structname>v4l2_dbg_match</structname> - - &cs-ustr; - - - __u32 - type - See for a list of -possible types. - - - union - (anonymous) - - - - __u32 - addr - Match a chip by this number, interpreted according -to the type field. - - - - char - name[32] - Match a chip by this name, interpreted according -to the type field. - - - -
- - - struct <structname>v4l2_dbg_chip_name</structname> - - &cs-str; - - - struct v4l2_dbg_match - match - How to match the chip, see . - - - char - name[32] - The name of the chip. - - - __u32 - flags - Set by the driver. If V4L2_CHIP_FL_READABLE -is set, then the driver supports reading registers from the device. If -V4L2_CHIP_FL_WRITABLE is set, then it supports writing registers. - - - __u32 - reserved[8] - Reserved fields, both application and driver must set these to 0. - - - -
- - - - Chip Match Types - - &cs-def; - - - V4L2_CHIP_MATCH_BRIDGE - 0 - Match the nth chip on the card, zero for the - bridge chip. Does not match sub-devices. - - - V4L2_CHIP_MATCH_I2C_DRIVER - 1 - Match an &i2c; chip by its driver name. Can't be used with this ioctl. - - - V4L2_CHIP_MATCH_I2C_ADDR - 2 - Match a chip by its 7 bit &i2c; bus address. Can't be used with this ioctl. - - - V4L2_CHIP_MATCH_AC97 - 3 - Match the nth anciliary AC97 chip. Can't be used with this ioctl. - - - V4L2_CHIP_MATCH_SUBDEV - 4 - Match the nth sub-device. - - - -
-
- - - &return-value; - - - - EINVAL - - The match_type is invalid or -no device could be matched. - - - - -
diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml index db7844f2439f..d13bac9e2445 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml @@ -99,7 +99,7 @@ unchanged. match.addr selects the nth non-sub-device chip on the TV card. The number zero always selects the host chip, ⪚ the chip connected to the PCI or USB bus. You can find out which chips are -present with the &VIDIOC-DBG-G-CHIP-NAME; ioctl. +present with the &VIDIOC-DBG-G-CHIP-INFO; ioctl. When match.type is V4L2_CHIP_MATCH_I2C_DRIVER, @@ -109,7 +109,7 @@ For instance supported by the saa7127 driver, regardless of its &i2c; bus address. When multiple chips supported by the same driver are present, the effect of these ioctls is undefined. Again with the -&VIDIOC-DBG-G-CHIP-NAME; ioctl you can find out which &i2c; chips are +&VIDIOC-DBG-G-CHIP-INFO; ioctl you can find out which &i2c; chips are present. When match.type is @@ -131,14 +131,14 @@ on the TV card. Due to a flaw in the Linux &i2c; bus driver these ioctls may return successfully without actually reading or writing a register. To -catch the most likely failure we recommend a &VIDIOC-DBG-G-CHIP-NAME; +catch the most likely failure we recommend a &VIDIOC-DBG-G-CHIP-INFO; call confirming the presence of the selected &i2c; chip. These ioctls are optional, not all drivers may support them. However when a driver supports these ioctls it must also support -&VIDIOC-DBG-G-CHIP-NAME;. Conversely it may support -VIDIOC_DBG_G_CHIP_NAME but not these ioctls. +&VIDIOC-DBG-G-CHIP-INFO;. Conversely it may support +VIDIOC_DBG_G_CHIP_INFO but not these ioctls. VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER were introduced in Linux diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 39951f5731e1..c27c1f671396 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1332,8 +1332,8 @@ static int vidioc_g_chip_ident(struct file *file, void *priv, } #ifdef CONFIG_VIDEO_ADV_DEBUG -static int vidioc_g_chip_name(struct file *file, void *priv, - struct v4l2_dbg_chip_name *chip) +static int vidioc_g_chip_info(struct file *file, void *priv, + struct v4l2_dbg_chip_info *chip) { struct em28xx_fh *fh = priv; struct em28xx *dev = fh->dev; @@ -1797,7 +1797,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_g_chip_ident = vidioc_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_chip_name = vidioc_g_chip_name, + .vidioc_g_chip_info = vidioc_g_chip_info, .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif @@ -1827,7 +1827,7 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_g_chip_ident = vidioc_g_chip_ident, - .vidioc_g_chip_name = vidioc_g_chip_name, + .vidioc_g_chip_info = vidioc_g_chip_info, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 1c3b43cf773d..5923c5dfacd5 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -592,7 +592,7 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency); SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status); #ifdef CONFIG_VIDEO_ADV_DEBUG - set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_NAME), valid_ioctls); + set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_INFO), valid_ioctls); set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls); set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls); #endif diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index c48d0acd8bb9..f81bda1a48ec 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -638,9 +638,9 @@ static void v4l_print_dbg_chip_ident(const void *arg, bool write_only) p->ident, p->revision); } -static void v4l_print_dbg_chip_name(const void *arg, bool write_only) +static void v4l_print_dbg_chip_info(const void *arg, bool write_only) { - const struct v4l2_dbg_chip_name *p = arg; + const struct v4l2_dbg_chip_info *p = arg; pr_cont("type=%u, ", p->match.type); if (p->match.type == V4L2_CHIP_MATCH_I2C_DRIVER) @@ -1854,12 +1854,12 @@ static int v4l_dbg_g_chip_ident(const struct v4l2_ioctl_ops *ops, return ops->vidioc_g_chip_ident(file, fh, p); } -static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, +static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { #ifdef CONFIG_VIDEO_ADV_DEBUG struct video_device *vfd = video_devdata(file); - struct v4l2_dbg_chip_name *p = arg; + struct v4l2_dbg_chip_info *p = arg; struct v4l2_subdev *sd; int idx = 0; @@ -1875,8 +1875,8 @@ static int v4l_dbg_g_chip_name(const struct v4l2_ioctl_ops *ops, strlcpy(p->name, vfd->parent->driver->name, sizeof(p->name)); else strlcpy(p->name, "bridge", sizeof(p->name)); - if (ops->vidioc_g_chip_name) - return ops->vidioc_g_chip_name(file, fh, arg); + if (ops->vidioc_g_chip_info) + return ops->vidioc_g_chip_info(file, fh, arg); if (p->match.addr) return -EINVAL; return 0; @@ -2116,7 +2116,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_STD(VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings, v4l_print_dv_timings, 0), IOCTL_INFO_STD(VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap, v4l_print_dv_timings_cap, INFO_FL_CLEAR(v4l2_dv_timings_cap, type)), IOCTL_INFO_FNC(VIDIOC_ENUM_FREQ_BANDS, v4l_enum_freq_bands, v4l_print_freq_band, 0), - IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_NAME, v4l_dbg_g_chip_name, v4l_print_dbg_chip_name, INFO_FL_CLEAR(v4l2_dbg_chip_name, match)), + IOCTL_INFO_FNC(VIDIOC_DBG_G_CHIP_INFO, v4l_dbg_g_chip_info, v4l_print_dbg_chip_info, INFO_FL_CLEAR(v4l2_dbg_chip_info, match)), }; #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 6b917d69e408..931652f0e2af 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -244,8 +244,8 @@ struct v4l2_ioctl_ops { int (*vidioc_s_register) (struct file *file, void *fh, const struct v4l2_dbg_register *reg); - int (*vidioc_g_chip_name) (struct file *file, void *fh, - struct v4l2_dbg_chip_name *chip); + int (*vidioc_g_chip_info) (struct file *file, void *fh, + struct v4l2_dbg_chip_info *chip); #endif int (*vidioc_g_chip_ident) (struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip); diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 4c941c103c44..be43b4659527 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1839,8 +1839,8 @@ struct v4l2_dbg_chip_ident { #define V4L2_CHIP_FL_READABLE (1 << 0) #define V4L2_CHIP_FL_WRITABLE (1 << 1) -/* VIDIOC_DBG_G_CHIP_NAME */ -struct v4l2_dbg_chip_name { +/* VIDIOC_DBG_G_CHIP_INFO */ +struct v4l2_dbg_chip_info { struct v4l2_dbg_match match; char name[32]; __u32 flags; @@ -1938,7 +1938,7 @@ struct v4l2_create_buffers { /* Experimental, meant for debugging, testing and internal use. Never use this ioctl in applications! - Note: this ioctl is deprecated in favor of VIDIOC_DBG_G_CHIP_NAME and + Note: this ioctl is deprecated in favor of VIDIOC_DBG_G_CHIP_INFO and will go away in the future. */ #define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_dbg_chip_ident) @@ -1976,7 +1976,7 @@ struct v4l2_create_buffers { /* Experimental, meant for debugging, testing and internal use. Never use these in applications! */ -#define VIDIOC_DBG_G_CHIP_NAME _IOWR('V', 102, struct v4l2_dbg_chip_name) +#define VIDIOC_DBG_G_CHIP_INFO _IOWR('V', 102, struct v4l2_dbg_chip_info) /* Reminder: when adding new ioctls please add support for them to drivers/media/video/v4l2-compat-ioctl32.c as well! */ -- cgit v1.2.3 From 3de09fbbfaa521e68675bd30cfece252c4856600 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 8 Apr 2013 16:25:04 -0300 Subject: [media] em28xx: fix kernel oops when watching digital TV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dvb->adapter.priv should also be set to the i2c bus since that's what em28xx_tuner_callback expects. Signed-off-by: Hans Verkuil Tested-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-dvb.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 42a6a2696224..1f1f56ff6294 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -178,7 +178,8 @@ static inline int em28xx_dvb_urb_data_copy(struct em28xx *dev, struct urb *urb) static int em28xx_start_streaming(struct em28xx_dvb *dvb) { int rc; - struct em28xx *dev = dvb->adapter.priv; + struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv; + struct em28xx *dev = i2c_bus->dev; int dvb_max_packet_size, packet_multiplier, dvb_alt; if (dev->dvb_xfer_bulk) { @@ -217,7 +218,8 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb) static int em28xx_stop_streaming(struct em28xx_dvb *dvb) { - struct em28xx *dev = dvb->adapter.priv; + struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv; + struct em28xx *dev = i2c_bus->dev; em28xx_stop_urbs(dev); @@ -839,7 +841,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, if (dvb->fe[1]) dvb->fe[1]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl; - dvb->adapter.priv = dev; + dvb->adapter.priv = &dev->i2c_bus[dev->def_i2c_bus]; /* register frontend */ result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]); -- cgit v1.2.3 From 91e20e81087c990f3f9c0074ed740e63c666071b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 29 Jan 2013 08:52:19 -0300 Subject: [media] radio-si4713: remove audout ioctls The audout ioctls are not appropriate for radio transmitters, they apply to video output devices only. Remove them from this driver. Signed-off-by: Hans Verkuil Acked-by: Eduardo Valentin Tested-by: Eduardo Valentin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si4713.c | 32 -------------------------------- 1 file changed, 32 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 38b3f1541c4e..320f3012c850 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -59,35 +59,6 @@ static const struct v4l2_file_operations radio_si4713_fops = { }; /* Video4Linux Interface */ -static int radio_si4713_fill_audout(struct v4l2_audioout *vao) -{ - /* TODO: check presence of audio output */ - strlcpy(vao->name, "FM Modulator Audio Out", 32); - - return 0; -} - -static int radio_si4713_enumaudout(struct file *file, void *priv, - struct v4l2_audioout *vao) -{ - return radio_si4713_fill_audout(vao); -} - -static int radio_si4713_g_audout(struct file *file, void *priv, - struct v4l2_audioout *vao) -{ - int rval = radio_si4713_fill_audout(vao); - - vao->index = 0; - - return rval; -} - -static int radio_si4713_s_audout(struct file *file, void *priv, - const struct v4l2_audioout *vao) -{ - return vao->index ? -EINVAL : 0; -} /* radio_si4713_querycap - query device capabilities */ static int radio_si4713_querycap(struct file *file, void *priv, @@ -229,9 +200,6 @@ static long radio_si4713_default(struct file *file, void *p, } static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = { - .vidioc_enumaudout = radio_si4713_enumaudout, - .vidioc_g_audout = radio_si4713_g_audout, - .vidioc_s_audout = radio_si4713_s_audout, .vidioc_querycap = radio_si4713_querycap, .vidioc_queryctrl = radio_si4713_queryctrl, .vidioc_g_ext_ctrls = radio_si4713_g_ext_ctrls, -- cgit v1.2.3 From fdf51599c0fca3dc1e45924b71e09a862f34ec78 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 8 Apr 2013 06:11:12 -0300 Subject: [media] radio-si4713: embed struct video_device instead of allocating it Also set the v4l2_dev pointer in struct video_device as this was missing. Signed-off-by: Hans Verkuil Acked-by: Eduardo Valentin Tested-by: Eduardo Valentin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si4713.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 320f3012c850..70dc6527a12c 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -48,7 +48,7 @@ MODULE_ALIAS("platform:radio-si4713"); /* Driver state struct */ struct radio_si4713_device { struct v4l2_device v4l2_dev; - struct video_device *radio_dev; + struct video_device radio_dev; }; /* radio_si4713_fops - file operations interface */ @@ -217,7 +217,7 @@ static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = { static struct video_device radio_si4713_vdev_template = { .fops = &radio_si4713_fops, .name = "radio-si4713", - .release = video_device_release, + .release = video_device_release_empty, .ioctl_ops = &radio_si4713_ioctl_ops, .vfl_dir = VFL_DIR_TX, }; @@ -267,27 +267,18 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev) goto put_adapter; } - rsdev->radio_dev = video_device_alloc(); - if (!rsdev->radio_dev) { - dev_err(&pdev->dev, "Failed to alloc video device.\n"); - rval = -ENOMEM; - goto put_adapter; - } - - memcpy(rsdev->radio_dev, &radio_si4713_vdev_template, - sizeof(radio_si4713_vdev_template)); - video_set_drvdata(rsdev->radio_dev, rsdev); - if (video_register_device(rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) { + rsdev->radio_dev = radio_si4713_vdev_template; + rsdev->radio_dev.v4l2_dev = &rsdev->v4l2_dev; + video_set_drvdata(&rsdev->radio_dev, rsdev); + if (video_register_device(&rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) { dev_err(&pdev->dev, "Could not register video device.\n"); rval = -EIO; - goto free_vdev; + goto put_adapter; } dev_info(&pdev->dev, "New device successfully probed\n"); goto exit; -free_vdev: - video_device_release(rsdev->radio_dev); put_adapter: i2c_put_adapter(adapter); unregister_v4l2_dev: @@ -306,7 +297,7 @@ static int radio_si4713_pdriver_remove(struct platform_device *pdev) struct radio_si4713_device *rsdev; rsdev = container_of(v4l2_dev, struct radio_si4713_device, v4l2_dev); - video_unregister_device(rsdev->radio_dev); + video_unregister_device(&rsdev->radio_dev); i2c_put_adapter(client->adapter); v4l2_device_unregister(&rsdev->v4l2_dev); -- cgit v1.2.3 From a58841d0dcb79aebc558a1b55d29995f62aa61a4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 8 Apr 2013 06:27:43 -0300 Subject: [media] radio-si4713: improve querycap Set bus_info and fill in device_caps. Signed-off-by: Hans Verkuil Acked-by: Eduardo Valentin Tested-by: Eduardo Valentin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si4713.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 70dc6527a12c..f0f0a90c69ed 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -67,7 +67,10 @@ static int radio_si4713_querycap(struct file *file, void *priv, strlcpy(capability->driver, "radio-si4713", sizeof(capability->driver)); strlcpy(capability->card, "Silicon Labs Si4713 Modulator", sizeof(capability->card)); - capability->capabilities = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT; + strlcpy(capability->bus_info, "platform:radio-si4713", + sizeof(capability->bus_info)); + capability->device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT; + capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } -- cgit v1.2.3 From 55b2a312c29695520f813e61d668318169895ba7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 8 Apr 2013 06:31:30 -0300 Subject: [media] radio-si4713: use V4L2 core lock Simplify locking by using the V4L2 core lock mechanism. This allows us to remove all locking from the i2c module. This will also simplify the upcoming conversion to the control framework. Signed-off-by: Hans Verkuil Acked-by: Eduardo Valentin Tested-by: Eduardo Valentin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si4713.c | 4 + drivers/media/radio/si4713-i2c.c | 156 +++++++++---------------------------- drivers/media/radio/si4713-i2c.h | 1 - 3 files changed, 40 insertions(+), 121 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index f0f0a90c69ed..633c545438f7 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -49,6 +49,7 @@ MODULE_ALIAS("platform:radio-si4713"); struct radio_si4713_device { struct v4l2_device v4l2_dev; struct video_device radio_dev; + struct mutex lock; }; /* radio_si4713_fops - file operations interface */ @@ -247,6 +248,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev) rval = -ENOMEM; goto exit; } + mutex_init(&rsdev->lock); rval = v4l2_device_register(&pdev->dev, &rsdev->v4l2_dev); if (rval) { @@ -272,6 +274,8 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev) rsdev->radio_dev = radio_si4713_vdev_template; rsdev->radio_dev.v4l2_dev = &rsdev->v4l2_dev; + /* Serialize all access to the si4713 */ + rsdev->radio_dev.lock = &rsdev->lock; video_set_drvdata(&rsdev->radio_dev, rsdev); if (video_register_device(&rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) { dev_err(&pdev->dev, "Could not register video device.\n"); diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index e305c14272b5..1cb9a2e7f683 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c @@ -21,7 +21,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include @@ -458,15 +457,13 @@ static int si4713_checkrev(struct si4713_device *sdev) int rval; u8 resp[SI4713_GETREV_NRESP]; - mutex_lock(&sdev->mutex); - rval = si4713_send_command(sdev, SI4713_CMD_GET_REV, NULL, 0, resp, ARRAY_SIZE(resp), DEFAULT_TIMEOUT); if (rval < 0) - goto unlock; + return rval; if (resp[1] == SI4713_PRODUCT_NUMBER) { v4l2_info(&sdev->sd, "chip found @ 0x%02x (%s)\n", @@ -475,9 +472,6 @@ static int si4713_checkrev(struct si4713_device *sdev) v4l2_err(&sdev->sd, "Invalid product number\n"); rval = -EINVAL; } - -unlock: - mutex_unlock(&sdev->mutex); return rval; } @@ -778,17 +772,9 @@ static int si4713_tx_rds_ps(struct si4713_device *sdev, u8 psid, static int si4713_set_power_state(struct si4713_device *sdev, u8 value) { - int rval; - - mutex_lock(&sdev->mutex); - if (value) - rval = si4713_powerup(sdev); - else - rval = si4713_powerdown(sdev); - - mutex_unlock(&sdev->mutex); - return rval; + return si4713_powerup(sdev); + return si4713_powerdown(sdev); } static int si4713_set_mute(struct si4713_device *sdev, u16 mute) @@ -797,8 +783,6 @@ static int si4713_set_mute(struct si4713_device *sdev, u16 mute) mute = set_mute(mute); - mutex_lock(&sdev->mutex); - if (sdev->power_state) rval = si4713_write_property(sdev, SI4713_TX_LINE_INPUT_MUTE, mute); @@ -806,8 +790,6 @@ static int si4713_set_mute(struct si4713_device *sdev, u16 mute) if (rval >= 0) sdev->mute = get_mute(mute); - mutex_unlock(&sdev->mutex); - return rval; } @@ -820,15 +802,13 @@ static int si4713_set_rds_ps_name(struct si4713_device *sdev, char *ps_name) if (!strlen(ps_name)) memset(ps_name, 0, MAX_RDS_PS_NAME + 1); - mutex_lock(&sdev->mutex); - if (sdev->power_state) { /* Write the new ps name and clear the padding */ for (i = 0; i < MAX_RDS_PS_NAME; i += (RDS_BLOCK / 2)) { rval = si4713_tx_rds_ps(sdev, (i / (RDS_BLOCK / 2)), ps_name + i); if (rval < 0) - goto unlock; + return rval; } /* Setup the size to be sent */ @@ -841,19 +821,16 @@ static int si4713_set_rds_ps_name(struct si4713_device *sdev, char *ps_name) SI4713_TX_RDS_PS_MESSAGE_COUNT, rds_ps_nblocks(len)); if (rval < 0) - goto unlock; + return rval; rval = si4713_write_property(sdev, SI4713_TX_RDS_PS_REPEAT_COUNT, DEFAULT_RDS_PS_REPEAT_COUNT * 2); if (rval < 0) - goto unlock; + return rval; } strncpy(sdev->rds_info.ps_name, ps_name, MAX_RDS_PS_NAME); - -unlock: - mutex_unlock(&sdev->mutex); return rval; } @@ -864,14 +841,12 @@ static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt) u8 b_index = 0, cr_inserted = 0; s8 left; - mutex_lock(&sdev->mutex); - if (!sdev->power_state) goto copy; rval = si4713_tx_rds_buff(sdev, RDS_BLOCK_CLEAR, 0, 0, 0, &left); if (rval < 0) - goto unlock; + return rval; if (!strlen(rt)) goto copy; @@ -898,7 +873,7 @@ static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt) compose_u16(rt[t_index + 2], rt[t_index + 3]), &left); if (rval < 0) - goto unlock; + return rval; t_index += RDS_RADIOTEXT_BLK_SIZE; @@ -908,9 +883,6 @@ static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt) copy: strncpy(sdev->rds_info.radio_text, rt, MAX_RDS_RADIO_TEXT); - -unlock: - mutex_unlock(&sdev->mutex); return rval; } @@ -1114,9 +1086,7 @@ static int si4713_write_econtrol_tune(struct si4713_device *sdev, rval = validate_range(&sdev->sd, control); if (rval < 0) - goto exit; - - mutex_lock(&sdev->mutex); + return rval; switch (control->id) { case V4L2_CID_TUNE_POWER_LEVEL: @@ -1128,8 +1098,7 @@ static int si4713_write_econtrol_tune(struct si4713_device *sdev, antcap = control->value; break; default: - rval = -EINVAL; - goto unlock; + return -EINVAL; } if (sdev->power_state) @@ -1140,9 +1109,6 @@ static int si4713_write_econtrol_tune(struct si4713_device *sdev, sdev->antenna_capacitor = antcap; } -unlock: - mutex_unlock(&sdev->mutex); -exit: return rval; } @@ -1159,12 +1125,12 @@ static int si4713_write_econtrol_integers(struct si4713_device *sdev, rval = validate_range(&sdev->sd, control); if (rval < 0) - goto exit; + return rval; rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit, &mask, &property, &mul, &table, &size); if (rval < 0) - goto exit; + return rval; val = control->value; if (mul) { @@ -1172,24 +1138,22 @@ static int si4713_write_econtrol_integers(struct si4713_device *sdev, } else if (table) { rval = usecs_to_dev(control->value, table, size); if (rval < 0) - goto exit; + return rval; val = rval; rval = 0; } - mutex_lock(&sdev->mutex); - if (sdev->power_state) { if (mask) { rval = si4713_read_property(sdev, property, &val); if (rval < 0) - goto unlock; + return rval; val = set_bits(val, control->value, bit, mask); } rval = si4713_write_property(sdev, property, val); if (rval < 0) - goto unlock; + return rval; if (mask) val = control->value; } @@ -1199,16 +1163,13 @@ static int si4713_write_econtrol_integers(struct si4713_device *sdev, } else if (table) { rval = dev_to_usecs(val, table, size); if (rval < 0) - goto unlock; + return rval; *shadow = rval; rval = 0; } else { *shadow = val; } -unlock: - mutex_unlock(&sdev->mutex); -exit: return rval; } @@ -1231,9 +1192,7 @@ static int si4713_setup(struct si4713_device *sdev) return -ENOMEM; /* Get a local copy to avoid race */ - mutex_lock(&sdev->mutex); memcpy(tmp, sdev, sizeof(*sdev)); - mutex_unlock(&sdev->mutex); ctrl.id = V4L2_CID_RDS_TX_PI; ctrl.value = tmp->rds_info.pi; @@ -1338,17 +1297,15 @@ static int si4713_initialize(struct si4713_device *sdev) rval = si4713_set_power_state(sdev, POWER_ON); if (rval < 0) - goto exit; + return rval; rval = si4713_checkrev(sdev); if (rval < 0) - goto exit; + return rval; rval = si4713_set_power_state(sdev, POWER_OFF); if (rval < 0) - goto exit; - - mutex_lock(&sdev->mutex); + return rval; sdev->rds_info.pi = DEFAULT_RDS_PI; sdev->rds_info.pty = DEFAULT_RDS_PTY; @@ -1380,9 +1337,6 @@ static int si4713_initialize(struct si4713_device *sdev) sdev->stereo = 1; sdev->tune_rnl = DEFAULT_TUNE_RNL; - mutex_unlock(&sdev->mutex); - -exit: return rval; } @@ -1428,7 +1382,7 @@ exit: /* * si4713_update_tune_status - update properties from tx_tune_status - * command. Must be called with sdev->mutex held. + * command. * @sdev: si4713_device structure for the device we are communicating */ static int si4713_update_tune_status(struct si4713_device *sdev) @@ -1456,12 +1410,10 @@ static int si4713_read_econtrol_tune(struct si4713_device *sdev, { s32 rval = 0; - mutex_lock(&sdev->mutex); - if (sdev->power_state) { rval = si4713_update_tune_status(sdev); if (rval < 0) - goto unlock; + return rval; } switch (control->id) { @@ -1472,11 +1424,9 @@ static int si4713_read_econtrol_tune(struct si4713_device *sdev, control->value = sdev->antenna_capacitor; break; default: - rval = -EINVAL; + return -EINVAL; } -unlock: - mutex_unlock(&sdev->mutex); return rval; } @@ -1494,14 +1444,12 @@ static int si4713_read_econtrol_integers(struct si4713_device *sdev, rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit, &mask, &property, &mul, &table, &size); if (rval < 0) - goto exit; - - mutex_lock(&sdev->mutex); + return rval; if (sdev->power_state) { rval = si4713_read_property(sdev, property, &val); if (rval < 0) - goto unlock; + return rval; /* Keep negative values for threshold */ if (control->id == V4L2_CID_AUDIO_COMPRESSION_THRESHOLD) @@ -1516,9 +1464,6 @@ static int si4713_read_econtrol_integers(struct si4713_device *sdev, control->value = *shadow; -unlock: - mutex_unlock(&sdev->mutex); -exit: return rval; } @@ -1712,14 +1657,12 @@ static int si4713_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) if (!sdev) return -ENODEV; - mutex_lock(&sdev->mutex); - if (sdev->power_state) { rval = si4713_read_property(sdev, SI4713_TX_LINE_INPUT_MUTE, &sdev->mute); if (rval < 0) - goto unlock; + return rval; } switch (ctrl->id) { @@ -1728,8 +1671,6 @@ static int si4713_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) break; } -unlock: - mutex_unlock(&sdev->mutex); return rval; } @@ -1779,7 +1720,6 @@ static long si4713_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) if (!arg) return -EINVAL; - mutex_lock(&sdev->mutex); switch (cmd) { case SI4713_IOC_MEASURE_RNL: frequency = v4l2_to_si4713(rnl->frequency); @@ -1788,11 +1728,11 @@ static long si4713_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) /* Set desired measurement frequency */ rval = si4713_tx_tune_measure(sdev, frequency, 0); if (rval < 0) - goto unlock; + return rval; /* get results from tune status */ rval = si4713_update_tune_status(sdev); if (rval < 0) - goto unlock; + return rval; } rnl->rnl = sdev->tune_rnl; break; @@ -1802,8 +1742,6 @@ static long si4713_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) rval = -ENOIOCTLCMD; } -unlock: - mutex_unlock(&sdev->mutex); return rval; } @@ -1822,15 +1760,11 @@ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm) struct si4713_device *sdev = to_si4713_device(sd); int rval = 0; - if (!sdev) { - rval = -ENODEV; - goto exit; - } + if (!sdev) + return -ENODEV; - if (vm->index > 0) { - rval = -EINVAL; - goto exit; - } + if (vm->index > 0) + return -EINVAL; strncpy(vm->name, "FM Modulator", 32); vm->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW | @@ -1840,15 +1774,13 @@ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm) vm->rangelow = si4713_to_v4l2(FREQ_RANGE_LOW); vm->rangehigh = si4713_to_v4l2(FREQ_RANGE_HIGH); - mutex_lock(&sdev->mutex); - if (sdev->power_state) { u32 comp_en = 0; rval = si4713_read_property(sdev, SI4713_TX_COMPONENT_ENABLE, &comp_en); if (rval < 0) - goto unlock; + return rval; sdev->stereo = get_status_bit(comp_en, 1, 1 << 1); sdev->rds_info.enabled = get_status_bit(comp_en, 2, 1 << 2); @@ -1866,9 +1798,6 @@ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm) else vm->txsubchans &= ~V4L2_TUNER_SUB_RDS; -unlock: - mutex_unlock(&sdev->mutex); -exit: return rval; } @@ -1896,13 +1825,11 @@ static int si4713_s_modulator(struct v4l2_subdev *sd, const struct v4l2_modulato rds = !!(vm->txsubchans & V4L2_TUNER_SUB_RDS); - mutex_lock(&sdev->mutex); - if (sdev->power_state) { rval = si4713_read_property(sdev, SI4713_TX_COMPONENT_ENABLE, &p); if (rval < 0) - goto unlock; + return rval; p = set_bits(p, stereo, 1, 1 << 1); p = set_bits(p, rds, 2, 1 << 2); @@ -1910,14 +1837,12 @@ static int si4713_s_modulator(struct v4l2_subdev *sd, const struct v4l2_modulato rval = si4713_write_property(sdev, SI4713_TX_COMPONENT_ENABLE, p); if (rval < 0) - goto unlock; + return rval; } sdev->stereo = stereo; sdev->rds_info.enabled = rds; -unlock: - mutex_unlock(&sdev->mutex); return rval; } @@ -1929,23 +1854,19 @@ static int si4713_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) f->type = V4L2_TUNER_RADIO; - mutex_lock(&sdev->mutex); - if (sdev->power_state) { u16 freq; u8 p, a, n; rval = si4713_tx_tune_status(sdev, 0x00, &freq, &p, &a, &n); if (rval < 0) - goto unlock; + return rval; sdev->frequency = freq; } f->frequency = si4713_to_v4l2(sdev->frequency); -unlock: - mutex_unlock(&sdev->mutex); return rval; } @@ -1960,19 +1881,15 @@ static int si4713_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequenc if (frequency < FREQ_RANGE_LOW || frequency > FREQ_RANGE_HIGH) return -EDOM; - mutex_lock(&sdev->mutex); - if (sdev->power_state) { rval = si4713_tx_tune_freq(sdev, frequency); if (rval < 0) - goto unlock; + return rval; frequency = rval; rval = 0; } sdev->frequency = frequency; -unlock: - mutex_unlock(&sdev->mutex); return rval; } @@ -2030,7 +1947,6 @@ static int si4713_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&sdev->sd, client, &si4713_subdev_ops); - mutex_init(&sdev->mutex); init_completion(&sdev->work); if (client->irq) { diff --git a/drivers/media/radio/si4713-i2c.h b/drivers/media/radio/si4713-i2c.h index c6dfa7fb101c..979828da9d27 100644 --- a/drivers/media/radio/si4713-i2c.h +++ b/drivers/media/radio/si4713-i2c.h @@ -220,7 +220,6 @@ struct si4713_device { /* v4l2_subdev and i2c reference (v4l2_subdev priv data) */ struct v4l2_subdev sd; /* private data structures */ - struct mutex mutex; struct completion work; struct rds_info rds_info; struct limiter_info limiter_info; -- cgit v1.2.3 From b387754d7256b1fa3610ed8a85f9274df49d1178 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 8 Apr 2013 17:25:05 -0300 Subject: [media] radio-si4713: fix g/s_frequency - check for invalid modulators. - clamp frequency to valid range. Signed-off-by: Hans Verkuil Acked-by: Eduardo Valentin Tested-by: Eduardo Valentin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/si4713-i2c.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index 1cb9a2e7f683..56c9241ee7fb 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c @@ -1261,6 +1261,7 @@ static int si4713_setup(struct si4713_device *sdev) rval |= si4713_set_rds_radio_text(sdev, tmp->rds_info.radio_text); /* Device procedure needs to set frequency first */ + f.tuner = 0; f.frequency = tmp->frequency ? tmp->frequency : DEFAULT_FREQUENCY; f.frequency = si4713_to_v4l2(f.frequency); rval |= si4713_s_frequency(&sdev->sd, &f); @@ -1852,7 +1853,8 @@ static int si4713_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *f) struct si4713_device *sdev = to_si4713_device(sd); int rval = 0; - f->type = V4L2_TUNER_RADIO; + if (f->tuner) + return -EINVAL; if (sdev->power_state) { u16 freq; @@ -1877,9 +1879,11 @@ static int si4713_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequenc int rval = 0; u16 frequency = v4l2_to_si4713(f->frequency); + if (f->tuner) + return -EINVAL; + /* Check frequency range */ - if (frequency < FREQ_RANGE_LOW || frequency > FREQ_RANGE_HIGH) - return -EDOM; + frequency = clamp_t(u16, frequency, FREQ_RANGE_LOW, FREQ_RANGE_HIGH); if (sdev->power_state) { rval = si4713_tx_tune_freq(sdev, frequency); -- cgit v1.2.3 From 03aa1bcd92eca82735e1de6d3e71bebf6e1c516e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 8 Apr 2013 17:27:18 -0300 Subject: [media] radio-si4713: convert to the control framework Signed-off-by: Hans Verkuil Acked-by: Eduardo Valentin Tested-by: Eduardo Valentin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si4713.c | 89 +--- drivers/media/radio/si4713-i2c.c | 908 +++++++++---------------------------- drivers/media/radio/si4713-i2c.h | 65 ++- 3 files changed, 239 insertions(+), 823 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 633c545438f7..f8c6137573a8 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -76,61 +76,6 @@ static int radio_si4713_querycap(struct file *file, void *priv, return 0; } -/* radio_si4713_queryctrl - enumerate control items */ -static int radio_si4713_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - /* Must be sorted from low to high control ID! */ - static const u32 user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_AUDIO_MUTE, - 0 - }; - - /* Must be sorted from low to high control ID! */ - static const u32 fmtx_ctrls[] = { - V4L2_CID_FM_TX_CLASS, - V4L2_CID_RDS_TX_DEVIATION, - V4L2_CID_RDS_TX_PI, - V4L2_CID_RDS_TX_PTY, - V4L2_CID_RDS_TX_PS_NAME, - V4L2_CID_RDS_TX_RADIO_TEXT, - V4L2_CID_AUDIO_LIMITER_ENABLED, - V4L2_CID_AUDIO_LIMITER_RELEASE_TIME, - V4L2_CID_AUDIO_LIMITER_DEVIATION, - V4L2_CID_AUDIO_COMPRESSION_ENABLED, - V4L2_CID_AUDIO_COMPRESSION_GAIN, - V4L2_CID_AUDIO_COMPRESSION_THRESHOLD, - V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME, - V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME, - V4L2_CID_PILOT_TONE_ENABLED, - V4L2_CID_PILOT_TONE_DEVIATION, - V4L2_CID_PILOT_TONE_FREQUENCY, - V4L2_CID_TUNE_PREEMPHASIS, - V4L2_CID_TUNE_POWER_LEVEL, - V4L2_CID_TUNE_ANTENNA_CAPACITOR, - 0 - }; - static const u32 *ctrl_classes[] = { - user_ctrls, - fmtx_ctrls, - NULL - }; - struct radio_si4713_device *rsdev; - - rsdev = video_get_drvdata(video_devdata(file)); - - qc->id = v4l2_ctrl_next(ctrl_classes, qc->id); - if (qc->id == 0) - return -EINVAL; - - if (qc->id == V4L2_CID_USER_CLASS || qc->id == V4L2_CID_FM_TX_CLASS) - return v4l2_ctrl_query_fill(qc, 0, 0, 0, 0); - - return v4l2_device_call_until_err(&rsdev->v4l2_dev, 0, core, - queryctrl, qc); -} - /* * v4l2 ioctl call backs. * we are just a wrapper for v4l2_sub_devs. @@ -140,34 +85,6 @@ static inline struct v4l2_device *get_v4l2_dev(struct file *file) return &((struct radio_si4713_device *)video_drvdata(file))->v4l2_dev; } -static int radio_si4713_g_ext_ctrls(struct file *file, void *p, - struct v4l2_ext_controls *vecs) -{ - return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, - g_ext_ctrls, vecs); -} - -static int radio_si4713_s_ext_ctrls(struct file *file, void *p, - struct v4l2_ext_controls *vecs) -{ - return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, - s_ext_ctrls, vecs); -} - -static int radio_si4713_g_ctrl(struct file *file, void *p, - struct v4l2_control *vc) -{ - return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, - g_ctrl, vc); -} - -static int radio_si4713_s_ctrl(struct file *file, void *p, - struct v4l2_control *vc) -{ - return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, - s_ctrl, vc); -} - static int radio_si4713_g_modulator(struct file *file, void *p, struct v4l2_modulator *vm) { @@ -205,11 +122,6 @@ static long radio_si4713_default(struct file *file, void *p, static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = { .vidioc_querycap = radio_si4713_querycap, - .vidioc_queryctrl = radio_si4713_queryctrl, - .vidioc_g_ext_ctrls = radio_si4713_g_ext_ctrls, - .vidioc_s_ext_ctrls = radio_si4713_s_ext_ctrls, - .vidioc_g_ctrl = radio_si4713_g_ctrl, - .vidioc_s_ctrl = radio_si4713_s_ctrl, .vidioc_g_modulator = radio_si4713_g_modulator, .vidioc_s_modulator = radio_si4713_s_modulator, .vidioc_g_frequency = radio_si4713_g_frequency, @@ -274,6 +186,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev) rsdev->radio_dev = radio_si4713_vdev_template; rsdev->radio_dev.v4l2_dev = &rsdev->v4l2_dev; + rsdev->radio_dev.ctrl_handler = sd->ctrl_handler; /* Serialize all access to the si4713 */ rsdev->radio_dev.lock = &rsdev->lock; video_set_drvdata(&rsdev->radio_dev, rsdev); diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index 56c9241ee7fb..fe160882ee10 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c @@ -52,8 +52,6 @@ static const char *si4713_supply_names[SI4713_NUM_SUPPLIES] = { #define DEFAULT_RDS_PI 0x00 #define DEFAULT_RDS_PTY 0x00 -#define DEFAULT_RDS_PS_NAME "" -#define DEFAULT_RDS_RADIO_TEXT DEFAULT_RDS_PS_NAME #define DEFAULT_RDS_DEVIATION 0x00C8 #define DEFAULT_RDS_PS_REPEAT_COUNT 0x0003 #define DEFAULT_LIMITER_RTIME 0x1392 @@ -107,7 +105,6 @@ static const char *si4713_supply_names[SI4713_NUM_SUPPLIES] = { (status & SI4713_ERR)) /* mute definition */ #define set_mute(p) ((p & 1) | ((p & 1) << 1)); -#define get_mute(p) (p & 0x01) #ifdef DEBUG #define DBG_BUFFER(device, message, buffer, size) \ @@ -189,21 +186,6 @@ static int usecs_to_dev(unsigned long usecs, unsigned long const array[], return rval; } -static unsigned long dev_to_usecs(int value, unsigned long const array[], - int size) -{ - int i; - int rval = -EINVAL; - - for (i = 0; i < size / 2; i++) - if (array[i * 2] == value) { - rval = array[(i * 2) + 1]; - break; - } - - return rval; -} - /* si4713_handler: IRQ handler, just complete work */ static irqreturn_t si4713_handler(int irq, void *dev) { @@ -787,9 +769,6 @@ static int si4713_set_mute(struct si4713_device *sdev, u16 mute) rval = si4713_write_property(sdev, SI4713_TX_LINE_INPUT_MUTE, mute); - if (rval >= 0) - sdev->mute = get_mute(mute); - return rval; } @@ -830,7 +809,6 @@ static int si4713_set_rds_ps_name(struct si4713_device *sdev, char *ps_name) return rval; } - strncpy(sdev->rds_info.ps_name, ps_name, MAX_RDS_PS_NAME); return rval; } @@ -842,24 +820,23 @@ static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt) s8 left; if (!sdev->power_state) - goto copy; + return rval; rval = si4713_tx_rds_buff(sdev, RDS_BLOCK_CLEAR, 0, 0, 0, &left); if (rval < 0) return rval; if (!strlen(rt)) - goto copy; + return rval; do { /* RDS spec says that if the last block isn't used, * then apply a carriage return */ - if (t_index < (RDS_RADIOTEXT_INDEX_MAX * - RDS_RADIOTEXT_BLK_SIZE)) { + if (t_index < (RDS_RADIOTEXT_INDEX_MAX * RDS_RADIOTEXT_BLK_SIZE)) { for (i = 0; i < RDS_RADIOTEXT_BLK_SIZE; i++) { - if (!rt[t_index + i] || rt[t_index + i] == - RDS_CARRIAGE_RETURN) { + if (!rt[t_index + i] || + rt[t_index + i] == RDS_CARRIAGE_RETURN) { rt[t_index + i] = RDS_CARRIAGE_RETURN; cr_inserted = 1; break; @@ -881,13 +858,38 @@ static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt) break; } while (left > 0); -copy: - strncpy(sdev->rds_info.radio_text, rt, MAX_RDS_RADIO_TEXT); + return rval; +} + +/* + * si4713_update_tune_status - update properties from tx_tune_status + * command. Must be called with sdev->mutex held. + * @sdev: si4713_device structure for the device we are communicating + */ +static int si4713_update_tune_status(struct si4713_device *sdev) +{ + int rval; + u16 f = 0; + u8 p = 0, a = 0, n = 0; + + rval = si4713_tx_tune_status(sdev, 0x00, &f, &p, &a, &n); + + if (rval < 0) + goto exit; + +/* TODO: check that power_level and antenna_capacitor really are not + changed by the hardware. If they are, then these controls should become + volatiles. + sdev->power_level = p; + sdev->antenna_capacitor = a;*/ + sdev->tune_rnl = n; + +exit: return rval; } static int si4713_choose_econtrol_action(struct si4713_device *sdev, u32 id, - u32 **shadow, s32 *bit, s32 *mask, u16 *property, int *mul, + s32 *bit, s32 *mask, u16 *property, int *mul, unsigned long **table, int *size) { s32 rval = 0; @@ -897,277 +899,76 @@ static int si4713_choose_econtrol_action(struct si4713_device *sdev, u32 id, case V4L2_CID_RDS_TX_PI: *property = SI4713_TX_RDS_PI; *mul = 1; - *shadow = &sdev->rds_info.pi; break; case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: *property = SI4713_TX_ACOMP_THRESHOLD; *mul = 1; - *shadow = &sdev->acomp_info.threshold; break; case V4L2_CID_AUDIO_COMPRESSION_GAIN: *property = SI4713_TX_ACOMP_GAIN; *mul = 1; - *shadow = &sdev->acomp_info.gain; break; case V4L2_CID_PILOT_TONE_FREQUENCY: *property = SI4713_TX_PILOT_FREQUENCY; *mul = 1; - *shadow = &sdev->pilot_info.frequency; break; case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: *property = SI4713_TX_ACOMP_ATTACK_TIME; *mul = ATTACK_TIME_UNIT; - *shadow = &sdev->acomp_info.attack_time; break; case V4L2_CID_PILOT_TONE_DEVIATION: *property = SI4713_TX_PILOT_DEVIATION; *mul = 10; - *shadow = &sdev->pilot_info.deviation; break; case V4L2_CID_AUDIO_LIMITER_DEVIATION: *property = SI4713_TX_AUDIO_DEVIATION; *mul = 10; - *shadow = &sdev->limiter_info.deviation; break; case V4L2_CID_RDS_TX_DEVIATION: *property = SI4713_TX_RDS_DEVIATION; *mul = 1; - *shadow = &sdev->rds_info.deviation; break; case V4L2_CID_RDS_TX_PTY: *property = SI4713_TX_RDS_PS_MISC; *bit = 5; *mask = 0x1F << 5; - *shadow = &sdev->rds_info.pty; break; case V4L2_CID_AUDIO_LIMITER_ENABLED: *property = SI4713_TX_ACOMP_ENABLE; *bit = 1; *mask = 1 << 1; - *shadow = &sdev->limiter_info.enabled; break; case V4L2_CID_AUDIO_COMPRESSION_ENABLED: *property = SI4713_TX_ACOMP_ENABLE; *bit = 0; *mask = 1 << 0; - *shadow = &sdev->acomp_info.enabled; break; case V4L2_CID_PILOT_TONE_ENABLED: *property = SI4713_TX_COMPONENT_ENABLE; *bit = 0; *mask = 1 << 0; - *shadow = &sdev->pilot_info.enabled; break; case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: *property = SI4713_TX_LIMITER_RELEASE_TIME; *table = limiter_times; *size = ARRAY_SIZE(limiter_times); - *shadow = &sdev->limiter_info.release_time; break; case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: *property = SI4713_TX_ACOMP_RELEASE_TIME; *table = acomp_rtimes; *size = ARRAY_SIZE(acomp_rtimes); - *shadow = &sdev->acomp_info.release_time; break; case V4L2_CID_TUNE_PREEMPHASIS: *property = SI4713_TX_PREEMPHASIS; *table = preemphasis_values; *size = ARRAY_SIZE(preemphasis_values); - *shadow = &sdev->preemphasis; break; default: rval = -EINVAL; - } - - return rval; -} - -static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc); - -/* write string property */ -static int si4713_write_econtrol_string(struct si4713_device *sdev, - struct v4l2_ext_control *control) -{ - struct v4l2_queryctrl vqc; - int len; - s32 rval = 0; - - vqc.id = control->id; - rval = si4713_queryctrl(&sdev->sd, &vqc); - if (rval < 0) - goto exit; - - switch (control->id) { - case V4L2_CID_RDS_TX_PS_NAME: { - char ps_name[MAX_RDS_PS_NAME + 1]; - - len = control->size - 1; - if (len < 0 || len > MAX_RDS_PS_NAME) { - rval = -ERANGE; - goto exit; - } - rval = copy_from_user(ps_name, control->string, len); - if (rval) { - rval = -EFAULT; - goto exit; - } - ps_name[len] = '\0'; - - if (strlen(ps_name) % vqc.step) { - rval = -ERANGE; - goto exit; - } - - rval = si4713_set_rds_ps_name(sdev, ps_name); - } - break; - - case V4L2_CID_RDS_TX_RADIO_TEXT: { - char radio_text[MAX_RDS_RADIO_TEXT + 1]; - - len = control->size - 1; - if (len < 0 || len > MAX_RDS_RADIO_TEXT) { - rval = -ERANGE; - goto exit; - } - rval = copy_from_user(radio_text, control->string, len); - if (rval) { - rval = -EFAULT; - goto exit; - } - radio_text[len] = '\0'; - - if (strlen(radio_text) % vqc.step) { - rval = -ERANGE; - goto exit; - } - - rval = si4713_set_rds_radio_text(sdev, radio_text); - } - break; - - default: - rval = -EINVAL; - break; - } - -exit: - return rval; -} - -static int validate_range(struct v4l2_subdev *sd, - struct v4l2_ext_control *control) -{ - struct v4l2_queryctrl vqc; - int rval; - - vqc.id = control->id; - rval = si4713_queryctrl(sd, &vqc); - if (rval < 0) - goto exit; - - if (control->value < vqc.minimum || control->value > vqc.maximum) - rval = -ERANGE; - -exit: - return rval; -} - -/* properties which use tx_tune_power*/ -static int si4713_write_econtrol_tune(struct si4713_device *sdev, - struct v4l2_ext_control *control) -{ - s32 rval = 0; - u8 power, antcap; - - rval = validate_range(&sdev->sd, control); - if (rval < 0) - return rval; - - switch (control->id) { - case V4L2_CID_TUNE_POWER_LEVEL: - power = control->value; - antcap = sdev->antenna_capacitor; - break; - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - power = sdev->power_level; - antcap = control->value; break; - default: - return -EINVAL; - } - - if (sdev->power_state) - rval = si4713_tx_tune_power(sdev, power, antcap); - - if (rval == 0) { - sdev->power_level = power; - sdev->antenna_capacitor = antcap; - } - - return rval; -} - -static int si4713_write_econtrol_integers(struct si4713_device *sdev, - struct v4l2_ext_control *control) -{ - s32 rval; - u32 *shadow = NULL, val = 0; - s32 bit = 0, mask = 0; - u16 property = 0; - int mul = 0; - unsigned long *table = NULL; - int size = 0; - - rval = validate_range(&sdev->sd, control); - if (rval < 0) - return rval; - - rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit, - &mask, &property, &mul, &table, &size); - if (rval < 0) - return rval; - - val = control->value; - if (mul) { - val = control->value / mul; - } else if (table) { - rval = usecs_to_dev(control->value, table, size); - if (rval < 0) - return rval; - val = rval; - rval = 0; - } - - if (sdev->power_state) { - if (mask) { - rval = si4713_read_property(sdev, property, &val); - if (rval < 0) - return rval; - val = set_bits(val, control->value, bit, mask); - } - - rval = si4713_write_property(sdev, property, val); - if (rval < 0) - return rval; - if (mask) - val = control->value; - } - - if (mul) { - *shadow = val * mul; - } else if (table) { - rval = dev_to_usecs(val, table, size); - if (rval < 0) - return rval; - *shadow = rval; - rval = 0; - } else { - *shadow = val; } return rval; @@ -1181,110 +982,25 @@ static int si4713_s_modulator(struct v4l2_subdev *sd, const struct v4l2_modulato */ static int si4713_setup(struct si4713_device *sdev) { - struct v4l2_ext_control ctrl; struct v4l2_frequency f; struct v4l2_modulator vm; - struct si4713_device *tmp; - int rval = 0; - - tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - /* Get a local copy to avoid race */ - memcpy(tmp, sdev, sizeof(*sdev)); - - ctrl.id = V4L2_CID_RDS_TX_PI; - ctrl.value = tmp->rds_info.pi; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_COMPRESSION_THRESHOLD; - ctrl.value = tmp->acomp_info.threshold; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_COMPRESSION_GAIN; - ctrl.value = tmp->acomp_info.gain; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_PILOT_TONE_FREQUENCY; - ctrl.value = tmp->pilot_info.frequency; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME; - ctrl.value = tmp->acomp_info.attack_time; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_PILOT_TONE_DEVIATION; - ctrl.value = tmp->pilot_info.deviation; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_LIMITER_DEVIATION; - ctrl.value = tmp->limiter_info.deviation; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_RDS_TX_DEVIATION; - ctrl.value = tmp->rds_info.deviation; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_RDS_TX_PTY; - ctrl.value = tmp->rds_info.pty; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_LIMITER_ENABLED; - ctrl.value = tmp->limiter_info.enabled; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_COMPRESSION_ENABLED; - ctrl.value = tmp->acomp_info.enabled; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_PILOT_TONE_ENABLED; - ctrl.value = tmp->pilot_info.enabled; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_LIMITER_RELEASE_TIME; - ctrl.value = tmp->limiter_info.release_time; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME; - ctrl.value = tmp->acomp_info.release_time; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_TUNE_PREEMPHASIS; - ctrl.value = tmp->preemphasis; - rval |= si4713_write_econtrol_integers(sdev, &ctrl); - - ctrl.id = V4L2_CID_RDS_TX_PS_NAME; - rval |= si4713_set_rds_ps_name(sdev, tmp->rds_info.ps_name); - - ctrl.id = V4L2_CID_RDS_TX_RADIO_TEXT; - rval |= si4713_set_rds_radio_text(sdev, tmp->rds_info.radio_text); + int rval; /* Device procedure needs to set frequency first */ f.tuner = 0; - f.frequency = tmp->frequency ? tmp->frequency : DEFAULT_FREQUENCY; + f.frequency = sdev->frequency ? sdev->frequency : DEFAULT_FREQUENCY; f.frequency = si4713_to_v4l2(f.frequency); - rval |= si4713_s_frequency(&sdev->sd, &f); - - ctrl.id = V4L2_CID_TUNE_POWER_LEVEL; - ctrl.value = tmp->power_level; - rval |= si4713_write_econtrol_tune(sdev, &ctrl); - - ctrl.id = V4L2_CID_TUNE_ANTENNA_CAPACITOR; - ctrl.value = tmp->antenna_capacitor; - rval |= si4713_write_econtrol_tune(sdev, &ctrl); + rval = si4713_s_frequency(&sdev->sd, &f); vm.index = 0; - if (tmp->stereo) + if (sdev->stereo) vm.txsubchans = V4L2_TUNER_SUB_STEREO; else vm.txsubchans = V4L2_TUNER_SUB_MONO; - if (tmp->rds_info.enabled) + if (sdev->rds_enabled) vm.txsubchans |= V4L2_TUNER_SUB_RDS; si4713_s_modulator(&sdev->sd, &vm); - kfree(tmp); - return rval; } @@ -1308,406 +1024,116 @@ static int si4713_initialize(struct si4713_device *sdev) if (rval < 0) return rval; - sdev->rds_info.pi = DEFAULT_RDS_PI; - sdev->rds_info.pty = DEFAULT_RDS_PTY; - sdev->rds_info.deviation = DEFAULT_RDS_DEVIATION; - strlcpy(sdev->rds_info.ps_name, DEFAULT_RDS_PS_NAME, MAX_RDS_PS_NAME); - strlcpy(sdev->rds_info.radio_text, DEFAULT_RDS_RADIO_TEXT, - MAX_RDS_RADIO_TEXT); - sdev->rds_info.enabled = 1; - - sdev->limiter_info.release_time = DEFAULT_LIMITER_RTIME; - sdev->limiter_info.deviation = DEFAULT_LIMITER_DEV; - sdev->limiter_info.enabled = 1; - - sdev->pilot_info.deviation = DEFAULT_PILOT_DEVIATION; - sdev->pilot_info.frequency = DEFAULT_PILOT_FREQUENCY; - sdev->pilot_info.enabled = 1; - - sdev->acomp_info.release_time = DEFAULT_ACOMP_RTIME; - sdev->acomp_info.attack_time = DEFAULT_ACOMP_ATIME; - sdev->acomp_info.threshold = DEFAULT_ACOMP_THRESHOLD; - sdev->acomp_info.gain = DEFAULT_ACOMP_GAIN; - sdev->acomp_info.enabled = 1; sdev->frequency = DEFAULT_FREQUENCY; - sdev->preemphasis = DEFAULT_PREEMPHASIS; - sdev->mute = DEFAULT_MUTE; - sdev->power_level = DEFAULT_POWER_LEVEL; - sdev->antenna_capacitor = 0; sdev->stereo = 1; sdev->tune_rnl = DEFAULT_TUNE_RNL; - - return rval; -} - -/* read string property */ -static int si4713_read_econtrol_string(struct si4713_device *sdev, - struct v4l2_ext_control *control) -{ - s32 rval = 0; - - switch (control->id) { - case V4L2_CID_RDS_TX_PS_NAME: - if (strlen(sdev->rds_info.ps_name) + 1 > control->size) { - control->size = MAX_RDS_PS_NAME + 1; - rval = -ENOSPC; - goto exit; - } - rval = copy_to_user(control->string, sdev->rds_info.ps_name, - strlen(sdev->rds_info.ps_name) + 1); - if (rval) - rval = -EFAULT; - break; - - case V4L2_CID_RDS_TX_RADIO_TEXT: - if (strlen(sdev->rds_info.radio_text) + 1 > control->size) { - control->size = MAX_RDS_RADIO_TEXT + 1; - rval = -ENOSPC; - goto exit; - } - rval = copy_to_user(control->string, sdev->rds_info.radio_text, - strlen(sdev->rds_info.radio_text) + 1); - if (rval) - rval = -EFAULT; - break; - - default: - rval = -EINVAL; - break; - } - -exit: - return rval; -} - -/* - * si4713_update_tune_status - update properties from tx_tune_status - * command. - * @sdev: si4713_device structure for the device we are communicating - */ -static int si4713_update_tune_status(struct si4713_device *sdev) -{ - int rval; - u16 f = 0; - u8 p = 0, a = 0, n = 0; - - rval = si4713_tx_tune_status(sdev, 0x00, &f, &p, &a, &n); - - if (rval < 0) - goto exit; - - sdev->power_level = p; - sdev->antenna_capacitor = a; - sdev->tune_rnl = n; - -exit: - return rval; -} - -/* properties which use tx_tune_status */ -static int si4713_read_econtrol_tune(struct si4713_device *sdev, - struct v4l2_ext_control *control) -{ - s32 rval = 0; - - if (sdev->power_state) { - rval = si4713_update_tune_status(sdev); - if (rval < 0) - return rval; - } - - switch (control->id) { - case V4L2_CID_TUNE_POWER_LEVEL: - control->value = sdev->power_level; - break; - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - control->value = sdev->antenna_capacitor; - break; - default: - return -EINVAL; - } - - return rval; + return 0; } -static int si4713_read_econtrol_integers(struct si4713_device *sdev, - struct v4l2_ext_control *control) +/* si4713_s_ctrl - set the value of a control */ +static int si4713_s_ctrl(struct v4l2_ctrl *ctrl) { - s32 rval; - u32 *shadow = NULL, val = 0; + struct si4713_device *sdev = + container_of(ctrl->handler, struct si4713_device, ctrl_handler); + u32 val = 0; s32 bit = 0, mask = 0; u16 property = 0; int mul = 0; unsigned long *table = NULL; int size = 0; + bool force = false; + int c; + int ret = 0; - rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit, - &mask, &property, &mul, &table, &size); - if (rval < 0) - return rval; - - if (sdev->power_state) { - rval = si4713_read_property(sdev, property, &val); - if (rval < 0) - return rval; - - /* Keep negative values for threshold */ - if (control->id == V4L2_CID_AUDIO_COMPRESSION_THRESHOLD) - *shadow = (s16)val; - else if (mask) - *shadow = get_status_bit(val, bit, mask); - else if (mul) - *shadow = val * mul; - else - *shadow = dev_to_usecs(val, table, size); - } - - control->value = *shadow; - - return rval; -} - -/* - * Video4Linux Subdev Interface - */ -/* si4713_s_ext_ctrls - set extended controls value */ -static int si4713_s_ext_ctrls(struct v4l2_subdev *sd, - struct v4l2_ext_controls *ctrls) -{ - struct si4713_device *sdev = to_si4713_device(sd); - int i; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX) + if (ctrl->id != V4L2_CID_AUDIO_MUTE) return -EINVAL; - - for (i = 0; i < ctrls->count; i++) { - int err; - - switch ((ctrls->controls + i)->id) { - case V4L2_CID_RDS_TX_PS_NAME: - case V4L2_CID_RDS_TX_RADIO_TEXT: - err = si4713_write_econtrol_string(sdev, - ctrls->controls + i); - break; - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - case V4L2_CID_TUNE_POWER_LEVEL: - err = si4713_write_econtrol_tune(sdev, - ctrls->controls + i); - break; - default: - err = si4713_write_econtrol_integers(sdev, - ctrls->controls + i); - } - - if (err < 0) { - ctrls->error_idx = i; - return err; + if (ctrl->is_new) { + if (ctrl->val) { + ret = si4713_set_mute(sdev, ctrl->val); + if (!ret) + ret = si4713_set_power_state(sdev, POWER_DOWN); + return ret; } + ret = si4713_set_power_state(sdev, POWER_UP); + if (!ret) + ret = si4713_set_mute(sdev, ctrl->val); + if (!ret) + ret = si4713_setup(sdev); + if (ret) + return ret; + force = true; } - return 0; -} - -/* si4713_g_ext_ctrls - get extended controls value */ -static int si4713_g_ext_ctrls(struct v4l2_subdev *sd, - struct v4l2_ext_controls *ctrls) -{ - struct si4713_device *sdev = to_si4713_device(sd); - int i; + if (!sdev->power_state) + return 0; - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_FM_TX) - return -EINVAL; + for (c = 1; !ret && c < ctrl->ncontrols; c++) { + ctrl = ctrl->cluster[c]; - for (i = 0; i < ctrls->count; i++) { - int err; + if (!force && !ctrl->is_new) + continue; - switch ((ctrls->controls + i)->id) { + switch (ctrl->id) { case V4L2_CID_RDS_TX_PS_NAME: + ret = si4713_set_rds_ps_name(sdev, ctrl->string); + break; + case V4L2_CID_RDS_TX_RADIO_TEXT: - err = si4713_read_econtrol_string(sdev, - ctrls->controls + i); + ret = si4713_set_rds_radio_text(sdev, ctrl->string); break; + case V4L2_CID_TUNE_ANTENNA_CAPACITOR: + /* don't handle this control if we force setting all + * controls since in that case it will be handled by + * V4L2_CID_TUNE_POWER_LEVEL. */ + if (force) + break; + /* fall through */ case V4L2_CID_TUNE_POWER_LEVEL: - err = si4713_read_econtrol_tune(sdev, - ctrls->controls + i); + ret = si4713_tx_tune_power(sdev, + sdev->tune_pwr_level->val, sdev->tune_ant_cap->val); + if (!ret) { + /* Make sure we don't set this twice */ + sdev->tune_ant_cap->is_new = false; + sdev->tune_pwr_level->is_new = false; + } break; - default: - err = si4713_read_econtrol_integers(sdev, - ctrls->controls + i); - } - - if (err < 0) { - ctrls->error_idx = i; - return err; - } - } - - return 0; -} - -/* si4713_queryctrl - enumerate control items */ -static int si4713_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc) -{ - int rval = 0; - - switch (qc->id) { - /* User class controls */ - case V4L2_CID_AUDIO_MUTE: - rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, DEFAULT_MUTE); - break; - /* FM_TX class controls */ - case V4L2_CID_RDS_TX_PI: - rval = v4l2_ctrl_query_fill(qc, 0, 0xFFFF, 1, DEFAULT_RDS_PI); - break; - case V4L2_CID_RDS_TX_PTY: - rval = v4l2_ctrl_query_fill(qc, 0, 31, 1, DEFAULT_RDS_PTY); - break; - case V4L2_CID_RDS_TX_DEVIATION: - rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_DEVIATION, - 10, DEFAULT_RDS_DEVIATION); - break; - case V4L2_CID_RDS_TX_PS_NAME: - /* - * Report step as 8. From RDS spec, psname - * should be 8. But there are receivers which scroll strings - * sized as 8xN. - */ - rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_PS_NAME, 8, 0); - break; - case V4L2_CID_RDS_TX_RADIO_TEXT: - /* - * Report step as 32 (2A block). From RDS spec, - * radio text should be 32 for 2A block. But there are receivers - * which scroll strings sized as 32xN. Setting default to 32. - */ - rval = v4l2_ctrl_query_fill(qc, 0, MAX_RDS_RADIO_TEXT, 32, 0); - break; - case V4L2_CID_AUDIO_LIMITER_ENABLED: - rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - break; - case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: - rval = v4l2_ctrl_query_fill(qc, 250, MAX_LIMITER_RELEASE_TIME, - 50, DEFAULT_LIMITER_RTIME); - break; - case V4L2_CID_AUDIO_LIMITER_DEVIATION: - rval = v4l2_ctrl_query_fill(qc, 0, MAX_LIMITER_DEVIATION, - 10, DEFAULT_LIMITER_DEV); - break; - - case V4L2_CID_AUDIO_COMPRESSION_ENABLED: - rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - break; - case V4L2_CID_AUDIO_COMPRESSION_GAIN: - rval = v4l2_ctrl_query_fill(qc, 0, MAX_ACOMP_GAIN, 1, - DEFAULT_ACOMP_GAIN); - break; - case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: - rval = v4l2_ctrl_query_fill(qc, MIN_ACOMP_THRESHOLD, - MAX_ACOMP_THRESHOLD, 1, - DEFAULT_ACOMP_THRESHOLD); - break; - case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: - rval = v4l2_ctrl_query_fill(qc, 0, MAX_ACOMP_ATTACK_TIME, - 500, DEFAULT_ACOMP_ATIME); - break; - case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: - rval = v4l2_ctrl_query_fill(qc, 100000, MAX_ACOMP_RELEASE_TIME, - 100000, DEFAULT_ACOMP_RTIME); - break; - - case V4L2_CID_PILOT_TONE_ENABLED: - rval = v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); - break; - case V4L2_CID_PILOT_TONE_DEVIATION: - rval = v4l2_ctrl_query_fill(qc, 0, MAX_PILOT_DEVIATION, - 10, DEFAULT_PILOT_DEVIATION); - break; - case V4L2_CID_PILOT_TONE_FREQUENCY: - rval = v4l2_ctrl_query_fill(qc, 0, MAX_PILOT_FREQUENCY, - 1, DEFAULT_PILOT_FREQUENCY); - break; - - case V4L2_CID_TUNE_PREEMPHASIS: - rval = v4l2_ctrl_query_fill(qc, V4L2_PREEMPHASIS_DISABLED, - V4L2_PREEMPHASIS_75_uS, 1, - V4L2_PREEMPHASIS_50_uS); - break; - case V4L2_CID_TUNE_POWER_LEVEL: - rval = v4l2_ctrl_query_fill(qc, 0, 120, 1, DEFAULT_POWER_LEVEL); - break; - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - rval = v4l2_ctrl_query_fill(qc, 0, 191, 1, 0); - break; - default: - rval = -EINVAL; - break; - } - - return rval; -} - -/* si4713_g_ctrl - get the value of a control */ -static int si4713_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct si4713_device *sdev = to_si4713_device(sd); - int rval = 0; - - if (!sdev) - return -ENODEV; - - if (sdev->power_state) { - rval = si4713_read_property(sdev, SI4713_TX_LINE_INPUT_MUTE, - &sdev->mute); - - if (rval < 0) - return rval; - } - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = get_mute(sdev->mute); - break; - } - - return rval; -} - -/* si4713_s_ctrl - set the value of a control */ -static int si4713_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct si4713_device *sdev = to_si4713_device(sd); - int rval = 0; - - if (!sdev) - return -ENODEV; - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) { - rval = si4713_set_mute(sdev, ctrl->value); - if (rval < 0) - goto exit; - - rval = si4713_set_power_state(sdev, POWER_DOWN); - } else { - rval = si4713_set_power_state(sdev, POWER_UP); - if (rval < 0) - goto exit; + default: + ret = si4713_choose_econtrol_action(sdev, ctrl->id, &bit, + &mask, &property, &mul, &table, &size); + if (ret < 0) + break; + + val = ctrl->val; + if (mul) { + val = val / mul; + } else if (table) { + ret = usecs_to_dev(val, table, size); + if (ret < 0) + break; + val = ret; + ret = 0; + } - rval = si4713_setup(sdev); - if (rval < 0) - goto exit; + if (mask) { + ret = si4713_read_property(sdev, property, &val); + if (ret < 0) + break; + val = set_bits(val, ctrl->val, bit, mask); + } - rval = si4713_set_mute(sdev, ctrl->value); + ret = si4713_write_property(sdev, property, val); + if (ret < 0) + break; + if (mask) + val = ctrl->val; + break; } - break; } -exit: - return rval; + return ret; } /* si4713_ioctl - deal with private ioctls (only rnl for now) */ @@ -1746,15 +1172,6 @@ static long si4713_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) return rval; } -static const struct v4l2_subdev_core_ops si4713_subdev_core_ops = { - .queryctrl = si4713_queryctrl, - .g_ext_ctrls = si4713_g_ext_ctrls, - .s_ext_ctrls = si4713_s_ext_ctrls, - .g_ctrl = si4713_g_ctrl, - .s_ctrl = si4713_s_ctrl, - .ioctl = si4713_ioctl, -}; - /* si4713_g_modulator - get modulator attributes */ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm) { @@ -1784,7 +1201,6 @@ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm) return rval; sdev->stereo = get_status_bit(comp_en, 1, 1 << 1); - sdev->rds_info.enabled = get_status_bit(comp_en, 2, 1 << 2); } /* Report current audio mode: mono or stereo */ @@ -1794,7 +1210,7 @@ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm) vm->txsubchans = V4L2_TUNER_SUB_MONO; /* Report rds feature status */ - if (sdev->rds_info.enabled) + if (sdev->rds_enabled) vm->txsubchans |= V4L2_TUNER_SUB_RDS; else vm->txsubchans &= ~V4L2_TUNER_SUB_RDS; @@ -1842,7 +1258,7 @@ static int si4713_s_modulator(struct v4l2_subdev *sd, const struct v4l2_modulato } sdev->stereo = stereo; - sdev->rds_info.enabled = rds; + sdev->rds_enabled = rds; return rval; } @@ -1897,6 +1313,14 @@ static int si4713_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequenc return rval; } +static const struct v4l2_ctrl_ops si4713_ctrl_ops = { + .s_ctrl = si4713_s_ctrl, +}; + +static const struct v4l2_subdev_core_ops si4713_subdev_core_ops = { + .ioctl = si4713_ioctl, +}; + static const struct v4l2_subdev_tuner_ops si4713_subdev_tuner_ops = { .g_frequency = si4713_g_frequency, .s_frequency = si4713_s_frequency, @@ -1918,6 +1342,7 @@ static int si4713_probe(struct i2c_client *client, { struct si4713_device *sdev; struct si4713_platform_data *pdata = client->dev.platform_data; + struct v4l2_ctrl_handler *hdl; int rval, i; sdev = kzalloc(sizeof *sdev, GFP_KERNEL); @@ -1953,6 +1378,82 @@ static int si4713_probe(struct i2c_client *client, init_completion(&sdev->work); + hdl = &sdev->ctrl_handler; + v4l2_ctrl_handler_init(hdl, 20); + sdev->mute = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, DEFAULT_MUTE); + + sdev->rds_pi = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_RDS_TX_PI, 0, 0xffff, 1, DEFAULT_RDS_PI); + sdev->rds_pty = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_RDS_TX_PTY, 0, 31, 1, DEFAULT_RDS_PTY); + sdev->rds_deviation = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_RDS_TX_DEVIATION, 0, MAX_RDS_DEVIATION, + 10, DEFAULT_RDS_DEVIATION); + /* + * Report step as 8. From RDS spec, psname + * should be 8. But there are receivers which scroll strings + * sized as 8xN. + */ + sdev->rds_ps_name = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_RDS_TX_PS_NAME, 0, MAX_RDS_PS_NAME, 8, 0); + /* + * Report step as 32 (2A block). From RDS spec, + * radio text should be 32 for 2A block. But there are receivers + * which scroll strings sized as 32xN. Setting default to 32. + */ + sdev->rds_radio_text = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_RDS_TX_RADIO_TEXT, 0, MAX_RDS_RADIO_TEXT, 32, 0); + + sdev->limiter_enabled = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_AUDIO_LIMITER_ENABLED, 0, 1, 1, 1); + sdev->limiter_release_time = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_AUDIO_LIMITER_RELEASE_TIME, 250, + MAX_LIMITER_RELEASE_TIME, 10, DEFAULT_LIMITER_RTIME); + sdev->limiter_deviation = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_AUDIO_LIMITER_DEVIATION, 0, + MAX_LIMITER_DEVIATION, 10, DEFAULT_LIMITER_DEV); + + sdev->compression_enabled = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_AUDIO_COMPRESSION_ENABLED, 0, 1, 1, 1); + sdev->compression_gain = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_AUDIO_COMPRESSION_GAIN, 0, MAX_ACOMP_GAIN, 1, + DEFAULT_ACOMP_GAIN); + sdev->compression_threshold = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_AUDIO_COMPRESSION_THRESHOLD, MIN_ACOMP_THRESHOLD, + MAX_ACOMP_THRESHOLD, 1, + DEFAULT_ACOMP_THRESHOLD); + sdev->compression_attack_time = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME, 0, + MAX_ACOMP_ATTACK_TIME, 500, DEFAULT_ACOMP_ATIME); + sdev->compression_release_time = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME, 100000, + MAX_ACOMP_RELEASE_TIME, 100000, DEFAULT_ACOMP_RTIME); + + sdev->pilot_tone_enabled = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_PILOT_TONE_ENABLED, 0, 1, 1, 1); + sdev->pilot_tone_deviation = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_PILOT_TONE_DEVIATION, 0, MAX_PILOT_DEVIATION, + 10, DEFAULT_PILOT_DEVIATION); + sdev->pilot_tone_freq = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_PILOT_TONE_FREQUENCY, 0, MAX_PILOT_FREQUENCY, + 1, DEFAULT_PILOT_FREQUENCY); + + sdev->tune_preemphasis = v4l2_ctrl_new_std_menu(hdl, &si4713_ctrl_ops, + V4L2_CID_TUNE_PREEMPHASIS, + V4L2_PREEMPHASIS_75_uS, 0, V4L2_PREEMPHASIS_50_uS); + sdev->tune_pwr_level = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_TUNE_POWER_LEVEL, 0, 120, 1, DEFAULT_POWER_LEVEL); + sdev->tune_ant_cap = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops, + V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0, 191, 1, 0); + + if (hdl->error) { + rval = hdl->error; + goto free_ctrls; + } + v4l2_ctrl_cluster(20, &sdev->mute); + sdev->sd.ctrl_handler = hdl; + if (client->irq) { rval = request_irq(client->irq, si4713_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED, @@ -1977,6 +1478,8 @@ static int si4713_probe(struct i2c_client *client, free_irq: if (client->irq) free_irq(client->irq, sdev); +free_ctrls: + v4l2_ctrl_handler_free(hdl); put_reg: regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies); free_gpio: @@ -2001,6 +1504,7 @@ static int si4713_remove(struct i2c_client *client) free_irq(client->irq, sdev); v4l2_device_unregister_subdev(sd); + v4l2_ctrl_handler_free(sd->ctrl_handler); regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies); if (gpio_is_valid(sdev->gpio_reset)) gpio_free(sdev->gpio_reset); diff --git a/drivers/media/radio/si4713-i2c.h b/drivers/media/radio/si4713-i2c.h index 979828da9d27..25cdea26343b 100644 --- a/drivers/media/radio/si4713-i2c.h +++ b/drivers/media/radio/si4713-i2c.h @@ -16,6 +16,7 @@ #define SI4713_I2C_H #include +#include #include #define SI4713_PRODUCT_NUMBER 0x0D @@ -160,56 +161,33 @@ #define POWER_UP 0x01 #define POWER_DOWN 0x00 -struct rds_info { - u32 pi; #define MAX_RDS_PTY 31 - u32 pty; #define MAX_RDS_DEVIATION 90000 - u32 deviation; + /* * PSNAME is known to be defined as 8 character sized (RDS Spec). * However, there is receivers which scroll PSNAME 8xN sized. */ #define MAX_RDS_PS_NAME 96 - u8 ps_name[MAX_RDS_PS_NAME + 1]; + /* * MAX_RDS_RADIO_TEXT is known to be defined as 32 (2A group) or 64 (2B group) * character sized (RDS Spec). * However, there is receivers which scroll them as well. */ #define MAX_RDS_RADIO_TEXT 384 - u8 radio_text[MAX_RDS_RADIO_TEXT + 1]; - u32 enabled; -}; -struct limiter_info { #define MAX_LIMITER_RELEASE_TIME 102390 - u32 release_time; #define MAX_LIMITER_DEVIATION 90000 - u32 deviation; - u32 enabled; -}; -struct pilot_info { #define MAX_PILOT_DEVIATION 90000 - u32 deviation; #define MAX_PILOT_FREQUENCY 19000 - u32 frequency; - u32 enabled; -}; -struct acomp_info { #define MAX_ACOMP_RELEASE_TIME 1000000 - u32 release_time; #define MAX_ACOMP_ATTACK_TIME 5000 - u32 attack_time; #define MAX_ACOMP_THRESHOLD 0 #define MIN_ACOMP_THRESHOLD (-40) - s32 threshold; #define MAX_ACOMP_GAIN 20 - u32 gain; - u32 enabled; -}; #define SI4713_NUM_SUPPLIES 2 @@ -219,20 +197,41 @@ struct acomp_info { struct si4713_device { /* v4l2_subdev and i2c reference (v4l2_subdev priv data) */ struct v4l2_subdev sd; + struct v4l2_ctrl_handler ctrl_handler; /* private data structures */ + struct { /* si4713 control cluster */ + /* This is one big cluster since the mute control + * powers off the device and after unmuting again all + * controls need to be set at once. The only way of doing + * that is by making it one big cluster. */ + struct v4l2_ctrl *mute; + struct v4l2_ctrl *rds_ps_name; + struct v4l2_ctrl *rds_radio_text; + struct v4l2_ctrl *rds_pi; + struct v4l2_ctrl *rds_deviation; + struct v4l2_ctrl *rds_pty; + struct v4l2_ctrl *compression_enabled; + struct v4l2_ctrl *compression_threshold; + struct v4l2_ctrl *compression_gain; + struct v4l2_ctrl *compression_attack_time; + struct v4l2_ctrl *compression_release_time; + struct v4l2_ctrl *pilot_tone_enabled; + struct v4l2_ctrl *pilot_tone_freq; + struct v4l2_ctrl *pilot_tone_deviation; + struct v4l2_ctrl *limiter_enabled; + struct v4l2_ctrl *limiter_deviation; + struct v4l2_ctrl *limiter_release_time; + struct v4l2_ctrl *tune_preemphasis; + struct v4l2_ctrl *tune_pwr_level; + struct v4l2_ctrl *tune_ant_cap; + }; struct completion work; - struct rds_info rds_info; - struct limiter_info limiter_info; - struct pilot_info pilot_info; - struct acomp_info acomp_info; struct regulator_bulk_data supplies[SI4713_NUM_SUPPLIES]; int gpio_reset; + u32 power_state; + u32 rds_enabled; u32 frequency; u32 preemphasis; - u32 mute; - u32 power_level; - u32 power_state; - u32 antenna_capacitor; u32 stereo; u32 tune_rnl; }; -- cgit v1.2.3 From cd29ed853f90b39318643301d5389e80a7d466bc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 8 Apr 2013 07:23:32 -0300 Subject: [media] radio-si4713: add prio checking and control events Signed-off-by: Hans Verkuil Acked-by: Eduardo Valentin Tested-by: Eduardo Valentin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-si4713.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index f8c6137573a8..ba4cfc946868 100644 --- a/drivers/media/radio/radio-si4713.c +++ b/drivers/media/radio/radio-si4713.c @@ -31,6 +31,9 @@ #include #include #include +#include +#include +#include #include /* module parameters */ @@ -55,6 +58,9 @@ struct radio_si4713_device { /* radio_si4713_fops - file operations interface */ static const struct v4l2_file_operations radio_si4713_fops = { .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = v4l2_fh_release, + .poll = v4l2_ctrl_poll, /* Note: locking is done at the subdev level in the i2c driver. */ .unlocked_ioctl = video_ioctl2, }; @@ -126,6 +132,9 @@ static struct v4l2_ioctl_ops radio_si4713_ioctl_ops = { .vidioc_s_modulator = radio_si4713_s_modulator, .vidioc_g_frequency = radio_si4713_g_frequency, .vidioc_s_frequency = radio_si4713_s_frequency, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_default = radio_si4713_default, }; @@ -187,6 +196,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev) rsdev->radio_dev = radio_si4713_vdev_template; rsdev->radio_dev.v4l2_dev = &rsdev->v4l2_dev; rsdev->radio_dev.ctrl_handler = sd->ctrl_handler; + set_bit(V4L2_FL_USE_FH_PRIO, &rsdev->radio_dev.flags); /* Serialize all access to the si4713 */ rsdev->radio_dev.lock = &rsdev->lock; video_set_drvdata(&rsdev->radio_dev, rsdev); -- cgit v1.2.3 From 99c77aa4281c41fab255a4eb25ccc36a8c2e113d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 19 Mar 2013 09:30:50 -0300 Subject: [media] hdpvr: convert to the control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-video.c | 515 +++++++++------------------------- drivers/media/usb/hdpvr/hdpvr.h | 8 + 2 files changed, 145 insertions(+), 378 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 2983bf0d5f0f..a89012720e5a 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -710,335 +710,69 @@ static int vidioc_g_audio(struct file *file, void *private_data, return 0; } -static const s32 supported_v4l2_ctrls[] = { - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_SHARPNESS, - V4L2_CID_MPEG_AUDIO_ENCODING, - V4L2_CID_MPEG_VIDEO_ENCODING, - V4L2_CID_MPEG_VIDEO_BITRATE_MODE, - V4L2_CID_MPEG_VIDEO_BITRATE, - V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, -}; - -static int fill_queryctrl(struct hdpvr_options *opt, struct v4l2_queryctrl *qc, - int ac3, int fw_ver) -{ - int err; - - if (fw_ver > 0x15) { - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80); - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x40); - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x40); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, 0x0, 0x1e, 1, 0xf); - case V4L2_CID_SHARPNESS: - return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80); - } - } else { - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x86); - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80); - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80); - case V4L2_CID_SHARPNESS: - return v4l2_ctrl_query_fill(qc, 0x0, 0xff, 1, 0x80); - } - } - - switch (qc->id) { - case V4L2_CID_MPEG_AUDIO_ENCODING: - return v4l2_ctrl_query_fill( - qc, V4L2_MPEG_AUDIO_ENCODING_AAC, - ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 - : V4L2_MPEG_AUDIO_ENCODING_AAC, - 1, V4L2_MPEG_AUDIO_ENCODING_AAC); - case V4L2_CID_MPEG_VIDEO_ENCODING: - return v4l2_ctrl_query_fill( - qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC); - -/* case V4L2_CID_MPEG_VIDEO_? maybe keyframe interval: */ -/* return v4l2_ctrl_query_fill(qc, 0, 128, 128, 0); */ - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - return v4l2_ctrl_query_fill( - qc, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1, - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); - - case V4L2_CID_MPEG_VIDEO_BITRATE: - return v4l2_ctrl_query_fill(qc, 1000000, 13500000, 100000, - 6500000); - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - err = v4l2_ctrl_query_fill(qc, 1100000, 20200000, 100000, - 9000000); - if (!err && opt->bitrate_mode == HDPVR_CONSTANT) - qc->flags |= V4L2_CTRL_FLAG_INACTIVE; - return err; - default: - return -EINVAL; - } -} - -static int vidioc_queryctrl(struct file *file, void *private_data, - struct v4l2_queryctrl *qc) +static int hdpvr_try_ctrl(struct v4l2_ctrl *ctrl) { - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - int i, next; - u32 id = qc->id; - - memset(qc, 0, sizeof(*qc)); - - next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL); - qc->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL; - - for (i = 0; i < ARRAY_SIZE(supported_v4l2_ctrls); i++) { - if (next) { - if (qc->id < supported_v4l2_ctrls[i]) - qc->id = supported_v4l2_ctrls[i]; - else - continue; - } - - if (qc->id == supported_v4l2_ctrls[i]) - return fill_queryctrl(&dev->options, qc, - dev->flags & HDPVR_FLAG_AC3_CAP, - dev->fw_ver); - - if (qc->id < supported_v4l2_ctrls[i]) - break; - } - - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *private_data, - struct v4l2_control *ctrl) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; + struct hdpvr_device *dev = + container_of(ctrl->handler, struct hdpvr_device, hdl); switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = dev->options.brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = dev->options.contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = dev->options.saturation; - break; - case V4L2_CID_HUE: - ctrl->value = dev->options.hue; - break; - case V4L2_CID_SHARPNESS: - ctrl->value = dev->options.sharpness; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && + dev->video_bitrate->val >= dev->video_bitrate_peak->val) + dev->video_bitrate_peak->val = + dev->video_bitrate->val + 100000; break; - default: - return -EINVAL; } return 0; } -static int vidioc_s_ctrl(struct file *file, void *private_data, - struct v4l2_control *ctrl) +static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl) { - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - int retval; + struct hdpvr_device *dev = + container_of(ctrl->handler, struct hdpvr_device, hdl); + struct hdpvr_options *opt = &dev->options; + int ret = -EINVAL; switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - retval = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->value); - if (!retval) - dev->options.brightness = ctrl->value; - break; + ret = hdpvr_config_call(dev, CTRL_BRIGHTNESS, ctrl->val); + if (ret) + break; + dev->options.brightness = ctrl->val; + return 0; case V4L2_CID_CONTRAST: - retval = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->value); - if (!retval) - dev->options.contrast = ctrl->value; - break; + ret = hdpvr_config_call(dev, CTRL_CONTRAST, ctrl->val); + if (ret) + break; + dev->options.contrast = ctrl->val; + return 0; case V4L2_CID_SATURATION: - retval = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->value); - if (!retval) - dev->options.saturation = ctrl->value; - break; + ret = hdpvr_config_call(dev, CTRL_SATURATION, ctrl->val); + if (ret) + break; + dev->options.saturation = ctrl->val; + return 0; case V4L2_CID_HUE: - retval = hdpvr_config_call(dev, CTRL_HUE, ctrl->value); - if (!retval) - dev->options.hue = ctrl->value; - break; + ret = hdpvr_config_call(dev, CTRL_HUE, ctrl->val); + if (ret) + break; + dev->options.hue = ctrl->val; + return 0; case V4L2_CID_SHARPNESS: - retval = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->value); - if (!retval) - dev->options.sharpness = ctrl->value; - break; - default: - return -EINVAL; - } - - return retval; -} - - -static int hdpvr_get_ctrl(struct hdpvr_options *opt, - struct v4l2_ext_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_MPEG_AUDIO_ENCODING: - ctrl->value = opt->audio_codec; - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC; - break; -/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */ -/* ctrl->value = (opt->gop_mode & 0x2) ? 0 : 128; */ -/* break; */ - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - ctrl->value = opt->bitrate_mode == HDPVR_CONSTANT - ? V4L2_MPEG_VIDEO_BITRATE_MODE_CBR - : V4L2_MPEG_VIDEO_BITRATE_MODE_VBR; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - ctrl->value = opt->bitrate * 100000; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - ctrl->value = opt->peak_bitrate * 100000; - break; - case V4L2_CID_MPEG_STREAM_TYPE: - ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_TS; - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_g_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - int i, err = 0; - - if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - err = hdpvr_get_ctrl(&dev->options, ctrl); - if (err) { - ctrls->error_idx = i; - break; - } - } - return err; - - } - - return -EINVAL; -} - - -static int hdpvr_try_ctrl(struct v4l2_ext_control *ctrl, int ac3) -{ - int ret = -EINVAL; - - switch (ctrl->id) { - case V4L2_CID_MPEG_AUDIO_ENCODING: - if (ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AAC || - (ac3 && ctrl->value == V4L2_MPEG_AUDIO_ENCODING_AC3)) - ret = 0; - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - if (ctrl->value == V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC) - ret = 0; - break; -/* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */ -/* if (ctrl->value == 0 || ctrl->value == 128) */ -/* ret = 0; */ -/* break; */ - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR || - ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) - ret = 0; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - { - uint bitrate = ctrl->value / 100000; - if (bitrate >= 10 && bitrate <= 135) - ret = 0; - break; - } - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: - { - uint peak_bitrate = ctrl->value / 100000; - if (peak_bitrate >= 10 && peak_bitrate <= 202) - ret = 0; - break; - } - case V4L2_CID_MPEG_STREAM_TYPE: - if (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS) - ret = 0; - break; - default: - return -EINVAL; - } - return ret; -} - -static int vidioc_try_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - int i, err = 0; - - if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - err = hdpvr_try_ctrl(ctrl, - dev->flags & HDPVR_FLAG_AC3_CAP); - if (err) { - ctrls->error_idx = i; - break; - } - } - return err; - } - - return -EINVAL; -} - - -static int hdpvr_set_ctrl(struct hdpvr_device *dev, - struct v4l2_ext_control *ctrl) -{ - struct hdpvr_options *opt = &dev->options; - int ret = 0; - - switch (ctrl->id) { + ret = hdpvr_config_call(dev, CTRL_SHARPNESS, ctrl->val); + if (ret) + break; + dev->options.sharpness = ctrl->val; + return 0; case V4L2_CID_MPEG_AUDIO_ENCODING: if (dev->flags & HDPVR_FLAG_AC3_CAP) { - opt->audio_codec = ctrl->value; - ret = hdpvr_set_audio(dev, opt->audio_input, + opt->audio_codec = ctrl->val; + return hdpvr_set_audio(dev, opt->audio_input, opt->audio_codec); } - break; + return 0; case V4L2_CID_MPEG_VIDEO_ENCODING: - break; + return 0; /* case V4L2_CID_MPEG_VIDEO_B_FRAMES: */ /* if (ctrl->value == 0 && !(opt->gop_mode & 0x2)) { */ /* opt->gop_mode |= 0x2; */ @@ -1051,81 +785,37 @@ static int hdpvr_set_ctrl(struct hdpvr_device *dev, /* opt->gop_mode); */ /* } */ /* break; */ - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: - if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR && - opt->bitrate_mode != HDPVR_CONSTANT) { - opt->bitrate_mode = HDPVR_CONSTANT; - hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE, - opt->bitrate_mode); - } - if (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && - opt->bitrate_mode == HDPVR_CONSTANT) { - opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: { + uint peak_bitrate = dev->video_bitrate_peak->val / 100000; + uint bitrate = dev->video_bitrate->val / 100000; + + if (ctrl->is_new) { + if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + opt->bitrate_mode = HDPVR_CONSTANT; + else + opt->bitrate_mode = HDPVR_VARIABLE_AVERAGE; hdpvr_config_call(dev, CTRL_BITRATE_MODE_VALUE, opt->bitrate_mode); + v4l2_ctrl_activate(dev->video_bitrate_peak, + ctrl->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); } - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: { - uint bitrate = ctrl->value / 100000; - - opt->bitrate = bitrate; - if (bitrate >= opt->peak_bitrate) - opt->peak_bitrate = bitrate+1; - - hdpvr_set_bitrate(dev); - break; - } - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: { - uint peak_bitrate = ctrl->value / 100000; - if (opt->bitrate_mode == HDPVR_CONSTANT) - break; - - if (opt->bitrate < peak_bitrate) { + if (dev->video_bitrate_peak->is_new || + dev->video_bitrate->is_new) { + opt->bitrate = bitrate; opt->peak_bitrate = peak_bitrate; hdpvr_set_bitrate(dev); - } else - ret = -EINVAL; - break; + } + return 0; } case V4L2_CID_MPEG_STREAM_TYPE: - break; + return 0; default: - return -EINVAL; + break; } return ret; } -static int vidioc_s_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; - int i, err = 0; - - if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) { - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = ctrls->controls + i; - - err = hdpvr_try_ctrl(ctrl, - dev->flags & HDPVR_FLAG_AC3_CAP); - if (err) { - ctrls->error_idx = i; - break; - } - err = hdpvr_set_ctrl(dev, ctrl); - if (err) { - ctrls->error_idx = i; - break; - } - } - return err; - - } - - return -EINVAL; -} - static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, struct v4l2_fmtdesc *f) { @@ -1215,12 +905,6 @@ static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = { .vidioc_enumaudio = vidioc_enumaudio, .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, - .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, - .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_encoder_cmd = vidioc_encoder_cmd, @@ -1237,6 +921,7 @@ static void hdpvr_device_release(struct video_device *vdev) mutex_unlock(&dev->io_mutex); v4l2_device_unregister(&dev->v4l2_dev); + v4l2_ctrl_handler_free(&dev->hdl); /* deregister I2C adapter */ #if IS_ENABLED(CONFIG_I2C) @@ -1264,13 +949,85 @@ static const struct video_device hdpvr_video_template = { V4L2_STD_PAL_60, }; +static const struct v4l2_ctrl_ops hdpvr_ctrl_ops = { + .try_ctrl = hdpvr_try_ctrl, + .s_ctrl = hdpvr_s_ctrl, +}; + int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, int devnum) { + struct v4l2_ctrl_handler *hdl = &dev->hdl; + bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP; + int res; + + v4l2_ctrl_handler_init(hdl, 11); + if (dev->fw_ver > 0x15) { + v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x80); + v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, + V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x40); + v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, + V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x40); + v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, + V4L2_CID_HUE, 0x0, 0x1e, 1, 0xf); + v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, + V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80); + } else { + v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0x0, 0xff, 1, 0x86); + v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, + V4L2_CID_CONTRAST, 0x0, 0xff, 1, 0x80); + v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, + V4L2_CID_SATURATION, 0x0, 0xff, 1, 0x80); + v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, + V4L2_CID_HUE, 0x0, 0xff, 1, 0x80); + v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, + V4L2_CID_SHARPNESS, 0x0, 0xff, 1, 0x80); + } + + v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, + V4L2_CID_MPEG_STREAM_TYPE, + V4L2_MPEG_STREAM_TYPE_MPEG2_TS, + 0x1, V4L2_MPEG_STREAM_TYPE_MPEG2_TS); + v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, + V4L2_CID_MPEG_AUDIO_ENCODING, + ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : V4L2_MPEG_AUDIO_ENCODING_AAC, + 0x7, V4L2_MPEG_AUDIO_ENCODING_AAC); + v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, + V4L2_CID_MPEG_VIDEO_ENCODING, + V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 0x3, + V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC); + + dev->video_mode = v4l2_ctrl_new_std_menu(hdl, &hdpvr_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR); + + dev->video_bitrate = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE, + 1000000, 13500000, 100000, 6500000); + dev->video_bitrate_peak = v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + 1100000, 20200000, 100000, 9000000); + dev->v4l2_dev.ctrl_handler = hdl; + if (hdl->error) { + res = hdl->error; + v4l2_err(&dev->v4l2_dev, "Could not register controls\n"); + goto error; + } + v4l2_ctrl_cluster(3, &dev->video_mode); + res = v4l2_ctrl_handler_setup(hdl); + if (res < 0) { + v4l2_err(&dev->v4l2_dev, "Could not setup controls\n"); + goto error; + } + /* setup and register video device */ dev->video_dev = video_device_alloc(); if (!dev->video_dev) { v4l2_err(&dev->v4l2_dev, "video_device_alloc() failed\n"); + res = -ENOMEM; goto error; } @@ -1279,12 +1036,14 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, dev->video_dev->parent = parent; video_set_drvdata(dev->video_dev, dev); - if (video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum)) { + res = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum); + if (res < 0) { v4l2_err(&dev->v4l2_dev, "video_device registration failed\n"); goto error; } return 0; error: - return -ENOMEM; + v4l2_ctrl_handler_free(hdl); + return res; } diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h index fea3c6926997..2a4deab70762 100644 --- a/drivers/media/usb/hdpvr/hdpvr.h +++ b/drivers/media/usb/hdpvr/hdpvr.h @@ -16,6 +16,7 @@ #include #include +#include #include #define HDPVR_MAX 8 @@ -65,10 +66,17 @@ struct hdpvr_options { struct hdpvr_device { /* the v4l device for this device */ struct video_device *video_dev; + /* the control handler for this device */ + struct v4l2_ctrl_handler hdl; /* the usb device for this device */ struct usb_device *udev; /* v4l2-device unused */ struct v4l2_device v4l2_dev; + struct { /* video mode/bitrate control cluster */ + struct v4l2_ctrl *video_mode; + struct v4l2_ctrl *video_bitrate; + struct v4l2_ctrl *video_bitrate_peak; + }; /* the max packet size of the bulk endpoint */ size_t bulk_in_size; -- cgit v1.2.3 From ede197aac0c64021a0b2139d19edd8fa066530c2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 6 Apr 2013 06:00:17 -0300 Subject: [media] hdpvr: remove hdpvr_fh and just use v4l2_fh This prepares the driver for priority and control event handling. This patch also checks for correct streaming ownership and it makes a small improvement to the encoder_cmd ioctls: always zero 'flags' and drop the memset of 'raw' as that is already done by the v4l2 core. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-video.c | 115 +++++++++++++--------------------- drivers/media/usb/hdpvr/hdpvr.h | 4 +- 2 files changed, 46 insertions(+), 73 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index a89012720e5a..4bbcf480d5e7 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -35,10 +35,6 @@ list_size(&dev->free_buff_list), \ list_size(&dev->rec_buff_list)); } -struct hdpvr_fh { - struct hdpvr_device *dev; -}; - static uint list_size(struct list_head *list) { struct list_head *tmp; @@ -358,55 +354,21 @@ static int hdpvr_stop_streaming(struct hdpvr_device *dev) * video 4 linux 2 file operations */ -static int hdpvr_open(struct file *file) -{ - struct hdpvr_device *dev; - struct hdpvr_fh *fh; - int retval = -ENOMEM; - - dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file)); - if (!dev) { - pr_err("open failing with with ENODEV\n"); - retval = -ENODEV; - goto err; - } - - fh = kzalloc(sizeof(struct hdpvr_fh), GFP_KERNEL); - if (!fh) { - v4l2_err(&dev->v4l2_dev, "Out of memory\n"); - goto err; - } - /* lock the device to allow correctly handling errors - * in resumption */ - mutex_lock(&dev->io_mutex); - dev->open_count++; - mutex_unlock(&dev->io_mutex); - - fh->dev = dev; - - /* save our object in the file's private structure */ - file->private_data = fh; - - retval = 0; -err: - return retval; -} - static int hdpvr_release(struct file *file) { - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; + struct hdpvr_device *dev = video_drvdata(file); if (!dev) return -ENODEV; mutex_lock(&dev->io_mutex); - if (!(--dev->open_count) && dev->status == STATUS_STREAMING) + if (file->private_data == dev->owner) { hdpvr_stop_streaming(dev); - + dev->owner = NULL; + } mutex_unlock(&dev->io_mutex); - return 0; + return v4l2_fh_release(file); } /* @@ -416,8 +378,7 @@ static int hdpvr_release(struct file *file) static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, loff_t *pos) { - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; + struct hdpvr_device *dev = video_drvdata(file); struct hdpvr_buffer *buf = NULL; struct urb *urb; unsigned int ret = 0; @@ -440,6 +401,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, mutex_unlock(&dev->io_mutex); goto err; } + dev->owner = file->private_data; print_buffer_status(); } mutex_unlock(&dev->io_mutex); @@ -518,8 +480,7 @@ err: static unsigned int hdpvr_poll(struct file *filp, poll_table *wait) { struct hdpvr_buffer *buf = NULL; - struct hdpvr_fh *fh = filp->private_data; - struct hdpvr_device *dev = fh->dev; + struct hdpvr_device *dev = video_drvdata(filp); unsigned int mask = 0; mutex_lock(&dev->io_mutex); @@ -534,6 +495,8 @@ static unsigned int hdpvr_poll(struct file *filp, poll_table *wait) v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, "start_streaming failed\n"); dev->status = STATUS_IDLE; + } else { + dev->owner = filp->private_data; } print_buffer_status(); @@ -555,7 +518,7 @@ static unsigned int hdpvr_poll(struct file *filp, poll_table *wait) static const struct v4l2_file_operations hdpvr_fops = { .owner = THIS_MODULE, - .open = hdpvr_open, + .open = v4l2_fh_open, .release = hdpvr_release, .read = hdpvr_read, .poll = hdpvr_poll, @@ -584,8 +547,7 @@ static int vidioc_querycap(struct file *file, void *priv, static int vidioc_s_std(struct file *file, void *private_data, v4l2_std_id std) { - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; + struct hdpvr_device *dev = video_drvdata(file); u8 std_type = 1; if (std & (V4L2_STD_NTSC | V4L2_STD_PAL_60)) @@ -603,8 +565,7 @@ static const char *iname[] = { static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; + struct hdpvr_device *dev = video_drvdata(file); unsigned int n; n = i->index; @@ -626,8 +587,7 @@ static int vidioc_enum_input(struct file *file, void *priv, static int vidioc_s_input(struct file *file, void *private_data, unsigned int index) { - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; + struct hdpvr_device *dev = video_drvdata(file); int retval; if (index >= HDPVR_VIDEO_INPUTS) @@ -646,8 +606,7 @@ static int vidioc_s_input(struct file *file, void *private_data, static int vidioc_g_input(struct file *file, void *private_data, unsigned int *index) { - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; + struct hdpvr_device *dev = video_drvdata(file); *index = dev->options.video_input; return 0; @@ -680,8 +639,7 @@ static int vidioc_enumaudio(struct file *file, void *priv, static int vidioc_s_audio(struct file *file, void *private_data, const struct v4l2_audio *audio) { - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; + struct hdpvr_device *dev = video_drvdata(file); int retval; if (audio->index >= HDPVR_AUDIO_INPUTS) @@ -700,8 +658,7 @@ static int vidioc_s_audio(struct file *file, void *private_data, static int vidioc_g_audio(struct file *file, void *private_data, struct v4l2_audio *audio) { - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; + struct hdpvr_device *dev = video_drvdata(file); audio->index = dev->options.audio_input; audio->capability = V4L2_AUDCAP_STEREO; @@ -833,8 +790,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data, struct v4l2_format *f) { - struct hdpvr_fh *fh = file->private_data; - struct hdpvr_device *dev = fh->dev; + struct hdpvr_device *dev = video_drvdata(file); struct hdpvr_video_info *vid_info; if (!dev) @@ -860,26 +816,44 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data, static int vidioc_encoder_cmd(struct file *filp, void *priv, struct v4l2_encoder_cmd *a) { - struct hdpvr_fh *fh = filp->private_data; - struct hdpvr_device *dev = fh->dev; - int res; + struct hdpvr_device *dev = video_drvdata(filp); + int res = 0; mutex_lock(&dev->io_mutex); + a->flags = 0; - memset(&a->raw, 0, sizeof(a->raw)); switch (a->cmd) { case V4L2_ENC_CMD_START: - a->flags = 0; + if (dev->owner && filp->private_data != dev->owner) { + res = -EBUSY; + break; + } + if (dev->status == STATUS_STREAMING) + break; res = hdpvr_start_streaming(dev); + if (!res) + dev->owner = filp->private_data; + else + dev->status = STATUS_IDLE; break; case V4L2_ENC_CMD_STOP: + if (dev->owner && filp->private_data != dev->owner) { + res = -EBUSY; + break; + } + if (dev->status == STATUS_IDLE) + break; res = hdpvr_stop_streaming(dev); + if (!res) + dev->owner = NULL; break; default: v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, "Unsupported encoder cmd %d\n", a->cmd); res = -EINVAL; + break; } + mutex_unlock(&dev->io_mutex); return res; } @@ -887,6 +861,7 @@ static int vidioc_encoder_cmd(struct file *filp, void *priv, static int vidioc_try_encoder_cmd(struct file *filp, void *priv, struct v4l2_encoder_cmd *a) { + a->flags = 0; switch (a->cmd) { case V4L2_ENC_CMD_START: case V4L2_ENC_CMD_STOP: @@ -935,8 +910,6 @@ static void hdpvr_device_release(struct video_device *vdev) } static const struct video_device hdpvr_video_template = { -/* .type = VFL_TYPE_GRABBER, */ -/* .type2 = VID_TYPE_CAPTURE | VID_TYPE_MPEG_ENCODER, */ .fops = &hdpvr_fops, .release = hdpvr_device_release, .ioctl_ops = &hdpvr_ioctl_ops, @@ -1031,9 +1004,9 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, goto error; } - *(dev->video_dev) = hdpvr_video_template; + *dev->video_dev = hdpvr_video_template; strcpy(dev->video_dev->name, "Hauppauge HD PVR"); - dev->video_dev->parent = parent; + dev->video_dev->v4l2_dev = &dev->v4l2_dev; video_set_drvdata(dev->video_dev, dev); res = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum); diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h index 2a4deab70762..945009356127 100644 --- a/drivers/media/usb/hdpvr/hdpvr.h +++ b/drivers/media/usb/hdpvr/hdpvr.h @@ -85,8 +85,6 @@ struct hdpvr_device { /* holds the current device status */ __u8 status; - /* count the number of openers */ - uint open_count; /* holds the cureent set options */ struct hdpvr_options options; @@ -107,6 +105,8 @@ struct hdpvr_device { struct workqueue_struct *workqueue; /**/ struct work_struct worker; + /* current stream owner */ + struct v4l2_fh *owner; /* I2C adapter */ struct i2c_adapter i2c_adapter; -- cgit v1.2.3 From 65fe42d6054bb84c4abc4168310bd5d7c462456e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 12 Feb 2013 08:26:59 -0300 Subject: [media] hdpvr: add prio and control event support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-video.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 4bbcf480d5e7..e30ece215c87 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "hdpvr.h" #define BULK_URB_TIMEOUT 90 /* 0.09 seconds */ @@ -479,16 +480,15 @@ err: static unsigned int hdpvr_poll(struct file *filp, poll_table *wait) { + unsigned long req_events = poll_requested_events(wait); struct hdpvr_buffer *buf = NULL; struct hdpvr_device *dev = video_drvdata(filp); - unsigned int mask = 0; + unsigned int mask = v4l2_ctrl_poll(filp, wait); - mutex_lock(&dev->io_mutex); + if (!(req_events & (POLLIN | POLLRDNORM))) + return mask; - if (!video_is_registered(dev->video_dev)) { - mutex_unlock(&dev->io_mutex); - return -EIO; - } + mutex_lock(&dev->io_mutex); if (dev->status == STATUS_IDLE) { if (hdpvr_start_streaming(dev)) { @@ -880,10 +880,13 @@ static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = { .vidioc_enumaudio = vidioc_enumaudio, .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap= vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_encoder_cmd = vidioc_encoder_cmd, .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static void hdpvr_device_release(struct video_device *vdev) @@ -1008,6 +1011,7 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, strcpy(dev->video_dev->name, "Hauppauge HD PVR"); dev->video_dev->v4l2_dev = &dev->v4l2_dev; video_set_drvdata(dev->video_dev, dev); + set_bit(V4L2_FL_USE_FH_PRIO, &dev->video_dev->flags); res = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum); if (res < 0) { -- cgit v1.2.3 From 41022fcb3db75c9777bbd05da114c7eb597694df Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 12 Feb 2013 09:21:36 -0300 Subject: [media] hdpvr: support device_caps in querycap Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-video.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index e30ece215c87..406eda85f610 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -538,9 +538,9 @@ static int vidioc_querycap(struct file *file, void *priv, strcpy(cap->driver, "hdpvr"); strcpy(cap->card, "Hauppauge HD PVR"); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } -- cgit v1.2.3 From 97caa318b3ced2241cf1eda772a72c9c2ea19abb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 12 Feb 2013 09:26:30 -0300 Subject: [media] hdpvr: small fixes - return EBUSY instead of EAGAIN. - add missing break. - remove unnecessary buf type check (done by the core). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-video.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 406eda85f610..e14bf494f107 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -594,7 +594,7 @@ static int vidioc_s_input(struct file *file, void *private_data, return -EINVAL; if (dev->status != STATUS_IDLE) - return -EAGAIN; + return -EBUSY; retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1); if (!retval) @@ -646,7 +646,7 @@ static int vidioc_s_audio(struct file *file, void *private_data, return -EINVAL; if (dev->status != STATUS_IDLE) - return -EAGAIN; + return -EBUSY; retval = hdpvr_set_audio(dev, audio->index+1, dev->options.audio_codec); if (!retval) @@ -777,7 +777,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, struct v4l2_fmtdesc *f) { - if (f->index != 0 || f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (f->index != 0) return -EINVAL; f->flags = V4L2_FMT_FLAG_COMPRESSED; -- cgit v1.2.3 From 280847b532433ffe7a22795f926327805a127162 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 19 Mar 2013 09:34:58 -0300 Subject: [media] hdpvr: register the video node at the end of probe Video nodes can be used at once after registration, so make sure the full initialization is done before registering them. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-core.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index 73195fe7871c..248835b92d73 100644 --- a/drivers/media/usb/hdpvr/hdpvr-core.c +++ b/drivers/media/usb/hdpvr/hdpvr-core.c @@ -386,12 +386,6 @@ static int hdpvr_probe(struct usb_interface *interface, } mutex_unlock(&dev->io_mutex); - if (hdpvr_register_videodev(dev, &interface->dev, - video_nr[atomic_inc_return(&dev_nr)])) { - v4l2_err(&dev->v4l2_dev, "registering videodev failed\n"); - goto error; - } - #if IS_ENABLED(CONFIG_I2C) retval = hdpvr_register_i2c_adapter(dev); if (retval < 0) { @@ -414,6 +408,13 @@ static int hdpvr_probe(struct usb_interface *interface, } #endif + retval = hdpvr_register_videodev(dev, &interface->dev, + video_nr[atomic_inc_return(&dev_nr)]); + if (retval < 0) { + v4l2_err(&dev->v4l2_dev, "registering videodev failed\n"); + goto error; + } + /* let the user know what node this device is now attached to */ v4l2_info(&dev->v4l2_dev, "device now attached to %s\n", video_device_node_name(dev->video_dev)); -- cgit v1.2.3 From c7a2c84af549572c454a8d79011c7fac72b3e53d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Mar 2013 04:23:51 -0300 Subject: [media] hdpvr: recognize firmware version 0x1e This is the latest firmware version and - it seems - the most reliable. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-core.c | 1 + drivers/media/usb/hdpvr/hdpvr.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index 248835b92d73..8247c19d6260 100644 --- a/drivers/media/usb/hdpvr/hdpvr-core.c +++ b/drivers/media/usb/hdpvr/hdpvr-core.c @@ -174,6 +174,7 @@ static int device_authorization(struct hdpvr_device *dev) case HDPVR_FIRMWARE_VERSION_AC3: case HDPVR_FIRMWARE_VERSION_0X12: case HDPVR_FIRMWARE_VERSION_0X15: + case HDPVR_FIRMWARE_VERSION_0X1E: dev->flags |= HDPVR_FLAG_AC3_CAP; break; default: diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h index 945009356127..1c1298138f0d 100644 --- a/drivers/media/usb/hdpvr/hdpvr.h +++ b/drivers/media/usb/hdpvr/hdpvr.h @@ -38,6 +38,7 @@ #define HDPVR_FIRMWARE_VERSION_AC3 0x0d #define HDPVR_FIRMWARE_VERSION_0X12 0x12 #define HDPVR_FIRMWARE_VERSION_0X15 0x15 +#define HDPVR_FIRMWARE_VERSION_0X1E 0x1e /* #define HDPVR_DEBUG */ -- cgit v1.2.3 From 8f69da955873f5e33b60ff117856a2bf1309a336 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 19 Mar 2013 09:53:29 -0300 Subject: [media] hdpvr: add g/querystd, remove deprecated current_norm Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-video.c | 62 ++++++++++++++++++++++++++++------- drivers/media/usb/hdpvr/hdpvr.h | 5 ++- 2 files changed, 54 insertions(+), 13 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index e14bf494f107..042f204972a4 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -550,12 +550,50 @@ static int vidioc_s_std(struct file *file, void *private_data, struct hdpvr_device *dev = video_drvdata(file); u8 std_type = 1; - if (std & (V4L2_STD_NTSC | V4L2_STD_PAL_60)) + if (dev->options.video_input == HDPVR_COMPONENT) + return -ENODATA; + if (dev->status != STATUS_IDLE) + return -EBUSY; + if (std & V4L2_STD_525_60) std_type = 0; + dev->cur_std = std; + dev->width = 720; + dev->height = std_type ? 576 : 480; return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type); } +static int vidioc_g_std(struct file *file, void *private_data, + v4l2_std_id *std) +{ + struct hdpvr_device *dev = video_drvdata(file); + + if (dev->options.video_input == HDPVR_COMPONENT) + return -ENODATA; + *std = dev->cur_std; + return 0; +} + +static int vidioc_querystd(struct file *file, void *fh, v4l2_std_id *a) +{ + struct hdpvr_device *dev = video_drvdata(file); + struct hdpvr_video_info *vid_info; + + if (dev->options.video_input == HDPVR_COMPONENT) + return -ENODATA; + *a = V4L2_STD_ALL; + vid_info = get_video_info(dev); + if (vid_info == NULL) + return 0; + if (vid_info->width == 720 && + (vid_info->height == 480 || vid_info->height == 576)) { + *a = (vid_info->height == 480) ? + V4L2_STD_525_60 : V4L2_STD_625_50; + } + kfree(vid_info); + return 0; +} + static const char *iname[] = { [HDPVR_COMPONENT] = "Component", [HDPVR_SVIDEO] = "S-Video", @@ -565,7 +603,6 @@ static const char *iname[] = { static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { - struct hdpvr_device *dev = video_drvdata(file); unsigned int n; n = i->index; @@ -579,7 +616,8 @@ static int vidioc_enum_input(struct file *file, void *priv, i->audioset = 1<std = dev->video_dev->tvnorms; + i->capabilities = n ? V4L2_IN_CAP_STD : V4L2_IN_CAP_DV_TIMINGS; + i->std = n ? V4L2_STD_ALL : 0; return 0; } @@ -597,8 +635,11 @@ static int vidioc_s_input(struct file *file, void *private_data, return -EBUSY; retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1); - if (!retval) + if (!retval) { dev->options.video_input = index; + dev->video_dev->tvnorms = + index != HDPVR_COMPONENT ? V4L2_STD_ALL : 0; + } return retval; } @@ -776,7 +817,6 @@ static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl) static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, struct v4l2_fmtdesc *f) { - if (f->index != 0) return -EINVAL; @@ -874,6 +914,8 @@ static int vidioc_try_encoder_cmd(struct file *filp, void *priv, static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_s_std = vidioc_s_std, + .vidioc_g_std = vidioc_g_std, + .vidioc_querystd = vidioc_querystd, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, @@ -916,13 +958,6 @@ static const struct video_device hdpvr_video_template = { .fops = &hdpvr_fops, .release = hdpvr_device_release, .ioctl_ops = &hdpvr_ioctl_ops, - .tvnorms = - V4L2_STD_NTSC | V4L2_STD_SECAM | V4L2_STD_PAL_B | - V4L2_STD_PAL_G | V4L2_STD_PAL_H | V4L2_STD_PAL_I | - V4L2_STD_PAL_D | V4L2_STD_PAL_M | V4L2_STD_PAL_N | - V4L2_STD_PAL_60, - .current_norm = V4L2_STD_NTSC | V4L2_STD_PAL_M | - V4L2_STD_PAL_60, }; static const struct v4l2_ctrl_ops hdpvr_ctrl_ops = { @@ -937,6 +972,9 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, bool ac3 = dev->flags & HDPVR_FLAG_AC3_CAP; int res; + dev->cur_std = V4L2_STD_525_60; + dev->width = 720; + dev->height = 480; v4l2_ctrl_handler_init(hdl, 11); if (dev->fw_ver > 0x15) { v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h index 1c1298138f0d..050c6b9fec53 100644 --- a/drivers/media/usb/hdpvr/hdpvr.h +++ b/drivers/media/usb/hdpvr/hdpvr.h @@ -78,6 +78,8 @@ struct hdpvr_device { struct v4l2_ctrl *video_bitrate; struct v4l2_ctrl *video_bitrate_peak; }; + /* v4l2 format */ + uint width, height; /* the max packet size of the bulk endpoint */ size_t bulk_in_size; @@ -87,8 +89,9 @@ struct hdpvr_device { /* holds the current device status */ __u8 status; - /* holds the cureent set options */ + /* holds the current set options */ struct hdpvr_options options; + v4l2_std_id cur_std; uint flags; -- cgit v1.2.3 From 3315c59a45d5314c935a7dd82ab3c324c0d01343 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Mar 2013 15:29:52 -0300 Subject: [media] hdpvr: add dv_timings support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-video.c | 217 ++++++++++++++++++++++++++++++---- drivers/media/usb/hdpvr/hdpvr.h | 1 + 2 files changed, 194 insertions(+), 24 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 042f204972a4..43763097d9bf 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -36,6 +37,25 @@ list_size(&dev->free_buff_list), \ list_size(&dev->rec_buff_list)); } +static const struct v4l2_dv_timings hdpvr_dv_timings[] = { + V4L2_DV_BT_CEA_720X480I59_94, + V4L2_DV_BT_CEA_720X576I50, + V4L2_DV_BT_CEA_720X480P59_94, + V4L2_DV_BT_CEA_720X576P50, + V4L2_DV_BT_CEA_1280X720P50, + V4L2_DV_BT_CEA_1280X720P60, + V4L2_DV_BT_CEA_1920X1080I50, + V4L2_DV_BT_CEA_1920X1080I60, +}; + +/* Use 480i59 as the default timings */ +#define HDPVR_DEF_DV_TIMINGS_IDX (0) + +struct hdpvr_fh { + struct v4l2_fh fh; + bool legacy_mode; +}; + static uint list_size(struct list_head *list) { struct list_head *tmp; @@ -355,13 +375,23 @@ static int hdpvr_stop_streaming(struct hdpvr_device *dev) * video 4 linux 2 file operations */ +static int hdpvr_open(struct file *file) +{ + struct hdpvr_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL); + + if (fh == NULL) + return -ENOMEM; + fh->legacy_mode = true; + v4l2_fh_init(&fh->fh, video_devdata(file)); + v4l2_fh_add(&fh->fh); + file->private_data = fh; + return 0; +} + static int hdpvr_release(struct file *file) { struct hdpvr_device *dev = video_drvdata(file); - if (!dev) - return -ENODEV; - mutex_lock(&dev->io_mutex); if (file->private_data == dev->owner) { hdpvr_stop_streaming(dev); @@ -388,9 +418,6 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, if (*pos) return -ESPIPE; - if (!dev) - return -ENODEV; - mutex_lock(&dev->io_mutex); if (dev->status == STATUS_IDLE) { if (hdpvr_start_streaming(dev)) { @@ -518,7 +545,7 @@ static unsigned int hdpvr_poll(struct file *filp, poll_table *wait) static const struct v4l2_file_operations hdpvr_fops = { .owner = THIS_MODULE, - .open = v4l2_fh_open, + .open = hdpvr_open, .release = hdpvr_release, .read = hdpvr_read, .poll = hdpvr_poll, @@ -594,6 +621,121 @@ static int vidioc_querystd(struct file *file, void *fh, v4l2_std_id *a) return 0; } +static int vidioc_s_dv_timings(struct file *file, void *_fh, + struct v4l2_dv_timings *timings) +{ + struct hdpvr_device *dev = video_drvdata(file); + struct hdpvr_fh *fh = _fh; + int i; + + fh->legacy_mode = false; + if (dev->options.video_input) + return -ENODATA; + if (dev->status != STATUS_IDLE) + return -EBUSY; + for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) + if (v4l_match_dv_timings(timings, hdpvr_dv_timings + i, 0)) + break; + if (i == ARRAY_SIZE(hdpvr_dv_timings)) + return -EINVAL; + dev->cur_dv_timings = hdpvr_dv_timings[i]; + dev->width = hdpvr_dv_timings[i].bt.width; + dev->height = hdpvr_dv_timings[i].bt.height; + return 0; +} + +static int vidioc_g_dv_timings(struct file *file, void *_fh, + struct v4l2_dv_timings *timings) +{ + struct hdpvr_device *dev = video_drvdata(file); + struct hdpvr_fh *fh = _fh; + + fh->legacy_mode = false; + if (dev->options.video_input) + return -ENODATA; + *timings = dev->cur_dv_timings; + return 0; +} + +static int vidioc_query_dv_timings(struct file *file, void *_fh, + struct v4l2_dv_timings *timings) +{ + struct hdpvr_device *dev = video_drvdata(file); + struct hdpvr_fh *fh = _fh; + struct hdpvr_video_info *vid_info; + bool interlaced; + int ret = 0; + int i; + + fh->legacy_mode = false; + if (dev->options.video_input) + return -ENODATA; + vid_info = get_video_info(dev); + if (vid_info == NULL) + return -ENOLCK; + interlaced = vid_info->fps <= 30; + for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++) { + const struct v4l2_bt_timings *bt = &hdpvr_dv_timings[i].bt; + unsigned hsize; + unsigned vsize; + unsigned fps; + + hsize = bt->hfrontporch + bt->hsync + bt->hbackporch + bt->width; + vsize = bt->vfrontporch + bt->vsync + bt->vbackporch + + bt->il_vfrontporch + bt->il_vsync + bt->il_vbackporch + + bt->height; + fps = (unsigned)bt->pixelclock / (hsize * vsize); + if (bt->width != vid_info->width || + bt->height != vid_info->height || + bt->interlaced != interlaced || + (fps != vid_info->fps && fps + 1 != vid_info->fps)) + continue; + *timings = hdpvr_dv_timings[i]; + break; + } + if (i == ARRAY_SIZE(hdpvr_dv_timings)) + ret = -ERANGE; + kfree(vid_info); + return ret; +} + +static int vidioc_enum_dv_timings(struct file *file, void *_fh, + struct v4l2_enum_dv_timings *timings) +{ + struct hdpvr_device *dev = video_drvdata(file); + struct hdpvr_fh *fh = _fh; + + fh->legacy_mode = false; + memset(timings->reserved, 0, sizeof(timings->reserved)); + if (dev->options.video_input) + return -ENODATA; + if (timings->index >= ARRAY_SIZE(hdpvr_dv_timings)) + return -EINVAL; + timings->timings = hdpvr_dv_timings[timings->index]; + return 0; +} + +static int vidioc_dv_timings_cap(struct file *file, void *_fh, + struct v4l2_dv_timings_cap *cap) +{ + struct hdpvr_device *dev = video_drvdata(file); + struct hdpvr_fh *fh = _fh; + + fh->legacy_mode = false; + if (dev->options.video_input) + return -ENODATA; + cap->type = V4L2_DV_BT_656_1120; + cap->bt.min_width = 720; + cap->bt.max_width = 1920; + cap->bt.min_height = 480; + cap->bt.max_height = 1080; + cap->bt.min_pixelclock = 27000000; + cap->bt.max_pixelclock = 74250000; + cap->bt.standards = V4L2_DV_BT_STD_CEA861; + cap->bt.capabilities = V4L2_DV_BT_CAP_INTERLACED | V4L2_DV_BT_CAP_PROGRESSIVE; + return 0; +} + static const char *iname[] = { [HDPVR_COMPONENT] = "Component", [HDPVR_SVIDEO] = "S-Video", @@ -827,29 +969,48 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, return 0; } -static int vidioc_g_fmt_vid_cap(struct file *file, void *private_data, +static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh, struct v4l2_format *f) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_video_info *vid_info; - - if (!dev) - return -ENODEV; - - vid_info = get_video_info(dev); - if (!vid_info) - return -EFAULT; - - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + struct hdpvr_fh *fh = _fh; + + /* + * The original driver would always returns the current detected + * resolution as the format (and EFAULT if it couldn't be detected). + * With the introduction of VIDIOC_QUERY_DV_TIMINGS there is now a + * better way of doing this, but to stay compatible with existing + * applications we assume legacy mode every time an application opens + * the device. Only if one of the new DV_TIMINGS ioctls is called + * will the filehandle go into 'normal' mode where g_fmt returns the + * last set format. + */ + if (fh->legacy_mode) { + struct hdpvr_video_info *vid_info; + + vid_info = get_video_info(dev); + if (!vid_info) + return -EFAULT; + f->fmt.pix.width = vid_info->width; + f->fmt.pix.height = vid_info->height; + kfree(vid_info); + } else { + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + } f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; - f->fmt.pix.width = vid_info->width; - f->fmt.pix.height = vid_info->height; f->fmt.pix.sizeimage = dev->bulk_in_size; - f->fmt.pix.colorspace = 0; f->fmt.pix.bytesperline = 0; - f->fmt.pix.field = V4L2_FIELD_ANY; - - kfree(vid_info); + f->fmt.pix.priv = 0; + if (f->fmt.pix.width == 720) { + /* SDTV formats */ + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + } else { + /* HDTV formats */ + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE240M; + f->fmt.pix.field = V4L2_FIELD_NONE; + } return 0; } @@ -916,6 +1077,11 @@ static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = { .vidioc_s_std = vidioc_s_std, .vidioc_g_std = vidioc_g_std, .vidioc_querystd = vidioc_querystd, + .vidioc_s_dv_timings = vidioc_s_dv_timings, + .vidioc_g_dv_timings = vidioc_g_dv_timings, + .vidioc_query_dv_timings= vidioc_query_dv_timings, + .vidioc_enum_dv_timings = vidioc_enum_dv_timings, + .vidioc_dv_timings_cap = vidioc_dv_timings_cap, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, @@ -924,6 +1090,8 @@ static const struct v4l2_ioctl_ops hdpvr_ioctl_ops = { .vidioc_s_audio = vidioc_s_audio, .vidioc_enum_fmt_vid_cap= vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_encoder_cmd = vidioc_encoder_cmd, .vidioc_try_encoder_cmd = vidioc_try_encoder_cmd, .vidioc_log_status = v4l2_ctrl_log_status, @@ -975,6 +1143,7 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, dev->cur_std = V4L2_STD_525_60; dev->width = 720; dev->height = 480; + dev->cur_dv_timings = hdpvr_dv_timings[HDPVR_DEF_DV_TIMINGS_IDX]; v4l2_ctrl_handler_init(hdl, 11); if (dev->fw_ver > 0x15) { v4l2_ctrl_new_std(hdl, &hdpvr_ctrl_ops, diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h index 050c6b9fec53..1478f3d57630 100644 --- a/drivers/media/usb/hdpvr/hdpvr.h +++ b/drivers/media/usb/hdpvr/hdpvr.h @@ -92,6 +92,7 @@ struct hdpvr_device { /* holds the current set options */ struct hdpvr_options options; v4l2_std_id cur_std; + struct v4l2_dv_timings cur_dv_timings; uint flags; -- cgit v1.2.3 From 5854bf88599545572ce89fba6c4fa0bf6b6e226c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 10 Apr 2013 14:26:52 -0300 Subject: [media] hdpvr: allow g/s/enum/querystd when in legacy mode Both MythTV and gstreamer expect that they can set/get/query/enumerate the standards, even if the input is the component input for which standards really do not apply. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-video.c | 37 ++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 43763097d9bf..774ba0e820be 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -571,13 +571,14 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_s_std(struct file *file, void *private_data, +static int vidioc_s_std(struct file *file, void *_fh, v4l2_std_id std) { struct hdpvr_device *dev = video_drvdata(file); + struct hdpvr_fh *fh = _fh; u8 std_type = 1; - if (dev->options.video_input == HDPVR_COMPONENT) + if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) return -ENODATA; if (dev->status != STATUS_IDLE) return -EBUSY; @@ -590,25 +591,27 @@ static int vidioc_s_std(struct file *file, void *private_data, return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type); } -static int vidioc_g_std(struct file *file, void *private_data, +static int vidioc_g_std(struct file *file, void *_fh, v4l2_std_id *std) { struct hdpvr_device *dev = video_drvdata(file); + struct hdpvr_fh *fh = _fh; - if (dev->options.video_input == HDPVR_COMPONENT) + if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) return -ENODATA; *std = dev->cur_std; return 0; } -static int vidioc_querystd(struct file *file, void *fh, v4l2_std_id *a) +static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a) { struct hdpvr_device *dev = video_drvdata(file); struct hdpvr_video_info *vid_info; + struct hdpvr_fh *fh = _fh; - if (dev->options.video_input == HDPVR_COMPONENT) - return -ENODATA; *a = V4L2_STD_ALL; + if (dev->options.video_input == HDPVR_COMPONENT) + return fh->legacy_mode ? 0 : -ENODATA; vid_info = get_video_info(dev); if (vid_info == NULL) return 0; @@ -742,8 +745,7 @@ static const char *iname[] = { [HDPVR_COMPOSITE] = "Composite", }; -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) +static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i) { unsigned int n; @@ -764,7 +766,7 @@ static int vidioc_enum_input(struct file *file, void *priv, return 0; } -static int vidioc_s_input(struct file *file, void *private_data, +static int vidioc_s_input(struct file *file, void *_fh, unsigned int index) { struct hdpvr_device *dev = video_drvdata(file); @@ -779,8 +781,20 @@ static int vidioc_s_input(struct file *file, void *private_data, retval = hdpvr_config_call(dev, CTRL_VIDEO_INPUT_VALUE, index+1); if (!retval) { dev->options.video_input = index; + /* + * Unfortunately gstreamer calls ENUMSTD and bails out if it + * won't find any formats, even though component input is + * selected. This means that we have to leave tvnorms at + * V4L2_STD_ALL. We cannot use the 'legacy' trick since + * tvnorms is set at the device node level and not at the + * filehandle level. + * + * Comment this out for now, but if the legacy mode can be + * removed in the future, then this code should be enabled + * again. dev->video_dev->tvnorms = - index != HDPVR_COMPONENT ? V4L2_STD_ALL : 0; + (index != HDPVR_COMPONENT) ? V4L2_STD_ALL : 0; + */ } return retval; @@ -1126,6 +1140,7 @@ static const struct video_device hdpvr_video_template = { .fops = &hdpvr_fops, .release = hdpvr_device_release, .ioctl_ops = &hdpvr_ioctl_ops, + .tvnorms = V4L2_STD_ALL, }; static const struct v4l2_ctrl_ops hdpvr_ctrl_ops = { -- cgit v1.2.3 From 7c15b715ef301a7f8bb2dc8de335497ffde568a6 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 8 Apr 2013 13:47:03 -0300 Subject: [media] media: Fix randconfig error Fix randconfig error when USB is not enabled: ERROR: "usb_control_msg" [drivers/media/common/cypress_firmware.ko] undefined! Signed-off-by: Randy Dunlap Reviewed-by: Antti Palosaari Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index ba666c707d58..b85f88c8ddbd 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -18,6 +18,7 @@ config VIDEO_TVEEPROM config CYPRESS_FIRMWARE tristate "Cypress firmware helper routines" + depends on USB source "drivers/media/common/b2c2/Kconfig" source "drivers/media/common/saa7146/Kconfig" -- cgit v1.2.3 From 2b64cbd1da7a026e0779a1ba61e83ac5fcf544e7 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 11 Apr 2013 15:56:01 -0300 Subject: [media] em28xx: fix snapshot button support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The snapshot button support is currently broken, because module em28xx-rc is loaded only if the device has remote control support. Fix it by also loading this module if the device has a snapshot button. Signed-off-by: Frank Schäfer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 1d3866f53c9b..a3c305598b4b 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2810,7 +2810,8 @@ static void request_module_async(struct work_struct *work) if (dev->board.has_dvb) request_module("em28xx-dvb"); - if ((dev->board.ir_codes || dev->board.has_ir_i2c) && !disable_ir) + if (dev->board.has_snapshot_button || + ((dev->board.ir_codes || dev->board.has_ir_i2c) && !disable_ir)) request_module("em28xx-rc"); #endif /* CONFIG_MODULES */ } -- cgit v1.2.3 From 61ff5d69dc39fecfe52ee5c8d4695a0ad4444d34 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Thu, 11 Apr 2013 15:56:47 -0300 Subject: [media] em28xx: improve em2710/em2820 distinction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Chip id 18 is used by the em2710 and em2820. The current code assumes that if the device is a camera, the chip is an em2710 and an em2820 otherwise. But it turned out that the em2820 is also used in camera devices. "Silvercrest 1.3 MPix" webcams for example are available with both chips. Fortunately both variants are using different generic USD IDs which give us a hint about the used chip. Signed-off-by: Frank Schäfer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index a3c305598b4b..54ead1ec71a8 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2909,6 +2909,14 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, break; case CHIP_ID_EM2820: chip_name = "em2710/2820"; + if (dev->udev->descriptor.idVendor == 0xeb1a) { + __le16 idProd = dev->udev->descriptor.idProduct; + if (le16_to_cpu(idProd) == 0x2710) + chip_name = "em2710"; + else if (le16_to_cpu(idProd) == 0x2820) + chip_name = "em2820"; + } + /* NOTE: the em2820 is used in webcams, too ! */ break; case CHIP_ID_EM2840: chip_name = "em2840"; @@ -2974,14 +2982,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, em28xx_pre_card_setup(dev); - if (dev->chip_id == CHIP_ID_EM2820) { - if (dev->board.is_webcam) - chip_name = "em2710"; - else - chip_name = "em2820"; - snprintf(dev->name, sizeof(dev->name), "%s #%d", chip_name, dev->devno); - } - if (!dev->board.is_em2800) { /* Resets I2C speed */ retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); -- cgit v1.2.3 From b294a1921454fbcc6e983750ae977ce8a28f31bc Mon Sep 17 00:00:00 2001 From: Vladimir Barinov Date: Thu, 11 Apr 2013 18:06:46 -0300 Subject: [media] adv7180: fix querystd() method for no input signal When the input signal is not detected querystd() method should return V4L2_STD_UNKNOWN instead of previously latched analog video standard. Signed-off-by: Vladimir Barinov Signed-off-by: Sergei Shtylyov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 34f39d3b3e3e..afd561ab190d 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -135,6 +135,10 @@ struct adv7180_state { static v4l2_std_id adv7180_std_to_v4l2(u8 status1) { + /* in case V4L2_IN_ST_NO_SIGNAL */ + if (!(status1 & ADV7180_STATUS1_IN_LOCK)) + return V4L2_STD_UNKNOWN; + switch (status1 & ADV7180_STATUS1_AUTOD_MASK) { case ADV7180_STATUS1_AUTOD_NTSM_M_J: return V4L2_STD_NTSC; -- cgit v1.2.3 From 3778d05036cc7ddd983ae2451da579af00acdac2 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Tue, 12 Mar 2013 06:14:52 -0300 Subject: [media] media: davinci: kconfig: fix incorrect selects drivers/media/platform/davinci/Kconfig uses selects where it should be using 'depends on'. This results in warnings of the following sort when doing randconfig builds. warning: (VIDEO_DM6446_CCDC && VIDEO_DM355_CCDC && VIDEO_ISIF && VIDEO_DAVINCI_VPBE_DISPLAY) selects VIDEO_VPSS_SYSTEM which has unmet direct dependencies (MEDIA_SUPPORT && V4L_PLATFORM_DRIVERS && ARCH_DAVINCI) The VPIF kconfigs had a strange 'select' and 'depends on' cross linkage which have been fixed as well by removing unneeded VIDEO_DAVINCI_VPIF config symbol. Similarly, remove the unnecessary VIDEO_VPSS_SYSTEM and VIDEO_VPFE_CAPTURE. They don't select any independent functionality and were being used to manage code dependencies which can be handled using makefile. Selecting video modules is now dependent on all ARCH_DAVINCI instead of specific EVMs and SoCs earlier. This should help build coverage. Remove unnecessary 'default y' for some config symbols. While at it, fix the Kconfig help text to make it more readable and fix names of modules created during module build. Rename VIDEO_ISIF to VIDEO_DM365_ISIF as per suggestion from Prabhakar. This patch has only been build tested; I have tried to not break any existing assumptions. I do not have the setup to test video, so any test reports welcome. Reported-by: Russell King Signed-off-by: Sekhar Nori [prabhakar.csengg@gmail.com: Fixed typo] Signed-off-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/Kconfig | 103 +++++++++++--------------------- drivers/media/platform/davinci/Makefile | 17 ++---- 2 files changed, 41 insertions(+), 79 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig index ccfde4eb626a..afb3aec1320e 100644 --- a/drivers/media/platform/davinci/Kconfig +++ b/drivers/media/platform/davinci/Kconfig @@ -1,64 +1,33 @@ config VIDEO_DAVINCI_VPIF_DISPLAY - tristate "DM646x/DA850/OMAPL138 EVM Video Display" - depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM) + tristate "TI DaVinci VPIF V4L2-Display driver" + depends on VIDEO_DEV && ARCH_DAVINCI select VIDEOBUF2_DMA_CONTIG - select VIDEO_DAVINCI_VPIF select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT help Enables Davinci VPIF module used for display devices. - This module is common for following DM6467/DA850/OMAPL138 - based display devices. + This module is used for display on TI DM6467/DA850/OMAPL138 + SoCs. - To compile this driver as a module, choose M here: the - module will be called vpif_display. + To compile this driver as a module, choose M here. There will + be two modules called vpif.ko and vpif_display.ko config VIDEO_DAVINCI_VPIF_CAPTURE - tristate "DM646x/DA850/OMAPL138 EVM Video Capture" - depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM) + tristate "TI DaVinci VPIF video capture driver" + depends on VIDEO_DEV && ARCH_DAVINCI select VIDEOBUF2_DMA_CONTIG - select VIDEO_DAVINCI_VPIF help - Enables Davinci VPIF module used for captur devices. - This module is common for following DM6467/DA850/OMAPL138 - based capture devices. + Enables Davinci VPIF module used for capture devices. + This module is used for capture on TI DM6467/DA850/OMAPL138 + SoCs. - To compile this driver as a module, choose M here: the - module will be called vpif_capture. + To compile this driver as a module, choose M here. There will + be two modules called vpif.ko and vpif_capture.ko -config VIDEO_DAVINCI_VPIF - tristate "DaVinci VPIF Driver" - depends on VIDEO_DAVINCI_VPIF_DISPLAY || VIDEO_DAVINCI_VPIF_CAPTURE - help - Support for DaVinci VPIF Driver. - - To compile this driver as a module, choose M here: the - module will be called vpif. - -config VIDEO_VPSS_SYSTEM - tristate "VPSS System module driver" - depends on ARCH_DAVINCI - help - Support for vpss system module for video driver - -config VIDEO_VPFE_CAPTURE - tristate "VPFE Video Capture Driver" +config VIDEO_DM6446_CCDC + tristate "TI DM6446 CCDC video capture driver" depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3) - depends on I2C select VIDEOBUF_DMA_CONTIG - help - Support for DMx/AMx VPFE based frame grabber. This is the - common V4L2 module for following DMx/AMx SoCs from Texas - Instruments:- DM6446, DM365, DM355 & AM3517/05. - - To compile this driver as a module, choose M here: the - module will be called vpfe-capture. - -config VIDEO_DM6446_CCDC - tristate "DM6446 CCDC HW module" - depends on VIDEO_VPFE_CAPTURE - select VIDEO_VPSS_SYSTEM - default y help Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces with decoder modules such as TVP5146 over BT656 or @@ -66,14 +35,13 @@ config VIDEO_DM6446_CCDC module configures the interface and CCDC/ISIF to do video frame capture from slave decoders. - To compile this driver as a module, choose M here: the - module will be called vpfe. + To compile this driver as a module, choose M here. There will + be three modules called vpfe_capture.ko, vpss.ko and dm644x_ccdc.ko config VIDEO_DM355_CCDC - tristate "DM355 CCDC HW module" - depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE - select VIDEO_VPSS_SYSTEM - default y + tristate "TI DM355 CCDC video capture driver" + depends on VIDEO_V4L2 && ARCH_DAVINCI + select VIDEOBUF_DMA_CONTIG help Enables DM355 CCD hw module. DM355 CCDC hw interfaces with decoder modules such as TVP5146 over BT656 or @@ -81,31 +49,30 @@ config VIDEO_DM355_CCDC module configures the interface and CCDC/ISIF to do video frame capture from a slave decoders - To compile this driver as a module, choose M here: the - module will be called vpfe. + To compile this driver as a module, choose M here. There will + be three modules called vpfe_capture.ko, vpss.ko and dm355_ccdc.ko -config VIDEO_ISIF - tristate "ISIF HW module" - depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE - select VIDEO_VPSS_SYSTEM - default y +config VIDEO_DM365_ISIF + tristate "TI DM365 ISIF video capture driver" + depends on VIDEO_V4L2 && ARCH_DAVINCI + select VIDEOBUF_DMA_CONTIG help Enables ISIF hw module. This is the hardware module for - configuring ISIF in VPFE to capture Raw Bayer RGB data from + configuring ISIF in VPFE to capture Raw Bayer RGB data from a image sensor or YUV data from a YUV source. - To compile this driver as a module, choose M here: the - module will be called vpfe. + To compile this driver as a module, choose M here. There will + be three modules called vpfe_capture.ko, vpss.ko and isif.ko config VIDEO_DAVINCI_VPBE_DISPLAY - tristate "DM644X/DM365/DM355 VPBE HW module" - depends on ARCH_DAVINCI_DM644x || ARCH_DAVINCI_DM355 || ARCH_DAVINCI_DM365 - select VIDEO_VPSS_SYSTEM + tristate "TI DaVinci VPBE V4L2-Display driver" + depends on ARCH_DAVINCI select VIDEOBUF2_DMA_CONTIG help Enables Davinci VPBE module used for display devices. - This module is common for following DM644x/DM365/DM355 + This module is used for display on TI DM644x/DM365/DM355 based display devices. - To compile this driver as a module, choose M here: the - module will be called vpbe. + To compile this driver as a module, choose M here. There will + be five modules created called vpss.ko, vpbe.ko, vpbe_osd.ko, + vpbe_venc.ko and vpbe_display.ko diff --git a/drivers/media/platform/davinci/Makefile b/drivers/media/platform/davinci/Makefile index f40f5219ca50..d74d9eeb0e9e 100644 --- a/drivers/media/platform/davinci/Makefile +++ b/drivers/media/platform/davinci/Makefile @@ -2,19 +2,14 @@ # Makefile for the davinci video device drivers. # -# VPIF -obj-$(CONFIG_VIDEO_DAVINCI_VPIF) += vpif.o - #VPIF Display driver -obj-$(CONFIG_VIDEO_DAVINCI_VPIF_DISPLAY) += vpif_display.o +obj-$(CONFIG_VIDEO_DAVINCI_VPIF_DISPLAY) += vpif.o vpif_display.o #VPIF Capture driver -obj-$(CONFIG_VIDEO_DAVINCI_VPIF_CAPTURE) += vpif_capture.o +obj-$(CONFIG_VIDEO_DAVINCI_VPIF_CAPTURE) += vpif.o vpif_capture.o # Capture: DM6446 and DM355 -obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o -obj-$(CONFIG_VIDEO_VPFE_CAPTURE) += vpfe_capture.o -obj-$(CONFIG_VIDEO_DM6446_CCDC) += dm644x_ccdc.o -obj-$(CONFIG_VIDEO_DM355_CCDC) += dm355_ccdc.o -obj-$(CONFIG_VIDEO_ISIF) += isif.o -obj-$(CONFIG_VIDEO_DAVINCI_VPBE_DISPLAY) += vpbe.o vpbe_osd.o \ +obj-$(CONFIG_VIDEO_DM6446_CCDC) += vpfe_capture.o vpss.o dm644x_ccdc.o +obj-$(CONFIG_VIDEO_DM355_CCDC) += vpfe_capture.o vpss.o dm355_ccdc.o +obj-$(CONFIG_VIDEO_DM365_ISIF) += vpfe_capture.o vpss.o isif.o +obj-$(CONFIG_VIDEO_DAVINCI_VPBE_DISPLAY) += vpss.o vpbe.o vpbe_osd.o \ vpbe_venc.o vpbe_display.o -- cgit v1.2.3 From 407ccc65bfd2899ed008c4f8900f23ac15f75f9f Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Tue, 2 Apr 2013 09:41:30 -0300 Subject: [media] davinci: vpif: add pm_runtime support Add pm_runtime support to the TI Davinci VPIF driver. Signed-off-by: Lad, Prabhakar Acked-by: Hans Verkuil Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c index 3bc4db8f0f27..ea82a8bd2803 100644 --- a/drivers/media/platform/davinci/vpif.c +++ b/drivers/media/platform/davinci/vpif.c @@ -23,8 +23,8 @@ #include #include #include -#include #include +#include #include #include @@ -46,8 +46,6 @@ spinlock_t vpif_lock; void __iomem *vpif_base; EXPORT_SYMBOL_GPL(vpif_base); -struct clk *vpif_clk; - /** * vpif_ch_params: video standard configuration parameters for vpif * The table must include all presets from supported subdevices. @@ -443,19 +441,13 @@ static int vpif_probe(struct platform_device *pdev) goto fail; } - vpif_clk = clk_get(&pdev->dev, "vpif"); - if (IS_ERR(vpif_clk)) { - status = PTR_ERR(vpif_clk); - goto clk_fail; - } - clk_prepare_enable(vpif_clk); + pm_runtime_enable(&pdev->dev); + pm_runtime_get(&pdev->dev); spin_lock_init(&vpif_lock); dev_info(&pdev->dev, "vpif probe success\n"); return 0; -clk_fail: - iounmap(vpif_base); fail: release_mem_region(res->start, res_len); return status; @@ -463,11 +455,7 @@ fail: static int vpif_remove(struct platform_device *pdev) { - if (vpif_clk) { - clk_disable_unprepare(vpif_clk); - clk_put(vpif_clk); - } - + pm_runtime_disable(&pdev->dev); iounmap(vpif_base); release_mem_region(res->start, res_len); return 0; @@ -476,13 +464,13 @@ static int vpif_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int vpif_suspend(struct device *dev) { - clk_disable_unprepare(vpif_clk); + pm_runtime_put(dev); return 0; } static int vpif_resume(struct device *dev) { - clk_prepare_enable(vpif_clk); + pm_runtime_get(dev); return 0; } -- cgit v1.2.3 From 9a3e89b10f5e48c0d8cca7896c02bf4d76d0ae46 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Fri, 22 Mar 2013 04:53:12 -0300 Subject: [media] media: davinci: vpss: enable vpss clocks By default the VPSS clocks were enabled in capture driver for davinci family which creates duplicates for dm355/dm365/dm644x. This patch adds support to enable the VPSS clocks in VPSS driver, which avoids duplication of code and also adding clock aliases. This patch uses PM runtime API to enable/disable clock, instead of DaVinci clock framework. con_ids for master and slave clocks of vpss is added in pm_domain. This patch cleanups the VPSS clock enabling in the capture driver, and also removes the clock alias in machine file. Along side adds a vpss slave clock for DM365 as mentioned by Sekhar (https://patchwork.kernel.org/patch/1221261/). The Suspend/Resume in dm644x_ccdc.c which enabled/disabled the VPSS clock is now implemented as part of the VPSS driver. Signed-off-by: Lad, Prabhakar Acked-by: Sekhar Nori Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- arch/arm/mach-davinci/dm355.c | 7 ++--- arch/arm/mach-davinci/dm365.c | 11 +++++-- arch/arm/mach-davinci/dm644x.c | 9 ++---- arch/arm/mach-davinci/pm_domain.c | 2 +- drivers/media/platform/davinci/dm355_ccdc.c | 39 +----------------------- drivers/media/platform/davinci/dm644x_ccdc.c | 44 ---------------------------- drivers/media/platform/davinci/isif.c | 28 +++--------------- drivers/media/platform/davinci/vpss.c | 25 ++++++++++++++++ 8 files changed, 43 insertions(+), 122 deletions(-) (limited to 'drivers/media') diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index b49c3b77d55e..8e98bb06b1c1 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -345,8 +345,8 @@ static struct clk_lookup dm355_clks[] = { CLK(NULL, "pll1_aux", &pll1_aux_clk), CLK(NULL, "pll1_sysclkbp", &pll1_sysclkbp), CLK(NULL, "vpss_dac", &vpss_dac_clk), - CLK(NULL, "vpss_master", &vpss_master_clk), - CLK(NULL, "vpss_slave", &vpss_slave_clk), + CLK("vpss", "master", &vpss_master_clk), + CLK("vpss", "slave", &vpss_slave_clk), CLK(NULL, "clkout1", &clkout1_clk), CLK(NULL, "clkout2", &clkout2_clk), CLK(NULL, "pll2", &pll2_clk), @@ -873,9 +873,6 @@ static int __init dm355_init_devices(void) if (!cpu_is_davinci_dm355()) return 0; - /* Add ccdc clock aliases */ - clk_add_alias("master", dm355_ccdc_dev.name, "vpss_master", NULL); - clk_add_alias("slave", dm355_ccdc_dev.name, "vpss_master", NULL); davinci_cfg_reg(DM355_INT_EDMA_CC); platform_device_register(&dm355_edma_device); platform_device_register(&dm355_vpss_device); diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index 6c3980540be0..c61dd94daadc 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -257,6 +257,12 @@ static struct clk vpss_master_clk = { .flags = CLK_PSC, }; +static struct clk vpss_slave_clk = { + .name = "vpss_slave", + .parent = &pll1_sysclk5, + .lpsc = DAVINCI_LPSC_VPSSSLV, +}; + static struct clk arm_clk = { .name = "arm_clk", .parent = &pll2_sysclk2, @@ -449,7 +455,8 @@ static struct clk_lookup dm365_clks[] = { CLK(NULL, "pll2_sysclk8", &pll2_sysclk8), CLK(NULL, "pll2_sysclk9", &pll2_sysclk9), CLK(NULL, "vpss_dac", &vpss_dac_clk), - CLK(NULL, "vpss_master", &vpss_master_clk), + CLK("vpss", "master", &vpss_master_clk), + CLK("vpss", "slave", &vpss_slave_clk), CLK(NULL, "arm", &arm_clk), CLK(NULL, "uart0", &uart0_clk), CLK(NULL, "uart1", &uart1_clk), @@ -1239,8 +1246,6 @@ static int __init dm365_init_devices(void) clk_add_alias(NULL, dev_name(&dm365_mdio_device.dev), NULL, &dm365_emac_device.dev); - /* Add isif clock alias */ - clk_add_alias("master", dm365_isif_dev.name, "vpss_master", NULL); platform_device_register(&dm365_vpss_device); platform_device_register(&dm365_isif_dev); platform_device_register(&vpfe_capture_dev); diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index ee0e994748e0..c2a9273330bf 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -300,8 +300,8 @@ static struct clk_lookup dm644x_clks[] = { CLK(NULL, "dsp", &dsp_clk), CLK(NULL, "arm", &arm_clk), CLK(NULL, "vicp", &vicp_clk), - CLK(NULL, "vpss_master", &vpss_master_clk), - CLK(NULL, "vpss_slave", &vpss_slave_clk), + CLK("vpss", "master", &vpss_master_clk), + CLK("vpss", "slave", &vpss_slave_clk), CLK(NULL, "arm", &arm_clk), CLK(NULL, "uart0", &uart0_clk), CLK(NULL, "uart1", &uart1_clk), @@ -901,11 +901,6 @@ int __init dm644x_init_video(struct vpfe_config *vpfe_cfg, dm644x_vpfe_dev.dev.platform_data = vpfe_cfg; platform_device_register(&dm644x_ccdc_dev); platform_device_register(&dm644x_vpfe_dev); - /* Add ccdc clock aliases */ - clk_add_alias("master", dm644x_ccdc_dev.name, - "vpss_master", NULL); - clk_add_alias("slave", dm644x_ccdc_dev.name, - "vpss_slave", NULL); } if (vpbe_cfg) { diff --git a/arch/arm/mach-davinci/pm_domain.c b/arch/arm/mach-davinci/pm_domain.c index c90250e3bef8..6b98413cebd6 100644 --- a/arch/arm/mach-davinci/pm_domain.c +++ b/arch/arm/mach-davinci/pm_domain.c @@ -53,7 +53,7 @@ static struct dev_pm_domain davinci_pm_domain = { static struct pm_clk_notifier_block platform_bus_notifier = { .pm_domain = &davinci_pm_domain, - .con_ids = { "fck", NULL, }, + .con_ids = { "fck", "master", "slave", NULL }, }; static int __init davinci_pm_runtime_init(void) diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c index 2364dbab8046..05f8fb7f7b70 100644 --- a/drivers/media/platform/davinci/dm355_ccdc.c +++ b/drivers/media/platform/davinci/dm355_ccdc.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include @@ -59,10 +58,6 @@ static struct ccdc_oper_config { struct ccdc_params_raw bayer; /* YCbCr configuration */ struct ccdc_params_ycbcr ycbcr; - /* Master clock */ - struct clk *mclk; - /* slave clock */ - struct clk *sclk; /* ccdc base address */ void __iomem *base_addr; } ccdc_cfg = { @@ -997,32 +992,10 @@ static int dm355_ccdc_probe(struct platform_device *pdev) goto fail_nomem; } - /* Get and enable Master clock */ - ccdc_cfg.mclk = clk_get(&pdev->dev, "master"); - if (IS_ERR(ccdc_cfg.mclk)) { - status = PTR_ERR(ccdc_cfg.mclk); - goto fail_nomap; - } - if (clk_prepare_enable(ccdc_cfg.mclk)) { - status = -ENODEV; - goto fail_mclk; - } - - /* Get and enable Slave clock */ - ccdc_cfg.sclk = clk_get(&pdev->dev, "slave"); - if (IS_ERR(ccdc_cfg.sclk)) { - status = PTR_ERR(ccdc_cfg.sclk); - goto fail_mclk; - } - if (clk_prepare_enable(ccdc_cfg.sclk)) { - status = -ENODEV; - goto fail_sclk; - } - /* Platform data holds setup_pinmux function ptr */ if (NULL == pdev->dev.platform_data) { status = -ENODEV; - goto fail_sclk; + goto fail_nomap; } setup_pinmux = pdev->dev.platform_data; /* @@ -1033,12 +1006,6 @@ static int dm355_ccdc_probe(struct platform_device *pdev) ccdc_cfg.dev = &pdev->dev; printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); return 0; -fail_sclk: - clk_disable_unprepare(ccdc_cfg.sclk); - clk_put(ccdc_cfg.sclk); -fail_mclk: - clk_disable_unprepare(ccdc_cfg.mclk); - clk_put(ccdc_cfg.mclk); fail_nomap: iounmap(ccdc_cfg.base_addr); fail_nomem: @@ -1052,10 +1019,6 @@ static int dm355_ccdc_remove(struct platform_device *pdev) { struct resource *res; - clk_disable_unprepare(ccdc_cfg.sclk); - clk_disable_unprepare(ccdc_cfg.mclk); - clk_put(ccdc_cfg.mclk); - clk_put(ccdc_cfg.sclk); iounmap(ccdc_cfg.base_addr); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c index 971d639b6674..30fa08405d61 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc.c +++ b/drivers/media/platform/davinci/dm644x_ccdc.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -60,10 +59,6 @@ static struct ccdc_oper_config { struct ccdc_params_raw bayer; /* YCbCr configuration */ struct ccdc_params_ycbcr ycbcr; - /* Master clock */ - struct clk *mclk; - /* slave clock */ - struct clk *sclk; /* ccdc base address */ void __iomem *base_addr; } ccdc_cfg = { @@ -991,38 +986,9 @@ static int dm644x_ccdc_probe(struct platform_device *pdev) goto fail_nomem; } - /* Get and enable Master clock */ - ccdc_cfg.mclk = clk_get(&pdev->dev, "master"); - if (IS_ERR(ccdc_cfg.mclk)) { - status = PTR_ERR(ccdc_cfg.mclk); - goto fail_nomap; - } - if (clk_prepare_enable(ccdc_cfg.mclk)) { - status = -ENODEV; - goto fail_mclk; - } - - /* Get and enable Slave clock */ - ccdc_cfg.sclk = clk_get(&pdev->dev, "slave"); - if (IS_ERR(ccdc_cfg.sclk)) { - status = PTR_ERR(ccdc_cfg.sclk); - goto fail_mclk; - } - if (clk_prepare_enable(ccdc_cfg.sclk)) { - status = -ENODEV; - goto fail_sclk; - } ccdc_cfg.dev = &pdev->dev; printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); return 0; -fail_sclk: - clk_disable_unprepare(ccdc_cfg.sclk); - clk_put(ccdc_cfg.sclk); -fail_mclk: - clk_disable_unprepare(ccdc_cfg.mclk); - clk_put(ccdc_cfg.mclk); -fail_nomap: - iounmap(ccdc_cfg.base_addr); fail_nomem: release_mem_region(res->start, resource_size(res)); fail_nores: @@ -1034,10 +1000,6 @@ static int dm644x_ccdc_remove(struct platform_device *pdev) { struct resource *res; - clk_disable_unprepare(ccdc_cfg.mclk); - clk_disable_unprepare(ccdc_cfg.sclk); - clk_put(ccdc_cfg.mclk); - clk_put(ccdc_cfg.sclk); iounmap(ccdc_cfg.base_addr); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res) @@ -1052,18 +1014,12 @@ static int dm644x_ccdc_suspend(struct device *dev) ccdc_save_context(); /* Disable CCDC */ ccdc_enable(0); - /* Disable both master and slave clock */ - clk_disable_unprepare(ccdc_cfg.mclk); - clk_disable_unprepare(ccdc_cfg.sclk); return 0; } static int dm644x_ccdc_resume(struct device *dev) { - /* Enable both master and slave clock */ - clk_prepare_enable(ccdc_cfg.mclk); - clk_prepare_enable(ccdc_cfg.sclk); /* Restore CCDC context */ ccdc_restore_context(); diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c index abc3ae36645c..3332cca632e5 100644 --- a/drivers/media/platform/davinci/isif.c +++ b/drivers/media/platform/davinci/isif.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include @@ -88,8 +87,6 @@ static struct isif_oper_config { struct isif_ycbcr_config ycbcr; struct isif_params_raw bayer; enum isif_data_pack data_pack; - /* Master clock */ - struct clk *mclk; /* ISIF base address */ void __iomem *base_addr; /* ISIF Linear Table 0 */ @@ -1039,6 +1036,10 @@ static int isif_probe(struct platform_device *pdev) void *__iomem addr; int status = 0, i; + /* Platform data holds setup_pinmux function ptr */ + if (!pdev->dev.platform_data) + return -ENODEV; + /* * first try to register with vpfe. If not correct platform, then we * don't have to iomap @@ -1047,22 +1048,6 @@ static int isif_probe(struct platform_device *pdev) if (status < 0) return status; - /* Get and enable Master clock */ - isif_cfg.mclk = clk_get(&pdev->dev, "master"); - if (IS_ERR(isif_cfg.mclk)) { - status = PTR_ERR(isif_cfg.mclk); - goto fail_mclk; - } - if (clk_prepare_enable(isif_cfg.mclk)) { - status = -ENODEV; - goto fail_mclk; - } - - /* Platform data holds setup_pinmux function ptr */ - if (NULL == pdev->dev.platform_data) { - status = -ENODEV; - goto fail_mclk; - } setup_pinmux = pdev->dev.platform_data; /* * setup Mux configuration for ccdc which may be different for @@ -1124,9 +1109,6 @@ fail_nobase_res: release_mem_region(res->start, resource_size(res)); i--; } -fail_mclk: - clk_disable_unprepare(isif_cfg.mclk); - clk_put(isif_cfg.mclk); vpfe_unregister_ccdc_device(&isif_hw_dev); return status; } @@ -1146,8 +1128,6 @@ static int isif_remove(struct platform_device *pdev) i++; } vpfe_unregister_ccdc_device(&isif_hw_dev); - clk_disable_unprepare(isif_cfg.mclk); - clk_put(isif_cfg.mclk); return 0; } diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c index a19c552232d1..d36429d1bd69 100644 --- a/drivers/media/platform/davinci/vpss.c +++ b/drivers/media/platform/davinci/vpss.c @@ -25,6 +25,8 @@ #include #include #include +#include + #include MODULE_LICENSE("GPL"); @@ -490,6 +492,10 @@ static int vpss_probe(struct platform_device *pdev) } else oper_cfg.hw_ops.clear_wbl_overflow = dm644x_clear_wbl_overflow; + pm_runtime_enable(&pdev->dev); + + pm_runtime_get(&pdev->dev); + spin_lock_init(&oper_cfg.vpss_lock); dev_info(&pdev->dev, "%s vpss probe success\n", platform_name); return 0; @@ -507,6 +513,7 @@ static int vpss_remove(struct platform_device *pdev) { struct resource *res; + pm_runtime_disable(&pdev->dev); iounmap(oper_cfg.vpss_regs_base0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); @@ -518,10 +525,28 @@ static int vpss_remove(struct platform_device *pdev) return 0; } +static int vpss_suspend(struct device *dev) +{ + pm_runtime_put(dev); + return 0; +} + +static int vpss_resume(struct device *dev) +{ + pm_runtime_get(dev); + return 0; +} + +static const struct dev_pm_ops vpss_pm_ops = { + .suspend = vpss_suspend, + .resume = vpss_resume, +}; + static struct platform_driver vpss_driver = { .driver = { .name = "vpss", .owner = THIS_MODULE, + .pm = &vpss_pm_ops, }, .remove = vpss_remove, .probe = vpss_probe, -- cgit v1.2.3 From 08154695076c1aecd2f9bcde79825b45f5ac23b2 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Fri, 22 Mar 2013 04:53:13 -0300 Subject: [media] media: davinci: vpbe: venc: move the enabling of vpss clocks to driver The vpss clocks were enabled by calling a exported function from a driver in a machine code. calling driver code from platform code is incorrect way. This patch fixes this issue and calls the function from driver code itself. Signed-off-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe_venc.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c index f15f211a5508..87eef9be08ed 100644 --- a/drivers/media/platform/davinci/vpbe_venc.c +++ b/drivers/media/platform/davinci/vpbe_venc.c @@ -202,6 +202,25 @@ static void venc_enabledigitaloutput(struct v4l2_subdev *sd, int benable) } } +static void +venc_enable_vpss_clock(int venc_type, + enum vpbe_enc_timings_type type, + unsigned int pclock) +{ + if (venc_type == VPBE_VERSION_1) + return; + + if (venc_type == VPBE_VERSION_2 && (type == VPBE_ENC_STD || (type == + VPBE_ENC_DV_TIMINGS && pclock <= 27000000))) { + vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 1); + vpss_enable_clock(VPSS_VPBE_CLOCK, 1); + return; + } + + if (venc_type == VPBE_VERSION_3 && type == VPBE_ENC_STD) + vpss_enable_clock(VPSS_VENC_CLOCK_SEL, 0); +} + #define VDAC_CONFIG_SD_V3 0x0E21A6B6 #define VDAC_CONFIG_SD_V2 0x081141CF /* @@ -220,6 +239,7 @@ static int venc_set_ntsc(struct v4l2_subdev *sd) if (pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_525_60) < 0) return -EINVAL; + venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_STD, V4L2_STD_525_60); venc_enabledigitaloutput(sd, 0); if (venc->venc_type == VPBE_VERSION_3) { @@ -265,6 +285,7 @@ static int venc_set_pal(struct v4l2_subdev *sd) if (venc->pdata->setup_clock(VPBE_ENC_STD, V4L2_STD_625_50) < 0) return -EINVAL; + venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_STD, V4L2_STD_625_50); venc_enabledigitaloutput(sd, 0); if (venc->venc_type == VPBE_VERSION_3) { @@ -319,6 +340,7 @@ static int venc_set_480p59_94(struct v4l2_subdev *sd) if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0) return -EINVAL; + venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 27000000); venc_enabledigitaloutput(sd, 0); if (venc->venc_type == VPBE_VERSION_2) @@ -366,6 +388,7 @@ static int venc_set_576p50(struct v4l2_subdev *sd) if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 27000000) < 0) return -EINVAL; + venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 27000000); venc_enabledigitaloutput(sd, 0); if (venc->venc_type == VPBE_VERSION_2) @@ -406,6 +429,7 @@ static int venc_set_720p60_internal(struct v4l2_subdev *sd) if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0) return -EINVAL; + venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 74250000); venc_enabledigitaloutput(sd, 0); venc_write(sd, VENC_OSDCLK0, 0); @@ -434,6 +458,7 @@ static int venc_set_1080i30_internal(struct v4l2_subdev *sd) if (pdata->setup_clock(VPBE_ENC_DV_TIMINGS, 74250000) < 0) return -EINVAL; + venc_enable_vpss_clock(venc->venc_type, VPBE_ENC_DV_TIMINGS, 74250000); venc_enabledigitaloutput(sd, 0); venc_write(sd, VENC_OSDCLK0, 0); -- cgit v1.2.3 From 54d5e4beb8fdbf5d762ffe4cb67a53b55a74309e Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Tue, 2 Apr 2013 08:26:32 -0300 Subject: [media] davinic: vpss: trivial cleanup this patch removes unnecessary header file inclusions and fixes the typo's. Signed-off-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpss.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c index d36429d1bd69..8a2f01e344ee 100644 --- a/drivers/media/platform/davinci/vpss.c +++ b/drivers/media/platform/davinci/vpss.c @@ -17,13 +17,8 @@ * * common vpss system module platform driver for all video drivers. */ -#include -#include -#include #include #include -#include -#include #include #include @@ -101,7 +96,7 @@ enum vpss_platform_type { /* * vpss operations. Depends on platform. Not all functions are available - * on all platforms. The api, first check if a functio is available before + * on all platforms. The api, first check if a function is available before * invoking it. In the probe, the function ptrs are initialized based on * vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc. */ @@ -116,7 +111,7 @@ struct vpss_hw_ops { void (*set_sync_pol)(struct vpss_sync_pol); /* set the PG_FRAME_SIZE register*/ void (*set_pg_frame_size)(struct vpss_pg_frame_size); - /* check and clear interrupt if occured */ + /* check and clear interrupt if occurred */ int (*dma_complete_interrupt)(void); }; @@ -235,7 +230,7 @@ EXPORT_SYMBOL(vpss_clear_wbl_overflow); /* * dm355_enable_clock - Enable VPSS Clock - * @clock_sel: CLock to be enabled/disabled + * @clock_sel: Clock to be enabled/disabled * @en: enable/disable flag * * This is called to enable or disable a vpss clock -- cgit v1.2.3 From abcb6b99f5e5d2c3f6d950c97c7ab5e28029c06e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 8 Mar 2013 08:08:56 -0300 Subject: [media] soc-camera: fix typos in the default format-conversion table The default format conversion table mbus_fmt[] in soc_mediabus.c lists "natural" conversions between media-bus and fourcc pixel formats, that are achieved by storing data from the bus in RAM exactly as it arrives, only possibly padding missing high or low bits. Such data acquisition mode cannot change data endianness, therefore two locations with opposite endianness are erroneous. This change might affest the omap1-camera driver, existing configurations should be verified. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/soc_mediabus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/soc_camera/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c index 7569e7746c92..dc02deca7563 100644 --- a/drivers/media/platform/soc_camera/soc_mediabus.c +++ b/drivers/media/platform/soc_camera/soc_mediabus.c @@ -73,7 +73,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .name = "RGB555X", .bits_per_sample = 8, .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, + .order = SOC_MBUS_ORDER_BE, .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { @@ -93,7 +93,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .name = "RGB565X", .bits_per_sample = 8, .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, + .order = SOC_MBUS_ORDER_BE, .layout = SOC_MBUS_LAYOUT_PACKED, }, }, { -- cgit v1.2.3 From 4ec16da733b81b64e9c7823fd2ea506131013a8f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 9 Apr 2013 05:43:33 -0300 Subject: [media] rc: winbond-cir: fix potential double free in wbcir_probe() Since rc_unregister_device() frees its argument, the subsequently call to rc_free_device() on the same variable will cause a double free bug. Fix by set argument to NULL, thus when fall through to rc_free_device(), nothing will be done there. Signed-off-by: Wei Yongjun Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/winbond-cir.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 535a18dccbd0..87af2d3ba601 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -1151,6 +1151,7 @@ exit_release_wbase: release_region(data->wbase, WAKEUP_IOMEM_LEN); exit_unregister_device: rc_unregister_device(data->dev); + data->dev = NULL; exit_free_rc: rc_free_device(data->dev); exit_unregister_led: -- cgit v1.2.3 From 408208fbf289b4384a540ecf9ce1738f5d05b701 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 9 Apr 2013 05:43:53 -0300 Subject: [media] rc: ite-cir: fix potential double free in ite_probe() Since rc_unregister_device() frees its argument, the subsequently call to rc_free_device() on the same variable will cause a double free bug. Fix by set argument to NULL, thus when fall through to rc_free_device(), nothing will be done there. Signed-off-by: Wei Yongjun Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ite-cir.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index dd8237324c09..63b42252166a 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -1613,6 +1613,7 @@ exit_release_cir_addr: release_region(itdev->cir_addr, itdev->params.io_region_size); exit_unregister_device: rc_unregister_device(rdev); + rdev = NULL; exit_free_dev_rdev: rc_free_device(rdev); kfree(itdev); -- cgit v1.2.3 From f73e1851c3e196b7089eb5163a7f6bf491d9b46b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 9 Apr 2013 05:44:29 -0300 Subject: [media] rc: nuvoton-cir: fix potential double free in nvt_probe() Since rc_unregister_device() frees its argument, the subsequently call to rc_free_device() on the same variable will cause a double free bug. Fix by set argument to NULL, thus when fall through to rc_free_device(), nothing will be done there. Signed-off-by: Wei Yongjun Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/nuvoton-cir.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 40125d779049..21ee0dc1b7ec 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -1107,6 +1107,7 @@ exit_release_cir_addr: release_region(nvt->cir_addr, CIR_IOREG_LENGTH); exit_unregister_device: rc_unregister_device(rdev); + rdev = NULL; exit_free_dev_rdev: rc_free_device(rdev); kfree(nvt); -- cgit v1.2.3 From dbcd371b46a16a81a9975b57a11b61bbc2ba81e4 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 9 Apr 2013 05:47:42 -0300 Subject: [media] rc: ene_ir: fix potential double free in ene_probe() Since rc_unregister_device() frees its argument, the subsequently call to rc_free_device() on the same variable will cause a double free bug. Fix by set argument to NULL, thus when fall through to rc_free_device(), nothing will be done there. Signed-off-by: Wei Yongjun Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ene_ir.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index ee6c984cade2..ed184f68c17c 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1098,6 +1098,7 @@ exit_release_hw_io: release_region(dev->hw_io, ENE_IO_SIZE); exit_unregister_device: rc_unregister_device(rdev); + rdev = NULL; exit_free_dev_rdev: rc_free_device(rdev); kfree(dev); -- cgit v1.2.3 From 068a0df76023926af958a336a78bef60468d2033 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 11 Apr 2013 23:57:57 -0300 Subject: [media] media: vb2: add length check for mmap The length of mmap() can be bigger than length of vb2 buffer, so it should be checked. Signed-off-by: Seung-Woo Kim Acked-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 02bb5e721657..58c17444d22f 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -1886,6 +1886,11 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) vb = q->bufs[buffer]; + if (vb->v4l2_planes[plane].length < (vma->vm_end - vma->vm_start)) { + dprintk(1, "Invalid length\n"); + return -EINVAL; + } + ret = call_memop(q, mmap, vb->planes[plane].mem_priv, vma); if (ret) return ret; -- cgit v1.2.3 From 52f5ad6c5f16dedefbea447245192078484665ec Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 12 Apr 2013 13:59:02 -0300 Subject: [media] rc: add rc-reddo It is very similar than rc-msi-digivox-iii but new keytable is needed as there is one existing scancode mapped to different button. Also that one has less buttons. NEC extended protocol with address 0x61d6. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-reddo.c | 86 +++++++++++++++++++++++++++++++++++++ include/media/rc-map.h | 1 + 3 files changed, 88 insertions(+) create mode 100644 drivers/media/rc/keymaps/rc-reddo.c (limited to 'drivers/media') diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 778661971aed..04baac4db200 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-hauppauge.o \ rc-rc6-mce.o \ rc-real-audio-220-32-keys.o \ + rc-reddo.o \ rc-snapstream-firefly.o \ rc-streamzap.o \ rc-tbs-nec.o \ diff --git a/drivers/media/rc/keymaps/rc-reddo.c b/drivers/media/rc/keymaps/rc-reddo.c new file mode 100644 index 000000000000..b80b336e9284 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-reddo.c @@ -0,0 +1,86 @@ +/* + * MSI DIGIVOX mini III remote controller keytable + * + * Copyright (C) 2013 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +/* + * Derived from MSI DIGIVOX mini III remote (rc-msi-digivox-iii.c) + * + * Differences between these remotes are: + * + * 1) scancode 0x61d601 is mapped to different button: + * MSI DIGIVOX mini III "Source" = KEY_VIDEO + * Reddo "EPG" = KEY_EPG + * + * 2) Reddo remote has less buttons. Missing buttons are: colored buttons, + * navigation buttons and main power button. + */ + +static struct rc_map_table reddo[] = { + { 0x61d601, KEY_EPG }, /* EPG */ + { 0x61d602, KEY_3 }, + { 0x61d604, KEY_1 }, + { 0x61d605, KEY_5 }, + { 0x61d606, KEY_6 }, + { 0x61d607, KEY_CHANNELDOWN }, /* CH- */ + { 0x61d608, KEY_2 }, + { 0x61d609, KEY_CHANNELUP }, /* CH+ */ + { 0x61d60a, KEY_9 }, + { 0x61d60b, KEY_ZOOM }, /* Zoom */ + { 0x61d60c, KEY_7 }, + { 0x61d60d, KEY_8 }, + { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */ + { 0x61d60f, KEY_4 }, + { 0x61d610, KEY_ESC }, /* [back up arrow] */ + { 0x61d611, KEY_0 }, + { 0x61d612, KEY_OK }, /* [enter arrow] */ + { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */ + { 0x61d614, KEY_RECORD }, /* Rec */ + { 0x61d615, KEY_STOP }, /* Stop */ + { 0x61d616, KEY_PLAY }, /* Play */ + { 0x61d617, KEY_MUTE }, /* Mute */ + { 0x61d643, KEY_POWER2 }, /* [red power button] */ +}; + +static struct rc_map_list reddo_map = { + .map = { + .scan = reddo, + .size = ARRAY_SIZE(reddo), + .rc_type = RC_TYPE_NEC, + .name = RC_MAP_REDDO, + } +}; + +static int __init init_rc_map_reddo(void) +{ + return rc_map_register(&reddo_map); +} + +static void __exit exit_rc_map_reddo(void) +{ + rc_map_unregister(&reddo_map); +} + +module_init(init_rc_map_reddo) +module_exit(exit_rc_map_reddo) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Antti Palosaari "); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index f74ee6f89711..5d5d3a30f04a 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -172,6 +172,7 @@ void rc_map_init(void); #define RC_MAP_RC5_TV "rc-rc5-tv" #define RC_MAP_RC6_MCE "rc-rc6-mce" #define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys" +#define RC_MAP_REDDO "rc-reddo" #define RC_MAP_SNAPSTREAM_FIREFLY "rc-snapstream-firefly" #define RC_MAP_STREAMZAP "rc-streamzap" #define RC_MAP_TBS_NEC "rc-tbs-nec" -- cgit v1.2.3 From 831378dbb6ad3dfb17f777bd3a9b0ba243ed9c1f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 12 Apr 2013 13:59:03 -0300 Subject: [media] em28xx: map remote for 1b80:e425 Map RC_MAP_REDDO to that device. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 54ead1ec71a8..cc63f1963de5 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -1979,6 +1979,7 @@ struct em28xx_board em28xx_boards[] = { .tuner_type = TUNER_ABSENT, .tuner_gpio = maxmedia_ub425_tc, .has_dvb = 1, + .ir_codes = RC_MAP_REDDO, .def_i2c_bus = 1, .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, -- cgit v1.2.3 From 4c41dab4d69fb887884dc571fd70e4ddc41774fb Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Fri, 12 Apr 2013 13:59:04 -0300 Subject: [media] rc: fix single line indentation of keymaps/Makefile Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 04baac4db200..5ab94ea4bc28 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -89,7 +89,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-tevii-nec.o \ rc-tivo.o \ rc-total-media-in-hand.o \ - rc-total-media-in-hand-02.o \ + rc-total-media-in-hand-02.o \ rc-trekstor.o \ rc-tt-1500.o \ rc-twinhan1027.o \ -- cgit v1.2.3 From a9af5392520c9c30e355562b0bd641d49130284a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 15 Apr 2013 08:31:56 -0300 Subject: [media] cxd2820r_t2: Fix a warning: stream_id is unsigned drivers/media/dvb-frontends/cxd2820r_t2.c: In function 'cxd2820r_set_frontend_t2': drivers/media/dvb-frontends/cxd2820r_t2.c:128:2: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cxd2820r_t2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/cxd2820r_t2.c b/drivers/media/dvb-frontends/cxd2820r_t2.c index c2bfea7551e9..2ba130e245b6 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t2.c +++ b/drivers/media/dvb-frontends/cxd2820r_t2.c @@ -125,7 +125,7 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe) buf[2] = ((if_ctl >> 0) & 0xff); /* PLP filtering */ - if (c->stream_id < 0 || c->stream_id > 255) { + if (c->stream_id > 255) { dev_dbg(&priv->i2c->dev, "%s: Disable PLP filtering\n", __func__); ret = cxd2820r_wr_reg(priv, 0x023ad , 0); if (ret) -- cgit v1.2.3 From a877e2771a7f74b724cc09d96decd2ff3a37f2cd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 14 Apr 2013 10:53:07 -0300 Subject: [media] cx25821: do not expose broken video output streams The cx25821 driver has support for one audio output channel and two video output channels. This is implemented in a very ugly and very evil way through a custom ioctl that passes the filename of a file containing the video data, which is then read by the driver itself using vfs. There are a number of problems with this: 1) it's very ugly and very evil (I can't say that often enough). 2) V4L2 supports video output, so why not use that? 3) it's very buggy, closing the filehandle through which you passed the ioctl will oops the kernel. 4) it's a nasty security leak since this allows you to load any file in the system as a video or audio source, so in theory you can output /etc/passwd to audio or video out and record & decode it on another device. Because of all these issues we no longer register those output video nodes. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 1465591d000c..6b18320ebef1 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -461,7 +461,7 @@ int cx25821_video_register(struct cx25821_dev *dev) spin_lock_init(&dev->slock); - for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) { + for (i = 0; i < VID_CHANNEL_NUM; ++i) { cx25821_init_controls(dev, i); cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper, -- cgit v1.2.3 From 31b320739b4318a04c203918310b49a55a598bde Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 14 Apr 2013 11:07:02 -0300 Subject: [media] cx25821: the audio channel was registered as a video node Skip the audio channel when registering the video nodes. This fixes a bug where that incorrectly registered 'video' node was never unregistered. Note: this bug only surfaces if the video output nodes are enabled again after the previous patch disabled them. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-core.c | 8 +++----- drivers/media/pci/cx25821/cx25821-video.c | 5 ++++- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 1884e2cc35e9..1f47422d4889 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -1051,11 +1051,9 @@ void cx25821_dev_unregister(struct cx25821_dev *dev) if (!atomic_dec_and_test(&dev->refcount)) return; - for (i = 0; i < VID_CHANNEL_NUM; i++) - cx25821_video_unregister(dev, i); - - for (i = VID_UPSTREAM_SRAM_CHANNEL_I; - i <= AUDIO_UPSTREAM_SRAM_CHANNEL_B; i++) { + for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; i++) { + if (i == SRAM_CH08) /* audio channel */ + continue; cx25821_video_unregister(dev, i); } diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 6b18320ebef1..8bf9c890883b 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -462,6 +462,9 @@ int cx25821_video_register(struct cx25821_dev *dev) spin_lock_init(&dev->slock); for (i = 0; i < VID_CHANNEL_NUM; ++i) { + if (i == SRAM_CH08) /* audio channel */ + continue; + cx25821_init_controls(dev, i); cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper, @@ -788,7 +791,7 @@ static int video_open(struct file *file) { h = list_entry(list, struct cx25821_dev, devlist); - for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) { + for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; i++) { if (h->channels[i].video_dev && h->channels[i].video_dev->minor == minor) { dev = h; -- cgit v1.2.3 From 170bd5330383ce62127ef5b6eeeab9afebd7b838 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 05:19:41 -0300 Subject: [media] cx25821: fix compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/media/pci/cx25821/cx25821-video.c: In function ‘cx25821_video_register’: drivers/media/pci/cx25821/cx25821-video.c:518:1: warning: the frame size of 1600 bytes is larger than 1024 bytes [-Wframe-larger-than=] Fixed by just making the struct video_device template static const. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 9 ++++----- drivers/media/pci/cx25821/cx25821.h | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 8bf9c890883b..4eaa67a0833b 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -161,7 +161,7 @@ int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm) struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, struct pci_dev *pci, - struct video_device *template, + const struct video_device *template, char *type) { struct video_device *vfd; @@ -447,10 +447,7 @@ void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) int cx25821_video_register(struct cx25821_dev *dev) { - int err; - int i; - - struct video_device cx25821_video_device = { + static const struct video_device cx25821_video_device = { .name = "cx25821-video", .fops = &video_fops, .minor = -1, @@ -458,6 +455,8 @@ int cx25821_video_register(struct cx25821_dev *dev) .tvnorms = CX25821_NORMS, .current_norm = V4L2_STD_NTSC_M, }; + int err; + int i; spin_lock_init(&dev->slock); diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 8a9c0c869412..85693cdf0ee1 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -610,6 +610,6 @@ extern void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel, extern void cx25821_videoioctl_unregister(struct cx25821_dev *dev); extern struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, struct pci_dev *pci, - struct video_device *template, + const struct video_device *template, char *type); #endif -- cgit v1.2.3 From ffd3c2330473f6a07f36bf3bd64f7a1158bdd759 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 05:30:48 -0300 Subject: [media] cx25821: remove bogus radio/vbi/'video-ioctl' support This device does not support radio or vbi, so remove anything referring to that. In addition, the driver created an 'video ioctl' node, which was unused and was effectively identical to the first video node. This bogus video node is now removed, leaving us with 8 video capture nodes and 2 video output nodes. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-core.c | 13 -- drivers/media/pci/cx25821/cx25821-video.c | 201 +++++++++++++----------------- drivers/media/pci/cx25821/cx25821-video.h | 1 - drivers/media/pci/cx25821/cx25821.h | 16 --- 4 files changed, 88 insertions(+), 143 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 1f47422d4889..2b38a5005d0e 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -988,17 +988,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) cx25821_video_register(dev); - /* register IOCTL device */ - dev->ioctl_dev = cx25821_vdev_init(dev, dev->pci, - &cx25821_videoioctl_template, "video"); - - if (video_register_device - (dev->ioctl_dev, VFL_TYPE_GRABBER, VIDEO_IOCTL_CH) < 0) { - cx25821_videoioctl_unregister(dev); - pr_err("%s(): Failed to register video adapter for IOCTL, so unregistering videoioctl device\n", - __func__); - } - cx25821_dev_checkrevision(dev); CX25821_INFO("setup done!\n"); @@ -1057,8 +1046,6 @@ void cx25821_dev_unregister(struct cx25821_dev *dev) cx25821_video_unregister(dev, i); } - cx25821_videoioctl_unregister(dev); - cx25821_i2c_unregister(&dev->i2c_bus[0]); cx25821_iounmap(dev); } diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 4eaa67a0833b..e785bb98d533 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -33,13 +33,10 @@ MODULE_AUTHOR("Hiep Huynh "); MODULE_LICENSE("GPL"); static unsigned int video_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET }; module_param_array(video_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); MODULE_PARM_DESC(video_nr, "video device numbers"); -MODULE_PARM_DESC(radio_nr, "radio device numbers"); static unsigned int video_debug = VIDEO_DEBUG; module_param(video_debug, int, 0644); @@ -55,9 +52,6 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num); -static const struct v4l2_file_operations video_fops; -static const struct v4l2_ioctl_ops video_ioctl_ops; - #define FORMAT_FLAGS_PACKED 0x01 struct cx25821_fmt formats[] = { @@ -411,111 +405,6 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) return handled; } -void cx25821_videoioctl_unregister(struct cx25821_dev *dev) -{ - if (dev->ioctl_dev) { - if (video_is_registered(dev->ioctl_dev)) - video_unregister_device(dev->ioctl_dev); - else - video_device_release(dev->ioctl_dev); - - dev->ioctl_dev = NULL; - } -} - -void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) -{ - cx_clear(PCI_INT_MSK, 1); - - if (dev->channels[chan_num].video_dev) { - if (video_is_registered(dev->channels[chan_num].video_dev)) - video_unregister_device( - dev->channels[chan_num].video_dev); - else - video_device_release( - dev->channels[chan_num].video_dev); - - dev->channels[chan_num].video_dev = NULL; - - btcx_riscmem_free(dev->pci, - &dev->channels[chan_num].vidq.stopper); - - pr_warn("device %d released!\n", chan_num); - } - -} - -int cx25821_video_register(struct cx25821_dev *dev) -{ - static const struct video_device cx25821_video_device = { - .name = "cx25821-video", - .fops = &video_fops, - .minor = -1, - .ioctl_ops = &video_ioctl_ops, - .tvnorms = CX25821_NORMS, - .current_norm = V4L2_STD_NTSC_M, - }; - int err; - int i; - - spin_lock_init(&dev->slock); - - for (i = 0; i < VID_CHANNEL_NUM; ++i) { - if (i == SRAM_CH08) /* audio channel */ - continue; - - cx25821_init_controls(dev, i); - - cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper, - dev->channels[i].sram_channels->dma_ctl, 0x11, 0); - - dev->channels[i].sram_channels = &cx25821_sram_channels[i]; - dev->channels[i].video_dev = NULL; - dev->channels[i].resources = 0; - - cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff); - - INIT_LIST_HEAD(&dev->channels[i].vidq.active); - INIT_LIST_HEAD(&dev->channels[i].vidq.queued); - - dev->channels[i].timeout_data.dev = dev; - dev->channels[i].timeout_data.channel = - &cx25821_sram_channels[i]; - dev->channels[i].vidq.timeout.function = cx25821_vid_timeout; - dev->channels[i].vidq.timeout.data = - (unsigned long)&dev->channels[i].timeout_data; - init_timer(&dev->channels[i].vidq.timeout); - - /* register v4l devices */ - dev->channels[i].video_dev = cx25821_vdev_init(dev, dev->pci, - &cx25821_video_device, "video"); - - err = video_register_device(dev->channels[i].video_dev, - VFL_TYPE_GRABBER, video_nr[dev->nr]); - - if (err < 0) - goto fail_unreg; - - } - - /* set PCI interrupt */ - cx_set(PCI_INT_MSK, 0xff); - - /* initial device configuration */ - mutex_lock(&dev->lock); -#ifdef TUNER_FLAG - dev->tvnorm = cx25821_video_device.current_norm; - cx25821_set_tvnorm(dev, dev->tvnorm); -#endif - mutex_unlock(&dev->lock); - - return 0; - -fail_unreg: - cx25821_video_unregister(dev, i); - return err; -} - int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) { @@ -1983,10 +1872,96 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { #endif }; -struct video_device cx25821_videoioctl_template = { - .name = "cx25821-videoioctl", +static const struct video_device cx25821_video_device = { + .name = "cx25821-video", .fops = &video_fops, + .minor = -1, .ioctl_ops = &video_ioctl_ops, .tvnorms = CX25821_NORMS, .current_norm = V4L2_STD_NTSC_M, }; + +void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) +{ + cx_clear(PCI_INT_MSK, 1); + + if (dev->channels[chan_num].video_dev) { + if (video_is_registered(dev->channels[chan_num].video_dev)) + video_unregister_device( + dev->channels[chan_num].video_dev); + else + video_device_release( + dev->channels[chan_num].video_dev); + + dev->channels[chan_num].video_dev = NULL; + + btcx_riscmem_free(dev->pci, + &dev->channels[chan_num].vidq.stopper); + + pr_warn("device %d released!\n", chan_num); + } + +} + +int cx25821_video_register(struct cx25821_dev *dev) +{ + int err; + int i; + + spin_lock_init(&dev->slock); + + for (i = 0; i < VID_CHANNEL_NUM; ++i) { + if (i == SRAM_CH08) /* audio channel */ + continue; + + cx25821_init_controls(dev, i); + + cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper, + dev->channels[i].sram_channels->dma_ctl, 0x11, 0); + + dev->channels[i].sram_channels = &cx25821_sram_channels[i]; + dev->channels[i].video_dev = NULL; + dev->channels[i].resources = 0; + + cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff); + + INIT_LIST_HEAD(&dev->channels[i].vidq.active); + INIT_LIST_HEAD(&dev->channels[i].vidq.queued); + + dev->channels[i].timeout_data.dev = dev; + dev->channels[i].timeout_data.channel = + &cx25821_sram_channels[i]; + dev->channels[i].vidq.timeout.function = cx25821_vid_timeout; + dev->channels[i].vidq.timeout.data = + (unsigned long)&dev->channels[i].timeout_data; + init_timer(&dev->channels[i].vidq.timeout); + + /* register v4l devices */ + dev->channels[i].video_dev = cx25821_vdev_init(dev, dev->pci, + &cx25821_video_device, "video"); + + err = video_register_device(dev->channels[i].video_dev, + VFL_TYPE_GRABBER, video_nr[dev->nr]); + + if (err < 0) + goto fail_unreg; + + } + + /* set PCI interrupt */ + cx_set(PCI_INT_MSK, 0xff); + + /* initial device configuration */ + mutex_lock(&dev->lock); +#ifdef TUNER_FLAG + dev->tvnorm = cx25821_video_device.current_norm; + cx25821_set_tvnorm(dev, dev->tvnorm); +#endif + mutex_unlock(&dev->lock); + + return 0; + +fail_unreg: + cx25821_video_unregister(dev, i); + return err; +} diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index 11ba5eb93677..37cb0c1b2de0 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -76,7 +76,6 @@ extern struct sram_channel *channel7; extern struct sram_channel *channel9; extern struct sram_channel *channel10; extern struct sram_channel *channel11; -extern struct video_device cx25821_videoioctl_template; /* extern const u32 *ctrl_classes[]; */ extern unsigned int vid_limit; diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 85693cdf0ee1..04c3cb0b6f42 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -80,7 +80,6 @@ #define RESOURCE_VIDEO9 512 #define RESOURCE_VIDEO10 1024 #define RESOURCE_VIDEO11 2048 -#define RESOURCE_VIDEO_IOCTL 4096 #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ @@ -125,7 +124,6 @@ struct cx25821_tvnorm { struct cx25821_fh { struct cx25821_dev *dev; enum v4l2_buf_type type; - int radio; u32 resources; enum v4l2_priority prio; @@ -139,10 +137,7 @@ struct cx25821_fh { struct cx25821_fmt *fmt; unsigned int width, height; int channel_id; - - /* vbi capture */ struct videobuf_queue vidq; - struct videobuf_queue vbiq; /* H264 Encoder specifics ONLY */ struct videobuf_queue mpegq; @@ -153,7 +148,6 @@ enum cx25821_itype { CX25821_VMUX_COMPOSITE = 1, CX25821_VMUX_SVIDEO, CX25821_VMUX_DEBUG, - CX25821_RADIO, }; enum cx25821_src_sel_type { @@ -191,9 +185,7 @@ struct cx25821_board { enum port portb; enum port portc; unsigned int tuner_type; - unsigned int radio_type; unsigned char tuner_addr; - unsigned char radio_addr; u32 clk_freq; struct cx25821_input input[CX25821_NR_INPUT]; @@ -295,9 +287,6 @@ struct cx25821_dev { v4l2_std_id tvnorm; unsigned int tuner_type; unsigned char tuner_addr; - unsigned int radio_type; - unsigned char radio_addr; - unsigned int has_radio; unsigned int videc_type; unsigned char videc_addr; unsigned short _max_num_decoders; @@ -326,9 +315,6 @@ struct cx25821_dev { /* V4l */ u32 freq; - struct video_device *vbi_dev; - struct video_device *radio_dev; - struct video_device *ioctl_dev; spinlock_t slock; @@ -467,7 +453,6 @@ extern struct cx25821_subid cx25821_subids[]; #define VID_UPSTREAM_SRAM_CHANNEL_I SRAM_CH09 #define VID_UPSTREAM_SRAM_CHANNEL_J SRAM_CH10 #define AUDIO_UPSTREAM_SRAM_CHANNEL_B SRAM_CH11 -#define VIDEO_IOCTL_CH 11 struct sram_channel { char *name; @@ -607,7 +592,6 @@ extern int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev, unsigned int bpl, u32 risc); extern void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel, u32 format); -extern void cx25821_videoioctl_unregister(struct cx25821_dev *dev); extern struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, struct pci_dev *pci, const struct video_device *template, -- cgit v1.2.3 From 18c73af6961c528fe5ce95eb510ef63582d47014 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 05:50:18 -0300 Subject: [media] cx25821: remove unused fields, ioctls Do some spring cleaning: - there are no board defines with tuners, so remove bogus tuner support. - tv standard handling has nothing to do with tuners, so keep that. - replace the deprecated current_norm by g_std. - querystd isn't implemented, so remove the ioctl. - remove a bunch of unused fields in cx25821.h Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-cards.c | 1 - drivers/media/pci/cx25821/cx25821-video.c | 130 +++--------------------------- drivers/media/pci/cx25821/cx25821-video.h | 13 --- drivers/media/pci/cx25821/cx25821.h | 18 ----- 4 files changed, 10 insertions(+), 152 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-cards.c b/drivers/media/pci/cx25821/cx25821-cards.c index 99988c988095..c09ec68460e4 100644 --- a/drivers/media/pci/cx25821/cx25821-cards.c +++ b/drivers/media/pci/cx25821/cx25821-cards.c @@ -30,7 +30,6 @@ #include #include "cx25821.h" -#include "tuner-xc2028.h" /* board config info */ diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index e785bb98d533..8ff8fc218f38 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -138,7 +138,6 @@ void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, pr_err("%s: %d buffers handled (should be 1)\n", __func__, bc); } -#ifdef TUNER_FLAG int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm) { dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", @@ -151,7 +150,6 @@ int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm) return 0; } -#endif struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, struct pci_dev *pci, @@ -1036,8 +1034,6 @@ int cx25821_vidioc_querycap(struct file *file, void *priv, cap->version = CX25821_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if (UNSET != dev->tuner_type) - cap->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -1093,7 +1089,14 @@ int cx25821_vidioc_s_priority(struct file *file, void *f, prio); } -#ifdef TUNER_FLAG +int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms) +{ + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + + *tvnorms = dev->tvnorm; + return 0; +} + int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) { struct cx25821_fh *fh = priv; @@ -1120,7 +1123,6 @@ int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) return 0; } -#endif int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i) { @@ -1189,57 +1191,6 @@ int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) return 0; } -#ifdef TUNER_FLAG -int cx25821_vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = fh->dev; - - f->frequency = dev->freq; - - cx25821_call_all(dev, tuner, g_frequency, f); - - return 0; -} - -int cx25821_set_freq(struct cx25821_dev *dev, const struct v4l2_frequency *f) -{ - mutex_lock(&dev->lock); - dev->freq = f->frequency; - - cx25821_call_all(dev, tuner, s_frequency, f); - - /* When changing channels it is required to reset TVAUDIO */ - msleep(10); - - mutex_unlock(&dev->lock); - - return 0; -} - -int cx25821_vidioc_s_frequency(struct file *file, void *priv, - const struct v4l2_frequency *f) -{ - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev; - int err; - - if (fh) { - dev = fh->dev; - err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, - fh->prio); - if (0 != err) - return err; - } else { - pr_err("Invalid fh pointer!\n"); - return -EINVAL; - } - - return cx25821_set_freq(dev, f); -} -#endif - #ifdef CONFIG_VIDEO_ADV_DEBUG int cx25821_vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) @@ -1269,48 +1220,6 @@ int cx25821_vidioc_s_register(struct file *file, void *fh, #endif -#ifdef TUNER_FLAG -int cx25821_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - - if (unlikely(UNSET == dev->tuner_type)) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; - - t->signal = 0xffff; /* LOCKED */ - return 0; -} - -int cx25821_vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - struct cx25821_fh *fh = priv; - int err; - - if (fh) { - err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, - fh->prio); - if (0 != err) - return err; - } - - dprintk(1, "%s()\n", __func__); - if (UNSET == dev->tuner_type) - return -EINVAL; - if (0 != t->index) - return -EINVAL; - - return 0; -} - -#endif /*****************************************************************************/ static const struct v4l2_queryctrl no_ctl = { .name = "42", @@ -1523,14 +1432,6 @@ int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) return -EINVAL; } -int cx25821_vidioc_querystd(struct file *file, void *priv, v4l2_std_id * norm) -{ - /* medusa does not support video standard sensing of current input */ - *norm = CX25821_NORMS; - - return 0; -} - int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm) { if (tvnorm == V4L2_STD_PAL_BG) { @@ -1842,10 +1743,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_querybuf = cx25821_vidioc_querybuf, .vidioc_qbuf = cx25821_vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, -#ifdef TUNER_FLAG + .vidioc_g_std = cx25821_vidioc_g_std, .vidioc_s_std = cx25821_vidioc_s_std, - .vidioc_querystd = cx25821_vidioc_querystd, -#endif .vidioc_cropcap = cx25821_vidioc_cropcap, .vidioc_s_crop = cx25821_vidioc_s_crop, .vidioc_g_crop = cx25821_vidioc_g_crop, @@ -1860,12 +1759,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_log_status = vidioc_log_status, .vidioc_g_priority = cx25821_vidioc_g_priority, .vidioc_s_priority = cx25821_vidioc_s_priority, -#ifdef TUNER_FLAG - .vidioc_g_tuner = cx25821_vidioc_g_tuner, - .vidioc_s_tuner = cx25821_vidioc_s_tuner, - .vidioc_g_frequency = cx25821_vidioc_g_frequency, - .vidioc_s_frequency = cx25821_vidioc_s_frequency, -#endif #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = cx25821_vidioc_g_register, .vidioc_s_register = cx25821_vidioc_s_register, @@ -1878,7 +1771,6 @@ static const struct video_device cx25821_video_device = { .minor = -1, .ioctl_ops = &video_ioctl_ops, .tvnorms = CX25821_NORMS, - .current_norm = V4L2_STD_NTSC_M, }; void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) @@ -1953,10 +1845,8 @@ int cx25821_video_register(struct cx25821_dev *dev) /* initial device configuration */ mutex_lock(&dev->lock); -#ifdef TUNER_FLAG - dev->tvnorm = cx25821_video_device.current_norm; + dev->tvnorm = V4L2_STD_NTSC_M, cx25821_set_tvnorm(dev, dev->tvnorm); -#endif mutex_unlock(&dev->lock); return 0; diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index 37cb0c1b2de0..eb12e35d6de1 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -40,8 +40,6 @@ #include #include -#define TUNER_FLAG - #define VIDEO_DEBUG 0 #define dprintk(level, fmt, arg...) \ @@ -88,9 +86,7 @@ extern struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM]; extern void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, u32 count); -#ifdef TUNER_FLAG extern int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm); -#endif extern int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bit); @@ -146,19 +142,10 @@ extern int cx25821_vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctl); extern int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); -extern int cx25821_vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f); -extern int cx25821_set_freq(struct cx25821_dev *dev, const struct v4l2_frequency *f); -extern int cx25821_vidioc_s_frequency(struct file *file, void *priv, - const struct v4l2_frequency *f); extern int cx25821_vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg); extern int cx25821_vidioc_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg); -extern int cx25821_vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t); -extern int cx25821_vidioc_s_tuner(struct file *file, void *priv, - const struct v4l2_tuner *t); extern int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm); extern int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm); diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 04c3cb0b6f42..fdeecdf09ef5 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -33,7 +33,6 @@ #include #include -#include #include #include #include @@ -43,7 +42,6 @@ #include "cx25821-medusa-reg.h" #include "cx25821-sram.h" #include "cx25821-audio.h" -#include "media/cx2341x.h" #include #include @@ -184,8 +182,6 @@ struct cx25821_board { enum port porta; enum port portb; enum port portc; - unsigned int tuner_type; - unsigned char tuner_addr; u32 clk_freq; struct cx25821_input input[CX25821_NR_INPUT]; @@ -283,12 +279,7 @@ struct cx25821_dev { /* Analog video */ u32 resources; unsigned int input; - u32 tvaudio; v4l2_std_id tvnorm; - unsigned int tuner_type; - unsigned char tuner_addr; - unsigned int videc_type; - unsigned char videc_addr; unsigned short _max_num_decoders; /* Analog Audio Upstream */ @@ -314,8 +305,6 @@ struct cx25821_dev { char *_audiofilename; /* V4l */ - u32 freq; - spinlock_t slock; /* Video Upstream */ @@ -363,13 +352,6 @@ struct cx25821_dev { char *_filename_ch2; char *_defaultname_ch2; - /* MPEG Encoder ONLY settings */ - u32 cx23417_mailbox; - struct cx2341x_mpeg_params mpeg_params; - struct video_device *v4l_device; - atomic_t v4l_reader_count; - struct cx25821_tvnorm encodernorm; - u32 upstream_riscbuf_size; u32 upstream_databuf_size; u32 upstream_riscbuf_size_ch2; -- cgit v1.2.3 From 3dd473ca58838f1dd93e915cfa7a5c150186bb0f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 06:06:18 -0300 Subject: [media] cx25821: fix log_status, querycap log_status shouldn't print LOG STATUS lines, the core does that already. Fix querycap version number and add device_caps support. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 8ff8fc218f38..7cd888581f9e 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -923,21 +923,14 @@ static int vidioc_log_status(struct file *file, void *priv) { struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; struct cx25821_fh *fh = priv; - char name[32 + 2]; - - struct sram_channel *sram_ch = dev->channels[fh->channel_id] - .sram_channels; + struct sram_channel *sram_ch = + dev->channels[fh->channel_id].sram_channels; u32 tmp = 0; - snprintf(name, sizeof(name), "%s/2", dev->name); - pr_info("%s/2: ============ START LOG STATUS ============\n", - dev->name); cx25821_call_all(dev, core, log_status); tmp = cx_read(sram_ch->dma_ctl); pr_info("Video input 0 is %s\n", (tmp & 0x11) ? "streaming" : "stopped"); - pr_info("%s/2: ============= END LOG STATUS =============\n", - dev->name); return 0; } @@ -1027,13 +1020,19 @@ int cx25821_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + struct cx25821_fh *fh = priv; + const u32 cap_input = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT; strcpy(cap->driver, "cx25821"); strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->version = CX25821_VERSION_CODE; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; + if (fh->channel_id >= VID_CHANNEL_NUM) + cap->device_caps = cap_output; + else + cap->device_caps = cap_input; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } -- cgit v1.2.3 From bfef0d35e57c08dff295e3203d30f9ca4077415a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 06:28:54 -0300 Subject: [media] cx25821: make cx25821_sram_channels const And get rid of the channel0-11 external pointers and two more unused fields in cx25821.h. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-alsa.c | 2 +- drivers/media/pci/cx25821/cx25821-audio-upstream.c | 22 ++++++++--------- drivers/media/pci/cx25821/cx25821-core.c | 28 +++++----------------- .../media/pci/cx25821/cx25821-video-upstream-ch2.c | 20 ++++++++-------- drivers/media/pci/cx25821/cx25821-video-upstream.c | 22 ++++++++--------- drivers/media/pci/cx25821/cx25821-video.c | 14 ++++++----- drivers/media/pci/cx25821/cx25821-video.h | 15 +----------- drivers/media/pci/cx25821/cx25821.h | 26 +++++++------------- 8 files changed, 57 insertions(+), 92 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 1858a45dd081..b3cac75a4891 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -151,7 +151,7 @@ static int _cx25821_start_audio_dma(struct cx25821_audio_dev *chip) { struct cx25821_audio_buffer *buf = chip->buf; struct cx25821_dev *dev = chip->dev; - struct sram_channel *audio_ch = + const struct sram_channel *audio_ch = &cx25821_sram_channels[AUDIO_SRAM_CHANNEL]; u32 tmp = 0; diff --git a/drivers/media/pci/cx25821/cx25821-audio-upstream.c b/drivers/media/pci/cx25821/cx25821-audio-upstream.c index ea973202a66c..b9be535e32b8 100644 --- a/drivers/media/pci/cx25821/cx25821-audio-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-audio-upstream.c @@ -45,7 +45,7 @@ static int _intr_msk = FLD_AUD_SRC_RISCI1 | FLD_AUD_SRC_OF | FLD_AUD_SRC_SYNC | FLD_AUD_SRC_OPC_ERR; static int cx25821_sram_channel_setup_upstream_audio(struct cx25821_dev *dev, - struct sram_channel *ch, + const struct sram_channel *ch, unsigned int bpl, u32 risc) { unsigned int i, lines; @@ -106,7 +106,7 @@ static __le32 *cx25821_risc_field_upstream_audio(struct cx25821_dev *dev, int fifo_enable) { unsigned int line; - struct sram_channel *sram_ch = + const struct sram_channel *sram_ch = dev->channels[dev->_audio_upstream_channel].sram_channels; int offset = 0; @@ -215,7 +215,7 @@ static void cx25821_free_memory_audio(struct cx25821_dev *dev) void cx25821_stop_upstream_audio(struct cx25821_dev *dev) { - struct sram_channel *sram_ch = + const struct sram_channel *sram_ch = dev->channels[AUDIO_UPSTREAM_SRAM_CHANNEL_B].sram_channels; u32 tmp = 0; @@ -257,7 +257,7 @@ void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev) } static int cx25821_get_audio_data(struct cx25821_dev *dev, - struct sram_channel *sram_ch) + const struct sram_channel *sram_ch) { struct file *myfile; int frame_index_temp = dev->_audioframe_index; @@ -352,7 +352,7 @@ static void cx25821_audioups_handler(struct work_struct *work) } static int cx25821_openfile_audio(struct cx25821_dev *dev, - struct sram_channel *sram_ch) + const struct sram_channel *sram_ch) { struct file *myfile; int i = 0, j = 0; @@ -433,7 +433,7 @@ static int cx25821_openfile_audio(struct cx25821_dev *dev, } static int cx25821_audio_upstream_buffer_prepare(struct cx25821_dev *dev, - struct sram_channel *sram_ch, + const struct sram_channel *sram_ch, int bpl) { int ret = 0; @@ -495,7 +495,7 @@ static int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num, { int i = 0; u32 int_msk_tmp; - struct sram_channel *channel = dev->channels[chan_num].sram_channels; + const struct sram_channel *channel = dev->channels[chan_num].sram_channels; dma_addr_t risc_phys_jump_addr; __le32 *rp; @@ -587,7 +587,7 @@ static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id) struct cx25821_dev *dev = dev_id; u32 audio_status; int handled = 0; - struct sram_channel *sram_ch; + const struct sram_channel *sram_ch; if (!dev) return -1; @@ -611,7 +611,7 @@ static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id) } static void cx25821_wait_fifo_enable(struct cx25821_dev *dev, - struct sram_channel *sram_ch) + const struct sram_channel *sram_ch) { int count = 0; u32 tmp; @@ -635,7 +635,7 @@ static void cx25821_wait_fifo_enable(struct cx25821_dev *dev, } static int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev, - struct sram_channel *sram_ch) + const struct sram_channel *sram_ch) { u32 tmp = 0; int err = 0; @@ -699,7 +699,7 @@ fail_irq: int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) { - struct sram_channel *sram_ch; + const struct sram_channel *sram_ch; int err = 0; if (dev->_audio_is_running) { diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 2b38a5005d0e..48faf6fc273d 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -48,7 +48,7 @@ EXPORT_SYMBOL(cx25821_devlist_mutex); LIST_HEAD(cx25821_devlist); EXPORT_SYMBOL(cx25821_devlist); -struct sram_channel cx25821_sram_channels[] = { +const struct sram_channel cx25821_sram_channels[] = { [SRAM_CH00] = { .i = SRAM_CH00, .name = "VID A", @@ -317,20 +317,6 @@ struct sram_channel cx25821_sram_channels[] = { }; EXPORT_SYMBOL(cx25821_sram_channels); -struct sram_channel *channel0 = &cx25821_sram_channels[SRAM_CH00]; -struct sram_channel *channel1 = &cx25821_sram_channels[SRAM_CH01]; -struct sram_channel *channel2 = &cx25821_sram_channels[SRAM_CH02]; -struct sram_channel *channel3 = &cx25821_sram_channels[SRAM_CH03]; -struct sram_channel *channel4 = &cx25821_sram_channels[SRAM_CH04]; -struct sram_channel *channel5 = &cx25821_sram_channels[SRAM_CH05]; -struct sram_channel *channel6 = &cx25821_sram_channels[SRAM_CH06]; -struct sram_channel *channel7 = &cx25821_sram_channels[SRAM_CH07]; -struct sram_channel *channel9 = &cx25821_sram_channels[SRAM_CH09]; -struct sram_channel *channel10 = &cx25821_sram_channels[SRAM_CH10]; -struct sram_channel *channel11 = &cx25821_sram_channels[SRAM_CH11]; - -struct cx25821_dmaqueue mpegq; - static int cx25821_risc_decode(u32 risc) { static const char * const instr[16] = { @@ -457,7 +443,7 @@ static void cx25821_registers_init(struct cx25821_dev *dev) } int cx25821_sram_channel_setup(struct cx25821_dev *dev, - struct sram_channel *ch, + const struct sram_channel *ch, unsigned int bpl, u32 risc) { unsigned int i, lines; @@ -523,10 +509,9 @@ int cx25821_sram_channel_setup(struct cx25821_dev *dev, return 0; } -EXPORT_SYMBOL(cx25821_sram_channel_setup); int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev, - struct sram_channel *ch, + const struct sram_channel *ch, unsigned int bpl, u32 risc) { unsigned int i, lines; @@ -592,7 +577,7 @@ int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev, } EXPORT_SYMBOL(cx25821_sram_channel_setup_audio); -void cx25821_sram_channel_dump(struct cx25821_dev *dev, struct sram_channel *ch) +void cx25821_sram_channel_dump(struct cx25821_dev *dev, const struct sram_channel *ch) { static char *name[] = { "init risc lo", @@ -652,10 +637,9 @@ void cx25821_sram_channel_dump(struct cx25821_dev *dev, struct sram_channel *ch) pr_warn(" : cnt2_reg: 0x%08x\n", cx_read(ch->cnt2_reg)); } -EXPORT_SYMBOL(cx25821_sram_channel_dump); void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev, - struct sram_channel *ch) + const struct sram_channel *ch) { static const char * const name[] = { "init risc lo", @@ -803,7 +787,7 @@ void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select, } static void cx25821_set_vip_mode(struct cx25821_dev *dev, - struct sram_channel *ch) + const struct sram_channel *ch) { cx_write(ch->pix_frmt, PIXEL_FRMT_422); cx_write(ch->vip_ctl, PIXEL_ENGINE_VIP1); diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c index cf2723c7197f..2381bdce99fd 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c @@ -83,7 +83,7 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev, int fifo_enable, int field_type) { unsigned int line, i; - struct sram_channel *sram_ch = + const struct sram_channel *sram_ch = dev->channels[dev->_channel2_upstream_select].sram_channels; int dist_betwn_starts = bpl * 2; @@ -201,7 +201,7 @@ static int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev) { - struct sram_channel *sram_ch = + const struct sram_channel *sram_ch = dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels; u32 tmp = 0; @@ -257,7 +257,7 @@ void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev) } static int cx25821_get_frame_ch2(struct cx25821_dev *dev, - struct sram_channel *sram_ch) + const struct sram_channel *sram_ch) { struct file *myfile; int frame_index_temp = dev->_frame_index_ch2; @@ -363,7 +363,7 @@ static void cx25821_vidups_handler_ch2(struct work_struct *work) } static int cx25821_openfile_ch2(struct cx25821_dev *dev, - struct sram_channel *sram_ch) + const struct sram_channel *sram_ch) { struct file *myfile; int i = 0, j = 0; @@ -445,7 +445,7 @@ static int cx25821_openfile_ch2(struct cx25821_dev *dev, } static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev, - struct sram_channel *sram_ch, + const struct sram_channel *sram_ch, int bpl) { int ret = 0; @@ -515,7 +515,7 @@ static int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, u32 status) { u32 int_msk_tmp; - struct sram_channel *channel = dev->channels[chan_num].sram_channels; + const struct sram_channel *channel = dev->channels[chan_num].sram_channels; int singlefield_lines = NTSC_FIELD_HEIGHT; int line_size_in_bytes = Y422_LINE_SZ; int odd_risc_prog_size = 0; @@ -594,7 +594,7 @@ static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id) u32 vid_status; int handled = 0; int channel_num = 0; - struct sram_channel *sram_ch; + const struct sram_channel *sram_ch; if (!dev) return -1; @@ -618,7 +618,7 @@ static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id) } static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev, - struct sram_channel *ch, int pix_format) + const struct sram_channel *ch, int pix_format) { int width = WIDTH_D1; int height = dev->_lines_count_ch2; @@ -652,7 +652,7 @@ static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev, } static int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev, - struct sram_channel *sram_ch) + const struct sram_channel *sram_ch) { u32 tmp = 0; int err = 0; @@ -706,7 +706,7 @@ fail_irq: int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, int pixel_format) { - struct sram_channel *sram_ch; + const struct sram_channel *sram_ch; u32 tmp; int err = 0; int data_frame_size = 0; diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c index 7fc97110d973..223aae77c7eb 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c @@ -44,7 +44,7 @@ static int _intr_msk = FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | FLD_VID_SRC_OPC_ERR; int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev, - struct sram_channel *ch, + const struct sram_channel *ch, unsigned int bpl, u32 risc) { unsigned int i, lines; @@ -135,7 +135,7 @@ static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp, int fifo_enable, int field_type) { unsigned int line, i; - struct sram_channel *sram_ch = + const struct sram_channel *sram_ch = dev->channels[dev->_channel_upstream_select].sram_channels; int dist_betwn_starts = bpl * 2; @@ -247,7 +247,7 @@ static int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev) { - struct sram_channel *sram_ch = + const struct sram_channel *sram_ch = dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels; u32 tmp = 0; @@ -301,7 +301,7 @@ void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev) } static int cx25821_get_frame(struct cx25821_dev *dev, - struct sram_channel *sram_ch) + const struct sram_channel *sram_ch) { struct file *myfile; int frame_index_temp = dev->_frame_index; @@ -407,7 +407,7 @@ static void cx25821_vidups_handler(struct work_struct *work) } static int cx25821_openfile(struct cx25821_dev *dev, - struct sram_channel *sram_ch) + const struct sram_channel *sram_ch) { struct file *myfile; int i = 0, j = 0; @@ -489,7 +489,7 @@ static int cx25821_openfile(struct cx25821_dev *dev, } static int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev, - struct sram_channel *sram_ch, + const struct sram_channel *sram_ch, int bpl) { int ret = 0; @@ -555,7 +555,7 @@ static int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num, u32 status) { u32 int_msk_tmp; - struct sram_channel *channel = dev->channels[chan_num].sram_channels; + const struct sram_channel *channel = dev->channels[chan_num].sram_channels; int singlefield_lines = NTSC_FIELD_HEIGHT; int line_size_in_bytes = Y422_LINE_SZ; int odd_risc_prog_size = 0; @@ -643,7 +643,7 @@ static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id) u32 vid_status; int handled = 0; int channel_num = 0; - struct sram_channel *sram_ch; + const struct sram_channel *sram_ch; if (!dev) return -1; @@ -668,7 +668,7 @@ static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id) } static void cx25821_set_pixelengine(struct cx25821_dev *dev, - struct sram_channel *ch, + const struct sram_channel *ch, int pix_format) { int width = WIDTH_D1; @@ -701,7 +701,7 @@ static void cx25821_set_pixelengine(struct cx25821_dev *dev, } static int cx25821_start_video_dma_upstream(struct cx25821_dev *dev, - struct sram_channel *sram_ch) + const struct sram_channel *sram_ch) { u32 tmp = 0; int err = 0; @@ -755,7 +755,7 @@ fail_irq: int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, int pixel_format) { - struct sram_channel *sram_ch; + const struct sram_channel *sram_ch; u32 tmp; int err = 0; int data_frame_size = 0; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 7cd888581f9e..c418e0d38c24 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -258,7 +258,7 @@ int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input) int cx25821_start_video_dma(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, struct cx25821_buffer *buf, - struct sram_channel *channel) + const struct sram_channel *channel) { int tmp = 0; @@ -285,7 +285,7 @@ int cx25821_start_video_dma(struct cx25821_dev *dev, static int cx25821_restart_video_queue(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, - struct sram_channel *channel) + const struct sram_channel *channel) { struct cx25821_buffer *buf, *prev; struct list_head *item; @@ -338,7 +338,7 @@ static void cx25821_vid_timeout(unsigned long data) { struct cx25821_data *timeout_data = (struct cx25821_data *)data; struct cx25821_dev *dev = timeout_data->dev; - struct sram_channel *channel = timeout_data->channel; + const struct sram_channel *channel = timeout_data->channel; struct cx25821_dmaqueue *q = &dev->channels[channel->i].vidq; struct cx25821_buffer *buf; unsigned long flags; @@ -365,7 +365,7 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) u32 count = 0; int handled = 0; u32 mask; - struct sram_channel *channel = dev->channels[chan_num].sram_channels; + const struct sram_channel *channel = dev->channels[chan_num].sram_channels; mask = cx_read(channel->int_msk); if (0 == (status & mask)) @@ -787,9 +787,11 @@ static int video_release(struct file *file) { struct cx25821_fh *fh = file->private_data; struct cx25821_dev *dev = fh->dev; + const struct sram_channel *sram_ch = + dev->channels[0].sram_channels; /* stop the risc engine and fifo */ - cx_write(channel0->dma_ctl, 0); /* FIFO and RISC disable */ + cx_write(sram_ch->dma_ctl, 0); /* FIFO and RISC disable */ /* stop video capture */ if (cx25821_res_check(fh, RESOURCE_VIDEO0)) { @@ -923,7 +925,7 @@ static int vidioc_log_status(struct file *file, void *priv) { struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; struct cx25821_fh *fh = priv; - struct sram_channel *sram_ch = + const struct sram_channel *sram_ch = dev->channels[fh->channel_id].sram_channels; u32 tmp = 0; diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index eb12e35d6de1..505b7f0b45b4 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -63,19 +63,6 @@ do { \ #define MEDUSA_READ 910 #define MEDUSA_WRITE 911 -extern struct sram_channel *channel0; -extern struct sram_channel *channel1; -extern struct sram_channel *channel2; -extern struct sram_channel *channel3; -extern struct sram_channel *channel4; -extern struct sram_channel *channel5; -extern struct sram_channel *channel6; -extern struct sram_channel *channel7; -extern struct sram_channel *channel9; -extern struct sram_channel *channel10; -extern struct sram_channel *channel11; -/* extern const u32 *ctrl_classes[]; */ - extern unsigned int vid_limit; #define FORMAT_FLAGS_PACKED 0x01 @@ -98,7 +85,7 @@ extern int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input); extern int cx25821_start_video_dma(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, struct cx25821_buffer *buf, - struct sram_channel *channel); + const struct sram_channel *channel); extern int cx25821_set_scale(struct cx25821_dev *dev, unsigned int width, unsigned int height, enum v4l2_field field); diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index fdeecdf09ef5..d7e71f46defc 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -126,20 +126,11 @@ struct cx25821_fh { enum v4l2_priority prio; - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip *clips; - unsigned int nclips; - /* video capture */ struct cx25821_fmt *fmt; unsigned int width, height; int channel_id; struct videobuf_queue vidq; - - /* H264 Encoder specifics ONLY */ - struct videobuf_queue mpegq; - atomic_t v4l_reading; }; enum cx25821_itype { @@ -222,7 +213,7 @@ struct cx25821_dmaqueue { struct cx25821_data { struct cx25821_dev *dev; - struct sram_channel *channel; + const struct sram_channel *channel; }; struct cx25821_channel { @@ -237,7 +228,7 @@ struct cx25821_channel { struct video_device *video_dev; struct cx25821_dmaqueue vidq; - struct sram_channel *sram_channels; + const struct sram_channel *sram_channels; struct mutex lock; int resources; @@ -470,7 +461,8 @@ struct sram_channel { u32 jumponly; u32 irq_bit; }; -extern struct sram_channel cx25821_sram_channels[]; + +extern const struct sram_channel cx25821_sram_channels[]; #define STATUS_SUCCESS 0 #define STATUS_UNSUCCESSFUL -1 @@ -518,7 +510,7 @@ extern int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder); extern int cx25821_sram_channel_setup(struct cx25821_dev *dev, - struct sram_channel *ch, unsigned int bpl, + const struct sram_channel *ch, unsigned int bpl, u32 risc); extern int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, @@ -537,16 +529,16 @@ extern void cx25821_free_buffer(struct videobuf_queue *q, extern int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, u32 reg, u32 mask, u32 value); extern void cx25821_sram_channel_dump(struct cx25821_dev *dev, - struct sram_channel *ch); + const struct sram_channel *ch); extern void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev, - struct sram_channel *ch); + const struct sram_channel *ch); extern struct cx25821_dev *cx25821_dev_get(struct pci_dev *pci); extern void cx25821_print_irqbits(char *name, char *tag, char **strings, int len, u32 bits, u32 mask); extern void cx25821_dev_unregister(struct cx25821_dev *dev); extern int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev, - struct sram_channel *ch, + const struct sram_channel *ch, unsigned int bpl, u32 risc); extern int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, @@ -570,7 +562,7 @@ extern void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev); extern void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev); extern void cx25821_stop_upstream_audio(struct cx25821_dev *dev); extern int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev, - struct sram_channel *ch, + const struct sram_channel *ch, unsigned int bpl, u32 risc); extern void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel, u32 format); -- cgit v1.2.3 From a8f35ce3d6f5b776463f03403e0319c2415401f7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 07:07:40 -0300 Subject: [media] cx25821: remove unnecessary global devlist This device list is not necessary. The kernel already has all that information, so just use that instead. Also remove a bogus refcount and some dead 'private_free' code in the alsa driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-alsa.c | 79 ++++++++++--------------------- drivers/media/pci/cx25821/cx25821-core.c | 21 +------- drivers/media/pci/cx25821/cx25821-video.c | 38 ++++----------- drivers/media/pci/cx25821/cx25821.h | 9 ++-- 4 files changed, 41 insertions(+), 106 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index b3cac75a4891..81361c26c54e 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -59,7 +59,6 @@ do { \ Data type declarations - Can be moded to a header file later ****************************************************************************/ -static struct snd_card *snd_cx25821_cards[SNDRV_CARDS]; static int devno; struct cx25821_audio_buffer { @@ -626,34 +625,6 @@ static DEFINE_PCI_DEVICE_TABLE(cx25821_audio_pci_tbl) = { MODULE_DEVICE_TABLE(pci, cx25821_audio_pci_tbl); -/* - * Not used in the function snd_cx25821_dev_free so removing - * from the file. - */ -/* -static int snd_cx25821_free(struct cx25821_audio_dev *chip) -{ - if (chip->irq >= 0) - free_irq(chip->irq, chip); - - cx25821_dev_unregister(chip->dev); - pci_disable_device(chip->pci); - - return 0; -} -*/ - -/* - * Component Destructor - */ -static void snd_cx25821_dev_free(struct snd_card *card) -{ - struct cx25821_audio_dev *chip = card->private_data; - - /* snd_cx25821_free(chip); */ - snd_card_free(chip->card); -} - /* * Alsa Constructor - Component probe */ @@ -685,7 +656,6 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev) strcpy(card->driver, "cx25821"); /* Card "creation" */ - card->private_free = snd_cx25821_dev_free; chip = card->private_data; spin_lock_init(&chip->reg_lock); @@ -729,8 +699,7 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev) goto error; } - snd_cx25821_cards[devno] = card; - + dev->card = card; devno++; return 0; @@ -742,9 +711,31 @@ error: /**************************************************************************** LINUX MODULE INIT ****************************************************************************/ + +static int cx25821_alsa_exit_callback(struct device *dev, void *data) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); + struct cx25821_dev *cxdev = get_cx25821(v4l2_dev); + + snd_card_free(cxdev->card); + return 0; +} + static void cx25821_audio_fini(void) { - snd_card_free(snd_cx25821_cards[0]); + struct device_driver *drv = driver_find("cx25821", &pci_bus_type); + int ret; + + ret = driver_for_each_device(drv, NULL, NULL, cx25821_alsa_exit_callback); +} + +static int cx25821_alsa_init_callback(struct device *dev, void *data) +{ + struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); + struct cx25821_dev *cxdev = get_cx25821(v4l2_dev); + + cx25821_audio_initdev(cxdev); + return 0; } /* @@ -756,29 +747,11 @@ static void cx25821_audio_fini(void) */ static int cx25821_alsa_init(void) { - struct cx25821_dev *dev = NULL; - struct list_head *list; + struct device_driver *drv = driver_find("cx25821", &pci_bus_type); - mutex_lock(&cx25821_devlist_mutex); - list_for_each(list, &cx25821_devlist) { - dev = list_entry(list, struct cx25821_dev, devlist); - cx25821_audio_initdev(dev); - } - mutex_unlock(&cx25821_devlist_mutex); - - if (dev == NULL) - pr_info("ERROR ALSA: no cx25821 cards found\n"); - - return 0; + return driver_for_each_device(drv, NULL, NULL, cx25821_alsa_init_callback); } late_initcall(cx25821_alsa_init); module_exit(cx25821_audio_fini); - -/* ----------------------------------------------------------- */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 48faf6fc273d..6205ade04a97 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -41,13 +41,6 @@ static unsigned int card[] = {[0 ... (CX25821_MAXBOARDS - 1)] = UNSET }; module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card, "card type"); -static unsigned int cx25821_devcount; - -DEFINE_MUTEX(cx25821_devlist_mutex); -EXPORT_SYMBOL(cx25821_devlist_mutex); -LIST_HEAD(cx25821_devlist); -EXPORT_SYMBOL(cx25821_devlist); - const struct sram_channel cx25821_sram_channels[] = { [SRAM_CH00] = { .i = SRAM_CH00, @@ -871,6 +864,7 @@ static void cx25821_iounmap(struct cx25821_dev *dev) static int cx25821_dev_setup(struct cx25821_dev *dev) { + static unsigned int cx25821_devcount; int i; pr_info("\n***********************************\n"); @@ -879,15 +873,9 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) mutex_init(&dev->lock); - atomic_inc(&dev->refcount); - dev->nr = ++cx25821_devcount; sprintf(dev->name, "cx25821[%d]", dev->nr); - mutex_lock(&cx25821_devlist_mutex); - list_add_tail(&dev->devlist, &cx25821_devlist); - mutex_unlock(&cx25821_devlist_mutex); - if (dev->pci->device != 0x8210) { pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n", __func__, dev->pci->device); @@ -1021,9 +1009,6 @@ void cx25821_dev_unregister(struct cx25821_dev *dev) release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0)); - if (!atomic_dec_and_test(&dev->refcount)) - return; - for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; i++) { if (i == SRAM_CH08) /* audio channel */ continue; @@ -1414,10 +1399,6 @@ static void cx25821_finidev(struct pci_dev *pci_dev) if (pci_dev->irq) free_irq(pci_dev->irq, dev); - mutex_lock(&cx25821_devlist_mutex); - list_del(&dev->devlist); - mutex_unlock(&cx25821_devlist_mutex); - cx25821_dev_unregister(dev); v4l2_device_unregister(v4l2_dev); kfree(dev); diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index c418e0d38c24..a9aa09651cab 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -654,45 +654,28 @@ static struct videobuf_queue_ops cx25821_video_qops = { static int video_open(struct file *file) { struct video_device *vdev = video_devdata(file); - struct cx25821_dev *h, *dev = video_drvdata(file); + struct cx25821_dev *dev = video_drvdata(file); struct cx25821_fh *fh; - struct list_head *list; - int minor = video_devdata(file)->minor; enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; u32 pix_format; - int ch_id = 0; - int i; + int ch_id; dprintk(1, "open dev=%s type=%s\n", video_device_node_name(vdev), v4l2_type_names[type]); + for (ch_id = 0; ch_id < MAX_VID_CHANNEL_NUM - 1; ch_id++) + if (dev->channels[ch_id].video_dev == vdev) + break; + + /* Can't happen */ + if (ch_id >= MAX_VID_CHANNEL_NUM - 1) + return -ENODEV; + /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (NULL == fh) return -ENOMEM; - mutex_lock(&cx25821_devlist_mutex); - - list_for_each(list, &cx25821_devlist) - { - h = list_entry(list, struct cx25821_dev, devlist); - - for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; i++) { - if (h->channels[i].video_dev && - h->channels[i].video_dev->minor == minor) { - dev = h; - ch_id = i; - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - } - } - - if (NULL == dev) { - mutex_unlock(&cx25821_devlist_mutex); - kfree(fh); - return -ENODEV; - } - file->private_data = fh; fh->dev = dev; fh->type = type; @@ -719,7 +702,6 @@ static int video_open(struct file *file) fh, NULL); dprintk(1, "post videobuf_queue_init()\n"); - mutex_unlock(&cx25821_devlist_mutex); return 0; } diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index d7e71f46defc..195b00407b5a 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -238,9 +238,9 @@ struct cx25821_channel { int cif_width; }; +struct snd_card; + struct cx25821_dev { - struct list_head devlist; - atomic_t refcount; struct v4l2_device v4l2_dev; /* pci stuff */ @@ -252,6 +252,8 @@ struct cx25821_dev { u8 __iomem *bmmio; int pci_irqmask; int hwrevision; + /* used by cx25821-alsa */ + struct snd_card *card; u32 clk_freq; @@ -403,9 +405,6 @@ static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev) #define cx25821_call_all(dev, o, f, args...) \ v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args) -extern struct list_head cx25821_devlist; -extern struct mutex cx25821_devlist_mutex; - extern struct cx25821_board cx25821_boards[]; extern struct cx25821_subid cx25821_subids[]; -- cgit v1.2.3 From 6b1dce251fa21caea4e0021fd3fd0d8dcdece784 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 07:39:19 -0300 Subject: [media] cx25821: s_input didn't check for invalid input The s_input implementation allowed input 1 even if that didn't exist. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index a9aa09651cab..9ddc7ac03a73 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -1163,10 +1163,8 @@ int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) return err; } - if (i >= CX25821_NR_INPUT) { - dprintk(1, "%s(): -EINVAL\n", __func__); + if (i >= CX25821_NR_INPUT || INPUT(i)->type == 0) return -EINVAL; - } mutex_lock(&dev->lock); cx25821_video_mux(dev, i); -- cgit v1.2.3 From 95c232a24b73199f464e3234510ae4729196f38d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 07:41:29 -0300 Subject: [media] cx25821: make lots of externals static A lot of functions and variables were external when they really can be declared as static. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 313 ++++++++++++++---------------- drivers/media/pci/cx25821/cx25821-video.h | 74 ------- drivers/media/pci/cx25821/cx25821.h | 9 +- 3 files changed, 153 insertions(+), 243 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 9ddc7ac03a73..9e948eff6b88 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -46,15 +46,13 @@ static unsigned int irq_debug; module_param(irq_debug, int, 0644); MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); -unsigned int vid_limit = 16; +static unsigned int vid_limit = 16; module_param(vid_limit, int, 0644); MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); -static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num); - #define FORMAT_FLAGS_PACKED 0x01 -struct cx25821_fmt formats[] = { +static const struct cx25821_fmt formats[] = { { .name = "8 bpp, gray", .fourcc = V4L2_PIX_FMT_GREY, @@ -83,12 +81,7 @@ struct cx25821_fmt formats[] = { }, }; -int cx25821_get_format_size(void) -{ - return ARRAY_SIZE(formats); -} - -struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc) +static const struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc) { unsigned int i; @@ -138,7 +131,7 @@ void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, pr_err("%s: %d buffers handled (should be 1)\n", __func__, bc); } -int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm) +static int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm) { dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", __func__, (unsigned int)norm, v4l2_norm_to_name(norm)); @@ -151,7 +144,7 @@ int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm) return 0; } -struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, +static struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, struct pci_dev *pci, const struct video_device *template, char *type) @@ -237,7 +230,7 @@ void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, mutex_unlock(&dev->lock); } -int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input) +static int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input) { struct v4l2_routing route; memset(&route, 0, sizeof(route)); @@ -403,7 +396,7 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) return handled; } -int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, +static int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) { struct cx25821_fh *fh = q->priv_data; @@ -419,7 +412,7 @@ int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, return 0; } -int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, +static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field) { struct cx25821_fh *fh = q->priv_data; @@ -546,7 +539,7 @@ fail: return rc; } -void cx25821_buffer_release(struct videobuf_queue *q, +static void cx25821_buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) { struct cx25821_buffer *buf = @@ -555,7 +548,7 @@ void cx25821_buffer_release(struct videobuf_queue *q, cx25821_free_buffer(q, buf); } -struct videobuf_queue *get_queue(struct cx25821_fh *fh) +static struct videobuf_queue *get_queue(struct cx25821_fh *fh) { switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -566,7 +559,7 @@ struct videobuf_queue *get_queue(struct cx25821_fh *fh) } } -int cx25821_get_resource(struct cx25821_fh *fh, int resource) +static int cx25821_get_resource(struct cx25821_fh *fh, int resource) { switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -577,7 +570,7 @@ int cx25821_get_resource(struct cx25821_fh *fh, int resource) } } -int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma) +static int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma) { struct cx25821_fh *fh = file->private_data; @@ -795,6 +788,70 @@ static int video_release(struct file *file) return 0; } +/* VIDEO IOCTLS */ +static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx25821_fh *fh = priv; + + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->vidq.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.bytesperline = (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} + +static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + const struct cx25821_fmt *fmt; + enum v4l2_field field; + unsigned int maxw, maxh; + + fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; + + field = f->fmt.pix.field; + maxw = 720; + maxh = 576; + + if (V4L2_FIELD_ANY == field) { + if (f->fmt.pix.height > maxh / 2) + field = V4L2_FIELD_INTERLACED; + else + field = V4L2_FIELD_TOP; + } + + switch (field) { + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + maxh = maxh / 2; + break; + case V4L2_FIELD_INTERLACED: + break; + default: + return -EINVAL; + } + + f->fmt.pix.field = field; + if (f->fmt.pix.height < 32) + f->fmt.pix.height = 32; + if (f->fmt.pix.height > maxh) + f->fmt.pix.height = maxh; + if (f->fmt.pix.width < 48) + f->fmt.pix.width = 48; + if (f->fmt.pix.width > maxw) + f->fmt.pix.width = maxw; + f->fmt.pix.width &= ~0x03; + f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + + return 0; +} static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct cx25821_fh *fh = priv; @@ -832,6 +889,43 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return 0; } +static int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm) +{ + if (tvnorm == V4L2_STD_PAL_BG) { + if (width == 352 || width == 720) + return 1; + else + return 0; + } + + if (tvnorm == V4L2_STD_NTSC_M) { + if (width == 320 || width == 352 || width == 720) + return 1; + else + return 0; + } + return 0; +} + +static int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm) +{ + if (tvnorm == V4L2_STD_PAL_BG) { + if (height == 576 || height == 288) + return 1; + else + return 0; + } + + if (tvnorm == V4L2_STD_NTSC_M) { + if (height == 480 || height == 240) + return 1; + else + return 0; + } + + return 0; +} + static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { @@ -918,89 +1012,8 @@ static int vidioc_log_status(struct file *file, void *priv) return 0; } -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - int err; - - if (fh) { - err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, - fh->prio); - if (0 != err) - return err; - } - - return cx25821_set_control(dev, ctl, fh->channel_id); -} - -/* VIDEO IOCTLS */ -int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx25821_fh *fh = priv; - - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.bytesperline = (f->fmt.pix.width * fh->fmt->depth) >> 3; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} - -int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cx25821_fmt *fmt; - enum v4l2_field field; - unsigned int maxw, maxh; - - fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) - return -EINVAL; - - field = f->fmt.pix.field; - maxw = 720; - maxh = 576; - - if (V4L2_FIELD_ANY == field) { - if (f->fmt.pix.height > maxh / 2) - field = V4L2_FIELD_INTERLACED; - else - field = V4L2_FIELD_TOP; - } - - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; - } - - f->fmt.pix.field = field; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - f->fmt.pix.width &= ~0x03; - f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - - return 0; -} -int cx25821_vidioc_querycap(struct file *file, void *priv, +static int cx25821_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; @@ -1020,7 +1033,7 @@ int cx25821_vidioc_querycap(struct file *file, void *priv, return 0; } -int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, +static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (unlikely(f->index >= ARRAY_SIZE(formats))) @@ -1032,27 +1045,27 @@ int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -int cx25821_vidioc_reqbufs(struct file *file, void *priv, +static int cx25821_vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) { struct cx25821_fh *fh = priv; return videobuf_reqbufs(get_queue(fh), p); } -int cx25821_vidioc_querybuf(struct file *file, void *priv, +static int cx25821_vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct cx25821_fh *fh = priv; return videobuf_querybuf(get_queue(fh), p); } -int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) +static int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct cx25821_fh *fh = priv; return videobuf_qbuf(get_queue(fh), p); } -int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) +static int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) { struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev; struct cx25821_fh *fh = f; @@ -1062,7 +1075,7 @@ int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) return 0; } -int cx25821_vidioc_s_priority(struct file *file, void *f, +static int cx25821_vidioc_s_priority(struct file *file, void *f, enum v4l2_priority prio) { struct cx25821_fh *fh = f; @@ -1072,7 +1085,7 @@ int cx25821_vidioc_s_priority(struct file *file, void *f, prio); } -int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms) +static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms) { struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; @@ -1107,18 +1120,20 @@ int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) return 0; } -int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i) +static int cx25821_vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *i) { static const char * const iname[] = { [CX25821_VMUX_COMPOSITE] = "Composite", [CX25821_VMUX_SVIDEO] = "S-Video", [CX25821_VMUX_DEBUG] = "for debug only", }; + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; unsigned int n; dprintk(1, "%s()\n", __func__); n = i->index; - if (n >= 2) + if (n >= CX25821_NR_INPUT) return -EINVAL; if (0 == INPUT(n)->type) @@ -1131,15 +1146,7 @@ int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i) return 0; } -int cx25821_vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - dprintk(1, "%s()\n", __func__); - return cx25821_enum_input(dev, i); -} - -int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i) +static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i) { struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; @@ -1148,7 +1155,7 @@ int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i) return 0; } -int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) +static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) { struct cx25821_fh *fh = priv; struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; @@ -1262,7 +1269,7 @@ static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl) return 0; } -int cx25821_vidioc_queryctrl(struct file *file, void *priv, +static int cx25821_vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qctrl) { return cx25821_ctrl_query(qctrl); @@ -1281,7 +1288,7 @@ static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id) return NULL; } -int cx25821_vidioc_g_ctrl(struct file *file, void *priv, +static int cx25821_vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctl) { struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; @@ -1310,7 +1317,7 @@ int cx25821_vidioc_g_ctrl(struct file *file, void *priv, return 0; } -int cx25821_set_control(struct cx25821_dev *dev, +static int cx25821_set_control(struct cx25821_dev *dev, struct v4l2_control *ctl, int chan_num) { int err; @@ -1360,6 +1367,23 @@ int cx25821_set_control(struct cx25821_dev *dev, return err; } +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctl) +{ + struct cx25821_fh *fh = priv; + struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + int err; + + if (fh) { + err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, + fh->prio); + if (0 != err) + return err; + } + + return cx25821_set_control(dev, ctl, fh->channel_id); +} + static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num) { struct v4l2_control ctrl; @@ -1372,7 +1396,7 @@ static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num) } } -int cx25821_vidioc_cropcap(struct file *file, void *priv, +static int cx25821_vidioc_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cropcap) { struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; @@ -1391,7 +1415,7 @@ int cx25821_vidioc_cropcap(struct file *file, void *priv, return 0; } -int cx25821_vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop *crop) +static int cx25821_vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop *crop) { struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; struct cx25821_fh *fh = priv; @@ -1407,49 +1431,12 @@ int cx25821_vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop return -EINVAL; } -int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) +static int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) { /* cx25821_vidioc_g_crop not supported */ return -EINVAL; } -int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm) -{ - if (tvnorm == V4L2_STD_PAL_BG) { - if (width == 352 || width == 720) - return 1; - else - return 0; - } - - if (tvnorm == V4L2_STD_NTSC_M) { - if (width == 320 || width == 352 || width == 720) - return 1; - else - return 0; - } - return 0; -} - -int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm) -{ - if (tvnorm == V4L2_STD_PAL_BG) { - if (height == 576 || height == 288) - return 1; - else - return 0; - } - - if (tvnorm == V4L2_STD_NTSC_M) { - if (height == 480 || height == 240) - return 1; - else - return 0; - } - - return 0; -} - static long video_ioctl_upstream9(struct file *file, unsigned int cmd, unsigned long arg) { diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index 505b7f0b45b4..9d70020d9256 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -63,97 +63,23 @@ do { \ #define MEDUSA_READ 910 #define MEDUSA_WRITE 911 -extern unsigned int vid_limit; - #define FORMAT_FLAGS_PACKED 0x01 -extern struct cx25821_fmt formats[]; -extern struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc); -extern struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM]; - extern void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, u32 count); -extern int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm); - extern int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bit); extern int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit); extern int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit); extern void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bits); -extern int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input); extern int cx25821_start_video_dma(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, struct cx25821_buffer *buf, const struct sram_channel *channel); -extern int cx25821_set_scale(struct cx25821_dev *dev, unsigned int width, - unsigned int height, enum v4l2_field field); extern int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status); extern void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num); extern int cx25821_video_register(struct cx25821_dev *dev); -extern int cx25821_get_format_size(void); - -extern int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size); -extern int cx25821_buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field); -extern void cx25821_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb); -extern struct videobuf_queue *get_queue(struct cx25821_fh *fh); -extern int cx25821_get_resource(struct cx25821_fh *fh, int resource); -extern int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma); -extern int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f); -extern int cx25821_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap); -extern int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f); -extern int cx25821_vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p); -extern int cx25821_vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p); -extern int cx25821_vidioc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p); -extern int cx25821_vidioc_s_std(struct file *file, void *priv, - v4l2_std_id tvnorms); -extern int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i); -extern int cx25821_vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i); -extern int cx25821_vidioc_g_input(struct file *file, void *priv, - unsigned int *i); -extern int cx25821_vidioc_s_input(struct file *file, void *priv, - unsigned int i); -extern int cx25821_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl); -extern int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f); -extern int cx25821_vidioc_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg); -extern int cx25821_vidioc_s_register(struct file *file, void *fh, - const struct v4l2_dbg_register *reg); - -extern int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm); -extern int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm); - -extern int cx25821_vidioc_g_priority(struct file *file, void *f, - enum v4l2_priority *p); -extern int cx25821_vidioc_s_priority(struct file *file, void *f, - enum v4l2_priority prio); - -extern int cx25821_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qctrl); -extern int cx25821_set_control(struct cx25821_dev *dev, - struct v4l2_control *ctrl, int chan_num); - -extern int cx25821_vidioc_cropcap(struct file *file, void *fh, - struct v4l2_cropcap *cropcap); -extern int cx25821_vidioc_s_crop(struct file *file, void *priv, - const struct v4l2_crop *crop); -extern int cx25821_vidioc_g_crop(struct file *file, void *priv, - struct v4l2_crop *crop); -extern int cx25821_vidioc_querystd(struct file *file, void *priv, - v4l2_std_id *norm); #endif diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 195b00407b5a..033993f1fb08 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -127,7 +127,7 @@ struct cx25821_fh { enum v4l2_priority prio; /* video capture */ - struct cx25821_fmt *fmt; + const struct cx25821_fmt *fmt; unsigned int width, height; int channel_id; struct videobuf_queue vidq; @@ -152,7 +152,7 @@ struct cx25821_buffer { /* cx25821 specific */ unsigned int bpl; struct btcx_riscmem risc; - struct cx25821_fmt *fmt; + const struct cx25821_fmt *fmt; u32 count; }; @@ -565,8 +565,5 @@ extern int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev, unsigned int bpl, u32 risc); extern void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel, u32 format); -extern struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, - struct pci_dev *pci, - const struct video_device *template, - char *type); + #endif -- cgit v1.2.3 From de9ea4cf7fd875460646f97c1f8addafe0454180 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 07:47:12 -0300 Subject: [media] cx25821: remove cropping ioctls This driver does not implement cropping, so remove the cropping ioctls. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 44 ------------------------------- 1 file changed, 44 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 9e948eff6b88..9919a0e93f4d 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -1396,47 +1396,6 @@ static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num) } } -static int cx25821_vidioc_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cropcap) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - - if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - cropcap->bounds.top = 0; - cropcap->bounds.left = 0; - cropcap->bounds.width = 720; - cropcap->bounds.height = dev->tvnorm == V4L2_STD_PAL_BG ? 576 : 480; - cropcap->pixelaspect.numerator = - dev->tvnorm == V4L2_STD_PAL_BG ? 59 : 10; - cropcap->pixelaspect.denominator = - dev->tvnorm == V4L2_STD_PAL_BG ? 54 : 11; - cropcap->defrect = cropcap->bounds; - return 0; -} - -static int cx25821_vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop *crop) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - struct cx25821_fh *fh = priv; - int err; - - if (fh) { - err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, - fh->prio); - if (0 != err) - return err; - } - /* cx25821_vidioc_s_crop not supported */ - return -EINVAL; -} - -static int cx25821_vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) -{ - /* cx25821_vidioc_g_crop not supported */ - return -EINVAL; -} - static long video_ioctl_upstream9(struct file *file, unsigned int cmd, unsigned long arg) { @@ -1713,9 +1672,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_dqbuf = vidioc_dqbuf, .vidioc_g_std = cx25821_vidioc_g_std, .vidioc_s_std = cx25821_vidioc_s_std, - .vidioc_cropcap = cx25821_vidioc_cropcap, - .vidioc_s_crop = cx25821_vidioc_s_crop, - .vidioc_g_crop = cx25821_vidioc_g_crop, .vidioc_enum_input = cx25821_vidioc_enum_input, .vidioc_g_input = cx25821_vidioc_g_input, .vidioc_s_input = cx25821_vidioc_s_input, -- cgit v1.2.3 From 89c21389f2a48afb2fb24fdf74433950cb9b19a2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 08:01:31 -0300 Subject: [media] cx25821: remove bogus dependencies This driver doesn't use DVB, RC, cx25840 or tveeprom. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/Kconfig | 7 +------ drivers/media/pci/cx25821/Makefile | 3 --- drivers/media/pci/cx25821/cx25821-cards.c | 21 --------------------- drivers/media/pci/cx25821/cx25821-core.c | 2 -- drivers/media/pci/cx25821/cx25821-gpio.c | 1 + drivers/media/pci/cx25821/cx25821-i2c.c | 3 ++- drivers/media/pci/cx25821/cx25821.h | 11 ----------- 7 files changed, 4 insertions(+), 44 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/Kconfig b/drivers/media/pci/cx25821/Kconfig index 4017c9420348..6439a847680c 100644 --- a/drivers/media/pci/cx25821/Kconfig +++ b/drivers/media/pci/cx25821/Kconfig @@ -1,14 +1,9 @@ config VIDEO_CX25821 tristate "Conexant cx25821 support" - depends on DVB_CORE && VIDEO_DEV && PCI && I2C + depends on VIDEO_DEV && PCI && I2C select I2C_ALGOBIT select VIDEO_BTCX - select VIDEO_TVEEPROM - depends on RC_CORE - select VIDEOBUF_DVB select VIDEOBUF_DMA_SG - select VIDEO_CX25840 - select VIDEO_CX2341X ---help--- This is a video4linux driver for Conexant 25821 based TV cards. diff --git a/drivers/media/pci/cx25821/Makefile b/drivers/media/pci/cx25821/Makefile index caa32b7b51f8..b54a32e88bd0 100644 --- a/drivers/media/pci/cx25821/Makefile +++ b/drivers/media/pci/cx25821/Makefile @@ -9,6 +9,3 @@ obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o ccflags-y += -Idrivers/media/i2c ccflags-y += -Idrivers/media/common -ccflags-y += -Idrivers/media/tuners -ccflags-y += -Idrivers/media/dvb-core -ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/pci/cx25821/cx25821-cards.c b/drivers/media/pci/cx25821/cx25821-cards.c index c09ec68460e4..2b2f1f4f87ac 100644 --- a/drivers/media/pci/cx25821/cx25821-cards.c +++ b/drivers/media/pci/cx25821/cx25821-cards.c @@ -26,8 +26,6 @@ #include #include #include -#include -#include #include "cx25821.h" @@ -50,22 +48,3 @@ struct cx25821_board cx25821_boards[] = { }; const unsigned int cx25821_bcount = ARRAY_SIZE(cx25821_boards); - -struct cx25821_subid cx25821_subids[] = { - { - .subvendor = 0x14f1, - .subdevice = 0x0920, - .card = CX25821_BOARD, - }, -}; - -void cx25821_card_setup(struct cx25821_dev *dev) -{ - static u8 eeprom[256]; - - if (dev->i2c_bus[0].i2c_rc == 0) { - dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, - sizeof(eeprom)); - } -} diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 6205ade04a97..82c2db0944e3 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -953,8 +953,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) CX25821_INFO("i2c register! bus->i2c_rc = %d\n", dev->i2c_bus[0].i2c_rc); - cx25821_card_setup(dev); - if (medusa_video_init(dev) < 0) CX25821_ERR("%s(): Failed to initialize medusa!\n", __func__); diff --git a/drivers/media/pci/cx25821/cx25821-gpio.c b/drivers/media/pci/cx25821/cx25821-gpio.c index 29e43b03c85e..95e8ddf62947 100644 --- a/drivers/media/pci/cx25821/cx25821-gpio.c +++ b/drivers/media/pci/cx25821/cx25821-gpio.c @@ -20,6 +20,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include "cx25821.h" /********************* GPIO stuffs *********************/ diff --git a/drivers/media/pci/cx25821/cx25821-i2c.c b/drivers/media/pci/cx25821/cx25821-i2c.c index a8dc945bbe17..dca37c7dba73 100644 --- a/drivers/media/pci/cx25821/cx25821-i2c.c +++ b/drivers/media/pci/cx25821/cx25821-i2c.c @@ -23,8 +23,9 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include "cx25821.h" +#include #include +#include "cx25821.h" static unsigned int i2c_debug; module_param(i2c_debug, int, 0644); diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 033993f1fb08..61c6cfc02d8c 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -33,9 +33,7 @@ #include #include -#include #include -#include #include "btcx-risc.h" #include "cx25821-reg.h" @@ -178,12 +176,6 @@ struct cx25821_board { struct cx25821_input input[CX25821_NR_INPUT]; }; -struct cx25821_subid { - u16 subvendor; - u16 subdevice; - u32 card; -}; - struct cx25821_i2c { struct cx25821_dev *dev; @@ -406,7 +398,6 @@ static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev) v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args) extern struct cx25821_board cx25821_boards[]; -extern struct cx25821_subid cx25821_subids[]; #define SRAM_CH00 0 /* Video A */ #define SRAM_CH01 1 /* Video B */ @@ -487,8 +478,6 @@ extern const struct sram_channel cx25821_sram_channels[]; pr_info("(%d): " fmt, dev->board, ##args) extern int cx25821_i2c_register(struct cx25821_i2c *bus); -extern void cx25821_card_setup(struct cx25821_dev *dev); -extern int cx25821_ir_init(struct cx25821_dev *dev); extern int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value); extern int cx25821_i2c_write(struct cx25821_i2c *bus, u16 reg_addr, int value); extern int cx25821_i2c_unregister(struct cx25821_i2c *bus); -- cgit v1.2.3 From 467870ca26c01cb0ac84e969a78160f8164919cc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 08:18:00 -0300 Subject: [media] cx25821: embed video_device, clean up some kernel log spam Embed the video_device struct instead of allocating it. Remove some of the annoying and ugly kernel messages shown during loading and unloading of the module. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-core.c | 15 +-------- drivers/media/pci/cx25821/cx25821-video.c | 54 ++++++++----------------------- drivers/media/pci/cx25821/cx25821.h | 2 +- 3 files changed, 16 insertions(+), 55 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 82c2db0944e3..f3a48a17c4c3 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -845,8 +845,7 @@ static void cx25821_dev_checkrevision(struct cx25821_dev *dev) { dev->hwrevision = cx_read(RDR_CFG2) & 0xff; - pr_info("%s(): Hardware revision = 0x%02x\n", - __func__, dev->hwrevision); + pr_info("Hardware revision = 0x%02x\n", dev->hwrevision); } static void cx25821_iounmap(struct cx25821_dev *dev) @@ -856,7 +855,6 @@ static void cx25821_iounmap(struct cx25821_dev *dev) /* Releasing IO memory */ if (dev->lmmio != NULL) { - CX25821_INFO("Releasing lmmio.\n"); iounmap(dev->lmmio); dev->lmmio = NULL; } @@ -867,10 +865,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) static unsigned int cx25821_devcount; int i; - pr_info("\n***********************************\n"); - pr_info("cx25821 set up\n"); - pr_info("***********************************\n\n"); - mutex_init(&dev->lock); dev->nr = ++cx25821_devcount; @@ -950,17 +944,12 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) /* cx25821_i2c_register(&dev->i2c_bus[1]); * cx25821_i2c_register(&dev->i2c_bus[2]); */ - CX25821_INFO("i2c register! bus->i2c_rc = %d\n", - dev->i2c_bus[0].i2c_rc); - if (medusa_video_init(dev) < 0) CX25821_ERR("%s(): Failed to initialize medusa!\n", __func__); cx25821_video_register(dev); cx25821_dev_checkrevision(dev); - CX25821_INFO("setup done!\n"); - return 0; } @@ -1337,8 +1326,6 @@ static int cx25821_initdev(struct pci_dev *pci_dev, goto fail_unregister_device; } - pr_info("Athena pci enable !\n"); - err = cx25821_dev_setup(dev); if (err) { if (err == -EBUSY) diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 9919a0e93f4d..41e3475efec3 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -144,26 +144,6 @@ static int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm) return 0; } -static struct video_device *cx25821_vdev_init(struct cx25821_dev *dev, - struct pci_dev *pci, - const struct video_device *template, - char *type) -{ - struct video_device *vfd; - dprintk(1, "%s()\n", __func__); - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->release = video_device_release; - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name, type, - cx25821_boards[dev->board].name); - video_set_drvdata(vfd, dev); - return vfd; -} - /* static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl) { @@ -657,7 +637,7 @@ static int video_open(struct file *file) v4l2_type_names[type]); for (ch_id = 0; ch_id < MAX_VID_CHANNEL_NUM - 1; ch_id++) - if (dev->channels[ch_id].video_dev == vdev) + if (&dev->channels[ch_id].vdev == vdev) break; /* Can't happen */ @@ -1692,6 +1672,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { static const struct video_device cx25821_video_device = { .name = "cx25821-video", .fops = &video_fops, + .release = video_device_release_empty, .minor = -1, .ioctl_ops = &video_ioctl_ops, .tvnorms = CX25821_NORMS, @@ -1701,22 +1682,12 @@ void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) { cx_clear(PCI_INT_MSK, 1); - if (dev->channels[chan_num].video_dev) { - if (video_is_registered(dev->channels[chan_num].video_dev)) - video_unregister_device( - dev->channels[chan_num].video_dev); - else - video_device_release( - dev->channels[chan_num].video_dev); - - dev->channels[chan_num].video_dev = NULL; + if (video_is_registered(&dev->channels[chan_num].vdev)) { + video_unregister_device(&dev->channels[chan_num].vdev); btcx_riscmem_free(dev->pci, &dev->channels[chan_num].vidq.stopper); - - pr_warn("device %d released!\n", chan_num); } - } int cx25821_video_register(struct cx25821_dev *dev) @@ -1727,6 +1698,8 @@ int cx25821_video_register(struct cx25821_dev *dev) spin_lock_init(&dev->slock); for (i = 0; i < VID_CHANNEL_NUM; ++i) { + struct video_device *vdev = &dev->channels[i].vdev; + if (i == SRAM_CH08) /* audio channel */ continue; @@ -1736,7 +1709,6 @@ int cx25821_video_register(struct cx25821_dev *dev) dev->channels[i].sram_channels->dma_ctl, 0x11, 0); dev->channels[i].sram_channels = &cx25821_sram_channels[i]; - dev->channels[i].video_dev = NULL; dev->channels[i].resources = 0; cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff); @@ -1753,15 +1725,16 @@ int cx25821_video_register(struct cx25821_dev *dev) init_timer(&dev->channels[i].vidq.timeout); /* register v4l devices */ - dev->channels[i].video_dev = cx25821_vdev_init(dev, dev->pci, - &cx25821_video_device, "video"); + *vdev = cx25821_video_device; + vdev->v4l2_dev = &dev->v4l2_dev; + snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i); + video_set_drvdata(vdev, dev); - err = video_register_device(dev->channels[i].video_dev, - VFL_TYPE_GRABBER, video_nr[dev->nr]); + err = video_register_device(vdev, VFL_TYPE_GRABBER, + video_nr[dev->nr]); if (err < 0) goto fail_unreg; - } /* set PCI interrupt */ @@ -1776,6 +1749,7 @@ int cx25821_video_register(struct cx25821_dev *dev) return 0; fail_unreg: - cx25821_video_unregister(dev, i); + while (i >= 0) + cx25821_video_unregister(dev, i--); return err; } diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 61c6cfc02d8c..df2ea22563e5 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -217,7 +217,7 @@ struct cx25821_channel { int ctl_saturation; struct cx25821_data timeout_data; - struct video_device *video_dev; + struct video_device vdev; struct cx25821_dmaqueue vidq; const struct sram_channel *sram_channels; -- cgit v1.2.3 From f8d7ee70919d44ef4f01f3c9bc49af54fdc433bc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 08:38:14 -0300 Subject: [media] cx25821: convert to the control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-core.c | 5 +- drivers/media/pci/cx25821/cx25821-video.c | 210 +++++------------------------- drivers/media/pci/cx25821/cx25821.h | 10 +- 3 files changed, 41 insertions(+), 184 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index f3a48a17c4c3..bf6c1812dd8c 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -880,8 +880,11 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) /* Apply a sensible clock frequency for the PCIe bridge */ dev->clk_freq = 28000000; - for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) + for (i = 0; i < MAX_VID_CHANNEL_NUM; i++) { + dev->channels[i].dev = dev; + dev->channels[i].id = i; dev->channels[i].sram_channels = &cx25821_sram_channels[i]; + } if (dev->nr > 1) CX25821_INFO("dev->nr > 1!"); diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 41e3475efec3..0c11f314c62e 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -1188,192 +1188,29 @@ int cx25821_vidioc_s_register(struct file *file, void *fh, #endif -/*****************************************************************************/ -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; - -static struct v4l2_queryctrl cx25821_ctls[] = { - /* --- video --- */ - { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 6200, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 5000, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 5000, - .type = V4L2_CTRL_TYPE_INTEGER, - }, { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 10000, - .step = 1, - .default_value = 5000, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; -static const int CX25821_CTLS = ARRAY_SIZE(cx25821_ctls); - -static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl) -{ - int i; - - if (qctrl->id < V4L2_CID_BASE || qctrl->id >= V4L2_CID_LASTP1) - return -EINVAL; - for (i = 0; i < CX25821_CTLS; i++) - if (cx25821_ctls[i].id == qctrl->id) - break; - if (i == CX25821_CTLS) { - *qctrl = no_ctl; - return 0; - } - *qctrl = cx25821_ctls[i]; - return 0; -} - -static int cx25821_vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - return cx25821_ctrl_query(qctrl); -} - -/* ------------------------------------------------------------------ */ -/* VIDEO CTRL IOCTLS */ - -static const struct v4l2_queryctrl *ctrl_by_id(unsigned int id) +static int cx25821_s_ctrl(struct v4l2_ctrl *ctrl) { - unsigned int i; + struct cx25821_channel *chan = + container_of(ctrl->handler, struct cx25821_channel, hdl); + struct cx25821_dev *dev = chan->dev; - for (i = 0; i < CX25821_CTLS; i++) - if (cx25821_ctls[i].id == id) - return cx25821_ctls + i; - return NULL; -} - -static int cx25821_vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - struct cx25821_fh *fh = priv; - - const struct v4l2_queryctrl *ctrl; - - ctrl = ctrl_by_id(ctl->id); - - if (NULL == ctrl) - return -EINVAL; - switch (ctl->id) { + switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - ctl->value = dev->channels[fh->channel_id].ctl_bright; + medusa_set_brightness(dev, ctrl->val, chan->id); break; case V4L2_CID_HUE: - ctl->value = dev->channels[fh->channel_id].ctl_hue; + medusa_set_hue(dev, ctrl->val, chan->id); break; case V4L2_CID_CONTRAST: - ctl->value = dev->channels[fh->channel_id].ctl_contrast; + medusa_set_contrast(dev, ctrl->val, chan->id); break; case V4L2_CID_SATURATION: - ctl->value = dev->channels[fh->channel_id].ctl_saturation; - break; - } - return 0; -} - -static int cx25821_set_control(struct cx25821_dev *dev, - struct v4l2_control *ctl, int chan_num) -{ - int err; - const struct v4l2_queryctrl *ctrl; - - err = -EINVAL; - - ctrl = ctrl_by_id(ctl->id); - - if (NULL == ctrl) - return err; - - switch (ctrl->type) { - case V4L2_CTRL_TYPE_BOOLEAN: - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_INTEGER: - if (ctl->value < ctrl->minimum) - ctl->value = ctrl->minimum; - if (ctl->value > ctrl->maximum) - ctl->value = ctrl->maximum; + medusa_set_saturation(dev, ctrl->val, chan->id); break; default: - /* nothing */ ; - } - - switch (ctl->id) { - case V4L2_CID_BRIGHTNESS: - dev->channels[chan_num].ctl_bright = ctl->value; - medusa_set_brightness(dev, ctl->value, chan_num); - break; - case V4L2_CID_HUE: - dev->channels[chan_num].ctl_hue = ctl->value; - medusa_set_hue(dev, ctl->value, chan_num); - break; - case V4L2_CID_CONTRAST: - dev->channels[chan_num].ctl_contrast = ctl->value; - medusa_set_contrast(dev, ctl->value, chan_num); - break; - case V4L2_CID_SATURATION: - dev->channels[chan_num].ctl_saturation = ctl->value; - medusa_set_saturation(dev, ctl->value, chan_num); - break; - } - - err = 0; - - return err; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - int err; - - if (fh) { - err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, - fh->prio); - if (0 != err) - return err; - } - - return cx25821_set_control(dev, ctl, fh->channel_id); -} - -static void cx25821_init_controls(struct cx25821_dev *dev, int chan_num) -{ - struct v4l2_control ctrl; - int i; - for (i = 0; i < CX25821_CTLS; i++) { - ctrl.id = cx25821_ctls[i].id; - ctrl.value = cx25821_ctls[i].default_value; - - cx25821_set_control(dev, &ctrl, chan_num); + return -EINVAL; } + return 0; } static long video_ioctl_upstream9(struct file *file, unsigned int cmd, @@ -1629,7 +1466,10 @@ static long cx25821_video_ioctl(struct file *file, return video_ioctl2(file, cmd, arg); } -/* exported stuff */ +static const struct v4l2_ctrl_ops cx25821_ctrl_ops = { + .s_ctrl = cx25821_s_ctrl, +}; + static const struct v4l2_file_operations video_fops = { .owner = THIS_MODULE, .open = video_open, @@ -1655,9 +1495,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_enum_input = cx25821_vidioc_enum_input, .vidioc_g_input = cx25821_vidioc_g_input, .vidioc_s_input = cx25821_vidioc_s_input, - .vidioc_g_ctrl = cx25821_vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_queryctrl = cx25821_vidioc_queryctrl, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_log_status = vidioc_log_status, @@ -1684,6 +1521,7 @@ void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) if (video_is_registered(&dev->channels[chan_num].vdev)) { video_unregister_device(&dev->channels[chan_num].vdev); + v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl); btcx_riscmem_free(dev->pci, &dev->channels[chan_num].vidq.stopper); @@ -1699,11 +1537,24 @@ int cx25821_video_register(struct cx25821_dev *dev) for (i = 0; i < VID_CHANNEL_NUM; ++i) { struct video_device *vdev = &dev->channels[i].vdev; + struct v4l2_ctrl_handler *hdl = &dev->channels[i].hdl; if (i == SRAM_CH08) /* audio channel */ continue; - cx25821_init_controls(dev, i); + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200); + v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops, + V4L2_CID_CONTRAST, 0, 10000, 1, 5000); + v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops, + V4L2_CID_SATURATION, 0, 10000, 1, 5000); + v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops, + V4L2_CID_HUE, 0, 10000, 1, 5000); + if (hdl->error) { + err = hdl->error; + goto fail_unreg; + } cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper, dev->channels[i].sram_channels->dma_ctl, 0x11, 0); @@ -1727,6 +1578,7 @@ int cx25821_video_register(struct cx25821_dev *dev) /* register v4l devices */ *vdev = cx25821_video_device; vdev->v4l2_dev = &dev->v4l2_dev; + vdev->ctrl_handler = hdl; snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i); video_set_drvdata(vdev, dev); diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index df2ea22563e5..c63f7f571614 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -33,6 +33,7 @@ #include #include +#include #include #include "btcx-risc.h" @@ -208,13 +209,14 @@ struct cx25821_data { const struct sram_channel *channel; }; +struct cx25821_dev; + struct cx25821_channel { + unsigned id; + struct cx25821_dev *dev; struct v4l2_prio_state prio; - int ctl_bright; - int ctl_contrast; - int ctl_hue; - int ctl_saturation; + struct v4l2_ctrl_handler hdl; struct cx25821_data timeout_data; struct video_device vdev; -- cgit v1.2.3 From bad1f29d0f98972665e6503a286d058125212aa5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 14 Apr 2013 11:13:43 -0300 Subject: [media] cx25821: remove TRUE/FALSE/STATUS_(UN)SUCCESSFUL defines Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-core.c | 2 +- drivers/media/pci/cx25821/cx25821-medusa-video.c | 2 +- drivers/media/pci/cx25821/cx25821.h | 5 ----- 3 files changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index bf6c1812dd8c..ba417c978415 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -814,7 +814,7 @@ static void cx25821_initialize(struct cx25821_dev *dev) cx25821_sram_channel_setup(dev, dev->channels[i].sram_channels, 1440, 0); dev->channels[i].pixel_formats = PIXEL_FRMT_422; - dev->channels[i].use_cif_resolution = FALSE; + dev->channels[i].use_cif_resolution = 0; } /* Probably only affect Downstream */ diff --git a/drivers/media/pci/cx25821/cx25821-medusa-video.c b/drivers/media/pci/cx25821/cx25821-medusa-video.c index 6a92e5c70c2a..6ab3ae08348e 100644 --- a/drivers/media/pci/cx25821/cx25821-medusa-video.c +++ b/drivers/media/pci/cx25821/cx25821-medusa-video.c @@ -404,7 +404,7 @@ static int medusa_initialize_pal(struct cx25821_dev *dev) int medusa_set_videostandard(struct cx25821_dev *dev) { - int status = STATUS_SUCCESS; + int status = 0; u32 value = 0, tmp = 0; if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK) diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index c63f7f571614..95dbf70d8667 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -52,8 +52,6 @@ #define CX25821_MAXBOARDS 2 -#define TRUE 1 -#define FALSE 0 #define LINE_SIZE_D1 1440 /* Number of decoders and encoders */ @@ -456,9 +454,6 @@ struct sram_channel { extern const struct sram_channel cx25821_sram_channels[]; -#define STATUS_SUCCESS 0 -#define STATUS_UNSUCCESSFUL -1 - #define cx_read(reg) readl(dev->lmmio + ((reg)>>2)) #define cx_write(reg, value) writel((value), dev->lmmio + ((reg)>>2)) -- cgit v1.2.3 From b6f8727e9f4cff765de2b24e82c1b2cfc1a74a86 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 08:44:56 -0300 Subject: [media] cx25821: remove unnecessary debug messages The v4l2 core already has support for debugging ioctls/file operations. No need to do that again. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 0c11f314c62e..6088ee996b92 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -633,9 +633,6 @@ static int video_open(struct file *file) u32 pix_format; int ch_id; - dprintk(1, "open dev=%s type=%s\n", video_device_node_name(vdev), - v4l2_type_names[type]); - for (ch_id = 0; ch_id < MAX_VID_CHANNEL_NUM - 1; ch_id++) if (&dev->channels[ch_id].vdev == vdev) break; @@ -922,7 +919,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, return err; } - dprintk(2, "%s()\n", __func__); err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f); if (0 != err) @@ -956,8 +952,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, dev->channels[fh->channel_id].cif_width = fh->width; medusa_set_resolution(dev, fh->width, SRAM_CH00); - dprintk(2, "%s(): width=%d height=%d field=%d\n", __func__, fh->width, - fh->height, fh->vidq.field); v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt); @@ -1079,8 +1073,6 @@ int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; int err; - dprintk(1, "%s()\n", __func__); - if (fh) { err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, fh->prio); @@ -1110,7 +1102,6 @@ static int cx25821_vidioc_enum_input(struct file *file, void *priv, }; struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; unsigned int n; - dprintk(1, "%s()\n", __func__); n = i->index; if (n >= CX25821_NR_INPUT) @@ -1131,7 +1122,6 @@ static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; *i = dev->input; - dprintk(1, "%s(): returns %d\n", __func__, *i); return 0; } @@ -1141,8 +1131,6 @@ static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; int err; - dprintk(1, "%s(%d)\n", __func__, i); - if (fh) { err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, fh->prio); -- cgit v1.2.3 From be178cb4f41f70e29108ce4eb5a8a77a62f1922f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 14 Apr 2013 11:53:35 -0300 Subject: [media] cx25821: use core locking This allows us to replace .ioctl with .unlocked_ioctl. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-medusa-video.c | 44 --------------- drivers/media/pci/cx25821/cx25821-video.c | 72 +++++++++--------------- drivers/media/pci/cx25821/cx25821-video.h | 6 -- drivers/media/pci/cx25821/cx25821.h | 1 - 4 files changed, 27 insertions(+), 96 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-medusa-video.c b/drivers/media/pci/cx25821/cx25821-medusa-video.c index 6ab3ae08348e..22fa04415ccc 100644 --- a/drivers/media/pci/cx25821/cx25821-medusa-video.c +++ b/drivers/media/pci/cx25821/cx25821-medusa-video.c @@ -94,8 +94,6 @@ static int medusa_initialize_ntsc(struct cx25821_dev *dev) u32 value = 0; u32 tmp = 0; - mutex_lock(&dev->lock); - for (i = 0; i < MAX_DECODERS; i++) { /* set video format NTSC-M */ value = cx25821_i2c_read(&dev->i2c_bus[0], @@ -222,8 +220,6 @@ static int medusa_initialize_ntsc(struct cx25821_dev *dev) value |= 0x00080200; ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value); - mutex_unlock(&dev->lock); - return ret_val; } @@ -265,8 +261,6 @@ static int medusa_initialize_pal(struct cx25821_dev *dev) u32 value = 0; u32 tmp = 0; - mutex_lock(&dev->lock); - for (i = 0; i < MAX_DECODERS; i++) { /* set video format PAL-BDGHI */ value = cx25821_i2c_read(&dev->i2c_bus[0], @@ -397,8 +391,6 @@ static int medusa_initialize_pal(struct cx25821_dev *dev) value &= 0xFFF7FDFF; ret_val = cx25821_i2c_write(&dev->i2c_bus[0], BYP_AB_CTRL, value); - mutex_unlock(&dev->lock); - return ret_val; } @@ -434,8 +426,6 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width, u32 vscale = 0x0; const int MAX_WIDTH = 720; - mutex_lock(&dev->lock); - /* validate the width */ if (width > MAX_WIDTH) { pr_info("%s(): width %d > MAX_WIDTH %d ! resetting to MAX_WIDTH\n", @@ -485,8 +475,6 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width, cx25821_i2c_write(&dev->i2c_bus[0], VSCALE_CTRL + (0x200 * decoder), vscale); } - - mutex_unlock(&dev->lock); } static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder, @@ -496,11 +484,8 @@ static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder, u32 tmp = 0; u32 disp_cnt_reg = DISP_AB_CNT; - mutex_lock(&dev->lock); - /* no support */ if (decoder < VDEC_A || decoder > VDEC_H) { - mutex_unlock(&dev->lock); return; } @@ -535,8 +520,6 @@ static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder, } cx25821_i2c_write(&dev->i2c_bus[0], disp_cnt_reg, fld_cnt); - - mutex_unlock(&dev->lock); } /* Map to Medusa register setting */ @@ -587,10 +570,8 @@ int medusa_set_brightness(struct cx25821_dev *dev, int brightness, int decoder) int value = 0; u32 val = 0, tmp = 0; - mutex_lock(&dev->lock); if ((brightness > VIDEO_PROCAMP_MAX) || (brightness < VIDEO_PROCAMP_MIN)) { - mutex_unlock(&dev->lock); return -1; } ret_val = mapM(VIDEO_PROCAMP_MIN, VIDEO_PROCAMP_MAX, brightness, @@ -601,7 +582,6 @@ int medusa_set_brightness(struct cx25821_dev *dev, int brightness, int decoder) val &= 0xFFFFFF00; ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], VDEC_A_BRITE_CTRL + (0x200 * decoder), val | value); - mutex_unlock(&dev->lock); return ret_val; } @@ -611,10 +591,7 @@ int medusa_set_contrast(struct cx25821_dev *dev, int contrast, int decoder) int value = 0; u32 val = 0, tmp = 0; - mutex_lock(&dev->lock); - if ((contrast > VIDEO_PROCAMP_MAX) || (contrast < VIDEO_PROCAMP_MIN)) { - mutex_unlock(&dev->lock); return -1; } @@ -626,7 +603,6 @@ int medusa_set_contrast(struct cx25821_dev *dev, int contrast, int decoder) ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], VDEC_A_CNTRST_CTRL + (0x200 * decoder), val | value); - mutex_unlock(&dev->lock); return ret_val; } @@ -636,10 +612,7 @@ int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder) int value = 0; u32 val = 0, tmp = 0; - mutex_lock(&dev->lock); - if ((hue > VIDEO_PROCAMP_MAX) || (hue < VIDEO_PROCAMP_MIN)) { - mutex_unlock(&dev->lock); return -1; } @@ -654,7 +627,6 @@ int medusa_set_hue(struct cx25821_dev *dev, int hue, int decoder) ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], VDEC_A_HUE_CTRL + (0x200 * decoder), val | value); - mutex_unlock(&dev->lock); return ret_val; } @@ -664,11 +636,8 @@ int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder) int value = 0; u32 val = 0, tmp = 0; - mutex_lock(&dev->lock); - if ((saturation > VIDEO_PROCAMP_MAX) || (saturation < VIDEO_PROCAMP_MIN)) { - mutex_unlock(&dev->lock); return -1; } @@ -687,7 +656,6 @@ int medusa_set_saturation(struct cx25821_dev *dev, int saturation, int decoder) ret_val |= cx25821_i2c_write(&dev->i2c_bus[0], VDEC_A_VSAT_CTRL + (0x200 * decoder), val | value); - mutex_unlock(&dev->lock); return ret_val; } @@ -699,8 +667,6 @@ int medusa_video_init(struct cx25821_dev *dev) int ret_val = 0; int i = 0; - mutex_lock(&dev->lock); - _num_decoders = dev->_max_num_decoders; /* disable Auto source selection on all video decoders */ @@ -719,13 +685,9 @@ int medusa_video_init(struct cx25821_dev *dev) if (ret_val < 0) goto error; - mutex_unlock(&dev->lock); - for (i = 0; i < _num_decoders; i++) medusa_set_decoderduration(dev, i, _display_field_cnt[i]); - mutex_lock(&dev->lock); - /* Select monitor as DENC A input, power up the DAC */ value = cx25821_i2c_read(&dev->i2c_bus[0], DENC_AB_CTRL, &tmp); value &= 0xFF70FF70; @@ -774,14 +736,8 @@ int medusa_video_init(struct cx25821_dev *dev) if (ret_val < 0) goto error; - - mutex_unlock(&dev->lock); - ret_val = medusa_set_videostandard(dev); - return ret_val; - error: - mutex_unlock(&dev->lock); return ret_val; } diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 6088ee996b92..ab79bd5e5f68 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -144,27 +144,8 @@ static int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm) return 0; } -/* -static int cx25821_ctrl_query(struct v4l2_queryctrl *qctrl) -{ - int i; - - if (qctrl->id < V4L2_CID_BASE || qctrl->id >= V4L2_CID_LASTP1) - return -EINVAL; - for (i = 0; i < CX25821_CTLS; i++) - if (cx25821_ctls[i].v.id == qctrl->id) - break; - if (i == CX25821_CTLS) { - *qctrl = no_ctl; - return 0; - } - *qctrl = cx25821_ctls[i].v; - return 0; -} -*/ - /* resource management */ -int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, +static int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bit) { dprintk(1, "%s()\n", __func__); @@ -173,41 +154,36 @@ int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, return 1; /* is it free? */ - mutex_lock(&dev->lock); if (dev->channels[fh->channel_id].resources & bit) { /* no, someone else uses it */ - mutex_unlock(&dev->lock); return 0; } /* it's free, grab it */ fh->resources |= bit; dev->channels[fh->channel_id].resources |= bit; dprintk(1, "res: get %d\n", bit); - mutex_unlock(&dev->lock); return 1; } -int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit) +static int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit) { return fh->resources & bit; } -int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit) +static int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit) { return fh->dev->channels[fh->channel_id].resources & bit; } -void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, +static void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, unsigned int bits) { BUG_ON((fh->resources & bits) != bits); dprintk(1, "%s()\n", __func__); - mutex_lock(&dev->lock); fh->resources &= ~bits; dev->channels[fh->channel_id].resources &= ~bits; dprintk(1, "res: put %d\n", bits); - mutex_unlock(&dev->lock); } static int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input) @@ -669,7 +645,7 @@ static int video_open(struct file *file) videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, &dev->pci->dev, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer), - fh, NULL); + fh, &dev->lock); dprintk(1, "post videobuf_queue_init()\n"); @@ -680,19 +656,25 @@ static ssize_t video_read(struct file *file, char __user * data, size_t count, loff_t *ppos) { struct cx25821_fh *fh = file->private_data; + struct cx25821_dev *dev = fh->dev; + int err; switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (mutex_lock_interruptible(&dev->lock)) + return -ERESTARTSYS; if (cx25821_res_locked(fh, RESOURCE_VIDEO0)) - return -EBUSY; - - return videobuf_read_one(&fh->vidq, data, count, ppos, + err = -EBUSY; + else + err = videobuf_read_one(&fh->vidq, data, count, ppos, file->f_flags & O_NONBLOCK); + mutex_unlock(&dev->lock); + return err; default: - BUG(); - return 0; + return -ENODEV; } + } static unsigned int video_poll(struct file *file, @@ -742,6 +724,7 @@ static int video_release(struct file *file) const struct sram_channel *sram_ch = dev->channels[0].sram_channels; + mutex_lock(&dev->lock); /* stop the risc engine and fifo */ cx_write(sram_ch->dma_ctl, 0); /* FIFO and RISC disable */ @@ -750,6 +733,7 @@ static int video_release(struct file *file) videobuf_queue_cancel(&fh->vidq); cx25821_res_free(dev, fh, RESOURCE_VIDEO0); } + mutex_unlock(&dev->lock); if (fh->vidq.read_buf) { cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf); @@ -1083,9 +1067,7 @@ int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) if (dev->tvnorm == tvnorms) return 0; - mutex_lock(&dev->lock); cx25821_set_tvnorm(dev, tvnorms); - mutex_unlock(&dev->lock); medusa_set_videostandard(dev); @@ -1141,9 +1123,7 @@ static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) if (i >= CX25821_NR_INPUT || INPUT(i)->type == 0) return -EINVAL; - mutex_lock(&dev->lock); cx25821_video_mux(dev, i); - mutex_unlock(&dev->lock); return 0; } @@ -1465,7 +1445,7 @@ static const struct v4l2_file_operations video_fops = { .read = video_read, .poll = video_poll, .mmap = cx25821_video_mmap, - .ioctl = cx25821_video_ioctl, + .unlocked_ioctl = cx25821_video_ioctl, }; static const struct v4l2_ioctl_ops video_ioctl_ops = { @@ -1521,6 +1501,10 @@ int cx25821_video_register(struct cx25821_dev *dev) int err; int i; + /* initial device configuration */ + dev->tvnorm = V4L2_STD_NTSC_M, + cx25821_set_tvnorm(dev, dev->tvnorm); + spin_lock_init(&dev->slock); for (i = 0; i < VID_CHANNEL_NUM; ++i) { @@ -1543,6 +1527,9 @@ int cx25821_video_register(struct cx25821_dev *dev) err = hdl->error; goto fail_unreg; } + err = v4l2_ctrl_handler_setup(hdl); + if (err) + goto fail_unreg; cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper, dev->channels[i].sram_channels->dma_ctl, 0x11, 0); @@ -1567,6 +1554,7 @@ int cx25821_video_register(struct cx25821_dev *dev) *vdev = cx25821_video_device; vdev->v4l2_dev = &dev->v4l2_dev; vdev->ctrl_handler = hdl; + vdev->lock = &dev->lock; snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i); video_set_drvdata(vdev, dev); @@ -1580,12 +1568,6 @@ int cx25821_video_register(struct cx25821_dev *dev) /* set PCI interrupt */ cx_set(PCI_INT_MSK, 0xff); - /* initial device configuration */ - mutex_lock(&dev->lock); - dev->tvnorm = V4L2_STD_NTSC_M, - cx25821_set_tvnorm(dev, dev->tvnorm); - mutex_unlock(&dev->lock); - return 0; fail_unreg: diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index 9d70020d9256..b0f0d5395490 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -67,12 +67,6 @@ do { \ extern void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, u32 count); -extern int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, - unsigned int bit); -extern int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit); -extern int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit); -extern void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, - unsigned int bits); extern int cx25821_start_video_dma(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, struct cx25821_buffer *buf, diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 95dbf70d8667..ad56232154e6 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -222,7 +222,6 @@ struct cx25821_channel { const struct sram_channel *sram_channels; - struct mutex lock; int resources; int pixel_formats; -- cgit v1.2.3 From 11f095aa4154d27bdb15909b12a9d3922ab55cde Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 14 Apr 2013 11:54:56 -0300 Subject: [media] cx25821: remove 'type' field from cx25821_fh Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 56 +++++++++---------------------- drivers/media/pci/cx25821/cx25821.h | 1 - 2 files changed, 15 insertions(+), 42 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index ab79bd5e5f68..2aba24f2a3d8 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -506,24 +506,12 @@ static void cx25821_buffer_release(struct videobuf_queue *q, static struct videobuf_queue *get_queue(struct cx25821_fh *fh) { - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return &fh->vidq; - default: - BUG(); - return NULL; - } + return &fh->vidq; } static int cx25821_get_resource(struct cx25821_fh *fh, int resource) { - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return resource; - default: - BUG(); - return 0; - } + return resource; } static int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma) @@ -605,7 +593,6 @@ static int video_open(struct file *file) struct video_device *vdev = video_devdata(file); struct cx25821_dev *dev = video_drvdata(file); struct cx25821_fh *fh; - enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; u32 pix_format; int ch_id; @@ -624,7 +611,6 @@ static int video_open(struct file *file) file->private_data = fh; fh->dev = dev; - fh->type = type; fh->width = 720; fh->channel_id = ch_id; @@ -659,22 +645,15 @@ static ssize_t video_read(struct file *file, char __user * data, size_t count, struct cx25821_dev *dev = fh->dev; int err; - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (mutex_lock_interruptible(&dev->lock)) - return -ERESTARTSYS; - if (cx25821_res_locked(fh, RESOURCE_VIDEO0)) - err = -EBUSY; - else - err = videobuf_read_one(&fh->vidq, data, count, ppos, - file->f_flags & O_NONBLOCK); - mutex_unlock(&dev->lock); - return err; - - default: - return -ENODEV; - } - + if (mutex_lock_interruptible(&dev->lock)) + return -ERESTARTSYS; + if (cx25821_res_locked(fh, RESOURCE_VIDEO0)) + err = -EBUSY; + else + err = videobuf_read_one(&fh->vidq, data, count, ppos, + file->f_flags & O_NONBLOCK); + mutex_unlock(&dev->lock); + return err; } static unsigned int video_poll(struct file *file, @@ -818,14 +797,11 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) struct cx25821_fh *fh = priv; struct cx25821_dev *dev = fh->dev; - if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) - return -EINVAL; - - if (unlikely(i != fh->type)) + if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - if (unlikely(!cx25821_res_get(dev, fh, cx25821_get_resource(fh, - RESOURCE_VIDEO0)))) + if (!cx25821_res_get(dev, fh, + cx25821_get_resource(fh, RESOURCE_VIDEO0))) return -EBUSY; return videobuf_streamon(get_queue(fh)); @@ -837,9 +813,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) struct cx25821_dev *dev = fh->dev; int err, res; - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (i != fh->type) + if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; res = cx25821_get_resource(fh, RESOURCE_VIDEO0); diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index ad56232154e6..d1c91c9e911a 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -118,7 +118,6 @@ struct cx25821_tvnorm { struct cx25821_fh { struct cx25821_dev *dev; - enum v4l2_buf_type type; u32 resources; enum v4l2_priority prio; -- cgit v1.2.3 From 2efe2cc4305ad9a8ea4db5881808c4db1c451091 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 10:00:52 -0300 Subject: [media] cx25821: move vidq from cx25821_fh to cx25821_channel This is not a per-filehandle object, it's a per-channel object. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 235 ++++++++++++++---------------- drivers/media/pci/cx25821/cx25821.h | 8 +- 2 files changed, 115 insertions(+), 128 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 2aba24f2a3d8..d88316c5f5de 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -288,7 +288,7 @@ static void cx25821_vid_timeout(unsigned long data) struct cx25821_data *timeout_data = (struct cx25821_data *)data; struct cx25821_dev *dev = timeout_data->dev; const struct sram_channel *channel = timeout_data->channel; - struct cx25821_dmaqueue *q = &dev->channels[channel->i].vidq; + struct cx25821_dmaqueue *q = &dev->channels[channel->i].dma_vidq; struct cx25821_buffer *buf; unsigned long flags; @@ -334,7 +334,7 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) if (status & FLD_VID_DST_RISC1) { spin_lock(&dev->slock); count = cx_read(channel->gpcnt); - cx25821_video_wakeup(dev, &dev->channels[channel->i].vidq, + cx25821_video_wakeup(dev, &dev->channels[channel->i].dma_vidq, count); spin_unlock(&dev->slock); handled++; @@ -345,7 +345,7 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) dprintk(2, "stopper video\n"); spin_lock(&dev->slock); cx25821_restart_video_queue(dev, - &dev->channels[channel->i].vidq, channel); + &dev->channels[channel->i].dma_vidq, channel); spin_unlock(&dev->slock); handled++; } @@ -355,9 +355,9 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status) static int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) { - struct cx25821_fh *fh = q->priv_data; + struct cx25821_channel *chan = q->priv_data; - *size = fh->fmt->depth * fh->width * fh->height >> 3; + *size = chan->fmt->depth * chan->width * chan->height >> 3; if (0 == *count) *count = 32; @@ -371,32 +371,32 @@ static int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count, static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field) { - struct cx25821_fh *fh = q->priv_data; - struct cx25821_dev *dev = fh->dev; + struct cx25821_channel *chan = q->priv_data; + struct cx25821_dev *dev = chan->dev; struct cx25821_buffer *buf = container_of(vb, struct cx25821_buffer, vb); int rc, init_buffer = 0; u32 line0_offset; struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); int bpl_local = LINE_SIZE_D1; - int channel_opened = fh->channel_id; + int channel_opened = chan->id; - BUG_ON(NULL == fh->fmt); - if (fh->width < 48 || fh->width > 720 || - fh->height < 32 || fh->height > 576) + BUG_ON(NULL == chan->fmt); + if (chan->width < 48 || chan->width > 720 || + chan->height < 32 || chan->height > 576) return -EINVAL; - buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; + buf->vb.size = (chan->width * chan->height * chan->fmt->depth) >> 3; if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) return -EINVAL; - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; + if (buf->fmt != chan->fmt || + buf->vb.width != chan->width || + buf->vb.height != chan->height || buf->vb.field != field) { + buf->fmt = chan->fmt; + buf->vb.width = chan->width; + buf->vb.height = chan->height; buf->vb.field = field; init_buffer = 1; } @@ -413,7 +413,6 @@ static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buff dprintk(1, "init_buffer=%d\n", init_buffer); if (init_buffer) { - channel_opened = dev->channel_opened; if (channel_opened < 0 || channel_opened > 7) channel_opened = 7; @@ -483,8 +482,8 @@ static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buff } dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - buf, buf->vb.i, fh->width, fh->height, fh->fmt->depth, - fh->fmt->name, (unsigned long)buf->risc.dma); + buf, buf->vb.i, chan->width, chan->height, chan->fmt->depth, + chan->fmt->name, (unsigned long)buf->risc.dma); buf->vb.state = VIDEOBUF_PREPARED; @@ -504,11 +503,6 @@ static void cx25821_buffer_release(struct videobuf_queue *q, cx25821_free_buffer(q, buf); } -static struct videobuf_queue *get_queue(struct cx25821_fh *fh) -{ - return &fh->vidq; -} - static int cx25821_get_resource(struct cx25821_fh *fh, int resource) { return resource; @@ -516,9 +510,9 @@ static int cx25821_get_resource(struct cx25821_fh *fh, int resource) static int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma) { - struct cx25821_fh *fh = file->private_data; + struct cx25821_channel *chan = video_drvdata(file); - return videobuf_mmap_mapper(get_queue(fh), vma); + return videobuf_mmap_mapper(&chan->vidq, vma); } @@ -527,9 +521,9 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) struct cx25821_buffer *buf = container_of(vb, struct cx25821_buffer, vb); struct cx25821_buffer *prev; - struct cx25821_fh *fh = vq->priv_data; - struct cx25821_dev *dev = fh->dev; - struct cx25821_dmaqueue *q = &dev->channels[fh->channel_id].vidq; + struct cx25821_channel *chan = vq->priv_data; + struct cx25821_dev *dev = chan->dev; + struct cx25821_dmaqueue *q = &dev->channels[chan->id].dma_vidq; /* add jump to stopper */ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); @@ -546,8 +540,7 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) } else if (list_empty(&q->active)) { list_add_tail(&buf->vb.queue, &q->active); - cx25821_start_video_dma(dev, q, buf, - dev->channels[fh->channel_id].sram_channels); + cx25821_start_video_dma(dev, q, buf, chan->sram_channels); buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); @@ -590,19 +583,9 @@ static struct videobuf_queue_ops cx25821_video_qops = { static int video_open(struct file *file) { - struct video_device *vdev = video_devdata(file); - struct cx25821_dev *dev = video_drvdata(file); + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; struct cx25821_fh *fh; - u32 pix_format; - int ch_id; - - for (ch_id = 0; ch_id < MAX_VID_CHANNEL_NUM - 1; ch_id++) - if (&dev->channels[ch_id].vdev == vdev) - break; - - /* Can't happen */ - if (ch_id >= MAX_VID_CHANNEL_NUM - 1) - return -ENODEV; /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); @@ -611,27 +594,11 @@ static int video_open(struct file *file) file->private_data = fh; fh->dev = dev; - fh->width = 720; - fh->channel_id = ch_id; - - if (dev->tvnorm & V4L2_STD_PAL_BG || dev->tvnorm & V4L2_STD_PAL_DK) - fh->height = 576; - else - fh->height = 480; + fh->channel_id = chan->id; dev->channel_opened = fh->channel_id; - if (dev->channels[ch_id].pixel_formats == PIXEL_FRMT_411) - pix_format = V4L2_PIX_FMT_Y41P; - else - pix_format = V4L2_PIX_FMT_YUYV; - fh->fmt = cx25821_format_by_fourcc(pix_format); - - v4l2_prio_open(&dev->channels[ch_id].prio, &fh->prio); - videobuf_queue_sg_init(&fh->vidq, &cx25821_video_qops, &dev->pci->dev, - &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer), - fh, &dev->lock); + v4l2_prio_open(&chan->prio, &fh->prio); dprintk(1, "post videobuf_queue_init()\n"); @@ -642,6 +609,7 @@ static ssize_t video_read(struct file *file, char __user * data, size_t count, loff_t *ppos) { struct cx25821_fh *fh = file->private_data; + struct cx25821_channel *chan = video_drvdata(file); struct cx25821_dev *dev = fh->dev; int err; @@ -650,7 +618,7 @@ static ssize_t video_read(struct file *file, char __user * data, size_t count, if (cx25821_res_locked(fh, RESOURCE_VIDEO0)) err = -EBUSY; else - err = videobuf_read_one(&fh->vidq, data, count, ppos, + err = videobuf_read_one(&chan->vidq, data, count, ppos, file->f_flags & O_NONBLOCK); mutex_unlock(&dev->lock); return err; @@ -660,17 +628,18 @@ static unsigned int video_poll(struct file *file, struct poll_table_struct *wait) { struct cx25821_fh *fh = file->private_data; + struct cx25821_channel *chan = video_drvdata(file); struct cx25821_buffer *buf; if (cx25821_res_check(fh, RESOURCE_VIDEO0)) { /* streaming capture */ - if (list_empty(&fh->vidq.stream)) + if (list_empty(&chan->vidq.stream)) return POLLERR; - buf = list_entry(fh->vidq.stream.next, + buf = list_entry(chan->vidq.stream.next, struct cx25821_buffer, vb.stream); } else { /* read() capture */ - buf = (struct cx25821_buffer *)fh->vidq.read_buf; + buf = (struct cx25821_buffer *)chan->vidq.read_buf; if (NULL == buf) return POLLERR; } @@ -680,12 +649,11 @@ static unsigned int video_poll(struct file *file, if (buf->vb.state == VIDEOBUF_DONE) { struct cx25821_dev *dev = fh->dev; - if (dev && dev->channels[fh->channel_id] - .use_cif_resolution) { + if (dev && chan->use_cif_resolution) { u8 cam_id = *((char *)buf->vb.baddr + 3); memcpy((char *)buf->vb.baddr, - (char *)buf->vb.baddr + (fh->width * 2), - (fh->width * 2)); + (char *)buf->vb.baddr + (chan->width * 2), + (chan->width * 2)); *((char *)buf->vb.baddr + 3) = cam_id; } } @@ -698,8 +666,9 @@ static unsigned int video_poll(struct file *file, static int video_release(struct file *file) { + struct cx25821_channel *chan = video_drvdata(file); struct cx25821_fh *fh = file->private_data; - struct cx25821_dev *dev = fh->dev; + struct cx25821_dev *dev = chan->dev; const struct sram_channel *sram_ch = dev->channels[0].sram_channels; @@ -709,19 +678,19 @@ static int video_release(struct file *file) /* stop video capture */ if (cx25821_res_check(fh, RESOURCE_VIDEO0)) { - videobuf_queue_cancel(&fh->vidq); + videobuf_queue_cancel(&chan->vidq); cx25821_res_free(dev, fh, RESOURCE_VIDEO0); } mutex_unlock(&dev->lock); - if (fh->vidq.read_buf) { - cx25821_buffer_release(&fh->vidq, fh->vidq.read_buf); - kfree(fh->vidq.read_buf); + if (chan->vidq.read_buf) { + cx25821_buffer_release(&chan->vidq, chan->vidq.read_buf); + kfree(chan->vidq.read_buf); } - videobuf_mmap_free(&fh->vidq); + videobuf_mmap_free(&chan->vidq); - v4l2_prio_close(&dev->channels[fh->channel_id].prio, fh->prio); + v4l2_prio_close(&chan->prio, fh->prio); file->private_data = NULL; kfree(fh); @@ -732,13 +701,13 @@ static int video_release(struct file *file) static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx25821_fh *fh = priv; + struct cx25821_channel *chan = video_drvdata(file); - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; - f->fmt.pix.bytesperline = (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.width = chan->width; + f->fmt.pix.height = chan->height; + f->fmt.pix.field = chan->vidq.field; + f->fmt.pix.pixelformat = chan->fmt->fourcc; + f->fmt.pix.bytesperline = (f->fmt.pix.width * chan->fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; return 0; @@ -794,6 +763,7 @@ static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, } static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { + struct cx25821_channel *chan = video_drvdata(file); struct cx25821_fh *fh = priv; struct cx25821_dev *dev = fh->dev; @@ -804,11 +774,12 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) cx25821_get_resource(fh, RESOURCE_VIDEO0))) return -EBUSY; - return videobuf_streamon(get_queue(fh)); + return videobuf_streamon(&chan->vidq); } static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { + struct cx25821_channel *chan = video_drvdata(file); struct cx25821_fh *fh = priv; struct cx25821_dev *dev = fh->dev; int err, res; @@ -817,7 +788,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return -EINVAL; res = cx25821_get_resource(fh, RESOURCE_VIDEO0); - err = videobuf_streamoff(get_queue(fh)); + err = videobuf_streamoff(&chan->vidq); if (err < 0) return err; cx25821_res_free(dev, fh, res); @@ -865,6 +836,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx25821_fh *fh = priv; + struct cx25821_channel *chan = video_drvdata(file); struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; struct v4l2_mbus_framefmt mbus_fmt; int err; @@ -882,15 +854,15 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (0 != err) return err; - fh->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); - fh->vidq.field = f->fmt.pix.field; + chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); + chan->vidq.field = f->fmt.pix.field; /* check if width and height is valid based on set standard */ if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) - fh->width = f->fmt.pix.width; + chan->width = f->fmt.pix.width; if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) - fh->height = f->fmt.pix.height; + chan->height = f->fmt.pix.height; if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P) pix_format = PIXEL_FRMT_411; @@ -902,13 +874,13 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, cx25821_set_pixel_format(dev, SRAM_CH00, pix_format); /* check if cif resolution */ - if (fh->width == 320 || fh->width == 352) - dev->channels[fh->channel_id].use_cif_resolution = 1; + if (chan->width == 320 || chan->width == 352) + chan->use_cif_resolution = 1; else - dev->channels[fh->channel_id].use_cif_resolution = 0; + chan->use_cif_resolution = 0; - dev->channels[fh->channel_id].cif_width = fh->width; - medusa_set_resolution(dev, fh->width, SRAM_CH00); + chan->cif_width = chan->width; + medusa_set_resolution(dev, chan->width, SRAM_CH00); v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt); @@ -919,12 +891,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) { int ret_val = 0; - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + struct cx25821_channel *chan = video_drvdata(file); - ret_val = videobuf_dqbuf(get_queue(fh), p, file->f_flags & O_NONBLOCK); - - p->sequence = dev->channels[fh->channel_id].vidq.count; + ret_val = videobuf_dqbuf(&chan->vidq, p, file->f_flags & O_NONBLOCK); + p->sequence = chan->dma_vidq.count; return ret_val; } @@ -980,21 +950,24 @@ static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, static int cx25821_vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) { - struct cx25821_fh *fh = priv; - return videobuf_reqbufs(get_queue(fh), p); + struct cx25821_channel *chan = video_drvdata(file); + + return videobuf_reqbufs(&chan->vidq, p); } static int cx25821_vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) { - struct cx25821_fh *fh = priv; - return videobuf_querybuf(get_queue(fh), p); + struct cx25821_channel *chan = video_drvdata(file); + + return videobuf_querybuf(&chan->vidq, p); } static int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) { - struct cx25821_fh *fh = priv; - return videobuf_qbuf(get_queue(fh), p); + struct cx25821_channel *chan = video_drvdata(file); + + return videobuf_qbuf(&chan->vidq, p); } static int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) @@ -1466,7 +1439,7 @@ void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl); btcx_riscmem_free(dev->pci, - &dev->channels[chan_num].vidq.stopper); + &dev->channels[chan_num].dma_vidq.stopper); } } @@ -1482,8 +1455,9 @@ int cx25821_video_register(struct cx25821_dev *dev) spin_lock_init(&dev->slock); for (i = 0; i < VID_CHANNEL_NUM; ++i) { - struct video_device *vdev = &dev->channels[i].vdev; - struct v4l2_ctrl_handler *hdl = &dev->channels[i].hdl; + struct cx25821_channel *chan = &dev->channels[i]; + struct video_device *vdev = &chan->vdev; + struct v4l2_ctrl_handler *hdl = &chan->hdl; if (i == SRAM_CH08) /* audio channel */ continue; @@ -1505,24 +1479,37 @@ int cx25821_video_register(struct cx25821_dev *dev) if (err) goto fail_unreg; - cx25821_risc_stopper(dev->pci, &dev->channels[i].vidq.stopper, - dev->channels[i].sram_channels->dma_ctl, 0x11, 0); + cx25821_risc_stopper(dev->pci, &chan->dma_vidq.stopper, + chan->sram_channels->dma_ctl, 0x11, 0); - dev->channels[i].sram_channels = &cx25821_sram_channels[i]; - dev->channels[i].resources = 0; + chan->sram_channels = &cx25821_sram_channels[i]; + chan->resources = 0; + chan->width = 720; + if (dev->tvnorm & V4L2_STD_625_50) + chan->height = 576; + else + chan->height = 480; - cx_write(dev->channels[i].sram_channels->int_stat, 0xffffffff); + if (chan->pixel_formats == PIXEL_FRMT_411) + chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_Y41P); + else + chan->fmt = cx25821_format_by_fourcc(V4L2_PIX_FMT_YUYV); - INIT_LIST_HEAD(&dev->channels[i].vidq.active); - INIT_LIST_HEAD(&dev->channels[i].vidq.queued); + cx_write(chan->sram_channels->int_stat, 0xffffffff); - dev->channels[i].timeout_data.dev = dev; - dev->channels[i].timeout_data.channel = - &cx25821_sram_channels[i]; - dev->channels[i].vidq.timeout.function = cx25821_vid_timeout; - dev->channels[i].vidq.timeout.data = - (unsigned long)&dev->channels[i].timeout_data; - init_timer(&dev->channels[i].vidq.timeout); + INIT_LIST_HEAD(&chan->dma_vidq.active); + INIT_LIST_HEAD(&chan->dma_vidq.queued); + + chan->timeout_data.dev = dev; + chan->timeout_data.channel = &cx25821_sram_channels[i]; + chan->dma_vidq.timeout.function = cx25821_vid_timeout; + chan->dma_vidq.timeout.data = (unsigned long)&chan->timeout_data; + init_timer(&chan->dma_vidq.timeout); + + videobuf_queue_sg_init(&chan->vidq, &cx25821_video_qops, &dev->pci->dev, + &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer), + chan, &dev->lock); /* register v4l devices */ *vdev = cx25821_video_device; @@ -1530,7 +1517,7 @@ int cx25821_video_register(struct cx25821_dev *dev) vdev->ctrl_handler = hdl; vdev->lock = &dev->lock; snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i); - video_set_drvdata(vdev, dev); + video_set_drvdata(vdev, chan); err = video_register_device(vdev, VFL_TYPE_GRABBER, video_nr[dev->nr]); diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index d1c91c9e911a..06dadb5d9e56 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -123,10 +123,7 @@ struct cx25821_fh { enum v4l2_priority prio; /* video capture */ - const struct cx25821_fmt *fmt; - unsigned int width, height; int channel_id; - struct videobuf_queue vidq; }; enum cx25821_itype { @@ -217,12 +214,15 @@ struct cx25821_channel { struct cx25821_data timeout_data; struct video_device vdev; - struct cx25821_dmaqueue vidq; + struct cx25821_dmaqueue dma_vidq; + struct videobuf_queue vidq; const struct sram_channel *sram_channels; int resources; + const struct cx25821_fmt *fmt; + unsigned int width, height; int pixel_formats; int use_cif_resolution; int cif_width; -- cgit v1.2.3 From 84293f0843931b13d8331093bafacd1d70dd5efb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 14 Apr 2013 11:56:39 -0300 Subject: [media] cx25821: replace resource management functions with fh ownership Just remember which filehandle is streaming instead of using complicated resource masks. After this patch we can replace cx25821_fh with v4l2_fh. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 130 ++++++++---------------------- drivers/media/pci/cx25821/cx25821.h | 5 +- 2 files changed, 35 insertions(+), 100 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index d88316c5f5de..e7a2db158a0e 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -144,48 +144,6 @@ static int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm) return 0; } -/* resource management */ -static int cx25821_res_get(struct cx25821_dev *dev, struct cx25821_fh *fh, - unsigned int bit) -{ - dprintk(1, "%s()\n", __func__); - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - /* is it free? */ - if (dev->channels[fh->channel_id].resources & bit) { - /* no, someone else uses it */ - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->channels[fh->channel_id].resources |= bit; - dprintk(1, "res: get %d\n", bit); - return 1; -} - -static int cx25821_res_check(struct cx25821_fh *fh, unsigned int bit) -{ - return fh->resources & bit; -} - -static int cx25821_res_locked(struct cx25821_fh *fh, unsigned int bit) -{ - return fh->dev->channels[fh->channel_id].resources & bit; -} - -static void cx25821_res_free(struct cx25821_dev *dev, struct cx25821_fh *fh, - unsigned int bits) -{ - BUG_ON((fh->resources & bits) != bits); - dprintk(1, "%s()\n", __func__); - - fh->resources &= ~bits; - dev->channels[fh->channel_id].resources &= ~bits; - dprintk(1, "res: put %d\n", bits); -} - static int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input) { struct v4l2_routing route; @@ -503,11 +461,6 @@ static void cx25821_buffer_release(struct videobuf_queue *q, cx25821_free_buffer(q, buf); } -static int cx25821_get_resource(struct cx25821_fh *fh, int resource) -{ - return resource; -} - static int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma) { struct cx25821_channel *chan = video_drvdata(file); @@ -611,15 +564,19 @@ static ssize_t video_read(struct file *file, char __user * data, size_t count, struct cx25821_fh *fh = file->private_data; struct cx25821_channel *chan = video_drvdata(file); struct cx25821_dev *dev = fh->dev; - int err; + int err = 0; if (mutex_lock_interruptible(&dev->lock)) return -ERESTARTSYS; - if (cx25821_res_locked(fh, RESOURCE_VIDEO0)) + if (chan->streaming_fh && chan->streaming_fh != fh) { err = -EBUSY; - else - err = videobuf_read_one(&chan->vidq, data, count, ppos, + goto unlock; + } + chan->streaming_fh = fh; + + err = videobuf_read_one(&chan->vidq, data, count, ppos, file->f_flags & O_NONBLOCK); +unlock: mutex_unlock(&dev->lock); return err; } @@ -627,41 +584,25 @@ static ssize_t video_read(struct file *file, char __user * data, size_t count, static unsigned int video_poll(struct file *file, struct poll_table_struct *wait) { - struct cx25821_fh *fh = file->private_data; struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_buffer *buf; - if (cx25821_res_check(fh, RESOURCE_VIDEO0)) { - /* streaming capture */ - if (list_empty(&chan->vidq.stream)) - return POLLERR; - buf = list_entry(chan->vidq.stream.next, - struct cx25821_buffer, vb.stream); - } else { - /* read() capture */ - buf = (struct cx25821_buffer *)chan->vidq.read_buf; - if (NULL == buf) - return POLLERR; - } + return videobuf_poll_stream(file, &chan->vidq, wait); - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) { - if (buf->vb.state == VIDEOBUF_DONE) { - struct cx25821_dev *dev = fh->dev; - - if (dev && chan->use_cif_resolution) { - u8 cam_id = *((char *)buf->vb.baddr + 3); - memcpy((char *)buf->vb.baddr, - (char *)buf->vb.baddr + (chan->width * 2), - (chan->width * 2)); - *((char *)buf->vb.baddr + 3) = cam_id; - } - } + /* This doesn't belong in poll(). This can be done + * much better with vb2. We keep this code here as a + * reminder. + if ((res & POLLIN) && buf->vb.state == VIDEOBUF_DONE) { + struct cx25821_dev *dev = chan->dev; - return POLLIN | POLLRDNORM; + if (dev && chan->use_cif_resolution) { + u8 cam_id = *((char *)buf->vb.baddr + 3); + memcpy((char *)buf->vb.baddr, + (char *)buf->vb.baddr + (chan->width * 2), + (chan->width * 2)); + *((char *)buf->vb.baddr + 3) = cam_id; + } } - - return 0; + */ } static int video_release(struct file *file) @@ -677,11 +618,10 @@ static int video_release(struct file *file) cx_write(sram_ch->dma_ctl, 0); /* FIFO and RISC disable */ /* stop video capture */ - if (cx25821_res_check(fh, RESOURCE_VIDEO0)) { + if (chan->streaming_fh == fh) { videobuf_queue_cancel(&chan->vidq); - cx25821_res_free(dev, fh, RESOURCE_VIDEO0); + chan->streaming_fh = NULL; } - mutex_unlock(&dev->lock); if (chan->vidq.read_buf) { cx25821_buffer_release(&chan->vidq, chan->vidq.read_buf); @@ -689,6 +629,7 @@ static int video_release(struct file *file) } videobuf_mmap_free(&chan->vidq); + mutex_unlock(&dev->lock); v4l2_prio_close(&chan->prio, fh->prio); file->private_data = NULL; @@ -765,14 +706,13 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct cx25821_channel *chan = video_drvdata(file); struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = fh->dev; if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - if (!cx25821_res_get(dev, fh, - cx25821_get_resource(fh, RESOURCE_VIDEO0))) + if (chan->streaming_fh && chan->streaming_fh != fh) return -EBUSY; + chan->streaming_fh = fh; return videobuf_streamon(&chan->vidq); } @@ -781,18 +721,17 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { struct cx25821_channel *chan = video_drvdata(file); struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = fh->dev; - int err, res; if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - res = cx25821_get_resource(fh, RESOURCE_VIDEO0); - err = videobuf_streamoff(&chan->vidq); - if (err < 0) - return err; - cx25821_res_free(dev, fh, res); - return 0; + if (chan->streaming_fh && chan->streaming_fh != fh) + return -EBUSY; + if (chan->streaming_fh == NULL) + return 0; + + chan->streaming_fh = NULL; + return videobuf_streamoff(&chan->vidq); } static int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm) @@ -1483,7 +1422,6 @@ int cx25821_video_register(struct cx25821_dev *dev) chan->sram_channels->dma_ctl, 0x11, 0); chan->sram_channels = &cx25821_sram_channels[i]; - chan->resources = 0; chan->width = 720; if (dev->tvnorm & V4L2_STD_625_50) chan->height = 576; diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 06dadb5d9e56..128c9f320dfb 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -118,7 +118,6 @@ struct cx25821_tvnorm { struct cx25821_fh { struct cx25821_dev *dev; - u32 resources; enum v4l2_priority prio; @@ -208,6 +207,7 @@ struct cx25821_dev; struct cx25821_channel { unsigned id; struct cx25821_dev *dev; + struct cx25821_fh *streaming_fh; struct v4l2_prio_state prio; struct v4l2_ctrl_handler hdl; @@ -219,8 +219,6 @@ struct cx25821_channel { const struct sram_channel *sram_channels; - int resources; - const struct cx25821_fmt *fmt; unsigned int width, height; int pixel_formats; @@ -260,7 +258,6 @@ struct cx25821_dev { char name[32]; /* Analog video */ - u32 resources; unsigned int input; v4l2_std_id tvnorm; unsigned short _max_num_decoders; -- cgit v1.2.3 From 8d125c507dee259d12299c9eb6e8d32ac1f8ae6d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 14 Apr 2013 11:57:18 -0300 Subject: [media] cx25821: switch to v4l2_fh, add event and prio handling It is now possible to remove cx25821_fh and replace it with v4l2_fh, which in turn makes event handling and core prio handling possible. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 193 +++++++++--------------------- drivers/media/pci/cx25821/cx25821-video.h | 1 + drivers/media/pci/cx25821/cx25821.h | 13 +- 3 files changed, 59 insertions(+), 148 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index e7a2db158a0e..f82da1e69e60 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -337,7 +337,6 @@ static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buff u32 line0_offset; struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); int bpl_local = LINE_SIZE_D1; - int channel_opened = chan->id; BUG_ON(NULL == chan->fmt); if (chan->width < 48 || chan->width > 720 || @@ -371,33 +370,22 @@ static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buff dprintk(1, "init_buffer=%d\n", init_buffer); if (init_buffer) { - channel_opened = dev->channel_opened; - if (channel_opened < 0 || channel_opened > 7) - channel_opened = 7; - - if (dev->channels[channel_opened].pixel_formats == - PIXEL_FRMT_411) + if (chan->pixel_formats == PIXEL_FRMT_411) buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3; else buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width); - if (dev->channels[channel_opened].pixel_formats == - PIXEL_FRMT_411) { + if (chan->pixel_formats == PIXEL_FRMT_411) { bpl_local = buf->bpl; } else { bpl_local = buf->bpl; /* Default */ - if (channel_opened >= 0 && channel_opened <= 7) { - if (dev->channels[channel_opened] - .use_cif_resolution) { - if (dev->tvnorm & V4L2_STD_PAL_BG || - dev->tvnorm & V4L2_STD_PAL_DK) - bpl_local = 352 << 1; - else - bpl_local = dev->channels[ - channel_opened]. - cif_width << 1; - } + if (chan->use_cif_resolution) { + if (dev->tvnorm & V4L2_STD_PAL_BG || + dev->tvnorm & V4L2_STD_PAL_DK) + bpl_local = 352 << 1; + else + bpl_local = chan->cif_width << 1; } } @@ -534,36 +522,12 @@ static struct videobuf_queue_ops cx25821_video_qops = { .buf_release = cx25821_buffer_release, }; -static int video_open(struct file *file) -{ - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - struct cx25821_fh *fh; - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) - return -ENOMEM; - - file->private_data = fh; - fh->dev = dev; - fh->channel_id = chan->id; - - dev->channel_opened = fh->channel_id; - - v4l2_prio_open(&chan->prio, &fh->prio); - - dprintk(1, "post videobuf_queue_init()\n"); - - return 0; -} - static ssize_t video_read(struct file *file, char __user * data, size_t count, loff_t *ppos) { - struct cx25821_fh *fh = file->private_data; + struct v4l2_fh *fh = file->private_data; struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = fh->dev; + struct cx25821_dev *dev = chan->dev; int err = 0; if (mutex_lock_interruptible(&dev->lock)) @@ -585,8 +549,12 @@ static unsigned int video_poll(struct file *file, struct poll_table_struct *wait) { struct cx25821_channel *chan = video_drvdata(file); + unsigned long req_events = poll_requested_events(wait); + unsigned int res = v4l2_ctrl_poll(file, wait); - return videobuf_poll_stream(file, &chan->vidq, wait); + if (req_events & (POLLIN | POLLRDNORM)) + res |= videobuf_poll_stream(file, &chan->vidq, wait); + return res; /* This doesn't belong in poll(). This can be done * much better with vb2. We keep this code here as a @@ -608,7 +576,7 @@ static unsigned int video_poll(struct file *file, static int video_release(struct file *file) { struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_fh *fh = file->private_data; + struct v4l2_fh *fh = file->private_data; struct cx25821_dev *dev = chan->dev; const struct sram_channel *sram_ch = dev->channels[0].sram_channels; @@ -631,11 +599,7 @@ static int video_release(struct file *file) videobuf_mmap_free(&chan->vidq); mutex_unlock(&dev->lock); - v4l2_prio_close(&chan->prio, fh->prio); - file->private_data = NULL; - kfree(fh); - - return 0; + return v4l2_fh_release(file); } /* VIDEO IOCTLS */ @@ -705,14 +669,13 @@ static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_fh *fh = priv; if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - if (chan->streaming_fh && chan->streaming_fh != fh) + if (chan->streaming_fh && chan->streaming_fh != priv) return -EBUSY; - chan->streaming_fh = fh; + chan->streaming_fh = priv; return videobuf_streamon(&chan->vidq); } @@ -720,12 +683,11 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_fh *fh = priv; if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - if (chan->streaming_fh && chan->streaming_fh != fh) + if (chan->streaming_fh && chan->streaming_fh != priv) return -EBUSY; if (chan->streaming_fh == NULL) return 0; @@ -774,20 +736,12 @@ static int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm) static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx25821_fh *fh = priv; struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + struct cx25821_dev *dev = chan->dev; struct v4l2_mbus_framefmt mbus_fmt; int err; int pix_format = PIXEL_FRMT_422; - if (fh) { - err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, - fh->prio); - if (0 != err) - return err; - } - err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f); if (0 != err) @@ -840,10 +794,9 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) static int vidioc_log_status(struct file *file, void *priv) { - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - struct cx25821_fh *fh = priv; - const struct sram_channel *sram_ch = - dev->channels[fh->channel_id].sram_channels; + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; + const struct sram_channel *sram_ch = chan->sram_channels; u32 tmp = 0; cx25821_call_all(dev, core, log_status); @@ -857,8 +810,8 @@ static int vidioc_log_status(struct file *file, void *priv) static int cx25821_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - struct cx25821_fh *fh = priv; + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; const u32 cap_input = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT; @@ -866,7 +819,7 @@ static int cx25821_vidioc_querycap(struct file *file, void *priv, strcpy(cap->driver, "cx25821"); strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - if (fh->channel_id >= VID_CHANNEL_NUM) + if (chan->id >= VID_CHANNEL_NUM) cap->device_caps = cap_output; else cap->device_caps = cap_input; @@ -909,46 +862,18 @@ static int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer return videobuf_qbuf(&chan->vidq, p); } -static int cx25821_vidioc_g_priority(struct file *file, void *f, enum v4l2_priority *p) -{ - struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev; - struct cx25821_fh *fh = f; - - *p = v4l2_prio_max(&dev->channels[fh->channel_id].prio); - - return 0; -} - -static int cx25821_vidioc_s_priority(struct file *file, void *f, - enum v4l2_priority prio) -{ - struct cx25821_fh *fh = f; - struct cx25821_dev *dev = ((struct cx25821_fh *)f)->dev; - - return v4l2_prio_change(&dev->channels[fh->channel_id].prio, &fh->prio, - prio); -} - static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms) { - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + struct cx25821_channel *chan = video_drvdata(file); - *tvnorms = dev->tvnorm; + *tvnorms = chan->dev->tvnorm; return 0; } int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) { - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - int err; - - if (fh) { - err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, - fh->prio); - if (0 != err) - return err; - } + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; if (dev->tvnorm == tvnorms) return 0; @@ -968,7 +893,8 @@ static int cx25821_vidioc_enum_input(struct file *file, void *priv, [CX25821_VMUX_SVIDEO] = "S-Video", [CX25821_VMUX_DEBUG] = "for debug only", }; - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; unsigned int n; n = i->index; @@ -987,7 +913,8 @@ static int cx25821_vidioc_enum_input(struct file *file, void *priv, static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i) { - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; *i = dev->input; return 0; @@ -995,16 +922,8 @@ static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) { - struct cx25821_fh *fh = priv; - struct cx25821_dev *dev = ((struct cx25821_fh *)priv)->dev; - int err; - - if (fh) { - err = v4l2_prio_check(&dev->channels[fh->channel_id].prio, - fh->prio); - if (0 != err) - return err; - } + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; if (i >= CX25821_NR_INPUT || INPUT(i)->type == 0) return -EINVAL; @@ -1017,7 +936,8 @@ static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) int cx25821_vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { - struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev; + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; if (!v4l2_chip_match_host(®->match)) return -EINVAL; @@ -1030,7 +950,8 @@ int cx25821_vidioc_g_register(struct file *file, void *fh, int cx25821_vidioc_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) { - struct cx25821_dev *dev = ((struct cx25821_fh *)fh)->dev; + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; if (!v4l2_chip_match_host(®->match)) return -EINVAL; @@ -1070,8 +991,8 @@ static int cx25821_s_ctrl(struct v4l2_ctrl *ctrl) static long video_ioctl_upstream9(struct file *file, unsigned int cmd, unsigned long arg) { - struct cx25821_fh *fh = file->private_data; - struct cx25821_dev *dev = fh->dev; + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; int command = 0; struct upstream_user_struct *data_from_user; @@ -1110,8 +1031,8 @@ static long video_ioctl_upstream9(struct file *file, unsigned int cmd, static long video_ioctl_upstream10(struct file *file, unsigned int cmd, unsigned long arg) { - struct cx25821_fh *fh = file->private_data; - struct cx25821_dev *dev = fh->dev; + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; int command = 0; struct upstream_user_struct *data_from_user; @@ -1150,8 +1071,8 @@ static long video_ioctl_upstream10(struct file *file, unsigned int cmd, static long video_ioctl_upstream11(struct file *file, unsigned int cmd, unsigned long arg) { - struct cx25821_fh *fh = file->private_data; - struct cx25821_dev *dev = fh->dev; + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; int command = 0; struct upstream_user_struct *data_from_user; @@ -1190,8 +1111,8 @@ static long video_ioctl_upstream11(struct file *file, unsigned int cmd, static long video_ioctl_set(struct file *file, unsigned int cmd, unsigned long arg) { - struct cx25821_fh *fh = file->private_data; - struct cx25821_dev *dev = fh->dev; + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; struct downstream_user_struct *data_from_user; int command; int width = 720; @@ -1300,18 +1221,17 @@ static long video_ioctl_set(struct file *file, unsigned int cmd, static long cx25821_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { + struct cx25821_channel *chan = video_drvdata(file); int ret = 0; - struct cx25821_fh *fh = file->private_data; - /* check to see if it's the video upstream */ - if (fh->channel_id == SRAM_CH09) { + if (chan->id == SRAM_CH09) { ret = video_ioctl_upstream9(file, cmd, arg); return ret; - } else if (fh->channel_id == SRAM_CH10) { + } else if (chan->id == SRAM_CH10) { ret = video_ioctl_upstream10(file, cmd, arg); return ret; - } else if (fh->channel_id == SRAM_CH11) { + } else if (chan->id == SRAM_CH11) { ret = video_ioctl_upstream11(file, cmd, arg); ret = video_ioctl_set(file, cmd, arg); return ret; @@ -1326,7 +1246,7 @@ static const struct v4l2_ctrl_ops cx25821_ctrl_ops = { static const struct v4l2_file_operations video_fops = { .owner = THIS_MODULE, - .open = video_open, + .open = v4l2_fh_open, .release = video_release, .read = video_read, .poll = video_poll, @@ -1352,8 +1272,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_log_status = vidioc_log_status, - .vidioc_g_priority = cx25821_vidioc_g_priority, - .vidioc_s_priority = cx25821_vidioc_s_priority, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = cx25821_vidioc_g_register, .vidioc_s_register = cx25821_vidioc_s_register, @@ -1454,6 +1374,7 @@ int cx25821_video_register(struct cx25821_dev *dev) vdev->v4l2_dev = &dev->v4l2_dev; vdev->ctrl_handler = hdl; vdev->lock = &dev->lock; + set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags); snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i); video_set_drvdata(vdev, chan); diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index b0f0d5395490..eb54e5347cc4 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -39,6 +39,7 @@ #include "cx25821.h" #include #include +#include #define VIDEO_DEBUG 0 diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 128c9f320dfb..40b16b01349b 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -116,15 +116,6 @@ struct cx25821_tvnorm { u32 cxoformat; }; -struct cx25821_fh { - struct cx25821_dev *dev; - - enum v4l2_priority prio; - - /* video capture */ - int channel_id; -}; - enum cx25821_itype { CX25821_VMUX_COMPOSITE = 1, CX25821_VMUX_SVIDEO, @@ -207,8 +198,7 @@ struct cx25821_dev; struct cx25821_channel { unsigned id; struct cx25821_dev *dev; - struct cx25821_fh *streaming_fh; - struct v4l2_prio_state prio; + struct v4l2_fh *streaming_fh; struct v4l2_ctrl_handler hdl; struct cx25821_data timeout_data; @@ -360,7 +350,6 @@ struct cx25821_dev { int pixel_format; int channel_select; int command; - int channel_opened; }; struct upstream_user_struct { -- cgit v1.2.3 From 988f7b80ab6e541aef5972d347d6cc7d905abd21 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 13:06:00 -0300 Subject: [media] cx25821: g/s/try/enum_fmt related fixes and cleanups - fill in colorspace - zero priv - delete unsupported formats - fix field handling - s_std should update width/height - proper mapping of width/height to valid resolutions Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 134 +++++++----------------------- 1 file changed, 32 insertions(+), 102 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index f82da1e69e60..aec6fdfe944d 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -54,11 +54,6 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); static const struct cx25821_fmt formats[] = { { - .name = "8 bpp, gray", - .fourcc = V4L2_PIX_FMT_GREY, - .depth = 8, - .flags = FORMAT_FLAGS_PACKED, - }, { .name = "4:1:1, packed, Y41P", .fourcc = V4L2_PIX_FMT_Y41P, .depth = 12, @@ -68,16 +63,6 @@ static const struct cx25821_fmt formats[] = { .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:2:0, YUV", - .fourcc = V4L2_PIX_FMT_YUV420, - .depth = 12, - .flags = FORMAT_FLAGS_PACKED, }, }; @@ -85,14 +70,9 @@ static const struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc) { unsigned int i; - if (fourcc == V4L2_PIX_FMT_Y41P || fourcc == V4L2_PIX_FMT_YUV411P) - return formats + 1; - for (i = 0; i < ARRAY_SIZE(formats); i++) if (formats[i].fourcc == fourcc) return formats + i; - - pr_err("%s(0x%08x) NOT FOUND\n", __func__, fourcc); return NULL; } @@ -381,8 +361,7 @@ static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buff bpl_local = buf->bpl; /* Default */ if (chan->use_cif_resolution) { - if (dev->tvnorm & V4L2_STD_PAL_BG || - dev->tvnorm & V4L2_STD_PAL_DK) + if (dev->tvnorm & V4L2_STD_625_50) bpl_local = 352 << 1; else bpl_local = chan->cif_width << 1; @@ -612,8 +591,10 @@ static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.height = chan->height; f->fmt.pix.field = chan->vidq.field; f->fmt.pix.pixelformat = chan->fmt->fourcc; - f->fmt.pix.bytesperline = (f->fmt.pix.width * chan->fmt->depth) >> 3; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.bytesperline = (chan->width * chan->fmt->depth) >> 3; + f->fmt.pix.sizeimage = chan->height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.priv = 0; return 0; } @@ -621,48 +602,39 @@ static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; const struct cx25821_fmt *fmt; - enum v4l2_field field; + enum v4l2_field field = f->fmt.pix.field; unsigned int maxw, maxh; + unsigned w; fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); if (NULL == fmt) return -EINVAL; - - field = f->fmt.pix.field; maxw = 720; - maxh = 576; - - if (V4L2_FIELD_ANY == field) { - if (f->fmt.pix.height > maxh / 2) - field = V4L2_FIELD_INTERLACED; - else - field = V4L2_FIELD_TOP; - } - - switch (field) { - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - maxh = maxh / 2; - break; - case V4L2_FIELD_INTERLACED: - break; - default: - return -EINVAL; + maxh = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480; + + w = f->fmt.pix.width; + if (field != V4L2_FIELD_BOTTOM) + field = V4L2_FIELD_TOP; + if (w < 352) { + w = 176; + f->fmt.pix.height = maxh / 4; + } else if (w < 720) { + w = 352; + f->fmt.pix.height = maxh / 2; + } else { + w = 720; + f->fmt.pix.height = maxh; + field = V4L2_FIELD_INTERLACED; } - f->fmt.pix.field = field; - if (f->fmt.pix.height < 32) - f->fmt.pix.height = 32; - if (f->fmt.pix.height > maxh) - f->fmt.pix.height = maxh; - if (f->fmt.pix.width < 48) - f->fmt.pix.width = 48; - if (f->fmt.pix.width > maxw) - f->fmt.pix.width = maxw; - f->fmt.pix.width &= ~0x03; + f->fmt.pix.width = w; f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.priv = 0; return 0; } @@ -696,43 +668,6 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) return videobuf_streamoff(&chan->vidq); } -static int cx25821_is_valid_width(u32 width, v4l2_std_id tvnorm) -{ - if (tvnorm == V4L2_STD_PAL_BG) { - if (width == 352 || width == 720) - return 1; - else - return 0; - } - - if (tvnorm == V4L2_STD_NTSC_M) { - if (width == 320 || width == 352 || width == 720) - return 1; - else - return 0; - } - return 0; -} - -static int cx25821_is_valid_height(u32 height, v4l2_std_id tvnorm) -{ - if (tvnorm == V4L2_STD_PAL_BG) { - if (height == 576 || height == 288) - return 1; - else - return 0; - } - - if (tvnorm == V4L2_STD_NTSC_M) { - if (height == 480 || height == 240) - return 1; - else - return 0; - } - - return 0; -} - static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { @@ -749,20 +684,13 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); chan->vidq.field = f->fmt.pix.field; - - /* check if width and height is valid based on set standard */ - if (cx25821_is_valid_width(f->fmt.pix.width, dev->tvnorm)) - chan->width = f->fmt.pix.width; - - if (cx25821_is_valid_height(f->fmt.pix.height, dev->tvnorm)) - chan->height = f->fmt.pix.height; + chan->width = f->fmt.pix.width; + chan->height = f->fmt.pix.height; if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P) pix_format = PIXEL_FRMT_411; - else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV) - pix_format = PIXEL_FRMT_422; else - return -EINVAL; + pix_format = PIXEL_FRMT_422; cx25821_set_pixel_format(dev, SRAM_CH00, pix_format); @@ -879,6 +807,8 @@ int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) return 0; cx25821_set_tvnorm(dev, tvnorms); + chan->width = 720; + chan->height = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480; medusa_set_videostandard(dev); -- cgit v1.2.3 From 7704cfb9cde649d514029a180cdfb7ccf0a36032 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 13:14:06 -0300 Subject: [media] cx25821: remove custom ioctls that duplicate v4l2 ioctls No idea why these custom ioctls exist: they have perfectly normal v4l2 counterparts which are already implemented. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 128 ++---------------------------- drivers/media/pci/cx25821/cx25821-video.h | 8 -- drivers/media/pci/cx25821/cx25821.h | 13 --- 3 files changed, 6 insertions(+), 143 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index aec6fdfe944d..d3aa166740cd 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -1038,134 +1038,18 @@ static long video_ioctl_upstream11(struct file *file, unsigned int cmd, return 0; } -static long video_ioctl_set(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - struct downstream_user_struct *data_from_user; - int command; - int width = 720; - int selected_channel = 0; - int pix_format = 0; - int i = 0; - int cif_enable = 0; - int cif_width = 0; - - data_from_user = (struct downstream_user_struct *)arg; - - if (!data_from_user) { - pr_err("%s(): User data is INVALID. Returning\n", __func__); - return 0; - } - - command = data_from_user->command; - - if (command != SET_VIDEO_STD && command != SET_PIXEL_FORMAT - && command != ENABLE_CIF_RESOLUTION && command != REG_READ - && command != REG_WRITE && command != MEDUSA_READ - && command != MEDUSA_WRITE) { - return 0; - } - - switch (command) { - case SET_VIDEO_STD: - if (!strcmp(data_from_user->vid_stdname, "PAL")) - dev->tvnorm = V4L2_STD_PAL_BG; - else - dev->tvnorm = V4L2_STD_NTSC_M; - medusa_set_videostandard(dev); - break; - - case SET_PIXEL_FORMAT: - selected_channel = data_from_user->decoder_select; - pix_format = data_from_user->pixel_format; - - if (!(selected_channel <= 7 && selected_channel >= 0)) { - selected_channel -= 4; - selected_channel = selected_channel % 8; - } - - if (selected_channel >= 0) - cx25821_set_pixel_format(dev, selected_channel, - pix_format); - - break; - - case ENABLE_CIF_RESOLUTION: - selected_channel = data_from_user->decoder_select; - cif_enable = data_from_user->cif_resolution_enable; - cif_width = data_from_user->cif_width; - - if (cif_enable) { - if (dev->tvnorm & V4L2_STD_PAL_BG - || dev->tvnorm & V4L2_STD_PAL_DK) { - width = 352; - } else { - width = cif_width; - if (cif_width != 320 && cif_width != 352) - width = 320; - } - } - - if (!(selected_channel <= 7 && selected_channel >= 0)) { - selected_channel -= 4; - selected_channel = selected_channel % 8; - } - - if (selected_channel <= 7 && selected_channel >= 0) { - dev->channels[selected_channel].use_cif_resolution = - cif_enable; - dev->channels[selected_channel].cif_width = width; - } else { - for (i = 0; i < VID_CHANNEL_NUM; i++) { - dev->channels[i].use_cif_resolution = - cif_enable; - dev->channels[i].cif_width = width; - } - } - - medusa_set_resolution(dev, width, selected_channel); - break; - case REG_READ: - data_from_user->reg_data = cx_read(data_from_user->reg_address); - break; - case REG_WRITE: - cx_write(data_from_user->reg_address, data_from_user->reg_data); - break; - case MEDUSA_READ: - cx25821_i2c_read(&dev->i2c_bus[0], - (u16) data_from_user->reg_address, - &data_from_user->reg_data); - break; - case MEDUSA_WRITE: - cx25821_i2c_write(&dev->i2c_bus[0], - (u16) data_from_user->reg_address, - data_from_user->reg_data); - break; - } - - return 0; -} - static long cx25821_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct cx25821_channel *chan = video_drvdata(file); - int ret = 0; /* check to see if it's the video upstream */ - if (chan->id == SRAM_CH09) { - ret = video_ioctl_upstream9(file, cmd, arg); - return ret; - } else if (chan->id == SRAM_CH10) { - ret = video_ioctl_upstream10(file, cmd, arg); - return ret; - } else if (chan->id == SRAM_CH11) { - ret = video_ioctl_upstream11(file, cmd, arg); - ret = video_ioctl_set(file, cmd, arg); - return ret; - } + if (chan->id == SRAM_CH09) + return video_ioctl_upstream9(file, cmd, arg); + if (chan->id == SRAM_CH10) + return video_ioctl_upstream10(file, cmd, arg); + if (chan->id == SRAM_CH11) + return video_ioctl_upstream11(file, cmd, arg); return video_ioctl2(file, cmd, arg); } diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index eb54e5347cc4..8871c4e737e8 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -55,14 +55,6 @@ do { \ #define UPSTREAM_START_AUDIO 702 #define UPSTREAM_STOP_AUDIO 703 #define UPSTREAM_DUMP_REGISTERS 702 -#define SET_VIDEO_STD 800 -#define SET_PIXEL_FORMAT 1000 -#define ENABLE_CIF_RESOLUTION 1001 - -#define REG_READ 900 -#define REG_WRITE 901 -#define MEDUSA_READ 910 -#define MEDUSA_WRITE 911 #define FORMAT_FLAGS_PACKED 0x01 extern void cx25821_video_wakeup(struct cx25821_dev *dev, diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 40b16b01349b..cfda5ac4faaa 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -360,19 +360,6 @@ struct upstream_user_struct { int command; }; -struct downstream_user_struct { - char *vid_stdname; - int pixel_format; - int cif_resolution_enable; - int cif_width; - int decoder_select; - int command; - int reg_address; - int reg_data; -}; - -extern struct upstream_user_struct *up_data; - static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev) { return container_of(v4l2_dev, struct cx25821_dev, v4l2_dev); -- cgit v1.2.3 From a6aa0dc482d7aad5fc4366d4c92d07a10d712b82 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 13 Apr 2013 13:34:34 -0300 Subject: [media] cx25821: remove references to subdevices that aren't there This driver does not have subdevices, so why call subdev ops? After removing that it became apparent that only Composite is supported as input, so remove also any reference to other inputs. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-cards.c | 1 - drivers/media/pci/cx25821/cx25821-video.c | 111 ++---------------------------- drivers/media/pci/cx25821/cx25821.h | 26 ------- 3 files changed, 7 insertions(+), 131 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-cards.c b/drivers/media/pci/cx25821/cx25821-cards.c index 2b2f1f4f87ac..3b409feb03d8 100644 --- a/drivers/media/pci/cx25821/cx25821-cards.c +++ b/drivers/media/pci/cx25821/cx25821-cards.c @@ -42,7 +42,6 @@ struct cx25821_board cx25821_boards[] = { .name = "CX25821", .portb = CX25821_RAW, .portc = CX25821_264, - .input[0].type = CX25821_VMUX_COMPOSITE, }, }; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index d3aa166740cd..49686447cc4a 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -111,37 +111,6 @@ void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, pr_err("%s: %d buffers handled (should be 1)\n", __func__, bc); } -static int cx25821_set_tvnorm(struct cx25821_dev *dev, v4l2_std_id norm) -{ - dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", - __func__, (unsigned int)norm, v4l2_norm_to_name(norm)); - - dev->tvnorm = norm; - - /* Tell the internal A/V decoder */ - cx25821_call_all(dev, core, s_std, norm); - - return 0; -} - -static int cx25821_video_mux(struct cx25821_dev *dev, unsigned int input) -{ - struct v4l2_routing route; - memset(&route, 0, sizeof(route)); - - dprintk(1, "%s(): video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n", - __func__, input, INPUT(input)->vmux, INPUT(input)->gpio0, - INPUT(input)->gpio1, INPUT(input)->gpio2, INPUT(input)->gpio3); - dev->input = input; - - route.input = INPUT(input)->vmux; - - /* Tell the internal A/V decoder */ - cx25821_call_all(dev, video, s_routing, INPUT(input)->vmux, 0, 0); - - return 0; -} - int cx25821_start_video_dma(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, struct cx25821_buffer *buf, @@ -673,9 +642,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, { struct cx25821_channel *chan = video_drvdata(file); struct cx25821_dev *dev = chan->dev; - struct v4l2_mbus_framefmt mbus_fmt; - int err; int pix_format = PIXEL_FRMT_422; + int err; err = cx25821_vidioc_try_fmt_vid_cap(file, priv, f); @@ -702,10 +670,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, chan->cif_width = chan->width; medusa_set_resolution(dev, chan->width, SRAM_CH00); - - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); - cx25821_call_all(dev, video, s_mbus_fmt, &mbus_fmt); - return 0; } @@ -727,7 +691,6 @@ static int vidioc_log_status(struct file *file, void *priv) const struct sram_channel *sram_ch = chan->sram_channels; u32 tmp = 0; - cx25821_call_all(dev, core, log_status); tmp = cx_read(sram_ch->dma_ctl); pr_info("Video input 0 is %s\n", (tmp & 0x11) ? "streaming" : "stopped"); @@ -806,7 +769,7 @@ int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) if (dev->tvnorm == tvnorms) return 0; - cx25821_set_tvnorm(dev, tvnorms); + dev->tvnorm = tvnorms; chan->width = 720; chan->height = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480; @@ -818,81 +781,26 @@ int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) static int cx25821_vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { - static const char * const iname[] = { - [CX25821_VMUX_COMPOSITE] = "Composite", - [CX25821_VMUX_SVIDEO] = "S-Video", - [CX25821_VMUX_DEBUG] = "for debug only", - }; - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - unsigned int n; - - n = i->index; - if (n >= CX25821_NR_INPUT) - return -EINVAL; - - if (0 == INPUT(n)->type) + if (i->index) return -EINVAL; i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, iname[INPUT(n)->type]); - i->std = CX25821_NORMS; + strcpy(i->name, "Composite"); return 0; } static int cx25821_vidioc_g_input(struct file *file, void *priv, unsigned int *i) { - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - - *i = dev->input; + *i = 0; return 0; } static int cx25821_vidioc_s_input(struct file *file, void *priv, unsigned int i) { - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - - if (i >= CX25821_NR_INPUT || INPUT(i)->type == 0) - return -EINVAL; - - cx25821_video_mux(dev, i); - return 0; + return i ? -EINVAL : 0; } -#ifdef CONFIG_VIDEO_ADV_DEBUG -int cx25821_vidioc_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - - cx25821_call_all(dev, core, g_register, reg); - - return 0; -} - -int cx25821_vidioc_s_register(struct file *file, void *fh, - const struct v4l2_dbg_register *reg) -{ - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - - if (!v4l2_chip_match_host(®->match)) - return -EINVAL; - - cx25821_call_all(dev, core, s_register, reg); - - return 0; -} - -#endif - static int cx25821_s_ctrl(struct v4l2_ctrl *ctrl) { struct cx25821_channel *chan = @@ -1088,10 +996,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_log_status = vidioc_log_status, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = cx25821_vidioc_g_register, - .vidioc_s_register = cx25821_vidioc_s_register, -#endif }; static const struct video_device cx25821_video_device = { @@ -1122,8 +1026,7 @@ int cx25821_video_register(struct cx25821_dev *dev) int i; /* initial device configuration */ - dev->tvnorm = V4L2_STD_NTSC_M, - cx25821_set_tvnorm(dev, dev->tvnorm); + dev->tvnorm = V4L2_STD_NTSC_M; spin_lock_init(&dev->slock); diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index cfda5ac4faaa..67b3c550e454 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -62,7 +62,6 @@ /* Max number of inputs by card */ #define MAX_CX25821_INPUT 8 -#define INPUT(nr) (&cx25821_boards[dev->board].input[nr]) #define RESOURCE_VIDEO0 1 #define RESOURCE_VIDEO1 2 #define RESOURCE_VIDEO2 4 @@ -91,7 +90,6 @@ #define CX25821_BOARD_CONEXANT_ATHENA10 1 #define MAX_VID_CHANNEL_NUM 12 #define VID_CHANNEL_NUM 8 -#define CX25821_NR_INPUT 2 struct cx25821_fmt { char *name; @@ -101,14 +99,6 @@ struct cx25821_fmt { u32 cxformat; }; -struct cx25821_ctrl { - struct v4l2_queryctrl v; - u32 off; - u32 reg; - u32 mask; - u32 shift; -}; - struct cx25821_tvnorm { char *name; v4l2_std_id id; @@ -116,12 +106,6 @@ struct cx25821_tvnorm { u32 cxoformat; }; -enum cx25821_itype { - CX25821_VMUX_COMPOSITE = 1, - CX25821_VMUX_SVIDEO, - CX25821_VMUX_DEBUG, -}; - enum cx25821_src_sel_type { CX25821_SRC_SEL_EXT_656_VIDEO = 0, CX25821_SRC_SEL_PARALLEL_MPEG_VIDEO @@ -139,12 +123,6 @@ struct cx25821_buffer { u32 count; }; -struct cx25821_input { - enum cx25821_itype type; - unsigned int vmux; - u32 gpio0, gpio1, gpio2, gpio3; -}; - enum port { CX25821_UNDEFINED = 0, CX25821_RAW, @@ -158,7 +136,6 @@ struct cx25821_board { enum port portc; u32 clk_freq; - struct cx25821_input input[CX25821_NR_INPUT]; }; struct cx25821_i2c { @@ -365,9 +342,6 @@ static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev) return container_of(v4l2_dev, struct cx25821_dev, v4l2_dev); } -#define cx25821_call_all(dev, o, f, args...) \ - v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args) - extern struct cx25821_board cx25821_boards[]; #define SRAM_CH00 0 /* Video A */ -- cgit v1.2.3 From 1f1988706d77083040113094a4bee2e9e1bdc34f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 14 Apr 2013 12:07:13 -0300 Subject: [media] cx25821: setup output nodes correctly Drop the custom ioctls and enable the video output nodes again, this time using standard ioctls. The next step will be to provide a proper write() interface. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-core.c | 30 ----- drivers/media/pci/cx25821/cx25821-video.c | 214 ++++++++++-------------------- drivers/media/pci/cx25821/cx25821-video.h | 7 - drivers/media/pci/cx25821/cx25821.h | 16 --- 4 files changed, 67 insertions(+), 200 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index ba417c978415..9068d53a5b8f 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -956,36 +956,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev) return 0; } -void cx25821_start_upstream_video_ch1(struct cx25821_dev *dev, - struct upstream_user_struct *up_data) -{ - dev->_isNTSC = !strcmp(dev->vid_stdname, "NTSC") ? 1 : 0; - - dev->tvnorm = !dev->_isNTSC ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M; - medusa_set_videostandard(dev); - - cx25821_vidupstream_init_ch1(dev, dev->channel_select, - dev->pixel_format); -} - -void cx25821_start_upstream_video_ch2(struct cx25821_dev *dev, - struct upstream_user_struct *up_data) -{ - dev->_isNTSC_ch2 = !strcmp(dev->vid_stdname_ch2, "NTSC") ? 1 : 0; - - dev->tvnorm = !dev->_isNTSC_ch2 ? V4L2_STD_PAL_BG : V4L2_STD_NTSC_M; - medusa_set_videostandard(dev); - - cx25821_vidupstream_init_ch2(dev, dev->channel_select_ch2, - dev->pixel_format_ch2); -} - -void cx25821_start_upstream_audio(struct cx25821_dev *dev, - struct upstream_user_struct *up_data) -{ - cx25821_audio_upstream_init(dev, AUDIO_UPSTREAM_SRAM_CHANNEL_B); -} - void cx25821_dev_unregister(struct cx25821_dev *dev) { int i; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 49686447cc4a..8d5d13bb5f09 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -826,140 +826,27 @@ static int cx25821_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static long video_ioctl_upstream9(struct file *file, unsigned int cmd, - unsigned long arg) +static int cx25821_vidioc_enum_output(struct file *file, void *priv, + struct v4l2_output *o) { - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - int command = 0; - struct upstream_user_struct *data_from_user; - - data_from_user = (struct upstream_user_struct *)arg; - - if (!data_from_user) { - pr_err("%s(): Upstream data is INVALID. Returning\n", __func__); - return 0; - } - - command = data_from_user->command; - - if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO) - return 0; - - dev->input_filename = data_from_user->input_filename; - dev->input_audiofilename = data_from_user->input_filename; - dev->vid_stdname = data_from_user->vid_stdname; - dev->pixel_format = data_from_user->pixel_format; - dev->channel_select = data_from_user->channel_select; - dev->command = data_from_user->command; - - switch (command) { - case UPSTREAM_START_VIDEO: - cx25821_start_upstream_video_ch1(dev, data_from_user); - break; - - case UPSTREAM_STOP_VIDEO: - cx25821_stop_upstream_video_ch1(dev); - break; - } + if (o->index) + return -EINVAL; + o->type = V4L2_INPUT_TYPE_CAMERA; + o->std = CX25821_NORMS; + strcpy(o->name, "Composite"); return 0; } -static long video_ioctl_upstream10(struct file *file, unsigned int cmd, - unsigned long arg) +static int cx25821_vidioc_g_output(struct file *file, void *priv, unsigned int *o) { - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - int command = 0; - struct upstream_user_struct *data_from_user; - - data_from_user = (struct upstream_user_struct *)arg; - - if (!data_from_user) { - pr_err("%s(): Upstream data is INVALID. Returning\n", __func__); - return 0; - } - - command = data_from_user->command; - - if (command != UPSTREAM_START_VIDEO && command != UPSTREAM_STOP_VIDEO) - return 0; - - dev->input_filename_ch2 = data_from_user->input_filename; - dev->input_audiofilename = data_from_user->input_filename; - dev->vid_stdname_ch2 = data_from_user->vid_stdname; - dev->pixel_format_ch2 = data_from_user->pixel_format; - dev->channel_select_ch2 = data_from_user->channel_select; - dev->command_ch2 = data_from_user->command; - - switch (command) { - case UPSTREAM_START_VIDEO: - cx25821_start_upstream_video_ch2(dev, data_from_user); - break; - - case UPSTREAM_STOP_VIDEO: - cx25821_stop_upstream_video_ch2(dev); - break; - } - + *o = 0; return 0; } -static long video_ioctl_upstream11(struct file *file, unsigned int cmd, - unsigned long arg) +static int cx25821_vidioc_s_output(struct file *file, void *priv, unsigned int o) { - struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_dev *dev = chan->dev; - int command = 0; - struct upstream_user_struct *data_from_user; - - data_from_user = (struct upstream_user_struct *)arg; - - if (!data_from_user) { - pr_err("%s(): Upstream data is INVALID. Returning\n", __func__); - return 0; - } - - command = data_from_user->command; - - if (command != UPSTREAM_START_AUDIO && command != UPSTREAM_STOP_AUDIO) - return 0; - - dev->input_filename = data_from_user->input_filename; - dev->input_audiofilename = data_from_user->input_filename; - dev->vid_stdname = data_from_user->vid_stdname; - dev->pixel_format = data_from_user->pixel_format; - dev->channel_select = data_from_user->channel_select; - dev->command = data_from_user->command; - - switch (command) { - case UPSTREAM_START_AUDIO: - cx25821_start_upstream_audio(dev, data_from_user); - break; - - case UPSTREAM_STOP_AUDIO: - cx25821_stop_upstream_audio(dev); - break; - } - - return 0; -} - -static long cx25821_video_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct cx25821_channel *chan = video_drvdata(file); - - /* check to see if it's the video upstream */ - if (chan->id == SRAM_CH09) - return video_ioctl_upstream9(file, cmd, arg); - if (chan->id == SRAM_CH10) - return video_ioctl_upstream10(file, cmd, arg); - if (chan->id == SRAM_CH11) - return video_ioctl_upstream11(file, cmd, arg); - - return video_ioctl2(file, cmd, arg); + return o ? -EINVAL : 0; } static const struct v4l2_ctrl_ops cx25821_ctrl_ops = { @@ -973,7 +860,7 @@ static const struct v4l2_file_operations video_fops = { .read = video_read, .poll = video_poll, .mmap = cx25821_video_mmap, - .unlocked_ioctl = cx25821_video_ioctl, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops video_ioctl_ops = { @@ -1007,6 +894,32 @@ static const struct video_device cx25821_video_device = { .tvnorms = CX25821_NORMS, }; +static const struct v4l2_file_operations video_out_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = v4l2_fh_release, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops video_out_ioctl_ops = { + .vidioc_querycap = cx25821_vidioc_querycap, + .vidioc_g_std = cx25821_vidioc_g_std, + .vidioc_s_std = cx25821_vidioc_s_std, + .vidioc_enum_output = cx25821_vidioc_enum_output, + .vidioc_g_output = cx25821_vidioc_g_output, + .vidioc_s_output = cx25821_vidioc_s_output, + .vidioc_log_status = vidioc_log_status, +}; + +static const struct video_device cx25821_video_out_device = { + .name = "cx25821-video", + .fops = &video_out_fops, + .release = video_device_release_empty, + .minor = -1, + .ioctl_ops = &video_out_ioctl_ops, + .tvnorms = CX25821_NORMS, +}; + void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) { cx_clear(PCI_INT_MSK, 1); @@ -1030,30 +943,33 @@ int cx25821_video_register(struct cx25821_dev *dev) spin_lock_init(&dev->slock); - for (i = 0; i < VID_CHANNEL_NUM; ++i) { + for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) { struct cx25821_channel *chan = &dev->channels[i]; struct video_device *vdev = &chan->vdev; struct v4l2_ctrl_handler *hdl = &chan->hdl; + bool is_output = i > SRAM_CH08; if (i == SRAM_CH08) /* audio channel */ continue; - v4l2_ctrl_handler_init(hdl, 4); - v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200); - v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops, - V4L2_CID_CONTRAST, 0, 10000, 1, 5000); - v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops, - V4L2_CID_SATURATION, 0, 10000, 1, 5000); - v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops, - V4L2_CID_HUE, 0, 10000, 1, 5000); - if (hdl->error) { - err = hdl->error; - goto fail_unreg; + if (!is_output) { + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 10000, 1, 6200); + v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops, + V4L2_CID_CONTRAST, 0, 10000, 1, 5000); + v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops, + V4L2_CID_SATURATION, 0, 10000, 1, 5000); + v4l2_ctrl_new_std(hdl, &cx25821_ctrl_ops, + V4L2_CID_HUE, 0, 10000, 1, 5000); + if (hdl->error) { + err = hdl->error; + goto fail_unreg; + } + err = v4l2_ctrl_handler_setup(hdl); + if (err) + goto fail_unreg; } - err = v4l2_ctrl_handler_setup(hdl); - if (err) - goto fail_unreg; cx25821_risc_stopper(dev->pci, &chan->dma_vidq.stopper, chan->sram_channels->dma_ctl, 0x11, 0); @@ -1081,15 +997,19 @@ int cx25821_video_register(struct cx25821_dev *dev) chan->dma_vidq.timeout.data = (unsigned long)&chan->timeout_data; init_timer(&chan->dma_vidq.timeout); - videobuf_queue_sg_init(&chan->vidq, &cx25821_video_qops, &dev->pci->dev, - &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer), - chan, &dev->lock); + if (!is_output) + videobuf_queue_sg_init(&chan->vidq, &cx25821_video_qops, &dev->pci->dev, + &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer), + chan, &dev->lock); /* register v4l devices */ - *vdev = cx25821_video_device; + *vdev = is_output ? cx25821_video_out_device : cx25821_video_device; vdev->v4l2_dev = &dev->v4l2_dev; - vdev->ctrl_handler = hdl; + if (!is_output) + vdev->ctrl_handler = hdl; + else + vdev->vfl_dir = VFL_DIR_TX; vdev->lock = &dev->lock; set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags); snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i); diff --git a/drivers/media/pci/cx25821/cx25821-video.h b/drivers/media/pci/cx25821/cx25821-video.h index 8871c4e737e8..ab63b3858acf 100644 --- a/drivers/media/pci/cx25821/cx25821-video.h +++ b/drivers/media/pci/cx25821/cx25821-video.h @@ -49,13 +49,6 @@ do { \ printk(KERN_DEBUG "%s/0: " fmt, dev->name, ##arg); \ } while (0) -/* For IOCTL to identify running upstream */ -#define UPSTREAM_START_VIDEO 700 -#define UPSTREAM_STOP_VIDEO 701 -#define UPSTREAM_START_AUDIO 702 -#define UPSTREAM_STOP_AUDIO 703 -#define UPSTREAM_DUMP_REGISTERS 702 - #define FORMAT_FLAGS_PACKED 0x01 extern void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q, u32 count); diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 67b3c550e454..156ad6f2c634 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -329,14 +329,6 @@ struct cx25821_dev { int command; }; -struct upstream_user_struct { - char *input_filename; - char *vid_stdname; - int pixel_format; - int channel_select; - int command; -}; - static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev) { return container_of(v4l2_dev, struct cx25821_dev, v4l2_dev); @@ -480,14 +472,6 @@ extern int cx25821_audio_upstream_init(struct cx25821_dev *dev, extern void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev); extern void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev); extern void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev); -extern void cx25821_start_upstream_video_ch1(struct cx25821_dev *dev, - struct upstream_user_struct - *up_data); -extern void cx25821_start_upstream_video_ch2(struct cx25821_dev *dev, - struct upstream_user_struct - *up_data); -extern void cx25821_start_upstream_audio(struct cx25821_dev *dev, - struct upstream_user_struct *up_data); extern void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev); extern void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev); extern void cx25821_stop_upstream_audio(struct cx25821_dev *dev); -- cgit v1.2.3 From 4c1d0f73021393dda4a226b5c4c86b2d730d656c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 14 Apr 2013 07:13:02 -0300 Subject: [media] cx25821: group all fmt functions together No other changes, just function reordering. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 84 ++++++++++++++++--------------- 1 file changed, 43 insertions(+), 41 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 8d5d13bb5f09..d3cf259f19f9 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -551,6 +551,19 @@ static int video_release(struct file *file) } /* VIDEO IOCTLS */ + +static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (unlikely(f->index >= ARRAY_SIZE(formats))) + return -EINVAL; + + strlcpy(f->description, formats[f->index].name, sizeof(f->description)); + f->pixelformat = formats[f->index].fourcc; + + return 0; +} + static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { @@ -607,35 +620,6 @@ static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx25821_channel *chan = video_drvdata(file); - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (chan->streaming_fh && chan->streaming_fh != priv) - return -EBUSY; - chan->streaming_fh = priv; - - return videobuf_streamon(&chan->vidq); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx25821_channel *chan = video_drvdata(file); - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (chan->streaming_fh && chan->streaming_fh != priv) - return -EBUSY; - if (chan->streaming_fh == NULL) - return 0; - - chan->streaming_fh = NULL; - return videobuf_streamoff(&chan->vidq); -} static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) @@ -673,6 +657,36 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, return 0; } +static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx25821_channel *chan = video_drvdata(file); + + if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (chan->streaming_fh && chan->streaming_fh != priv) + return -EBUSY; + chan->streaming_fh = priv; + + return videobuf_streamon(&chan->vidq); +} + +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) +{ + struct cx25821_channel *chan = video_drvdata(file); + + if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (chan->streaming_fh && chan->streaming_fh != priv) + return -EBUSY; + if (chan->streaming_fh == NULL) + return 0; + + chan->streaming_fh = NULL; + return videobuf_streamoff(&chan->vidq); +} + static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) { int ret_val = 0; @@ -718,18 +732,6 @@ static int cx25821_vidioc_querycap(struct file *file, void *priv, return 0; } -static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (unlikely(f->index >= ARRAY_SIZE(formats))) - return -EINVAL; - - strlcpy(f->description, formats[f->index].name, sizeof(f->description)); - f->pixelformat = formats[f->index].fourcc; - - return 0; -} - static int cx25821_vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p) { -- cgit v1.2.3 From 0df13d99f7c90e3f96408c0ba425e9fb1e48bbd3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 14 Apr 2013 07:14:42 -0300 Subject: [media] cx25821: prepare querycap for output support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index d3cf259f19f9..dca339183672 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -719,7 +719,7 @@ static int cx25821_vidioc_querycap(struct file *file, void *priv, struct cx25821_dev *dev = chan->dev; const u32 cap_input = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT; + const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE; strcpy(cap->driver, "cx25821"); strlcpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card)); @@ -728,7 +728,7 @@ static int cx25821_vidioc_querycap(struct file *file, void *priv, cap->device_caps = cap_output; else cap->device_caps = cap_input; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + cap->capabilities = cap_input | cap_output | V4L2_CAP_DEVICE_CAPS; return 0; } -- cgit v1.2.3 From e90878ab151f733b67d725a1e1e5aee04f431ce5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 14 Apr 2013 11:40:26 -0300 Subject: [media] cx25821: add output format ioctls Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index dca339183672..70e33b125969 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -851,6 +851,48 @@ static int cx25821_vidioc_s_output(struct file *file, void *priv, unsigned int o return o ? -EINVAL : 0; } +static int cx25821_vidioc_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; + const struct cx25821_fmt *fmt; + + fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); + if (NULL == fmt) + return -EINVAL; + f->fmt.pix.width = 720; + f->fmt.pix.height = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.priv = 0; + return 0; +} + +static int vidioc_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cx25821_channel *chan = video_drvdata(file); + int err; + + err = cx25821_vidioc_try_fmt_vid_out(file, priv, f); + + if (0 != err) + return err; + + chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); + chan->vidq.field = f->fmt.pix.field; + chan->width = f->fmt.pix.width; + chan->height = f->fmt.pix.height; + if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P) + chan->pixel_formats = PIXEL_FRMT_411; + else + chan->pixel_formats = PIXEL_FRMT_422; + return 0; +} + static const struct v4l2_ctrl_ops cx25821_ctrl_ops = { .s_ctrl = cx25821_s_ctrl, }; @@ -905,6 +947,10 @@ static const struct v4l2_file_operations video_out_fops = { static const struct v4l2_ioctl_ops video_out_ioctl_ops = { .vidioc_querycap = cx25821_vidioc_querycap, + .vidioc_enum_fmt_vid_out = cx25821_vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_out = cx25821_vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_out = cx25821_vidioc_try_fmt_vid_out, + .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, .vidioc_g_std = cx25821_vidioc_g_std, .vidioc_s_std = cx25821_vidioc_s_std, .vidioc_enum_output = cx25821_vidioc_enum_output, -- cgit v1.2.3 From 7087d31b0c9dddbca71b8e33d3f0a3b719afa397 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 14 Apr 2013 12:10:32 -0300 Subject: [media] cx25821: drop cx25821-video-upstream-ch2.c/h cx25821-video-upstream_ch2.c/h is practically identical to cx25821-video-upstream.c/h so add support for ch2 into cx25821-video-upstream.c instead. After this we can replace the custom ioctls with a proper write() interface. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/Makefile | 1 - drivers/media/pci/cx25821/cx25821-core.c | 4 +- .../media/pci/cx25821/cx25821-video-upstream-ch2.c | 800 --------------------- .../media/pci/cx25821/cx25821-video-upstream-ch2.h | 138 ---- drivers/media/pci/cx25821/cx25821-video-upstream.c | 349 ++++----- drivers/media/pci/cx25821/cx25821-video.c | 19 +- drivers/media/pci/cx25821/cx25821.h | 127 ++-- 7 files changed, 243 insertions(+), 1195 deletions(-) delete mode 100644 drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c delete mode 100644 drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/Makefile b/drivers/media/pci/cx25821/Makefile index b54a32e88bd0..407830c89df4 100644 --- a/drivers/media/pci/cx25821/Makefile +++ b/drivers/media/pci/cx25821/Makefile @@ -1,7 +1,6 @@ cx25821-y := cx25821-core.o cx25821-cards.o cx25821-i2c.o \ cx25821-gpio.o cx25821-medusa-video.o \ cx25821-video.o cx25821-video-upstream.o \ - cx25821-video-upstream-ch2.o \ cx25821-audio-upstream.o obj-$(CONFIG_VIDEO_CX25821) += cx25821.o diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 9068d53a5b8f..230bd8641576 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -963,8 +963,6 @@ void cx25821_dev_unregister(struct cx25821_dev *dev) if (!dev->base_io_addr) return; - cx25821_free_mem_upstream_ch1(dev); - cx25821_free_mem_upstream_ch2(dev); cx25821_free_mem_upstream_audio(dev); release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0)); @@ -972,6 +970,8 @@ void cx25821_dev_unregister(struct cx25821_dev *dev) for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; i++) { if (i == SRAM_CH08) /* audio channel */ continue; + if (i == SRAM_CH09 || i == SRAM_CH10) + cx25821_free_mem_upstream(&dev->channels[i]); cx25821_video_unregister(dev, i); } diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c deleted file mode 100644 index 2381bdce99fd..000000000000 --- a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c +++ /dev/null @@ -1,800 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include "cx25821-video.h" -#include "cx25821-video-upstream-ch2.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); -MODULE_AUTHOR("Hiep Huynh "); -MODULE_LICENSE("GPL"); - -static int _intr_msk = FLD_VID_SRC_RISC1 | FLD_VID_SRC_UF | FLD_VID_SRC_SYNC | - FLD_VID_SRC_OPC_ERR; - -static __le32 *cx25821_update_riscprogram_ch2(struct cx25821_dev *dev, - __le32 *rp, unsigned int offset, - unsigned int bpl, u32 sync_line, - unsigned int lines, - int fifo_enable, int field_type) -{ - unsigned int line, i; - int dist_betwn_starts = bpl * 2; - - *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); - - if (USE_RISC_NOOP_VIDEO) { - for (i = 0; i < NUM_NO_OPS; i++) - *(rp++) = cpu_to_le32(RISC_NOOP); - } - - /* scan lines */ - for (line = 0; line < lines; line++) { - *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); - *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr_ch2 + offset); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - - if ((lines <= NTSC_FIELD_HEIGHT) || - (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) { - offset += dist_betwn_starts; - } - } - - return rp; -} - -static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev, - __le32 *rp, - dma_addr_t databuf_phys_addr, - unsigned int offset, - u32 sync_line, unsigned int bpl, - unsigned int lines, - int fifo_enable, int field_type) -{ - unsigned int line, i; - const struct sram_channel *sram_ch = - dev->channels[dev->_channel2_upstream_select].sram_channels; - int dist_betwn_starts = bpl * 2; - - /* sync instruction */ - if (sync_line != NO_SYNC_LINE) - *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); - - if (USE_RISC_NOOP_VIDEO) { - for (i = 0; i < NUM_NO_OPS; i++) - *(rp++) = cpu_to_le32(RISC_NOOP); - } - - /* scan lines */ - for (line = 0; line < lines; line++) { - *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); - *(rp++) = cpu_to_le32(databuf_phys_addr + offset); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - - if ((lines <= NTSC_FIELD_HEIGHT) || - (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC_ch2)) { - offset += dist_betwn_starts; - } - - /* - check if we need to enable the FIFO after the first 4 lines - For the upstream video channel, the risc engine will enable - the FIFO. - */ - if (fifo_enable && line == 3) { - *(rp++) = RISC_WRITECR; - *(rp++) = sram_ch->dma_ctl; - *(rp++) = FLD_VID_FIFO_EN; - *(rp++) = 0x00000001; - } - } - - return rp; -} - -static int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, - struct pci_dev *pci, - unsigned int top_offset, - unsigned int bpl, - unsigned int lines) -{ - __le32 *rp; - int fifo_enable = 0; - int singlefield_lines = lines >> 1; /*get line count for single field */ - int odd_num_lines = singlefield_lines; - int frame = 0; - int frame_size = 0; - int databuf_offset = 0; - int risc_program_size = 0; - int risc_flag = RISC_CNT_RESET; - unsigned int bottom_offset = bpl; - dma_addr_t risc_phys_jump_addr; - - if (dev->_isNTSC_ch2) { - odd_num_lines = singlefield_lines + 1; - risc_program_size = FRAME1_VID_PROG_SIZE; - if (bpl == Y411_LINE_SZ) - frame_size = FRAME_SIZE_NTSC_Y411; - else - frame_size = FRAME_SIZE_NTSC_Y422; - } else { - risc_program_size = PAL_VID_PROG_SIZE; - if (bpl == Y411_LINE_SZ) - frame_size = FRAME_SIZE_PAL_Y411; - else - frame_size = FRAME_SIZE_PAL_Y422; - } - - /* Virtual address of Risc buffer program */ - rp = dev->_dma_virt_addr_ch2; - - for (frame = 0; frame < NUM_FRAMES; frame++) { - databuf_offset = frame_size * frame; - - if (UNSET != top_offset) { - fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; - rp = cx25821_risc_field_upstream_ch2(dev, rp, - dev->_data_buf_phys_addr_ch2 + databuf_offset, - top_offset, 0, bpl, odd_num_lines, fifo_enable, - ODD_FIELD); - } - - fifo_enable = FIFO_DISABLE; - - /* Even field */ - rp = cx25821_risc_field_upstream_ch2(dev, rp, - dev->_data_buf_phys_addr_ch2 + databuf_offset, - bottom_offset, 0x200, bpl, singlefield_lines, - fifo_enable, EVEN_FIELD); - - if (frame == 0) { - risc_flag = RISC_CNT_RESET; - risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2 + - risc_program_size; - } else { - risc_flag = RISC_CNT_INC; - risc_phys_jump_addr = dev->_dma_phys_start_addr_ch2; - } - - /* - * Loop to 2ndFrameRISC or to Start of - * Risc program & generate IRQ - */ - *(rp++) = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | risc_flag); - *(rp++) = cpu_to_le32(risc_phys_jump_addr); - *(rp++) = cpu_to_le32(0); - } - - return 0; -} - -void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev) -{ - const struct sram_channel *sram_ch = - dev->channels[VID_UPSTREAM_SRAM_CHANNEL_J].sram_channels; - u32 tmp = 0; - - if (!dev->_is_running_ch2) { - pr_info("No video file is currently running so return!\n"); - return; - } - /* Disable RISC interrupts */ - tmp = cx_read(sram_ch->int_msk); - cx_write(sram_ch->int_msk, tmp & ~_intr_msk); - - /* Turn OFF risc and fifo */ - tmp = cx_read(sram_ch->dma_ctl); - cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN)); - - /* Clear data buffer memory */ - if (dev->_data_buf_virt_addr_ch2) - memset(dev->_data_buf_virt_addr_ch2, 0, - dev->_data_buf_size_ch2); - - dev->_is_running_ch2 = 0; - dev->_is_first_frame_ch2 = 0; - dev->_frame_count_ch2 = 0; - dev->_file_status_ch2 = END_OF_FILE; - - kfree(dev->_irq_queues_ch2); - dev->_irq_queues_ch2 = NULL; - - kfree(dev->_filename_ch2); - - tmp = cx_read(VID_CH_MODE_SEL); - cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); -} - -void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev) -{ - if (dev->_is_running_ch2) - cx25821_stop_upstream_video_ch2(dev); - - if (dev->_dma_virt_addr_ch2) { - pci_free_consistent(dev->pci, dev->_risc_size_ch2, - dev->_dma_virt_addr_ch2, - dev->_dma_phys_addr_ch2); - dev->_dma_virt_addr_ch2 = NULL; - } - - if (dev->_data_buf_virt_addr_ch2) { - pci_free_consistent(dev->pci, dev->_data_buf_size_ch2, - dev->_data_buf_virt_addr_ch2, - dev->_data_buf_phys_addr_ch2); - dev->_data_buf_virt_addr_ch2 = NULL; - } -} - -static int cx25821_get_frame_ch2(struct cx25821_dev *dev, - const struct sram_channel *sram_ch) -{ - struct file *myfile; - int frame_index_temp = dev->_frame_index_ch2; - int i = 0; - int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ? - Y411_LINE_SZ : Y422_LINE_SZ; - int frame_size = 0; - int frame_offset = 0; - ssize_t vfs_read_retval = 0; - char mybuf[line_size]; - loff_t file_offset; - loff_t pos; - mm_segment_t old_fs; - - if (dev->_file_status_ch2 == END_OF_FILE) - return 0; - - if (dev->_isNTSC_ch2) { - frame_size = (line_size == Y411_LINE_SZ) ? - FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422; - } else { - frame_size = (line_size == Y411_LINE_SZ) ? - FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; - } - - frame_offset = (frame_index_temp > 0) ? frame_size : 0; - file_offset = dev->_frame_count_ch2 * frame_size; - - myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0); - if (IS_ERR(myfile)) { - const int open_errno = -PTR_ERR(myfile); - pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, dev->_filename_ch2, open_errno); - return PTR_ERR(myfile); - } else { - if (!(myfile->f_op)) { - pr_err("%s(): File has no file operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - if (!myfile->f_op->read) { - pr_err("%s(): File has no READ operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - pos = myfile->f_pos; - old_fs = get_fs(); - set_fs(KERNEL_DS); - - for (i = 0; i < dev->_lines_count_ch2; i++) { - pos = file_offset; - - vfs_read_retval = vfs_read(myfile, mybuf, line_size, - &pos); - - if (vfs_read_retval > 0 && vfs_read_retval == line_size - && dev->_data_buf_virt_addr_ch2 != NULL) { - memcpy((void *)(dev->_data_buf_virt_addr_ch2 + - frame_offset / 4), mybuf, - vfs_read_retval); - } - - file_offset += vfs_read_retval; - frame_offset += vfs_read_retval; - - if (vfs_read_retval < line_size) { - pr_info("Done: exit %s() since no more bytes to read from Video file\n", - __func__); - break; - } - } - - if (i > 0) - dev->_frame_count_ch2++; - - dev->_file_status_ch2 = (vfs_read_retval == line_size) ? - IN_PROGRESS : END_OF_FILE; - - set_fs(old_fs); - filp_close(myfile, NULL); - } - - return 0; -} - -static void cx25821_vidups_handler_ch2(struct work_struct *work) -{ - struct cx25821_dev *dev = container_of(work, struct cx25821_dev, - _irq_work_entry_ch2); - - if (!dev) { - pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", - __func__); - return; - } - - cx25821_get_frame_ch2(dev, dev->channels[dev-> - _channel2_upstream_select].sram_channels); -} - -static int cx25821_openfile_ch2(struct cx25821_dev *dev, - const struct sram_channel *sram_ch) -{ - struct file *myfile; - int i = 0, j = 0; - int line_size = (dev->_pixel_format_ch2 == PIXEL_FRMT_411) ? - Y411_LINE_SZ : Y422_LINE_SZ; - ssize_t vfs_read_retval = 0; - char mybuf[line_size]; - loff_t pos; - loff_t offset = (unsigned long)0; - mm_segment_t old_fs; - - myfile = filp_open(dev->_filename_ch2, O_RDONLY | O_LARGEFILE, 0); - - if (IS_ERR(myfile)) { - const int open_errno = -PTR_ERR(myfile); - pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, dev->_filename_ch2, open_errno); - return PTR_ERR(myfile); - } else { - if (!(myfile->f_op)) { - pr_err("%s(): File has no file operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - if (!myfile->f_op->read) { - pr_err("%s(): File has no READ operations registered! Returning\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - pos = myfile->f_pos; - old_fs = get_fs(); - set_fs(KERNEL_DS); - - for (j = 0; j < NUM_FRAMES; j++) { - for (i = 0; i < dev->_lines_count_ch2; i++) { - pos = offset; - - vfs_read_retval = vfs_read(myfile, mybuf, - line_size, &pos); - - if (vfs_read_retval > 0 && - vfs_read_retval == line_size && - dev->_data_buf_virt_addr_ch2 != NULL) { - memcpy((void *)(dev-> - _data_buf_virt_addr_ch2 - + offset / 4), mybuf, - vfs_read_retval); - } - - offset += vfs_read_retval; - - if (vfs_read_retval < line_size) { - pr_info("Done: exit %s() since no more bytes to read from Video file\n", - __func__); - break; - } - } - - if (i > 0) - dev->_frame_count_ch2++; - - if (vfs_read_retval < line_size) - break; - } - - dev->_file_status_ch2 = (vfs_read_retval == line_size) ? - IN_PROGRESS : END_OF_FILE; - - set_fs(old_fs); - myfile->f_pos = 0; - filp_close(myfile, NULL); - } - - return 0; -} - -static int cx25821_upstream_buffer_prepare_ch2(struct cx25821_dev *dev, - const struct sram_channel *sram_ch, - int bpl) -{ - int ret = 0; - dma_addr_t dma_addr; - dma_addr_t data_dma_addr; - - if (dev->_dma_virt_addr_ch2 != NULL) { - pci_free_consistent(dev->pci, dev->upstream_riscbuf_size_ch2, - dev->_dma_virt_addr_ch2, - dev->_dma_phys_addr_ch2); - } - - dev->_dma_virt_addr_ch2 = pci_alloc_consistent(dev->pci, - dev->upstream_riscbuf_size_ch2, &dma_addr); - dev->_dma_virt_start_addr_ch2 = dev->_dma_virt_addr_ch2; - dev->_dma_phys_start_addr_ch2 = dma_addr; - dev->_dma_phys_addr_ch2 = dma_addr; - dev->_risc_size_ch2 = dev->upstream_riscbuf_size_ch2; - - if (!dev->_dma_virt_addr_ch2) { - pr_err("FAILED to allocate memory for Risc buffer! Returning\n"); - return -ENOMEM; - } - - /* Iniitize at this address until n bytes to 0 */ - memset(dev->_dma_virt_addr_ch2, 0, dev->_risc_size_ch2); - - if (dev->_data_buf_virt_addr_ch2 != NULL) { - pci_free_consistent(dev->pci, dev->upstream_databuf_size_ch2, - dev->_data_buf_virt_addr_ch2, - dev->_data_buf_phys_addr_ch2); - } - /* For Video Data buffer allocation */ - dev->_data_buf_virt_addr_ch2 = pci_alloc_consistent(dev->pci, - dev->upstream_databuf_size_ch2, &data_dma_addr); - dev->_data_buf_phys_addr_ch2 = data_dma_addr; - dev->_data_buf_size_ch2 = dev->upstream_databuf_size_ch2; - - if (!dev->_data_buf_virt_addr_ch2) { - pr_err("FAILED to allocate memory for data buffer! Returning\n"); - return -ENOMEM; - } - - /* Initialize at this address until n bytes to 0 */ - memset(dev->_data_buf_virt_addr_ch2, 0, dev->_data_buf_size_ch2); - - ret = cx25821_openfile_ch2(dev, sram_ch); - if (ret < 0) - return ret; - - /* Creating RISC programs */ - ret = cx25821_risc_buffer_upstream_ch2(dev, dev->pci, 0, bpl, - dev->_lines_count_ch2); - if (ret < 0) { - pr_info("Failed creating Video Upstream Risc programs!\n"); - goto error; - } - - return 0; - -error: - return ret; -} - -static int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, - int chan_num, - u32 status) -{ - u32 int_msk_tmp; - const struct sram_channel *channel = dev->channels[chan_num].sram_channels; - int singlefield_lines = NTSC_FIELD_HEIGHT; - int line_size_in_bytes = Y422_LINE_SZ; - int odd_risc_prog_size = 0; - dma_addr_t risc_phys_jump_addr; - __le32 *rp; - - if (status & FLD_VID_SRC_RISC1) { - /* We should only process one program per call */ - u32 prog_cnt = cx_read(channel->gpcnt); - - /* - * Since we've identified our IRQ, clear our bits from the - * interrupt mask and interrupt status registers - */ - int_msk_tmp = cx_read(channel->int_msk); - cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk); - cx_write(channel->int_stat, _intr_msk); - - spin_lock(&dev->slock); - - dev->_frame_index_ch2 = prog_cnt; - - queue_work(dev->_irq_queues_ch2, &dev->_irq_work_entry_ch2); - - if (dev->_is_first_frame_ch2) { - dev->_is_first_frame_ch2 = 0; - - if (dev->_isNTSC_ch2) { - singlefield_lines += 1; - odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE; - } else { - singlefield_lines = PAL_FIELD_HEIGHT; - odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE; - } - - if (dev->_dma_virt_start_addr_ch2 != NULL) { - if (dev->_pixel_format_ch2 == PIXEL_FRMT_411) - line_size_in_bytes = Y411_LINE_SZ; - else - line_size_in_bytes = Y422_LINE_SZ; - risc_phys_jump_addr = - dev->_dma_phys_start_addr_ch2 + - odd_risc_prog_size; - - rp = cx25821_update_riscprogram_ch2(dev, - dev->_dma_virt_start_addr_ch2, - TOP_OFFSET, line_size_in_bytes, - 0x0, singlefield_lines, - FIFO_DISABLE, ODD_FIELD); - - /* Jump to Even Risc program of 1st Frame */ - *(rp++) = cpu_to_le32(RISC_JUMP); - *(rp++) = cpu_to_le32(risc_phys_jump_addr); - *(rp++) = cpu_to_le32(0); - } - } - - spin_unlock(&dev->slock); - } - - if (dev->_file_status_ch2 == END_OF_FILE) { - pr_info("EOF Channel 2 Framecount = %d\n", - dev->_frame_count_ch2); - return -1; - } - /* ElSE, set the interrupt mask register, re-enable irq. */ - int_msk_tmp = cx_read(channel->int_msk); - cx_write(channel->int_msk, int_msk_tmp |= _intr_msk); - - return 0; -} - -static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id) -{ - struct cx25821_dev *dev = dev_id; - u32 vid_status; - int handled = 0; - int channel_num = 0; - const struct sram_channel *sram_ch; - - if (!dev) - return -1; - - channel_num = VID_UPSTREAM_SRAM_CHANNEL_J; - sram_ch = dev->channels[channel_num].sram_channels; - - vid_status = cx_read(sram_ch->int_stat); - - /* Only deal with our interrupt */ - if (vid_status) - handled = cx25821_video_upstream_irq_ch2(dev, channel_num, - vid_status); - - if (handled < 0) - cx25821_stop_upstream_video_ch2(dev); - else - handled += handled; - - return IRQ_RETVAL(handled); -} - -static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev, - const struct sram_channel *ch, int pix_format) -{ - int width = WIDTH_D1; - int height = dev->_lines_count_ch2; - int num_lines, odd_num_lines; - u32 value; - int vip_mode = PIXEL_ENGINE_VIP1; - - value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7); - value &= 0xFFFFFFEF; - value |= dev->_isNTSC_ch2 ? 0 : 0x10; - cx_write(ch->vid_fmt_ctl, value); - - /* - * set number of active pixels in each line. Default is 720 - * pixels in both NTSC and PAL format - */ - cx_write(ch->vid_active_ctl1, width); - - num_lines = (height / 2) & 0x3FF; - odd_num_lines = num_lines; - - if (dev->_isNTSC_ch2) - odd_num_lines += 1; - - value = (num_lines << 16) | odd_num_lines; - - /* set number of active lines in field 0 (top) and field 1 (bottom) */ - cx_write(ch->vid_active_ctl2, value); - - cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); -} - -static int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev, - const struct sram_channel *sram_ch) -{ - u32 tmp = 0; - int err = 0; - - /* - * 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface - * for channel A-C - */ - tmp = cx_read(VID_CH_MODE_SEL); - cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); - - /* - * Set the physical start address of the RISC program in the initial - * program counter(IPC) member of the cmds. - */ - cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr_ch2); - cx_write(sram_ch->cmds_start + 4, 0); /* Risc IPC High 64 bits 63-32 */ - - /* reset counter */ - cx_write(sram_ch->gpcnt_ctl, 3); - - /* Clear our bits from the interrupt status register. */ - cx_write(sram_ch->int_stat, _intr_msk); - - /* Set the interrupt mask register, enable irq. */ - cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << sram_ch->irq_bit)); - tmp = cx_read(sram_ch->int_msk); - cx_write(sram_ch->int_msk, tmp |= _intr_msk); - - err = request_irq(dev->pci->irq, cx25821_upstream_irq_ch2, - IRQF_SHARED, dev->name, dev); - if (err < 0) { - pr_err("%s: can't get upstream IRQ %d\n", - dev->name, dev->pci->irq); - goto fail_irq; - } - /* Start the DMA engine */ - tmp = cx_read(sram_ch->dma_ctl); - cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN); - - dev->_is_running_ch2 = 1; - dev->_is_first_frame_ch2 = 1; - - return 0; - -fail_irq: - cx25821_dev_unregister(dev); - return err; -} - -int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, - int pixel_format) -{ - const struct sram_channel *sram_ch; - u32 tmp; - int err = 0; - int data_frame_size = 0; - int risc_buffer_size = 0; - - if (dev->_is_running_ch2) { - pr_info("Video Channel is still running so return!\n"); - return 0; - } - - dev->_channel2_upstream_select = channel_select; - sram_ch = dev->channels[channel_select].sram_channels; - - INIT_WORK(&dev->_irq_work_entry_ch2, cx25821_vidups_handler_ch2); - dev->_irq_queues_ch2 = - create_singlethread_workqueue("cx25821_workqueue2"); - - if (!dev->_irq_queues_ch2) { - pr_err("create_singlethread_workqueue() for Video FAILED!\n"); - return -ENOMEM; - } - /* - * 656/VIP SRC Upstream Channel I & J and 7 - - * Host Bus Interface for channel A-C - */ - tmp = cx_read(VID_CH_MODE_SEL); - cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); - - dev->_is_running_ch2 = 0; - dev->_frame_count_ch2 = 0; - dev->_file_status_ch2 = RESET_STATUS; - dev->_lines_count_ch2 = dev->_isNTSC_ch2 ? 480 : 576; - dev->_pixel_format_ch2 = pixel_format; - dev->_line_size_ch2 = (dev->_pixel_format_ch2 == PIXEL_FRMT_422) ? - (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; - data_frame_size = dev->_isNTSC_ch2 ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; - risc_buffer_size = dev->_isNTSC_ch2 ? - NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; - - if (dev->input_filename_ch2) - dev->_filename_ch2 = kstrdup(dev->input_filename_ch2, - GFP_KERNEL); - else - dev->_filename_ch2 = kstrdup(dev->_defaultname_ch2, - GFP_KERNEL); - - if (!dev->_filename_ch2) { - err = -ENOENT; - goto error; - } - - /* Default if filename is empty string */ - if (strcmp(dev->_filename_ch2, "") == 0) { - if (dev->_isNTSC_ch2) { - dev->_filename_ch2 = (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? "/root/vid411.yuv" : - "/root/vidtest.yuv"; - } else { - dev->_filename_ch2 = (dev->_pixel_format_ch2 == - PIXEL_FRMT_411) ? "/root/pal411.yuv" : - "/root/pal422.yuv"; - } - } - - err = cx25821_sram_channel_setup_upstream(dev, sram_ch, - dev->_line_size_ch2, 0); - - /* setup fifo + format */ - cx25821_set_pixelengine_ch2(dev, sram_ch, dev->_pixel_format_ch2); - - dev->upstream_riscbuf_size_ch2 = risc_buffer_size * 2; - dev->upstream_databuf_size_ch2 = data_frame_size * 2; - - /* Allocating buffers and prepare RISC program */ - err = cx25821_upstream_buffer_prepare_ch2(dev, sram_ch, - dev->_line_size_ch2); - if (err < 0) { - pr_err("%s: Failed to set up Video upstream buffers!\n", - dev->name); - goto error; - } - - cx25821_start_video_dma_upstream_ch2(dev, sram_ch); - - return 0; - -error: - cx25821_dev_unregister(dev); - - return err; -} diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h deleted file mode 100644 index d42dab59b663..000000000000 --- a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Driver for the Conexant CX25821 PCIe bridge - * - * Copyright (C) 2009 Conexant Systems Inc. - * Authors , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#define OPEN_FILE_1 0 -#define NUM_PROGS 8 -#define NUM_FRAMES 2 -#define ODD_FIELD 0 -#define EVEN_FIELD 1 -#define TOP_OFFSET 0 -#define FIFO_DISABLE 0 -#define FIFO_ENABLE 1 -#define TEST_FRAMES 5 -#define END_OF_FILE 0 -#define IN_PROGRESS 1 -#define RESET_STATUS -1 -#define NUM_NO_OPS 5 - -/* PAL and NTSC line sizes and number of lines. */ -#define WIDTH_D1 720 -#define NTSC_LINES_PER_FRAME 480 -#define PAL_LINES_PER_FRAME 576 -#define PAL_LINE_SZ 1440 -#define Y422_LINE_SZ 1440 -#define Y411_LINE_SZ 1080 -#define NTSC_FIELD_HEIGHT 240 -#define NTSC_ODD_FLD_LINES 241 -#define PAL_FIELD_HEIGHT 288 - -#define FRAME_SIZE_NTSC_Y422 (NTSC_LINES_PER_FRAME * Y422_LINE_SZ) -#define FRAME_SIZE_NTSC_Y411 (NTSC_LINES_PER_FRAME * Y411_LINE_SZ) -#define FRAME_SIZE_PAL_Y422 (PAL_LINES_PER_FRAME * Y422_LINE_SZ) -#define FRAME_SIZE_PAL_Y411 (PAL_LINES_PER_FRAME * Y411_LINE_SZ) - -#define NTSC_DATA_BUF_SZ (Y422_LINE_SZ * NTSC_LINES_PER_FRAME) -#define PAL_DATA_BUF_SZ (Y422_LINE_SZ * PAL_LINES_PER_FRAME) - -#define RISC_WRITECR_INSTRUCTION_SIZE 16 -#define RISC_SYNC_INSTRUCTION_SIZE 4 -#define JUMP_INSTRUCTION_SIZE 12 -#define MAXSIZE_NO_OPS 36 -#define DWORD_SIZE 4 - -#define USE_RISC_NOOP_VIDEO 1 - -#ifdef USE_RISC_NOOP_VIDEO -#define PAL_US_VID_PROG_SIZE \ - (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + RISC_SYNC_INSTRUCTION_SIZE + \ - NUM_NO_OPS * DWORD_SIZE) - -#define PAL_RISC_BUF_SIZE (2 * PAL_US_VID_PROG_SIZE) - -#define PAL_VID_PROG_SIZE \ - ((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE + \ - 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ - JUMP_INSTRUCTION_SIZE + 2 * NUM_NO_OPS * DWORD_SIZE) - -#define ODD_FLD_PAL_PROG_SIZE \ - (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ - RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ - NUM_NO_OPS * DWORD_SIZE) - -#define NTSC_US_VID_PROG_SIZE \ - ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE + \ - NUM_NO_OPS * DWORD_SIZE) - -#define NTSC_RISC_BUF_SIZE \ - (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE)) - -#define FRAME1_VID_PROG_SIZE \ - ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * \ - 3 * DWORD_SIZE + 2 * RISC_SYNC_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE + \ - 2 * NUM_NO_OPS * DWORD_SIZE) - -#define ODD_FLD_NTSC_PROG_SIZE \ - (NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE + \ - RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ - NUM_NO_OPS * DWORD_SIZE) -#endif - -#ifndef USE_RISC_NOOP_VIDEO -#define PAL_US_VID_PROG_SIZE \ - ((PAL_FIELD_HEIGHT + 1) * 3 * DWORD_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE) - -#define PAL_RISC_BUF_SIZE \ - (2 * (RISC_SYNC_INSTRUCTION_SIZE + PAL_US_VID_PROG_SIZE)) - -#define PAL_VID_PROG_SIZE \ - ((PAL_FIELD_HEIGHT * 2) * 3 * DWORD_SIZE + \ - 2 * RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE + \ - JUMP_INSTRUCTION_SIZE) - -#define ODD_FLD_PAL_PROG_SIZE \ - (PAL_FIELD_HEIGHT * 3 * DWORD_SIZE + \ - RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) - -#define ODD_FLD_NTSC_PROG_SIZE \ - (NTSC_ODD_FLD_LINES * 3 * DWORD_SIZE + \ - RISC_SYNC_INSTRUCTION_SIZE + RISC_WRITECR_INSTRUCTION_SIZE) - -#define NTSC_US_VID_PROG_SIZE \ - ((NTSC_ODD_FLD_LINES + 1) * 3 * DWORD_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) - -#define NTSC_RISC_BUF_SIZE \ - (2 * (RISC_SYNC_INSTRUCTION_SIZE + NTSC_US_VID_PROG_SIZE)) - -#define FRAME1_VID_PROG_SIZE \ - ((NTSC_ODD_FLD_LINES + NTSC_FIELD_HEIGHT) * \ - 3 * DWORD_SIZE + 2 * RISC_SYNC_INSTRUCTION_SIZE + \ - RISC_WRITECR_INSTRUCTION_SIZE + JUMP_INSTRUCTION_SIZE) - -#endif diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c index 223aae77c7eb..37cfc834e5c0 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c @@ -97,12 +97,13 @@ int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev, return 0; } -static __le32 *cx25821_update_riscprogram(struct cx25821_dev *dev, +static __le32 *cx25821_update_riscprogram(struct cx25821_channel *chan, __le32 *rp, unsigned int offset, unsigned int bpl, u32 sync_line, unsigned int lines, int fifo_enable, int field_type) { + struct cx25821_video_out_data *out = chan->out; unsigned int line, i; int dist_betwn_starts = bpl * 2; @@ -116,11 +117,11 @@ static __le32 *cx25821_update_riscprogram(struct cx25821_dev *dev, /* scan lines */ for (line = 0; line < lines; line++) { *(rp++) = cpu_to_le32(RISC_READ | RISC_SOL | RISC_EOL | bpl); - *(rp++) = cpu_to_le32(dev->_data_buf_phys_addr + offset); + *(rp++) = cpu_to_le32(out->_data_buf_phys_addr + offset); *(rp++) = cpu_to_le32(0); /* bits 63-32 */ if ((lines <= NTSC_FIELD_HEIGHT) - || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC)) { + || (line < (NTSC_FIELD_HEIGHT - 1)) || !(out->is_60hz)) { offset += dist_betwn_starts; } } @@ -128,15 +129,15 @@ static __le32 *cx25821_update_riscprogram(struct cx25821_dev *dev, return rp; } -static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp, +static __le32 *cx25821_risc_field_upstream(struct cx25821_channel *chan, __le32 *rp, dma_addr_t databuf_phys_addr, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int lines, int fifo_enable, int field_type) { + struct cx25821_video_out_data *out = chan->out; unsigned int line, i; - const struct sram_channel *sram_ch = - dev->channels[dev->_channel_upstream_select].sram_channels; + const struct sram_channel *sram_ch = chan->sram_channels; int dist_betwn_starts = bpl * 2; /* sync instruction */ @@ -155,7 +156,7 @@ static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp, *(rp++) = cpu_to_le32(0); /* bits 63-32 */ if ((lines <= NTSC_FIELD_HEIGHT) - || (line < (NTSC_FIELD_HEIGHT - 1)) || !(dev->_isNTSC)) + || (line < (NTSC_FIELD_HEIGHT - 1)) || !(out->is_60hz)) /* to skip the other field line */ offset += dist_betwn_starts; @@ -173,11 +174,12 @@ static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp, return rp; } -static int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, +static int cx25821_risc_buffer_upstream(struct cx25821_channel *chan, struct pci_dev *pci, unsigned int top_offset, unsigned int bpl, unsigned int lines) { + struct cx25821_video_out_data *out = chan->out; __le32 *rp; int fifo_enable = 0; /* get line count for single field */ @@ -191,7 +193,7 @@ static int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, unsigned int bottom_offset = bpl; dma_addr_t risc_phys_jump_addr; - if (dev->_isNTSC) { + if (out->is_60hz) { odd_num_lines = singlefield_lines + 1; risc_program_size = FRAME1_VID_PROG_SIZE; frame_size = (bpl == Y411_LINE_SZ) ? @@ -203,15 +205,15 @@ static int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, } /* Virtual address of Risc buffer program */ - rp = dev->_dma_virt_addr; + rp = out->_dma_virt_addr; for (frame = 0; frame < NUM_FRAMES; frame++) { databuf_offset = frame_size * frame; if (UNSET != top_offset) { fifo_enable = (frame == 0) ? FIFO_ENABLE : FIFO_DISABLE; - rp = cx25821_risc_field_upstream(dev, rp, - dev->_data_buf_phys_addr + + rp = cx25821_risc_field_upstream(chan, rp, + out->_data_buf_phys_addr + databuf_offset, top_offset, 0, bpl, odd_num_lines, fifo_enable, ODD_FIELD); } @@ -219,18 +221,18 @@ static int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, fifo_enable = FIFO_DISABLE; /* Even Field */ - rp = cx25821_risc_field_upstream(dev, rp, - dev->_data_buf_phys_addr + + rp = cx25821_risc_field_upstream(chan, rp, + out->_data_buf_phys_addr + databuf_offset, bottom_offset, 0x200, bpl, singlefield_lines, fifo_enable, EVEN_FIELD); if (frame == 0) { risc_flag = RISC_CNT_RESET; - risc_phys_jump_addr = dev->_dma_phys_start_addr + + risc_phys_jump_addr = out->_dma_phys_start_addr + risc_program_size; } else { - risc_phys_jump_addr = dev->_dma_phys_start_addr; + risc_phys_jump_addr = out->_dma_phys_start_addr; risc_flag = RISC_CNT_INC; } @@ -245,13 +247,14 @@ static int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, return 0; } -void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev) +void cx25821_stop_upstream_video(struct cx25821_channel *chan) { - const struct sram_channel *sram_ch = - dev->channels[VID_UPSTREAM_SRAM_CHANNEL_I].sram_channels; + struct cx25821_video_out_data *out = chan->out; + struct cx25821_dev *dev = chan->dev; + const struct sram_channel *sram_ch = chan->sram_channels; u32 tmp = 0; - if (!dev->_is_running) { + if (!out->_is_running) { pr_info("No video file is currently running so return!\n"); return; } @@ -264,49 +267,53 @@ void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev) cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN)); /* Clear data buffer memory */ - if (dev->_data_buf_virt_addr) - memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size); + if (out->_data_buf_virt_addr) + memset(out->_data_buf_virt_addr, 0, out->_data_buf_size); - dev->_is_running = 0; - dev->_is_first_frame = 0; - dev->_frame_count = 0; - dev->_file_status = END_OF_FILE; + out->_is_running = 0; + out->_is_first_frame = 0; + out->_frame_count = 0; + out->_file_status = END_OF_FILE; - kfree(dev->_irq_queues); - dev->_irq_queues = NULL; + destroy_workqueue(out->_irq_queues); + out->_irq_queues = NULL; - kfree(dev->_filename); + kfree(out->_filename); tmp = cx_read(VID_CH_MODE_SEL); cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); } -void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev) +void cx25821_free_mem_upstream(struct cx25821_channel *chan) { - if (dev->_is_running) - cx25821_stop_upstream_video_ch1(dev); + struct cx25821_video_out_data *out = chan->out; + struct cx25821_dev *dev = chan->dev; - if (dev->_dma_virt_addr) { - pci_free_consistent(dev->pci, dev->_risc_size, - dev->_dma_virt_addr, dev->_dma_phys_addr); - dev->_dma_virt_addr = NULL; + if (out->_is_running) + cx25821_stop_upstream_video(chan); + + if (out->_dma_virt_addr) { + pci_free_consistent(dev->pci, out->_risc_size, + out->_dma_virt_addr, out->_dma_phys_addr); + out->_dma_virt_addr = NULL; } - if (dev->_data_buf_virt_addr) { - pci_free_consistent(dev->pci, dev->_data_buf_size, - dev->_data_buf_virt_addr, - dev->_data_buf_phys_addr); - dev->_data_buf_virt_addr = NULL; + if (out->_data_buf_virt_addr) { + pci_free_consistent(dev->pci, out->_data_buf_size, + out->_data_buf_virt_addr, + out->_data_buf_phys_addr); + out->_data_buf_virt_addr = NULL; } } -static int cx25821_get_frame(struct cx25821_dev *dev, +static int cx25821_get_frame(struct cx25821_channel *chan, const struct sram_channel *sram_ch) { + struct cx25821_video_out_data *out = chan->out; struct file *myfile; - int frame_index_temp = dev->_frame_index; + int frame_index_temp = out->_frame_index; int i = 0; - int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ? + int line_size = (out->_pixel_format == PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; int frame_size = 0; int frame_offset = 0; @@ -316,10 +323,10 @@ static int cx25821_get_frame(struct cx25821_dev *dev, loff_t pos; mm_segment_t old_fs; - if (dev->_file_status == END_OF_FILE) + if (out->_file_status == END_OF_FILE) return 0; - if (dev->_isNTSC) + if (out->is_60hz) frame_size = (line_size == Y411_LINE_SZ) ? FRAME_SIZE_NTSC_Y411 : FRAME_SIZE_NTSC_Y422; else @@ -327,14 +334,14 @@ static int cx25821_get_frame(struct cx25821_dev *dev, FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; frame_offset = (frame_index_temp > 0) ? frame_size : 0; - file_offset = dev->_frame_count * frame_size; + file_offset = out->_frame_count * frame_size; - myfile = filp_open(dev->_filename, O_RDONLY | O_LARGEFILE, 0); + myfile = filp_open(out->_filename, O_RDONLY | O_LARGEFILE, 0); if (IS_ERR(myfile)) { const int open_errno = -PTR_ERR(myfile); pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, dev->_filename, open_errno); + __func__, out->_filename, open_errno); return PTR_ERR(myfile); } else { if (!(myfile->f_op)) { @@ -355,15 +362,15 @@ static int cx25821_get_frame(struct cx25821_dev *dev, old_fs = get_fs(); set_fs(KERNEL_DS); - for (i = 0; i < dev->_lines_count; i++) { + for (i = 0; i < out->_lines_count; i++) { pos = file_offset; vfs_read_retval = vfs_read(myfile, mybuf, line_size, &pos); if (vfs_read_retval > 0 && vfs_read_retval == line_size - && dev->_data_buf_virt_addr != NULL) { - memcpy((void *)(dev->_data_buf_virt_addr + + && out->_data_buf_virt_addr != NULL) { + memcpy((void *)(out->_data_buf_virt_addr + frame_offset / 4), mybuf, vfs_read_retval); } @@ -379,9 +386,9 @@ static int cx25821_get_frame(struct cx25821_dev *dev, } if (i > 0) - dev->_frame_count++; + out->_frame_count++; - dev->_file_status = (vfs_read_retval == line_size) ? + out->_file_status = (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; set_fs(old_fs); @@ -393,25 +400,19 @@ static int cx25821_get_frame(struct cx25821_dev *dev, static void cx25821_vidups_handler(struct work_struct *work) { - struct cx25821_dev *dev = container_of(work, struct cx25821_dev, - _irq_work_entry); - - if (!dev) { - pr_err("ERROR %s(): since container_of(work_struct) FAILED!\n", - __func__); - return; - } + struct cx25821_video_out_data *out = + container_of(work, struct cx25821_video_out_data, _irq_work_entry); - cx25821_get_frame(dev, dev->channels[dev->_channel_upstream_select]. - sram_channels); + cx25821_get_frame(out->chan, out->chan->sram_channels); } -static int cx25821_openfile(struct cx25821_dev *dev, +static int cx25821_openfile(struct cx25821_channel *chan, const struct sram_channel *sram_ch) { + struct cx25821_video_out_data *out = chan->out; struct file *myfile; int i = 0, j = 0; - int line_size = (dev->_pixel_format == PIXEL_FRMT_411) ? + int line_size = (out->_pixel_format == PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; ssize_t vfs_read_retval = 0; char mybuf[line_size]; @@ -419,12 +420,12 @@ static int cx25821_openfile(struct cx25821_dev *dev, loff_t offset = (unsigned long)0; mm_segment_t old_fs; - myfile = filp_open(dev->_filename, O_RDONLY | O_LARGEFILE, 0); + myfile = filp_open(out->_filename, O_RDONLY | O_LARGEFILE, 0); if (IS_ERR(myfile)) { const int open_errno = -PTR_ERR(myfile); pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, dev->_filename, open_errno); + __func__, out->_filename, open_errno); return PTR_ERR(myfile); } else { if (!(myfile->f_op)) { @@ -446,7 +447,7 @@ static int cx25821_openfile(struct cx25821_dev *dev, set_fs(KERNEL_DS); for (j = 0; j < NUM_FRAMES; j++) { - for (i = 0; i < dev->_lines_count; i++) { + for (i = 0; i < out->_lines_count; i++) { pos = offset; vfs_read_retval = vfs_read(myfile, mybuf, @@ -454,8 +455,8 @@ static int cx25821_openfile(struct cx25821_dev *dev, if (vfs_read_retval > 0 && vfs_read_retval == line_size - && dev->_data_buf_virt_addr != NULL) { - memcpy((void *)(dev-> + && out->_data_buf_virt_addr != NULL) { + memcpy((void *)(out-> _data_buf_virt_addr + offset / 4), mybuf, vfs_read_retval); @@ -471,13 +472,13 @@ static int cx25821_openfile(struct cx25821_dev *dev, } if (i > 0) - dev->_frame_count++; + out->_frame_count++; if (vfs_read_retval < line_size) break; } - dev->_file_status = (vfs_read_retval == line_size) ? + out->_file_status = (vfs_read_retval == line_size) ? IN_PROGRESS : END_OF_FILE; set_fs(old_fs); @@ -488,58 +489,60 @@ static int cx25821_openfile(struct cx25821_dev *dev, return 0; } -static int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev, +static int cx25821_upstream_buffer_prepare(struct cx25821_channel *chan, const struct sram_channel *sram_ch, int bpl) { + struct cx25821_video_out_data *out = chan->out; + struct cx25821_dev *dev = chan->dev; int ret = 0; dma_addr_t dma_addr; dma_addr_t data_dma_addr; - if (dev->_dma_virt_addr != NULL) - pci_free_consistent(dev->pci, dev->upstream_riscbuf_size, - dev->_dma_virt_addr, dev->_dma_phys_addr); + if (out->_dma_virt_addr != NULL) + pci_free_consistent(dev->pci, out->upstream_riscbuf_size, + out->_dma_virt_addr, out->_dma_phys_addr); - dev->_dma_virt_addr = pci_alloc_consistent(dev->pci, - dev->upstream_riscbuf_size, &dma_addr); - dev->_dma_virt_start_addr = dev->_dma_virt_addr; - dev->_dma_phys_start_addr = dma_addr; - dev->_dma_phys_addr = dma_addr; - dev->_risc_size = dev->upstream_riscbuf_size; + out->_dma_virt_addr = pci_alloc_consistent(dev->pci, + out->upstream_riscbuf_size, &dma_addr); + out->_dma_virt_start_addr = out->_dma_virt_addr; + out->_dma_phys_start_addr = dma_addr; + out->_dma_phys_addr = dma_addr; + out->_risc_size = out->upstream_riscbuf_size; - if (!dev->_dma_virt_addr) { + if (!out->_dma_virt_addr) { pr_err("FAILED to allocate memory for Risc buffer! Returning\n"); return -ENOMEM; } /* Clear memory at address */ - memset(dev->_dma_virt_addr, 0, dev->_risc_size); + memset(out->_dma_virt_addr, 0, out->_risc_size); - if (dev->_data_buf_virt_addr != NULL) - pci_free_consistent(dev->pci, dev->upstream_databuf_size, - dev->_data_buf_virt_addr, - dev->_data_buf_phys_addr); + if (out->_data_buf_virt_addr != NULL) + pci_free_consistent(dev->pci, out->upstream_databuf_size, + out->_data_buf_virt_addr, + out->_data_buf_phys_addr); /* For Video Data buffer allocation */ - dev->_data_buf_virt_addr = pci_alloc_consistent(dev->pci, - dev->upstream_databuf_size, &data_dma_addr); - dev->_data_buf_phys_addr = data_dma_addr; - dev->_data_buf_size = dev->upstream_databuf_size; + out->_data_buf_virt_addr = pci_alloc_consistent(dev->pci, + out->upstream_databuf_size, &data_dma_addr); + out->_data_buf_phys_addr = data_dma_addr; + out->_data_buf_size = out->upstream_databuf_size; - if (!dev->_data_buf_virt_addr) { + if (!out->_data_buf_virt_addr) { pr_err("FAILED to allocate memory for data buffer! Returning\n"); return -ENOMEM; } /* Clear memory at address */ - memset(dev->_data_buf_virt_addr, 0, dev->_data_buf_size); + memset(out->_data_buf_virt_addr, 0, out->_data_buf_size); - ret = cx25821_openfile(dev, sram_ch); + ret = cx25821_openfile(chan, sram_ch); if (ret < 0) return ret; /* Create RISC programs */ - ret = cx25821_risc_buffer_upstream(dev, dev->pci, 0, bpl, - dev->_lines_count); + ret = cx25821_risc_buffer_upstream(chan, dev->pci, 0, bpl, + out->_lines_count); if (ret < 0) { pr_info("Failed creating Video Upstream Risc programs!\n"); goto error; @@ -551,11 +554,12 @@ error: return ret; } -static int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num, - u32 status) +static int cx25821_video_upstream_irq(struct cx25821_channel *chan, u32 status) { + struct cx25821_video_out_data *out = chan->out; + struct cx25821_dev *dev = chan->dev; u32 int_msk_tmp; - const struct sram_channel *channel = dev->channels[chan_num].sram_channels; + const struct sram_channel *channel = chan->sram_channels; int singlefield_lines = NTSC_FIELD_HEIGHT; int line_size_in_bytes = Y422_LINE_SZ; int odd_risc_prog_size = 0; @@ -574,14 +578,14 @@ static int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num, spin_lock(&dev->slock); - dev->_frame_index = prog_cnt; + out->_frame_index = prog_cnt; - queue_work(dev->_irq_queues, &dev->_irq_work_entry); + queue_work(out->_irq_queues, &out->_irq_work_entry); - if (dev->_is_first_frame) { - dev->_is_first_frame = 0; + if (out->_is_first_frame) { + out->_is_first_frame = 0; - if (dev->_isNTSC) { + if (out->is_60hz) { singlefield_lines += 1; odd_risc_prog_size = ODD_FLD_NTSC_PROG_SIZE; } else { @@ -589,17 +593,17 @@ static int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num, odd_risc_prog_size = ODD_FLD_PAL_PROG_SIZE; } - if (dev->_dma_virt_start_addr != NULL) { + if (out->_dma_virt_start_addr != NULL) { line_size_in_bytes = - (dev->_pixel_format == + (out->_pixel_format == PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; risc_phys_jump_addr = - dev->_dma_phys_start_addr + + out->_dma_phys_start_addr + odd_risc_prog_size; - rp = cx25821_update_riscprogram(dev, - dev->_dma_virt_start_addr, TOP_OFFSET, + rp = cx25821_update_riscprogram(chan, + out->_dma_virt_start_addr, TOP_OFFSET, line_size_in_bytes, 0x0, singlefield_lines, FIFO_DISABLE, ODD_FIELD); @@ -626,8 +630,8 @@ static int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num, __func__); } - if (dev->_file_status == END_OF_FILE) { - pr_err("EOF Channel 1 Framecount = %d\n", dev->_frame_count); + if (out->_file_status == END_OF_FILE) { + pr_err("EOF Channel 1 Framecount = %d\n", out->_frame_count); return -1; } /* ElSE, set the interrupt mask register, re-enable irq. */ @@ -639,47 +643,41 @@ static int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num, static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id) { - struct cx25821_dev *dev = dev_id; + struct cx25821_channel *chan = dev_id; + struct cx25821_dev *dev = chan->dev; u32 vid_status; int handled = 0; - int channel_num = 0; const struct sram_channel *sram_ch; if (!dev) return -1; - channel_num = VID_UPSTREAM_SRAM_CHANNEL_I; - - sram_ch = dev->channels[channel_num].sram_channels; + sram_ch = chan->sram_channels; vid_status = cx_read(sram_ch->int_stat); /* Only deal with our interrupt */ if (vid_status) - handled = cx25821_video_upstream_irq(dev, channel_num, - vid_status); - - if (handled < 0) - cx25821_stop_upstream_video_ch1(dev); - else - handled += handled; + handled = cx25821_video_upstream_irq(chan, vid_status); return IRQ_RETVAL(handled); } -static void cx25821_set_pixelengine(struct cx25821_dev *dev, +static void cx25821_set_pixelengine(struct cx25821_channel *chan, const struct sram_channel *ch, int pix_format) { + struct cx25821_video_out_data *out = chan->out; + struct cx25821_dev *dev = chan->dev; int width = WIDTH_D1; - int height = dev->_lines_count; + int height = out->_lines_count; int num_lines, odd_num_lines; u32 value; int vip_mode = OUTPUT_FRMT_656; value = ((pix_format & 0x3) << 12) | (vip_mode & 0x7); value &= 0xFFFFFFEF; - value |= dev->_isNTSC ? 0 : 0x10; + value |= out->is_60hz ? 0 : 0x10; cx_write(ch->vid_fmt_ctl, value); /* set number of active pixels in each line. @@ -689,7 +687,7 @@ static void cx25821_set_pixelengine(struct cx25821_dev *dev, num_lines = (height / 2) & 0x3FF; odd_num_lines = num_lines; - if (dev->_isNTSC) + if (out->is_60hz) odd_num_lines += 1; value = (num_lines << 16) | odd_num_lines; @@ -700,9 +698,11 @@ static void cx25821_set_pixelengine(struct cx25821_dev *dev, cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); } -static int cx25821_start_video_dma_upstream(struct cx25821_dev *dev, +static int cx25821_start_video_dma_upstream(struct cx25821_channel *chan, const struct sram_channel *sram_ch) { + struct cx25821_video_out_data *out = chan->out; + struct cx25821_dev *dev = chan->dev; u32 tmp = 0; int err = 0; @@ -715,7 +715,7 @@ static int cx25821_start_video_dma_upstream(struct cx25821_dev *dev, /* Set the physical start address of the RISC program in the initial * program counter(IPC) member of the cmds. */ - cx_write(sram_ch->cmds_start + 0, dev->_dma_phys_addr); + cx_write(sram_ch->cmds_start + 0, out->_dma_phys_addr); /* Risc IPC High 64 bits 63-32 */ cx_write(sram_ch->cmds_start + 4, 0); @@ -731,7 +731,7 @@ static int cx25821_start_video_dma_upstream(struct cx25821_dev *dev, cx_write(sram_ch->int_msk, tmp |= _intr_msk); err = request_irq(dev->pci->irq, cx25821_upstream_irq, - IRQF_SHARED, dev->name, dev); + IRQF_SHARED, dev->name, chan); if (err < 0) { pr_err("%s: can't get upstream IRQ %d\n", dev->name, dev->pci->irq); @@ -742,8 +742,8 @@ static int cx25821_start_video_dma_upstream(struct cx25821_dev *dev, tmp = cx_read(sram_ch->dma_ctl); cx_set(sram_ch->dma_ctl, tmp | FLD_VID_RISC_EN); - dev->_is_running = 1; - dev->_is_first_frame = 1; + out->_is_running = 1; + out->_is_first_frame = 1; return 0; @@ -752,9 +752,11 @@ fail_irq: return err; } -int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, +int cx25821_vidupstream_init(struct cx25821_channel *chan, int pixel_format) { + struct cx25821_video_out_data *out = chan->out; + struct cx25821_dev *dev = chan->dev; const struct sram_channel *sram_ch; u32 tmp; int err = 0; @@ -762,18 +764,17 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, int risc_buffer_size = 0; int str_length = 0; - if (dev->_is_running) { + if (out->_is_running) { pr_info("Video Channel is still running so return!\n"); return 0; } - dev->_channel_upstream_select = channel_select; - sram_ch = dev->channels[channel_select].sram_channels; + sram_ch = chan->sram_channels; - INIT_WORK(&dev->_irq_work_entry, cx25821_vidups_handler); - dev->_irq_queues = create_singlethread_workqueue("cx25821_workqueue"); + INIT_WORK(&out->_irq_work_entry, cx25821_vidups_handler); + out->_irq_queues = create_singlethread_workqueue("cx25821_workqueue"); - if (!dev->_irq_queues) { + if (!out->_irq_queues) { pr_err("create_singlethread_workqueue() for Video FAILED!\n"); return -ENOMEM; } @@ -783,76 +784,76 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, tmp = cx_read(VID_CH_MODE_SEL); cx_write(VID_CH_MODE_SEL, tmp | 0x1B0001FF); - dev->_is_running = 0; - dev->_frame_count = 0; - dev->_file_status = RESET_STATUS; - dev->_lines_count = dev->_isNTSC ? 480 : 576; - dev->_pixel_format = pixel_format; - dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ? + out->_is_running = 0; + out->_frame_count = 0; + out->_file_status = RESET_STATUS; + out->_lines_count = out->is_60hz ? 480 : 576; + out->_pixel_format = pixel_format; + out->_line_size = (out->_pixel_format == PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; - data_frame_size = dev->_isNTSC ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; - risc_buffer_size = dev->_isNTSC ? + data_frame_size = out->is_60hz ? NTSC_DATA_BUF_SZ : PAL_DATA_BUF_SZ; + risc_buffer_size = out->is_60hz ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; - if (dev->input_filename) { - str_length = strlen(dev->input_filename); - dev->_filename = kmemdup(dev->input_filename, str_length + 1, + if (out->input_filename) { + str_length = strlen(out->input_filename); + out->_filename = kmemdup(out->input_filename, str_length + 1, GFP_KERNEL); - if (!dev->_filename) { + if (!out->_filename) { err = -ENOENT; goto error; } } else { - str_length = strlen(dev->_defaultname); - dev->_filename = kmemdup(dev->_defaultname, str_length + 1, + str_length = strlen(out->_defaultname); + out->_filename = kmemdup(out->_defaultname, str_length + 1, GFP_KERNEL); - if (!dev->_filename) { + if (!out->_filename) { err = -ENOENT; goto error; } } /* Default if filename is empty string */ - if (strcmp(dev->_filename, "") == 0) { - if (dev->_isNTSC) { - dev->_filename = - (dev->_pixel_format == PIXEL_FRMT_411) ? + if (strcmp(out->_filename, "") == 0) { + if (out->is_60hz) { + out->_filename = + (out->_pixel_format == PIXEL_FRMT_411) ? "/root/vid411.yuv" : "/root/vidtest.yuv"; } else { - dev->_filename = - (dev->_pixel_format == PIXEL_FRMT_411) ? + out->_filename = + (out->_pixel_format == PIXEL_FRMT_411) ? "/root/pal411.yuv" : "/root/pal422.yuv"; } } - dev->_is_running = 0; - dev->_frame_count = 0; - dev->_file_status = RESET_STATUS; - dev->_lines_count = dev->_isNTSC ? 480 : 576; - dev->_pixel_format = pixel_format; - dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ? + out->_is_running = 0; + out->_frame_count = 0; + out->_file_status = RESET_STATUS; + out->_lines_count = out->is_60hz ? 480 : 576; + out->_pixel_format = pixel_format; + out->_line_size = (out->_pixel_format == PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; err = cx25821_sram_channel_setup_upstream(dev, sram_ch, - dev->_line_size, 0); + out->_line_size, 0); /* setup fifo + format */ - cx25821_set_pixelengine(dev, sram_ch, dev->_pixel_format); + cx25821_set_pixelengine(chan, sram_ch, out->_pixel_format); - dev->upstream_riscbuf_size = risc_buffer_size * 2; - dev->upstream_databuf_size = data_frame_size * 2; + out->upstream_riscbuf_size = risc_buffer_size * 2; + out->upstream_databuf_size = data_frame_size * 2; /* Allocating buffers and prepare RISC program */ - err = cx25821_upstream_buffer_prepare(dev, sram_ch, dev->_line_size); + err = cx25821_upstream_buffer_prepare(chan, sram_ch, out->_line_size); if (err < 0) { pr_err("%s: Failed to set up Video upstream buffers!\n", dev->name); goto error; } - cx25821_start_video_dma_upstream(dev, sram_ch); + cx25821_start_video_dma_upstream(chan, sram_ch); return 0; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 70e33b125969..dde0ba3d3401 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -893,6 +893,20 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, return 0; } +static int video_out_release(struct file *file) +{ + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_video_out_data *out = chan->out; + struct cx25821_dev *dev = chan->dev; + + mutex_lock(&dev->lock); + if ((chan->id == SRAM_CH09 || chan->id == SRAM_CH10) && out->_is_running) + cx25821_stop_upstream_video(chan); + mutex_unlock(&dev->lock); + + return v4l2_fh_release(file); +} + static const struct v4l2_ctrl_ops cx25821_ctrl_ops = { .s_ctrl = cx25821_s_ctrl, }; @@ -941,7 +955,7 @@ static const struct video_device cx25821_video_device = { static const struct v4l2_file_operations video_out_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, - .release = v4l2_fh_release, + .release = video_out_release, .unlocked_ioctl = video_ioctl2, }; @@ -1017,6 +1031,9 @@ int cx25821_video_register(struct cx25821_dev *dev) err = v4l2_ctrl_handler_setup(hdl); if (err) goto fail_unreg; + } else { + chan->out = &dev->vid_out_data[i - SRAM_CH09]; + chan->out->chan = chan; } cx25821_risc_stopper(dev->pci, &chan->dma_vidq.stopper, diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 156ad6f2c634..b0bc2e626ae7 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -172,6 +172,42 @@ struct cx25821_data { struct cx25821_dev; +struct cx25821_channel; + +struct cx25821_video_out_data { + struct cx25821_channel *chan; + int _line_size; + int _prog_cnt; + int _pixel_format; + int _is_first_frame; + int _is_running; + int _file_status; + int _lines_count; + int _frame_count; + unsigned int _risc_size; + + __le32 *_dma_virt_start_addr; + __le32 *_dma_virt_addr; + dma_addr_t _dma_phys_addr; + dma_addr_t _dma_phys_start_addr; + + unsigned int _data_buf_size; + __le32 *_data_buf_virt_addr; + dma_addr_t _data_buf_phys_addr; + + u32 upstream_riscbuf_size; + u32 upstream_databuf_size; + struct workqueue_struct *_irq_queues; + struct work_struct _irq_work_entry; + int is_60hz; + int _frame_index; + char *input_filename; + char *vid_stdname; + int pixel_format; + char *_filename; + char *_defaultname; +}; + struct cx25821_channel { unsigned id; struct cx25821_dev *dev; @@ -191,6 +227,9 @@ struct cx25821_channel { int pixel_formats; int use_cif_resolution; int cif_width; + + /* video output data for the video output channel */ + struct cx25821_video_out_data *out; }; struct snd_card; @@ -250,83 +289,18 @@ struct cx25821_dev { __le32 *_audiodata_buf_virt_addr; dma_addr_t _audiodata_buf_phys_addr; char *_audiofilename; - - /* V4l */ - spinlock_t slock; - - /* Video Upstream */ - int _line_size; - int _prog_cnt; - int _pixel_format; - int _is_first_frame; - int _is_running; - int _file_status; - int _lines_count; - int _frame_count; - int _channel_upstream_select; - unsigned int _risc_size; - - __le32 *_dma_virt_start_addr; - __le32 *_dma_virt_addr; - dma_addr_t _dma_phys_addr; - dma_addr_t _dma_phys_start_addr; - - unsigned int _data_buf_size; - __le32 *_data_buf_virt_addr; - dma_addr_t _data_buf_phys_addr; - char *_filename; - char *_defaultname; - - int _line_size_ch2; - int _prog_cnt_ch2; - int _pixel_format_ch2; - int _is_first_frame_ch2; - int _is_running_ch2; - int _file_status_ch2; - int _lines_count_ch2; - int _frame_count_ch2; - int _channel2_upstream_select; - unsigned int _risc_size_ch2; - - __le32 *_dma_virt_start_addr_ch2; - __le32 *_dma_virt_addr_ch2; - dma_addr_t _dma_phys_addr_ch2; - dma_addr_t _dma_phys_start_addr_ch2; - - unsigned int _data_buf_size_ch2; - __le32 *_data_buf_virt_addr_ch2; - dma_addr_t _data_buf_phys_addr_ch2; - char *_filename_ch2; - char *_defaultname_ch2; - - u32 upstream_riscbuf_size; - u32 upstream_databuf_size; - u32 upstream_riscbuf_size_ch2; - u32 upstream_databuf_size_ch2; u32 audio_upstream_riscbuf_size; u32 audio_upstream_databuf_size; - int _isNTSC; - int _frame_index; int _audioframe_index; - struct workqueue_struct *_irq_queues; - struct work_struct _irq_work_entry; - struct workqueue_struct *_irq_queues_ch2; - struct work_struct _irq_work_entry_ch2; struct workqueue_struct *_irq_audio_queues; struct work_struct _audio_work_entry; - char *input_filename; - char *input_filename_ch2; - int _frame_index_ch2; - int _isNTSC_ch2; - char *vid_stdname_ch2; - int pixel_format_ch2; - int channel_select_ch2; - int command_ch2; char *input_audiofilename; - char *vid_stdname; - int pixel_format; - int channel_select; - int command; + + /* V4l */ + spinlock_t slock; + + /* Video Upstream */ + struct cx25821_video_out_data vid_out_data[2]; }; static inline struct cx25821_dev *get_cx25821(struct v4l2_device *v4l2_dev) @@ -463,17 +437,12 @@ extern int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev, const struct sram_channel *ch, unsigned int bpl, u32 risc); -extern int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, - int channel_select, int pixel_format); -extern int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, - int channel_select, int pixel_format); +extern int cx25821_vidupstream_init(struct cx25821_channel *chan, int pixel_format); extern int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select); -extern void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev); -extern void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev); +extern void cx25821_free_mem_upstream(struct cx25821_channel *chan); extern void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev); -extern void cx25821_stop_upstream_video_ch1(struct cx25821_dev *dev); -extern void cx25821_stop_upstream_video_ch2(struct cx25821_dev *dev); +extern void cx25821_stop_upstream_video(struct cx25821_channel *chan); extern void cx25821_stop_upstream_audio(struct cx25821_dev *dev); extern int cx25821_sram_channel_setup_upstream(struct cx25821_dev *dev, const struct sram_channel *ch, -- cgit v1.2.3 From ea3f7ac6e931f9aaa45e0a8445406f14e2a62011 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 14 Apr 2013 12:02:19 -0300 Subject: [media] cx25821: replace custom ioctls with write() Ideally this should be implemented with vb2, but it'll do for now. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-core.c | 3 +- drivers/media/pci/cx25821/cx25821-video-upstream.c | 248 +++------------------ drivers/media/pci/cx25821/cx25821-video.c | 37 ++- drivers/media/pci/cx25821/cx25821.h | 12 +- 4 files changed, 72 insertions(+), 228 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 230bd8641576..35bea792b5e4 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -775,8 +775,8 @@ void cx25821_set_pixel_format(struct cx25821_dev *dev, int channel_select, if (channel_select <= 7 && channel_select >= 0) { cx_write(dev->channels[channel_select].sram_channels->pix_frmt, format); - dev->channels[channel_select].pixel_formats = format; } + dev->channels[channel_select].pixel_formats = format; } static void cx25821_set_vip_mode(struct cx25821_dev *dev, @@ -820,6 +820,7 @@ static void cx25821_initialize(struct cx25821_dev *dev) /* Probably only affect Downstream */ for (i = VID_UPSTREAM_SRAM_CHANNEL_I; i <= VID_UPSTREAM_SRAM_CHANNEL_J; i++) { + dev->channels[i].pixel_formats = PIXEL_FRMT_422; cx25821_set_vip_mode(dev, dev->channels[i].sram_channels); } diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c index 37cfc834e5c0..88ffef410c50 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c @@ -25,16 +25,11 @@ #include "cx25821-video.h" #include "cx25821-video-upstream.h" -#include #include #include #include #include -#include -#include -#include #include -#include MODULE_DESCRIPTION("v4l2 driver module for cx25821 based TV cards"); MODULE_AUTHOR("Hiep Huynh "); @@ -258,6 +253,10 @@ void cx25821_stop_upstream_video(struct cx25821_channel *chan) pr_info("No video file is currently running so return!\n"); return; } + + /* Set the interrupt mask register, disable irq. */ + cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) & ~(1 << sram_ch->irq_bit)); + /* Disable RISC interrupts */ tmp = cx_read(sram_ch->int_msk); cx_write(sram_ch->int_msk, tmp & ~_intr_msk); @@ -266,6 +265,8 @@ void cx25821_stop_upstream_video(struct cx25821_channel *chan) tmp = cx_read(sram_ch->dma_ctl); cx_write(sram_ch->dma_ctl, tmp & ~(FLD_VID_FIFO_EN | FLD_VID_RISC_EN)); + free_irq(dev->pci->irq, chan); + /* Clear data buffer memory */ if (out->_data_buf_virt_addr) memset(out->_data_buf_virt_addr, 0, out->_data_buf_size); @@ -275,11 +276,6 @@ void cx25821_stop_upstream_video(struct cx25821_channel *chan) out->_frame_count = 0; out->_file_status = END_OF_FILE; - destroy_workqueue(out->_irq_queues); - out->_irq_queues = NULL; - - kfree(out->_filename); - tmp = cx_read(VID_CH_MODE_SEL); cx_write(VID_CH_MODE_SEL, tmp & 0xFFFFFE00); } @@ -306,25 +302,15 @@ void cx25821_free_mem_upstream(struct cx25821_channel *chan) } } -static int cx25821_get_frame(struct cx25821_channel *chan, - const struct sram_channel *sram_ch) +int cx25821_write_frame(struct cx25821_channel *chan, + const char __user *data, size_t count) { struct cx25821_video_out_data *out = chan->out; - struct file *myfile; - int frame_index_temp = out->_frame_index; - int i = 0; int line_size = (out->_pixel_format == PIXEL_FRMT_411) ? Y411_LINE_SZ : Y422_LINE_SZ; int frame_size = 0; int frame_offset = 0; - ssize_t vfs_read_retval = 0; - char mybuf[line_size]; - loff_t file_offset; - loff_t pos; - mm_segment_t old_fs; - - if (out->_file_status == END_OF_FILE) - return 0; + int curpos = out->curpos; if (out->is_60hz) frame_size = (line_size == Y411_LINE_SZ) ? @@ -333,160 +319,27 @@ static int cx25821_get_frame(struct cx25821_channel *chan, frame_size = (line_size == Y411_LINE_SZ) ? FRAME_SIZE_PAL_Y411 : FRAME_SIZE_PAL_Y422; - frame_offset = (frame_index_temp > 0) ? frame_size : 0; - file_offset = out->_frame_count * frame_size; - - myfile = filp_open(out->_filename, O_RDONLY | O_LARGEFILE, 0); - - if (IS_ERR(myfile)) { - const int open_errno = -PTR_ERR(myfile); - pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, out->_filename, open_errno); - return PTR_ERR(myfile); - } else { - if (!(myfile->f_op)) { - pr_err("%s(): File has no file operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - if (!myfile->f_op->read) { - pr_err("%s(): File has no READ operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - pos = myfile->f_pos; - old_fs = get_fs(); - set_fs(KERNEL_DS); - - for (i = 0; i < out->_lines_count; i++) { - pos = file_offset; - - vfs_read_retval = vfs_read(myfile, mybuf, line_size, - &pos); - - if (vfs_read_retval > 0 && vfs_read_retval == line_size - && out->_data_buf_virt_addr != NULL) { - memcpy((void *)(out->_data_buf_virt_addr + - frame_offset / 4), mybuf, - vfs_read_retval); - } - - file_offset += vfs_read_retval; - frame_offset += vfs_read_retval; - - if (vfs_read_retval < line_size) { - pr_info("Done: exit %s() since no more bytes to read from Video file\n", - __func__); - break; - } - } - - if (i > 0) - out->_frame_count++; - - out->_file_status = (vfs_read_retval == line_size) ? - IN_PROGRESS : END_OF_FILE; - - set_fs(old_fs); - filp_close(myfile, NULL); + if (curpos == 0) { + out->cur_frame_index = out->_frame_index; + if (wait_event_interruptible(out->waitq, out->cur_frame_index != out->_frame_index)) + return -EINTR; + out->cur_frame_index = out->_frame_index; } - return 0; -} - -static void cx25821_vidups_handler(struct work_struct *work) -{ - struct cx25821_video_out_data *out = - container_of(work, struct cx25821_video_out_data, _irq_work_entry); - - cx25821_get_frame(out->chan, out->chan->sram_channels); -} + frame_offset = out->cur_frame_index ? frame_size : 0; -static int cx25821_openfile(struct cx25821_channel *chan, - const struct sram_channel *sram_ch) -{ - struct cx25821_video_out_data *out = chan->out; - struct file *myfile; - int i = 0, j = 0; - int line_size = (out->_pixel_format == PIXEL_FRMT_411) ? - Y411_LINE_SZ : Y422_LINE_SZ; - ssize_t vfs_read_retval = 0; - char mybuf[line_size]; - loff_t pos; - loff_t offset = (unsigned long)0; - mm_segment_t old_fs; - - myfile = filp_open(out->_filename, O_RDONLY | O_LARGEFILE, 0); - - if (IS_ERR(myfile)) { - const int open_errno = -PTR_ERR(myfile); - pr_err("%s(): ERROR opening file(%s) with errno = %d!\n", - __func__, out->_filename, open_errno); - return PTR_ERR(myfile); - } else { - if (!(myfile->f_op)) { - pr_err("%s(): File has no file operations registered!\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - if (!myfile->f_op->read) { - pr_err("%s(): File has no READ operations registered! Returning\n", - __func__); - filp_close(myfile, NULL); - return -EIO; - } - - pos = myfile->f_pos; - old_fs = get_fs(); - set_fs(KERNEL_DS); - - for (j = 0; j < NUM_FRAMES; j++) { - for (i = 0; i < out->_lines_count; i++) { - pos = offset; - - vfs_read_retval = vfs_read(myfile, mybuf, - line_size, &pos); - - if (vfs_read_retval > 0 - && vfs_read_retval == line_size - && out->_data_buf_virt_addr != NULL) { - memcpy((void *)(out-> - _data_buf_virt_addr + - offset / 4), mybuf, - vfs_read_retval); - } - - offset += vfs_read_retval; - - if (vfs_read_retval < line_size) { - pr_info("Done: exit %s() since no more bytes to read from Video file\n", - __func__); - break; - } - } - - if (i > 0) - out->_frame_count++; - - if (vfs_read_retval < line_size) - break; - } - - out->_file_status = (vfs_read_retval == line_size) ? - IN_PROGRESS : END_OF_FILE; - - set_fs(old_fs); - myfile->f_pos = 0; - filp_close(myfile, NULL); + if (frame_size - curpos < count) + count = frame_size - curpos; + memcpy((char *)out->_data_buf_virt_addr + frame_offset + curpos, + data, count); + curpos += count; + if (curpos == frame_size) { + out->_frame_count++; + curpos = 0; } + out->curpos = curpos; - return 0; + return count; } static int cx25821_upstream_buffer_prepare(struct cx25821_channel *chan, @@ -536,10 +389,6 @@ static int cx25821_upstream_buffer_prepare(struct cx25821_channel *chan, /* Clear memory at address */ memset(out->_data_buf_virt_addr, 0, out->_data_buf_size); - ret = cx25821_openfile(chan, sram_ch); - if (ret < 0) - return ret; - /* Create RISC programs */ ret = cx25821_risc_buffer_upstream(chan, dev->pci, 0, bpl, out->_lines_count); @@ -576,12 +425,12 @@ static int cx25821_video_upstream_irq(struct cx25821_channel *chan, u32 status) cx_write(channel->int_msk, int_msk_tmp & ~_intr_msk); cx_write(channel->int_stat, _intr_msk); + wake_up(&out->waitq); + spin_lock(&dev->slock); out->_frame_index = prog_cnt; - queue_work(out->_irq_queues, &out->_irq_work_entry); - if (out->_is_first_frame) { out->_is_first_frame = 0; @@ -762,7 +611,6 @@ int cx25821_vidupstream_init(struct cx25821_channel *chan, int err = 0; int data_frame_size = 0; int risc_buffer_size = 0; - int str_length = 0; if (out->_is_running) { pr_info("Video Channel is still running so return!\n"); @@ -771,13 +619,8 @@ int cx25821_vidupstream_init(struct cx25821_channel *chan, sram_ch = chan->sram_channels; - INIT_WORK(&out->_irq_work_entry, cx25821_vidups_handler); - out->_irq_queues = create_singlethread_workqueue("cx25821_workqueue"); + out->is_60hz = dev->tvnorm & V4L2_STD_525_60; - if (!out->_irq_queues) { - pr_err("create_singlethread_workqueue() for Video FAILED!\n"); - return -ENOMEM; - } /* 656/VIP SRC Upstream Channel I & J and 7 - Host Bus Interface for * channel A-C */ @@ -795,39 +638,6 @@ int cx25821_vidupstream_init(struct cx25821_channel *chan, risc_buffer_size = out->is_60hz ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; - if (out->input_filename) { - str_length = strlen(out->input_filename); - out->_filename = kmemdup(out->input_filename, str_length + 1, - GFP_KERNEL); - - if (!out->_filename) { - err = -ENOENT; - goto error; - } - } else { - str_length = strlen(out->_defaultname); - out->_filename = kmemdup(out->_defaultname, str_length + 1, - GFP_KERNEL); - - if (!out->_filename) { - err = -ENOENT; - goto error; - } - } - - /* Default if filename is empty string */ - if (strcmp(out->_filename, "") == 0) { - if (out->is_60hz) { - out->_filename = - (out->_pixel_format == PIXEL_FRMT_411) ? - "/root/vid411.yuv" : "/root/vidtest.yuv"; - } else { - out->_filename = - (out->_pixel_format == PIXEL_FRMT_411) ? - "/root/pal411.yuv" : "/root/pal422.yuv"; - } - } - out->_is_running = 0; out->_frame_count = 0; out->_file_status = RESET_STATUS; @@ -835,6 +645,8 @@ int cx25821_vidupstream_init(struct cx25821_channel *chan, out->_pixel_format = pixel_format; out->_line_size = (out->_pixel_format == PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; + out->curpos = 0; + init_waitqueue_head(&out->waitq); err = cx25821_sram_channel_setup_upstream(dev, sram_ch, out->_line_size, 0); diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index dde0ba3d3401..b194138961df 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -893,15 +893,47 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, return 0; } +static ssize_t video_write(struct file *file, const char __user *data, size_t count, + loff_t *ppos) +{ + struct cx25821_channel *chan = video_drvdata(file); + struct cx25821_dev *dev = chan->dev; + struct v4l2_fh *fh = file->private_data; + int err = 0; + + if (mutex_lock_interruptible(&dev->lock)) + return -ERESTARTSYS; + if (chan->streaming_fh && chan->streaming_fh != fh) { + err = -EBUSY; + goto unlock; + } + if (!chan->streaming_fh) { + err = cx25821_vidupstream_init(chan, chan->pixel_formats); + if (err) + goto unlock; + chan->streaming_fh = fh; + } + + err = cx25821_write_frame(chan, data, count); + count -= err; + *ppos += err; + +unlock: + mutex_unlock(&dev->lock); + return err; +} + static int video_out_release(struct file *file) { struct cx25821_channel *chan = video_drvdata(file); - struct cx25821_video_out_data *out = chan->out; struct cx25821_dev *dev = chan->dev; + struct v4l2_fh *fh = file->private_data; mutex_lock(&dev->lock); - if ((chan->id == SRAM_CH09 || chan->id == SRAM_CH10) && out->_is_running) + if (chan->streaming_fh == fh) { cx25821_stop_upstream_video(chan); + chan->streaming_fh = NULL; + } mutex_unlock(&dev->lock); return v4l2_fh_release(file); @@ -955,6 +987,7 @@ static const struct video_device cx25821_video_device = { static const struct v4l2_file_operations video_out_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, + .write = video_write, .release = video_out_release, .unlocked_ioctl = video_ioctl2, }; diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index b0bc2e626ae7..90bdc196929f 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -197,15 +197,11 @@ struct cx25821_video_out_data { u32 upstream_riscbuf_size; u32 upstream_databuf_size; - struct workqueue_struct *_irq_queues; - struct work_struct _irq_work_entry; int is_60hz; int _frame_index; - char *input_filename; - char *vid_stdname; - int pixel_format; - char *_filename; - char *_defaultname; + int cur_frame_index; + int curpos; + wait_queue_head_t waitq; }; struct cx25821_channel { @@ -440,6 +436,8 @@ extern int cx25821_sram_channel_setup_audio(struct cx25821_dev *dev, extern int cx25821_vidupstream_init(struct cx25821_channel *chan, int pixel_format); extern int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select); +extern int cx25821_write_frame(struct cx25821_channel *chan, + const char __user *data, size_t count); extern void cx25821_free_mem_upstream(struct cx25821_channel *chan); extern void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev); extern void cx25821_stop_upstream_video(struct cx25821_channel *chan); -- cgit v1.2.3 From 486a7a2813c7d6e0b864c4b51027bcae3359071e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 14 Apr 2013 12:47:57 -0300 Subject: [media] cx25821: remove cx25821-audio-upstream.c from the Makefile The audio output is currently not used as this should be rewritten as an alsa driver. For the time being remove this source from the Makefile. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/Makefile | 3 +-- drivers/media/pci/cx25821/cx25821-core.c | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/Makefile b/drivers/media/pci/cx25821/Makefile index 407830c89df4..fb76c3d3713a 100644 --- a/drivers/media/pci/cx25821/Makefile +++ b/drivers/media/pci/cx25821/Makefile @@ -1,7 +1,6 @@ cx25821-y := cx25821-core.o cx25821-cards.o cx25821-i2c.o \ cx25821-gpio.o cx25821-medusa-video.o \ - cx25821-video.o cx25821-video-upstream.o \ - cx25821-audio-upstream.o + cx25821-video.o cx25821-video-upstream.o obj-$(CONFIG_VIDEO_CX25821) += cx25821.o obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 35bea792b5e4..b762c5b2ca10 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -964,8 +964,6 @@ void cx25821_dev_unregister(struct cx25821_dev *dev) if (!dev->base_io_addr) return; - cx25821_free_mem_upstream_audio(dev); - release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0)); for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; i++) { -- cgit v1.2.3 From 430c73fa476808d825cb2cab37bbfabbc0a31d42 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Tue, 16 Apr 2013 08:06:30 -0300 Subject: [media] em28xx: Put remaining .vidioc_g_chip_info instance under ADV_DEBUG Commit cd634f1 ("[media] v4l2: put VIDIOC_DBG_G_CHIP_NAME under ADV_DEBUG") missed the initializer of radio_ioctl_ops: drivers/media/usb/em28xx/em28xx-video.c:1830:2: error: unknown field 'vidioc_g_chip_info' specified in initializer drivers/media/usb/em28xx/em28xx-video.c:1830:26: error: 'vidioc_g_chip_info' undeclared here (not in a function) Signed-off-by: Michal Marek Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index c27c1f671396..32d60e5546bc 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1827,8 +1827,8 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, .vidioc_g_chip_ident = vidioc_g_chip_ident, - .vidioc_g_chip_info = vidioc_g_chip_info, #ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_chip_info = vidioc_g_chip_info, .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif -- cgit v1.2.3 From bebe3c69de77fed87c1e36cc18e9c80985391918 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 16 Apr 2013 14:26:54 -0300 Subject: [media] zoran: Don't print proc_dir_entry data in debug [RFC] Don't print proc_dir_entry data in debug as we're soon to have no direct access to the contents of the PDE. Print what was put in there instead. Signed-off-by: David Howells Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/zoran/zoran_procfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/zoran/zoran_procfs.c b/drivers/media/pci/zoran/zoran_procfs.c index e084b0a21b1b..1512b5d40533 100644 --- a/drivers/media/pci/zoran/zoran_procfs.c +++ b/drivers/media/pci/zoran/zoran_procfs.c @@ -201,7 +201,7 @@ zoran_proc_init (struct zoran *zr) dprintk(2, KERN_INFO "%s: procfs entry /proc/%s allocated. data=%p\n", - ZR_DEVNAME(zr), name, zr->zoran_proc->data); + ZR_DEVNAME(zr), name, zr); } else { dprintk(1, KERN_ERR "%s: Unable to initialise /proc/%s\n", ZR_DEVNAME(zr), name); -- cgit v1.2.3 From 76dea4cf52784474ca6adc4a2addf55e128b3634 Mon Sep 17 00:00:00 2001 From: William Steidtmann Date: Mon, 15 Apr 2013 17:17:11 -0300 Subject: [media] mceusb: add some missing cmd sizes Fix mceusb_cmdsize() which returns incorrect datasize=0 for sub-commands MCE_RSP_GETPORTSTATUS, MCE_RSP_GETWAKESOURCE, MCE_RSP_EQDEVDETAILS, MCE_RSP_EQEMVER, and MCE_RSP_EQIRNUMPORTS. While here, change mceusb_cmdsize() name to reflect that it returns data size not cmd size. Signed-off-by: William Steidtmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 5b5b6e6f79e8..3c761014d3ce 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -482,7 +482,7 @@ static char SET_RX_SENSOR[] = {MCE_CMD_PORT_IR, MCE_RSP_EQIRRXPORTEN, 0x00}; */ -static int mceusb_cmdsize(u8 cmd, u8 subcmd) +static int mceusb_cmd_datasize(u8 cmd, u8 subcmd) { int datasize = 0; @@ -493,6 +493,9 @@ static int mceusb_cmdsize(u8 cmd, u8 subcmd) break; case MCE_CMD_PORT_SYS: switch (subcmd) { + case MCE_RSP_GETPORTSTATUS: + datasize = 5; + break; case MCE_RSP_EQWAKEVERSION: datasize = 4; break; @@ -500,6 +503,9 @@ static int mceusb_cmdsize(u8 cmd, u8 subcmd) datasize = 2; break; case MCE_RSP_EQWAKESUPPORT: + case MCE_RSP_GETWAKESOURCE: + case MCE_RSP_EQDEVDETAILS: + case MCE_RSP_EQEMVER: datasize = 1; break; } @@ -509,6 +515,7 @@ static int mceusb_cmdsize(u8 cmd, u8 subcmd) case MCE_RSP_EQIRCFS: case MCE_RSP_EQIRTIMEOUT: case MCE_RSP_EQIRRXCFCNT: + case MCE_RSP_EQIRNUMPORTS: datasize = 2; break; case MCE_CMD_SIG_END: @@ -968,7 +975,7 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) for (; i < buf_len; i++) { switch (ir->parser_state) { case SUBCMD: - ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]); + ir->rem = mceusb_cmd_datasize(ir->cmd, ir->buf_in[i]); mceusb_dev_printdata(ir, ir->buf_in, i - 1, ir->rem + 2, false); mceusb_handle_command(ir, i); -- cgit v1.2.3 From 99ca5557fff4a4d1d87874384354d42f6c395e1a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 16 Apr 2013 19:43:06 -0300 Subject: [media] it913x: rename its tuner driver to tuner_it913x There are three drivers with *it913x name on it, and they all belong to the same device: a tuner, at it913x.c; a frontend: it913x-fe.c; a bridge: it913x.c, renamed to dvb_usb_it913x by the building system. This is confusing. Even more confusing are the two .c files with the same name under different directories, with different contents and different functions. So, prepend the tuner one. This also breaks the out-of-tree compilation system. Reported-by: Frederic Fays Acked-by: Antti Palosaari Reviewed-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/Makefile | 2 +- drivers/media/tuners/it913x.c | 447 ------------------------------- drivers/media/tuners/it913x.h | 45 ---- drivers/media/tuners/it913x_priv.h | 78 ------ drivers/media/tuners/tuner_it913x.c | 447 +++++++++++++++++++++++++++++++ drivers/media/tuners/tuner_it913x.h | 45 ++++ drivers/media/tuners/tuner_it913x_priv.h | 78 ++++++ drivers/media/usb/dvb-usb-v2/af9035.h | 2 +- 8 files changed, 572 insertions(+), 572 deletions(-) delete mode 100644 drivers/media/tuners/it913x.c delete mode 100644 drivers/media/tuners/it913x.h delete mode 100644 drivers/media/tuners/it913x_priv.h create mode 100644 drivers/media/tuners/tuner_it913x.c create mode 100644 drivers/media/tuners/tuner_it913x.h create mode 100644 drivers/media/tuners/tuner_it913x_priv.h (limited to 'drivers/media') diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile index f136a6d83120..2ebe4b725b51 100644 --- a/drivers/media/tuners/Makefile +++ b/drivers/media/tuners/Makefile @@ -34,7 +34,7 @@ obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o -obj-$(CONFIG_MEDIA_TUNER_IT913X) += it913x.o +obj-$(CONFIG_MEDIA_TUNER_IT913X) += tuner_it913x.o ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c deleted file mode 100644 index 4d7a24761050..000000000000 --- a/drivers/media/tuners/it913x.c +++ /dev/null @@ -1,447 +0,0 @@ -/* - * ITE Tech IT9137 silicon tuner driver - * - * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) - * IT9137 Copyright (C) ITE Tech Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#include "it913x_priv.h" - -struct it913x_state { - struct i2c_adapter *i2c_adap; - u8 i2c_addr; - u8 chip_ver; - u8 tuner_type; - u8 firmware_ver; - u16 tun_xtal; - u8 tun_fdiv; - u8 tun_clk_mode; - u32 tun_fn_min; -}; - -/* read multiple registers */ -static int it913x_rd_regs(struct it913x_state *state, - u32 reg, u8 *data, u8 count) -{ - int ret; - u8 b[3]; - struct i2c_msg msg[2] = { - { .addr = state->i2c_addr, .flags = 0, - .buf = b, .len = sizeof(b) }, - { .addr = state->i2c_addr, .flags = I2C_M_RD, - .buf = data, .len = count } - }; - b[0] = (u8)(reg >> 16) & 0xff; - b[1] = (u8)(reg >> 8) & 0xff; - b[2] = (u8) reg & 0xff; - b[0] |= 0x80; /* All reads from demodulator */ - - ret = i2c_transfer(state->i2c_adap, msg, 2); - - return ret; -} - -/* read single register */ -static int it913x_rd_reg(struct it913x_state *state, u32 reg) -{ - int ret; - u8 b[1]; - ret = it913x_rd_regs(state, reg, &b[0], sizeof(b)); - return (ret < 0) ? -ENODEV : b[0]; -} - -/* write multiple registers */ -static int it913x_wr_regs(struct it913x_state *state, - u8 pro, u32 reg, u8 buf[], u8 count) -{ - u8 b[256]; - struct i2c_msg msg[1] = { - { .addr = state->i2c_addr, .flags = 0, - .buf = b, .len = 3 + count } - }; - int ret; - b[0] = (u8)(reg >> 16) & 0xff; - b[1] = (u8)(reg >> 8) & 0xff; - b[2] = (u8) reg & 0xff; - memcpy(&b[3], buf, count); - - if (pro == PRO_DMOD) - b[0] |= 0x80; - - ret = i2c_transfer(state->i2c_adap, msg, 1); - - if (ret < 0) - return -EIO; - - return 0; -} - -/* write single register */ -static int it913x_wr_reg(struct it913x_state *state, - u8 pro, u32 reg, u32 data) -{ - int ret; - u8 b[4]; - u8 s; - - b[0] = data >> 24; - b[1] = (data >> 16) & 0xff; - b[2] = (data >> 8) & 0xff; - b[3] = data & 0xff; - /* expand write as needed */ - if (data < 0x100) - s = 3; - else if (data < 0x1000) - s = 2; - else if (data < 0x100000) - s = 1; - else - s = 0; - - ret = it913x_wr_regs(state, pro, reg, &b[s], sizeof(b) - s); - - return ret; -} - -static int it913x_script_loader(struct it913x_state *state, - struct it913xset *loadscript) -{ - int ret, i; - if (loadscript == NULL) - return -EINVAL; - - for (i = 0; i < 1000; ++i) { - if (loadscript[i].pro == 0xff) - break; - ret = it913x_wr_regs(state, loadscript[i].pro, - loadscript[i].address, - loadscript[i].reg, loadscript[i].count); - if (ret < 0) - return -ENODEV; - } - return 0; -} - -static int it913x_init(struct dvb_frontend *fe) -{ - struct it913x_state *state = fe->tuner_priv; - int ret, i, reg; - u8 val, nv_val; - u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; - u8 b[2]; - - reg = it913x_rd_reg(state, 0xec86); - switch (reg) { - case 0: - state->tun_clk_mode = reg; - state->tun_xtal = 2000; - state->tun_fdiv = 3; - val = 16; - break; - case -ENODEV: - return -ENODEV; - case 1: - default: - state->tun_clk_mode = reg; - state->tun_xtal = 640; - state->tun_fdiv = 1; - val = 6; - break; - } - - reg = it913x_rd_reg(state, 0xed03); - - if (reg < 0) - return -ENODEV; - else if (reg < ARRAY_SIZE(nv)) - nv_val = nv[reg]; - else - nv_val = 2; - - for (i = 0; i < 50; i++) { - ret = it913x_rd_regs(state, 0xed23, &b[0], sizeof(b)); - reg = (b[1] << 8) + b[0]; - if (reg > 0) - break; - if (ret < 0) - return -ENODEV; - udelay(2000); - } - state->tun_fn_min = state->tun_xtal * reg; - state->tun_fn_min /= (state->tun_fdiv * nv_val); - dev_dbg(&state->i2c_adap->dev, "%s: Tuner fn_min %d\n", __func__, - state->tun_fn_min); - - if (state->chip_ver > 1) - msleep(50); - else { - for (i = 0; i < 50; i++) { - reg = it913x_rd_reg(state, 0xec82); - if (reg > 0) - break; - if (reg < 0) - return -ENODEV; - udelay(2000); - } - } - - /* Power Up Tuner - common all versions */ - ret = it913x_wr_reg(state, PRO_DMOD, 0xec40, 0x1); - ret |= it913x_wr_reg(state, PRO_DMOD, 0xfba8, 0x0); - ret |= it913x_wr_reg(state, PRO_DMOD, 0xec57, 0x0); - ret |= it913x_wr_reg(state, PRO_DMOD, 0xec58, 0x0); - - return it913x_wr_reg(state, PRO_DMOD, 0xed81, val); -} - -static int it9137_set_params(struct dvb_frontend *fe) -{ - struct it913x_state *state = fe->tuner_priv; - struct it913xset *set_tuner = set_it9137_template; - struct dtv_frontend_properties *p = &fe->dtv_property_cache; - u32 bandwidth = p->bandwidth_hz; - u32 frequency_m = p->frequency; - int ret, reg; - u32 frequency = frequency_m / 1000; - u32 freq, temp_f, tmp; - u16 iqik_m_cal; - u16 n_div; - u8 n; - u8 l_band; - u8 lna_band; - u8 bw; - - if (state->firmware_ver == 1) - set_tuner = set_it9135_template; - else - set_tuner = set_it9137_template; - - dev_dbg(&state->i2c_adap->dev, "%s: Tuner Frequency %d Bandwidth %d\n", - __func__, frequency, bandwidth); - - if (frequency >= 51000 && frequency <= 440000) { - l_band = 0; - lna_band = 0; - } else if (frequency > 440000 && frequency <= 484000) { - l_band = 1; - lna_band = 1; - } else if (frequency > 484000 && frequency <= 533000) { - l_band = 1; - lna_band = 2; - } else if (frequency > 533000 && frequency <= 587000) { - l_band = 1; - lna_band = 3; - } else if (frequency > 587000 && frequency <= 645000) { - l_band = 1; - lna_band = 4; - } else if (frequency > 645000 && frequency <= 710000) { - l_band = 1; - lna_band = 5; - } else if (frequency > 710000 && frequency <= 782000) { - l_band = 1; - lna_band = 6; - } else if (frequency > 782000 && frequency <= 860000) { - l_band = 1; - lna_band = 7; - } else if (frequency > 1450000 && frequency <= 1492000) { - l_band = 1; - lna_band = 0; - } else if (frequency > 1660000 && frequency <= 1685000) { - l_band = 1; - lna_band = 1; - } else - return -EINVAL; - set_tuner[0].reg[0] = lna_band; - - switch (bandwidth) { - case 5000000: - bw = 0; - break; - case 6000000: - bw = 2; - break; - case 7000000: - bw = 4; - break; - default: - case 8000000: - bw = 6; - break; - } - - set_tuner[1].reg[0] = bw; - set_tuner[2].reg[0] = 0xa0 | (l_band << 3); - - if (frequency > 53000 && frequency <= 74000) { - n_div = 48; - n = 0; - } else if (frequency > 74000 && frequency <= 111000) { - n_div = 32; - n = 1; - } else if (frequency > 111000 && frequency <= 148000) { - n_div = 24; - n = 2; - } else if (frequency > 148000 && frequency <= 222000) { - n_div = 16; - n = 3; - } else if (frequency > 222000 && frequency <= 296000) { - n_div = 12; - n = 4; - } else if (frequency > 296000 && frequency <= 445000) { - n_div = 8; - n = 5; - } else if (frequency > 445000 && frequency <= state->tun_fn_min) { - n_div = 6; - n = 6; - } else if (frequency > state->tun_fn_min && frequency <= 950000) { - n_div = 4; - n = 7; - } else if (frequency > 1450000 && frequency <= 1680000) { - n_div = 2; - n = 0; - } else - return -EINVAL; - - reg = it913x_rd_reg(state, 0xed81); - iqik_m_cal = (u16)reg * n_div; - - if (reg < 0x20) { - if (state->tun_clk_mode == 0) - iqik_m_cal = (iqik_m_cal * 9) >> 5; - else - iqik_m_cal >>= 1; - } else { - iqik_m_cal = 0x40 - iqik_m_cal; - if (state->tun_clk_mode == 0) - iqik_m_cal = ~((iqik_m_cal * 9) >> 5); - else - iqik_m_cal = ~(iqik_m_cal >> 1); - } - - temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv; - freq = temp_f / state->tun_xtal; - tmp = freq * state->tun_xtal; - - if ((temp_f - tmp) >= (state->tun_xtal >> 1)) - freq++; - - freq += (u32) n << 13; - /* Frequency OMEGA_IQIK_M_CAL_MID*/ - temp_f = freq + (u32)iqik_m_cal; - - set_tuner[3].reg[0] = temp_f & 0xff; - set_tuner[4].reg[0] = (temp_f >> 8) & 0xff; - - dev_dbg(&state->i2c_adap->dev, "%s: High Frequency = %04x\n", - __func__, temp_f); - - /* Lower frequency */ - set_tuner[5].reg[0] = freq & 0xff; - set_tuner[6].reg[0] = (freq >> 8) & 0xff; - - dev_dbg(&state->i2c_adap->dev, "%s: low Frequency = %04x\n", - __func__, freq); - - ret = it913x_script_loader(state, set_tuner); - - return (ret < 0) ? -ENODEV : 0; -} - -/* Power sequence */ -/* Power Up Tuner on -> Frontend suspend off -> Tuner clk on */ -/* Power Down Frontend suspend on -> Tuner clk off -> Tuner off */ - -static int it913x_sleep(struct dvb_frontend *fe) -{ - struct it913x_state *state = fe->tuner_priv; - return it913x_script_loader(state, it9137_tuner_off); -} - -static int it913x_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - return 0; -} - -static const struct dvb_tuner_ops it913x_tuner_ops = { - .info = { - .name = "ITE Tech IT913X", - .frequency_min = 174000000, - .frequency_max = 862000000, - }, - - .release = it913x_release, - - .init = it913x_init, - .sleep = it913x_sleep, - .set_params = it9137_set_params, -}; - -struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, u8 i2c_addr, u8 config) -{ - struct it913x_state *state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct it913x_state), GFP_KERNEL); - if (state == NULL) - return NULL; - - state->i2c_adap = i2c_adap; - state->i2c_addr = i2c_addr; - - switch (config) { - case AF9033_TUNER_IT9135_38: - case AF9033_TUNER_IT9135_51: - case AF9033_TUNER_IT9135_52: - state->chip_ver = 0x01; - break; - case AF9033_TUNER_IT9135_60: - case AF9033_TUNER_IT9135_61: - case AF9033_TUNER_IT9135_62: - state->chip_ver = 0x02; - break; - default: - dev_dbg(&i2c_adap->dev, - "%s: invalid config=%02x\n", __func__, config); - goto error; - } - - state->tuner_type = config; - state->firmware_ver = 1; - - fe->tuner_priv = state; - memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops, - sizeof(struct dvb_tuner_ops)); - - dev_info(&i2c_adap->dev, - "%s: ITE Tech IT913X successfully attached\n", - KBUILD_MODNAME); - dev_dbg(&i2c_adap->dev, "%s: config=%02x chip_ver=%02x\n", - __func__, config, state->chip_ver); - - return fe; -error: - kfree(state); - return NULL; -} -EXPORT_SYMBOL(it913x_attach); - -MODULE_DESCRIPTION("ITE Tech IT913X silicon tuner driver"); -MODULE_AUTHOR("Antti Palosaari "); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/it913x.h b/drivers/media/tuners/it913x.h deleted file mode 100644 index 12dd36bd9e79..000000000000 --- a/drivers/media/tuners/it913x.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ITE Tech IT9137 silicon tuner driver - * - * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) - * IT9137 Copyright (C) ITE Tech Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#ifndef IT913X_H -#define IT913X_H - -#include "dvb_frontend.h" - -#if defined(CONFIG_MEDIA_TUNER_IT913X) || \ - (defined(CONFIG_MEDIA_TUNER_IT913X_MODULE) && defined(MODULE)) -extern struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - u8 config); -#else -static inline struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, - struct i2c_adapter *i2c_adap, - u8 i2c_addr, - u8 config) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif - -#endif diff --git a/drivers/media/tuners/it913x_priv.h b/drivers/media/tuners/it913x_priv.h deleted file mode 100644 index 00dcf3c27888..000000000000 --- a/drivers/media/tuners/it913x_priv.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * ITE Tech IT9137 silicon tuner driver - * - * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) - * IT9137 Copyright (C) ITE Tech Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= - */ - -#ifndef IT913X_PRIV_H -#define IT913X_PRIV_H - -#include "it913x.h" -#include "af9033.h" - -#define PRO_LINK 0x0 -#define PRO_DMOD 0x1 -#define TRIGGER_OFSM 0x0000 - -struct it913xset { u32 pro; - u32 address; - u8 reg[15]; - u8 count; -}; - -/* Tuner setting scripts (still keeping it9137) */ -static struct it913xset it9137_tuner_off[] = { - {PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off */ - {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */ - {PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04}, - {PRO_DMOD, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00}, 0x0c}, - {PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04}, - {PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00}, 0x09}, - {PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00}, 0x0a}, - {PRO_DMOD, 0xec20, {0x00}, 0x01}, - {PRO_DMOD, 0xec3f, {0x01}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ -}; - -static struct it913xset set_it9135_template[] = { - {PRO_DMOD, 0xee06, {0x00}, 0x01}, - {PRO_DMOD, 0xec56, {0x00}, 0x01}, - {PRO_DMOD, 0xec4c, {0x00}, 0x01}, - {PRO_DMOD, 0xec4d, {0x00}, 0x01}, - {PRO_DMOD, 0xec4e, {0x00}, 0x01}, - {PRO_DMOD, 0x011e, {0x00}, 0x01}, /* Older Devices */ - {PRO_DMOD, 0x011f, {0x00}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ -}; - -static struct it913xset set_it9137_template[] = { - {PRO_DMOD, 0xee06, {0x00}, 0x01}, - {PRO_DMOD, 0xec56, {0x00}, 0x01}, - {PRO_DMOD, 0xec4c, {0x00}, 0x01}, - {PRO_DMOD, 0xec4d, {0x00}, 0x01}, - {PRO_DMOD, 0xec4e, {0x00}, 0x01}, - {PRO_DMOD, 0xec4f, {0x00}, 0x01}, - {PRO_DMOD, 0xec50, {0x00}, 0x01}, - {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ -}; - -#endif diff --git a/drivers/media/tuners/tuner_it913x.c b/drivers/media/tuners/tuner_it913x.c new file mode 100644 index 000000000000..6f30d7e535b8 --- /dev/null +++ b/drivers/media/tuners/tuner_it913x.c @@ -0,0 +1,447 @@ +/* + * ITE Tech IT9137 silicon tuner driver + * + * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) + * IT9137 Copyright (C) ITE Tech Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#include "tuner_it913x_priv.h" + +struct it913x_state { + struct i2c_adapter *i2c_adap; + u8 i2c_addr; + u8 chip_ver; + u8 tuner_type; + u8 firmware_ver; + u16 tun_xtal; + u8 tun_fdiv; + u8 tun_clk_mode; + u32 tun_fn_min; +}; + +/* read multiple registers */ +static int it913x_rd_regs(struct it913x_state *state, + u32 reg, u8 *data, u8 count) +{ + int ret; + u8 b[3]; + struct i2c_msg msg[2] = { + { .addr = state->i2c_addr, .flags = 0, + .buf = b, .len = sizeof(b) }, + { .addr = state->i2c_addr, .flags = I2C_M_RD, + .buf = data, .len = count } + }; + b[0] = (u8)(reg >> 16) & 0xff; + b[1] = (u8)(reg >> 8) & 0xff; + b[2] = (u8) reg & 0xff; + b[0] |= 0x80; /* All reads from demodulator */ + + ret = i2c_transfer(state->i2c_adap, msg, 2); + + return ret; +} + +/* read single register */ +static int it913x_rd_reg(struct it913x_state *state, u32 reg) +{ + int ret; + u8 b[1]; + ret = it913x_rd_regs(state, reg, &b[0], sizeof(b)); + return (ret < 0) ? -ENODEV : b[0]; +} + +/* write multiple registers */ +static int it913x_wr_regs(struct it913x_state *state, + u8 pro, u32 reg, u8 buf[], u8 count) +{ + u8 b[256]; + struct i2c_msg msg[1] = { + { .addr = state->i2c_addr, .flags = 0, + .buf = b, .len = 3 + count } + }; + int ret; + b[0] = (u8)(reg >> 16) & 0xff; + b[1] = (u8)(reg >> 8) & 0xff; + b[2] = (u8) reg & 0xff; + memcpy(&b[3], buf, count); + + if (pro == PRO_DMOD) + b[0] |= 0x80; + + ret = i2c_transfer(state->i2c_adap, msg, 1); + + if (ret < 0) + return -EIO; + + return 0; +} + +/* write single register */ +static int it913x_wr_reg(struct it913x_state *state, + u8 pro, u32 reg, u32 data) +{ + int ret; + u8 b[4]; + u8 s; + + b[0] = data >> 24; + b[1] = (data >> 16) & 0xff; + b[2] = (data >> 8) & 0xff; + b[3] = data & 0xff; + /* expand write as needed */ + if (data < 0x100) + s = 3; + else if (data < 0x1000) + s = 2; + else if (data < 0x100000) + s = 1; + else + s = 0; + + ret = it913x_wr_regs(state, pro, reg, &b[s], sizeof(b) - s); + + return ret; +} + +static int it913x_script_loader(struct it913x_state *state, + struct it913xset *loadscript) +{ + int ret, i; + if (loadscript == NULL) + return -EINVAL; + + for (i = 0; i < 1000; ++i) { + if (loadscript[i].pro == 0xff) + break; + ret = it913x_wr_regs(state, loadscript[i].pro, + loadscript[i].address, + loadscript[i].reg, loadscript[i].count); + if (ret < 0) + return -ENODEV; + } + return 0; +} + +static int it913x_init(struct dvb_frontend *fe) +{ + struct it913x_state *state = fe->tuner_priv; + int ret, i, reg; + u8 val, nv_val; + u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2}; + u8 b[2]; + + reg = it913x_rd_reg(state, 0xec86); + switch (reg) { + case 0: + state->tun_clk_mode = reg; + state->tun_xtal = 2000; + state->tun_fdiv = 3; + val = 16; + break; + case -ENODEV: + return -ENODEV; + case 1: + default: + state->tun_clk_mode = reg; + state->tun_xtal = 640; + state->tun_fdiv = 1; + val = 6; + break; + } + + reg = it913x_rd_reg(state, 0xed03); + + if (reg < 0) + return -ENODEV; + else if (reg < ARRAY_SIZE(nv)) + nv_val = nv[reg]; + else + nv_val = 2; + + for (i = 0; i < 50; i++) { + ret = it913x_rd_regs(state, 0xed23, &b[0], sizeof(b)); + reg = (b[1] << 8) + b[0]; + if (reg > 0) + break; + if (ret < 0) + return -ENODEV; + udelay(2000); + } + state->tun_fn_min = state->tun_xtal * reg; + state->tun_fn_min /= (state->tun_fdiv * nv_val); + dev_dbg(&state->i2c_adap->dev, "%s: Tuner fn_min %d\n", __func__, + state->tun_fn_min); + + if (state->chip_ver > 1) + msleep(50); + else { + for (i = 0; i < 50; i++) { + reg = it913x_rd_reg(state, 0xec82); + if (reg > 0) + break; + if (reg < 0) + return -ENODEV; + udelay(2000); + } + } + + /* Power Up Tuner - common all versions */ + ret = it913x_wr_reg(state, PRO_DMOD, 0xec40, 0x1); + ret |= it913x_wr_reg(state, PRO_DMOD, 0xfba8, 0x0); + ret |= it913x_wr_reg(state, PRO_DMOD, 0xec57, 0x0); + ret |= it913x_wr_reg(state, PRO_DMOD, 0xec58, 0x0); + + return it913x_wr_reg(state, PRO_DMOD, 0xed81, val); +} + +static int it9137_set_params(struct dvb_frontend *fe) +{ + struct it913x_state *state = fe->tuner_priv; + struct it913xset *set_tuner = set_it9137_template; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 bandwidth = p->bandwidth_hz; + u32 frequency_m = p->frequency; + int ret, reg; + u32 frequency = frequency_m / 1000; + u32 freq, temp_f, tmp; + u16 iqik_m_cal; + u16 n_div; + u8 n; + u8 l_band; + u8 lna_band; + u8 bw; + + if (state->firmware_ver == 1) + set_tuner = set_it9135_template; + else + set_tuner = set_it9137_template; + + dev_dbg(&state->i2c_adap->dev, "%s: Tuner Frequency %d Bandwidth %d\n", + __func__, frequency, bandwidth); + + if (frequency >= 51000 && frequency <= 440000) { + l_band = 0; + lna_band = 0; + } else if (frequency > 440000 && frequency <= 484000) { + l_band = 1; + lna_band = 1; + } else if (frequency > 484000 && frequency <= 533000) { + l_band = 1; + lna_band = 2; + } else if (frequency > 533000 && frequency <= 587000) { + l_band = 1; + lna_band = 3; + } else if (frequency > 587000 && frequency <= 645000) { + l_band = 1; + lna_band = 4; + } else if (frequency > 645000 && frequency <= 710000) { + l_band = 1; + lna_band = 5; + } else if (frequency > 710000 && frequency <= 782000) { + l_band = 1; + lna_band = 6; + } else if (frequency > 782000 && frequency <= 860000) { + l_band = 1; + lna_band = 7; + } else if (frequency > 1450000 && frequency <= 1492000) { + l_band = 1; + lna_band = 0; + } else if (frequency > 1660000 && frequency <= 1685000) { + l_band = 1; + lna_band = 1; + } else + return -EINVAL; + set_tuner[0].reg[0] = lna_band; + + switch (bandwidth) { + case 5000000: + bw = 0; + break; + case 6000000: + bw = 2; + break; + case 7000000: + bw = 4; + break; + default: + case 8000000: + bw = 6; + break; + } + + set_tuner[1].reg[0] = bw; + set_tuner[2].reg[0] = 0xa0 | (l_band << 3); + + if (frequency > 53000 && frequency <= 74000) { + n_div = 48; + n = 0; + } else if (frequency > 74000 && frequency <= 111000) { + n_div = 32; + n = 1; + } else if (frequency > 111000 && frequency <= 148000) { + n_div = 24; + n = 2; + } else if (frequency > 148000 && frequency <= 222000) { + n_div = 16; + n = 3; + } else if (frequency > 222000 && frequency <= 296000) { + n_div = 12; + n = 4; + } else if (frequency > 296000 && frequency <= 445000) { + n_div = 8; + n = 5; + } else if (frequency > 445000 && frequency <= state->tun_fn_min) { + n_div = 6; + n = 6; + } else if (frequency > state->tun_fn_min && frequency <= 950000) { + n_div = 4; + n = 7; + } else if (frequency > 1450000 && frequency <= 1680000) { + n_div = 2; + n = 0; + } else + return -EINVAL; + + reg = it913x_rd_reg(state, 0xed81); + iqik_m_cal = (u16)reg * n_div; + + if (reg < 0x20) { + if (state->tun_clk_mode == 0) + iqik_m_cal = (iqik_m_cal * 9) >> 5; + else + iqik_m_cal >>= 1; + } else { + iqik_m_cal = 0x40 - iqik_m_cal; + if (state->tun_clk_mode == 0) + iqik_m_cal = ~((iqik_m_cal * 9) >> 5); + else + iqik_m_cal = ~(iqik_m_cal >> 1); + } + + temp_f = frequency * (u32)n_div * (u32)state->tun_fdiv; + freq = temp_f / state->tun_xtal; + tmp = freq * state->tun_xtal; + + if ((temp_f - tmp) >= (state->tun_xtal >> 1)) + freq++; + + freq += (u32) n << 13; + /* Frequency OMEGA_IQIK_M_CAL_MID*/ + temp_f = freq + (u32)iqik_m_cal; + + set_tuner[3].reg[0] = temp_f & 0xff; + set_tuner[4].reg[0] = (temp_f >> 8) & 0xff; + + dev_dbg(&state->i2c_adap->dev, "%s: High Frequency = %04x\n", + __func__, temp_f); + + /* Lower frequency */ + set_tuner[5].reg[0] = freq & 0xff; + set_tuner[6].reg[0] = (freq >> 8) & 0xff; + + dev_dbg(&state->i2c_adap->dev, "%s: low Frequency = %04x\n", + __func__, freq); + + ret = it913x_script_loader(state, set_tuner); + + return (ret < 0) ? -ENODEV : 0; +} + +/* Power sequence */ +/* Power Up Tuner on -> Frontend suspend off -> Tuner clk on */ +/* Power Down Frontend suspend on -> Tuner clk off -> Tuner off */ + +static int it913x_sleep(struct dvb_frontend *fe) +{ + struct it913x_state *state = fe->tuner_priv; + return it913x_script_loader(state, it9137_tuner_off); +} + +static int it913x_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + return 0; +} + +static const struct dvb_tuner_ops it913x_tuner_ops = { + .info = { + .name = "ITE Tech IT913X", + .frequency_min = 174000000, + .frequency_max = 862000000, + }, + + .release = it913x_release, + + .init = it913x_init, + .sleep = it913x_sleep, + .set_params = it9137_set_params, +}; + +struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, u8 i2c_addr, u8 config) +{ + struct it913x_state *state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct it913x_state), GFP_KERNEL); + if (state == NULL) + return NULL; + + state->i2c_adap = i2c_adap; + state->i2c_addr = i2c_addr; + + switch (config) { + case AF9033_TUNER_IT9135_38: + case AF9033_TUNER_IT9135_51: + case AF9033_TUNER_IT9135_52: + state->chip_ver = 0x01; + break; + case AF9033_TUNER_IT9135_60: + case AF9033_TUNER_IT9135_61: + case AF9033_TUNER_IT9135_62: + state->chip_ver = 0x02; + break; + default: + dev_dbg(&i2c_adap->dev, + "%s: invalid config=%02x\n", __func__, config); + goto error; + } + + state->tuner_type = config; + state->firmware_ver = 1; + + fe->tuner_priv = state; + memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + dev_info(&i2c_adap->dev, + "%s: ITE Tech IT913X successfully attached\n", + KBUILD_MODNAME); + dev_dbg(&i2c_adap->dev, "%s: config=%02x chip_ver=%02x\n", + __func__, config, state->chip_ver); + + return fe; +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(it913x_attach); + +MODULE_DESCRIPTION("ITE Tech IT913X silicon tuner driver"); +MODULE_AUTHOR("Antti Palosaari "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/tuner_it913x.h b/drivers/media/tuners/tuner_it913x.h new file mode 100644 index 000000000000..12dd36bd9e79 --- /dev/null +++ b/drivers/media/tuners/tuner_it913x.h @@ -0,0 +1,45 @@ +/* + * ITE Tech IT9137 silicon tuner driver + * + * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) + * IT9137 Copyright (C) ITE Tech Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef IT913X_H +#define IT913X_H + +#include "dvb_frontend.h" + +#if defined(CONFIG_MEDIA_TUNER_IT913X) || \ + (defined(CONFIG_MEDIA_TUNER_IT913X_MODULE) && defined(MODULE)) +extern struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + u8 config); +#else +static inline struct dvb_frontend *it913x_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c_adap, + u8 i2c_addr, + u8 config) +{ + pr_warn("%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif diff --git a/drivers/media/tuners/tuner_it913x_priv.h b/drivers/media/tuners/tuner_it913x_priv.h new file mode 100644 index 000000000000..ce652108aa5d --- /dev/null +++ b/drivers/media/tuners/tuner_it913x_priv.h @@ -0,0 +1,78 @@ +/* + * ITE Tech IT9137 silicon tuner driver + * + * Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com) + * IT9137 Copyright (C) ITE Tech Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.= + */ + +#ifndef IT913X_PRIV_H +#define IT913X_PRIV_H + +#include "tuner_it913x.h" +#include "af9033.h" + +#define PRO_LINK 0x0 +#define PRO_DMOD 0x1 +#define TRIGGER_OFSM 0x0000 + +struct it913xset { u32 pro; + u32 address; + u8 reg[15]; + u8 count; +}; + +/* Tuner setting scripts (still keeping it9137) */ +static struct it913xset it9137_tuner_off[] = { + {PRO_DMOD, 0xfba8, {0x01}, 0x01}, /* Tuner Clock Off */ + {PRO_DMOD, 0xec40, {0x00}, 0x01}, /* Power Down Tuner */ + {PRO_DMOD, 0xec02, {0x3f, 0x1f, 0x3f, 0x3f}, 0x04}, + {PRO_DMOD, 0xec06, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00}, 0x0c}, + {PRO_DMOD, 0xec12, {0x00, 0x00, 0x00, 0x00}, 0x04}, + {PRO_DMOD, 0xec17, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00}, 0x09}, + {PRO_DMOD, 0xec22, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00}, 0x0a}, + {PRO_DMOD, 0xec20, {0x00}, 0x01}, + {PRO_DMOD, 0xec3f, {0x01}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; + +static struct it913xset set_it9135_template[] = { + {PRO_DMOD, 0xee06, {0x00}, 0x01}, + {PRO_DMOD, 0xec56, {0x00}, 0x01}, + {PRO_DMOD, 0xec4c, {0x00}, 0x01}, + {PRO_DMOD, 0xec4d, {0x00}, 0x01}, + {PRO_DMOD, 0xec4e, {0x00}, 0x01}, + {PRO_DMOD, 0x011e, {0x00}, 0x01}, /* Older Devices */ + {PRO_DMOD, 0x011f, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; + +static struct it913xset set_it9137_template[] = { + {PRO_DMOD, 0xee06, {0x00}, 0x01}, + {PRO_DMOD, 0xec56, {0x00}, 0x01}, + {PRO_DMOD, 0xec4c, {0x00}, 0x01}, + {PRO_DMOD, 0xec4d, {0x00}, 0x01}, + {PRO_DMOD, 0xec4e, {0x00}, 0x01}, + {PRO_DMOD, 0xec4f, {0x00}, 0x01}, + {PRO_DMOD, 0xec50, {0x00}, 0x01}, + {0xff, 0x0000, {0x00}, 0x00}, /* Terminating Entry */ +}; + +#endif diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index 0f42b6cb3708..b5827ca3a01e 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -30,7 +30,7 @@ #include "mxl5007t.h" #include "tda18218.h" #include "fc2580.h" -#include "it913x.h" +#include "tuner_it913x.h" struct reg_val { u32 reg; -- cgit v1.2.3 From 098af4bde09792314ff106f545c405ffc5942c25 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 16 Apr 2013 19:56:05 -0300 Subject: [media] sta2x11_vip: Fix compilation if I2C is not set From Fengguang Wu : > drivers/media/pci/sta2x11/sta2x11_vip.c: In function 'sta2x11_vip_init_one': > drivers/media/pci/sta2x11/sta2x11_vip.c:1314:2: error: implicit declaration of function 'i2c_get_adapter' [-Werror=implicit-function-declaration] > drivers/media/pci/sta2x11/sta2x11_vip.c:1314:15: warning: assignment makes pointer from integer without a cast [enabled by default] > drivers/media/pci/sta2x11/sta2x11_vip.c:1330:2: error: implicit declaration of function 'i2c_put_adapter' [-Werror=implicit-function-declaration] And also: > warning: (STA2X11_VIP) selects VIDEO_ADV7180 which has unmet direct dependencies (MEDIA_SUPPORT && VIDEO_V4L2 && I2C) > drivers/media/i2c/adv7180.c: In function '__adv7180_status': > drivers/media/i2c/adv7180.c:194:2: error: implicit declaration of function 'i2c_smbus_read_byte_data' [-Werror=implicit-function-declaration] > drivers/media/i2c/adv7180.c: In function 'adv7180_s_routing': > drivers/media/i2c/adv7180.c:251:2: error: implicit declaration of function 'i2c_smbus_write_byte_data' [-Werror=implicit-function-declaration] > drivers/media/i2c/adv7180.c: In function 'adv7180_probe': > drivers/media/i2c/adv7180.c:551:2: error: implicit declaration of function 'i2c_check_functionality' [-Werror=implicit-function-declaration] > drivers/media/i2c/adv7180.c:554:2: error: implicit declaration of function 'i2c_adapter_id' [-Werror=implicit-function-declaration] > drivers/media/i2c/adv7180.c: At top level: > drivers/media/i2c/adv7180.c:663:1: warning: data definition has no type or storage class [enabled by default] > drivers/media/i2c/adv7180.c:663:1: warning: type defaults to 'int' in declaration of 'module_i2c_driver' [-Wimplicit-int] > drivers/media/i2c/adv7180.c:663:1: warning: parameter names (without types) in function declaration [enabled by default] > drivers/media/i2c/adv7180.c:649:26: warning: 'adv7180_driver' defined but not used [-Wunused-variable] This is due to the lack of I2C support: ... > CONFIG_I2C is not set ... So, Make sure that sta2x11_vip depends on I2C. Reported-by: Fengguang Wu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/sta2x11/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig index a94ccad02066..03130157db83 100644 --- a/drivers/media/pci/sta2x11/Kconfig +++ b/drivers/media/pci/sta2x11/Kconfig @@ -4,6 +4,7 @@ config STA2X11_VIP select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT select VIDEOBUF2_DMA_CONTIG depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS + depends on I2C help Say Y for support for STA2X11 VIP (Video Input Port) capture device. -- cgit v1.2.3 From a80abc58feda48f868d748bde8c88592c2892b1d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 5 Apr 2013 14:35:18 -0300 Subject: [media] r820t: Add a tuner driver for Rafael Micro R820T silicon tuner This driver was written from scratch, based on an existing driver that it is part of rtl-sdr git tree, released under GPLv2: https://groups.google.com/forum/#!topic/ultra-cheap-sdr/Y3rBEOFtHug https://github.com/n1gp/gr-baz http://cgit.osmocom.org/rtl-sdr/plain/src/tuner_r820t.c (there are also other variants of it out there) >From what I understood from the threads, the original driver was converted to userspace from a Realtek tree. I couldn't find the original tree. However, the original driver look awkward on my eyes. So, I decided to write a new version from it from the scratch, while trying to reproduce everything found there. TODO: - After locking, the original driver seems to have some routines to improve reception. This was not implemented here yet. - RF Gain set/get is not implemented. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/Kconfig | 7 + drivers/media/tuners/Makefile | 1 + drivers/media/tuners/r820t.c | 1486 +++++++++++++++++++++++++++++++++++++++++ drivers/media/tuners/r820t.h | 55 ++ 4 files changed, 1549 insertions(+) create mode 100644 drivers/media/tuners/r820t.c create mode 100644 drivers/media/tuners/r820t.h (limited to 'drivers/media') diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index ffabd66dd14d..f6768cad001a 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -248,4 +248,11 @@ config MEDIA_TUNER_IT913X default m if !MEDIA_SUBDRV_AUTOSELECT help ITE Tech IT913x silicon tuner driver. + +config MEDIA_TUNER_R820T + tristate "Rafael Micro R820T silicon tuner" + depends on MEDIA_SUPPORT && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + Rafael Micro R820T silicon tuner driver. endmenu diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile index 2ebe4b725b51..308f108eadba 100644 --- a/drivers/media/tuners/Makefile +++ b/drivers/media/tuners/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o obj-$(CONFIG_MEDIA_TUNER_IT913X) += tuner_it913x.o +obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c new file mode 100644 index 000000000000..7e02920f385a --- /dev/null +++ b/drivers/media/tuners/r820t.c @@ -0,0 +1,1486 @@ +/* + * Rafael Micro R820T driver + * + * Copyright (C) 2013 Mauro Carvalho Chehab + * + * This driver was written from scratch, based on an existing driver + * that it is part of rtl-sdr git tree, released under GPLv2: + * https://groups.google.com/forum/#!topic/ultra-cheap-sdr/Y3rBEOFtHug + * https://github.com/n1gp/gr-baz + * + * From what I understood from the threads, the original driver was converted + * to userspace from a Realtek tree. I couldn't find the original tree. + * However, the original driver look awkward on my eyes. So, I decided to + * write a new version from it from the scratch, while trying to reproduce + * everything found there. + * + * TODO: + * After locking, the original driver seems to have some routines to + * improve reception. This was not implemented here yet. + * + * RF Gain set/get is not implemented. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include "tuner-i2c.h" +#include +#include "r820t.h" + +/* + * FIXME: I think that there are only 32 registers, but better safe than + * sorry. After finishing the driver, we may review it. + */ +#define REG_SHADOW_START 5 +#define NUM_REGS 27 + +#define VER_NUM 49 + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +/* + * enums and structures + */ + +enum xtal_cap_value { + XTAL_LOW_CAP_30P = 0, + XTAL_LOW_CAP_20P, + XTAL_LOW_CAP_10P, + XTAL_LOW_CAP_0P, + XTAL_HIGH_CAP_0P +}; + +struct r820t_priv { + struct list_head hybrid_tuner_instance_list; + const struct r820t_config *cfg; + struct tuner_i2c_props i2c_props; + struct mutex lock; + + u8 regs[NUM_REGS]; + u8 buf[NUM_REGS + 1]; + enum xtal_cap_value xtal_cap_sel; + u16 pll; /* kHz */ + u32 int_freq; + u8 fil_cal_code; + bool imr_done; + + /* Store current mode */ + u32 delsys; + enum v4l2_tuner_type type; + v4l2_std_id std; + u32 bw; /* in MHz */ + + bool has_lock; +}; + +struct r820t_freq_range { + u32 freq; + u8 open_d; + u8 rf_mux_ploy; + u8 tf_c; + u8 xtal_cap20p; + u8 xtal_cap10p; + u8 xtal_cap0p; + u8 imr_mem; /* Not used, currently */ +}; + +#define VCO_POWER_REF 0x02 + +/* + * Static constants + */ + +static LIST_HEAD(hybrid_tuner_instance_list); +static DEFINE_MUTEX(r820t_list_mutex); + +/* Those initial values start from REG_SHADOW_START */ +static const u8 r820t_init_array[NUM_REGS] = { + 0x83, 0x32, 0x75, /* 05 to 07 */ + 0xc0, 0x40, 0xd6, 0x6c, /* 08 to 0b */ + 0xf5, 0x63, 0x75, 0x68, /* 0c to 0f */ + 0x6c, 0x83, 0x80, 0x00, /* 10 to 13 */ + 0x0f, 0x00, 0xc0, 0x30, /* 14 to 17 */ + 0x48, 0xcc, 0x60, 0x00, /* 18 to 1b */ + 0x54, 0xae, 0x4a, 0xc0 /* 1c to 1f */ +}; + +/* Tuner frequency ranges */ +static const struct r820t_freq_range freq_ranges[] = { + { + .freq = 0, + .open_d = 0x08, /* low */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0xdf, /* R27[7:0] band2,band0 */ + .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ + .xtal_cap10p = 0x01, + .xtal_cap0p = 0x00, + .imr_mem = 0, + }, { + .freq = 50, /* Start freq, in MHz */ + .open_d = 0x08, /* low */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0xbe, /* R27[7:0] band4,band1 */ + .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ + .xtal_cap10p = 0x01, + .xtal_cap0p = 0x00, + .imr_mem = 0, + }, { + .freq = 55, /* Start freq, in MHz */ + .open_d = 0x08, /* low */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x8b, /* R27[7:0] band7,band4 */ + .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ + .xtal_cap10p = 0x01, + .xtal_cap0p = 0x00, + .imr_mem = 0, + }, { + .freq = 60, /* Start freq, in MHz */ + .open_d = 0x08, /* low */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x7b, /* R27[7:0] band8,band4 */ + .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ + .xtal_cap10p = 0x01, + .xtal_cap0p = 0x00, + .imr_mem = 0, + }, { + .freq = 65, /* Start freq, in MHz */ + .open_d = 0x08, /* low */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x69, /* R27[7:0] band9,band6 */ + .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ + .xtal_cap10p = 0x01, + .xtal_cap0p = 0x00, + .imr_mem = 0, + }, { + .freq = 70, /* Start freq, in MHz */ + .open_d = 0x08, /* low */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x58, /* R27[7:0] band10,band7 */ + .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ + .xtal_cap10p = 0x01, + .xtal_cap0p = 0x00, + .imr_mem = 0, + }, { + .freq = 75, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x44, /* R27[7:0] band11,band11 */ + .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ + .xtal_cap10p = 0x01, + .xtal_cap0p = 0x00, + .imr_mem = 0, + }, { + .freq = 80, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x44, /* R27[7:0] band11,band11 */ + .xtal_cap20p = 0x02, /* R16[1:0] 20pF (10) */ + .xtal_cap10p = 0x01, + .xtal_cap0p = 0x00, + .imr_mem = 0, + }, { + .freq = 90, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x34, /* R27[7:0] band12,band11 */ + .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */ + .xtal_cap10p = 0x01, + .xtal_cap0p = 0x00, + .imr_mem = 0, + }, { + .freq = 100, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x34, /* R27[7:0] band12,band11 */ + .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */ + .xtal_cap10p = 0x01, + .xtal_cap0p = 0x00, + .imr_mem = 0, + }, { + .freq = 110, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x24, /* R27[7:0] band13,band11 */ + .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */ + .xtal_cap10p = 0x01, + .xtal_cap0p = 0x00, + .imr_mem = 1, + }, { + .freq = 120, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x24, /* R27[7:0] band13,band11 */ + .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */ + .xtal_cap10p = 0x01, + .xtal_cap0p = 0x00, + .imr_mem = 1, + }, { + .freq = 140, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x14, /* R27[7:0] band14,band11 */ + .xtal_cap20p = 0x01, /* R16[1:0] 10pF (01) */ + .xtal_cap10p = 0x01, + .xtal_cap0p = 0x00, + .imr_mem = 1, + }, { + .freq = 180, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x13, /* R27[7:0] band14,band12 */ + .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ + .xtal_cap10p = 0x00, + .xtal_cap0p = 0x00, + .imr_mem = 1, + }, { + .freq = 220, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x13, /* R27[7:0] band14,band12 */ + .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ + .xtal_cap10p = 0x00, + .xtal_cap0p = 0x00, + .imr_mem = 2, + }, { + .freq = 250, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x11, /* R27[7:0] highest,highest */ + .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ + .xtal_cap10p = 0x00, + .xtal_cap0p = 0x00, + .imr_mem = 2, + }, { + .freq = 280, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x02, /* R26[7:6]=0 (LPF) R26[1:0]=2 (low) */ + .tf_c = 0x00, /* R27[7:0] highest,highest */ + .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ + .xtal_cap10p = 0x00, + .xtal_cap0p = 0x00, + .imr_mem = 2, + }, { + .freq = 310, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x41, /* R26[7:6]=1 (bypass) R26[1:0]=1 (middle) */ + .tf_c = 0x00, /* R27[7:0] highest,highest */ + .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ + .xtal_cap10p = 0x00, + .xtal_cap0p = 0x00, + .imr_mem = 2, + }, { + .freq = 450, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x41, /* R26[7:6]=1 (bypass) R26[1:0]=1 (middle) */ + .tf_c = 0x00, /* R27[7:0] highest,highest */ + .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ + .xtal_cap10p = 0x00, + .xtal_cap0p = 0x00, + .imr_mem = 3, + }, { + .freq = 588, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x40, /* R26[7:6]=1 (bypass) R26[1:0]=0 (highest) */ + .tf_c = 0x00, /* R27[7:0] highest,highest */ + .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ + .xtal_cap10p = 0x00, + .xtal_cap0p = 0x00, + .imr_mem = 3, + }, { + .freq = 650, /* Start freq, in MHz */ + .open_d = 0x00, /* high */ + .rf_mux_ploy = 0x40, /* R26[7:6]=1 (bypass) R26[1:0]=0 (highest) */ + .tf_c = 0x00, /* R27[7:0] highest,highest */ + .xtal_cap20p = 0x00, /* R16[1:0] 0pF (00) */ + .xtal_cap10p = 0x00, + .xtal_cap0p = 0x00, + .imr_mem = 4, + } +}; + +static int r820t_xtal_capacitor[][2] = { + { 0x0b, XTAL_LOW_CAP_30P }, + { 0x02, XTAL_LOW_CAP_20P }, + { 0x01, XTAL_LOW_CAP_10P }, + { 0x00, XTAL_LOW_CAP_0P }, + { 0x10, XTAL_HIGH_CAP_0P }, +}; + +/* + * I2C read/write code and shadow registers logic + */ +static void shadow_store(struct r820t_priv *priv, u8 reg, const u8 *val, + int len) +{ + int r = reg - REG_SHADOW_START; + + if (r < 0) { + len += r; + r = 0; + } + if (len <= 0) + return; + if (len > NUM_REGS) + len = NUM_REGS; + + tuner_dbg("%s: prev reg=%02x len=%d: %*ph\n", + __func__, r + REG_SHADOW_START, len, len, val); + + memcpy(&priv->regs[r], val, len); +} + +static int r820t_write(struct r820t_priv *priv, u8 reg, const u8 *val, + int len) +{ + int rc, size, pos = 0; + + /* Store the shadow registers */ + shadow_store(priv, reg, val, len); + + do { + if (len > priv->cfg->max_i2c_msg_len - 1) + size = priv->cfg->max_i2c_msg_len - 1; + else + size = len; + + /* Fill I2C buffer */ + priv->buf[0] = reg; + memcpy(&priv->buf[1], &val[pos], size); + + rc = tuner_i2c_xfer_send(&priv->i2c_props, priv->buf, size + 1); + if (rc != size + 1) { + tuner_info("%s: i2c wr failed=%d reg=%02x len=%d: %*ph\n", + __func__, rc, reg, size, size, &priv->buf[1]); + if (rc < 0) + return rc; + return -EREMOTEIO; + } + tuner_dbg("%s: i2c wr reg=%02x len=%d: %*ph\n", + __func__, reg, size, size, &priv->buf[1]); + + reg += size; + len -= size; + pos += size; + } while (len > 0); + + return 0; +} + +static int r820t_write_reg(struct r820t_priv *priv, u8 reg, u8 val) +{ + return r820t_write(priv, reg, &val, 1); +} + +static int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val, + u8 bit_mask) +{ + int r = reg - REG_SHADOW_START; + + if (r >= 0 && r < NUM_REGS) + val = (priv->regs[r] & ~bit_mask) | (val & bit_mask); + else + return -EINVAL; + + return r820t_write(priv, reg, &val, 1); +} + +static int r820_read(struct r820t_priv *priv, u8 reg, u8 *val, int len) +{ + int rc; + u8 *p = &priv->buf[1]; + + priv->buf[0] = reg; + + rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, priv->buf, 1, p, len); + if (rc != len) { + tuner_info("%s: i2c rd failed=%d reg=%02x len=%d: %*ph\n", + __func__, rc, reg, len, len, p); + if (rc < 0) + return rc; + return -EREMOTEIO; + } + tuner_dbg("%s: i2c rd reg=%02x len=%d: %*ph\n", + __func__, reg, len, len, p); + + /* Copy data to the output buffer */ + memcpy(val, p, len); + + return 0; +} + +/* + * r820t tuning logic + */ + +static int r820t_set_mux(struct r820t_priv *priv, u32 freq) +{ + const struct r820t_freq_range *range; + int i, rc; + u8 val; + + /* Get the proper frequency range */ + freq = freq / 1000000; + for (i = 0; i < ARRAY_SIZE(freq_ranges) - 1; i++) { + if (freq < freq_ranges[i + 1].freq) + break; + } + range = &freq_ranges[i]; + + tuner_dbg("set r820t range#%d for frequency %d MHz\n", i, freq); + + /* Open Drain */ + rc = r820t_write_reg_mask(priv, 0x17, range->open_d, 0x08); + if (rc < 0) + return rc; + + /* RF_MUX,Polymux */ + rc = r820t_write_reg_mask(priv, 0x1a, range->rf_mux_ploy, 0xc3); + if (rc < 0) + return rc; + + /* TF BAND */ + rc = r820t_write_reg(priv, 0x1b, range->tf_c); + if (rc < 0) + return rc; + + /* XTAL CAP & Drive */ + switch (priv->xtal_cap_sel) { + case XTAL_LOW_CAP_30P: + case XTAL_LOW_CAP_20P: + val = range->xtal_cap20p | 0x08; + break; + case XTAL_LOW_CAP_10P: + val = range->xtal_cap10p | 0x08; + break; + case XTAL_HIGH_CAP_0P: + val = range->xtal_cap0p | 0x00; + break; + default: + case XTAL_LOW_CAP_0P: + val = range->xtal_cap0p | 0x08; + break; + } + rc = r820t_write_reg_mask(priv, 0x10, val, 0x0b); + if (rc < 0) + return rc; + + /* + * FIXME: the original driver has a logic there with preserves + * gain/phase from registers 8 and 9 reading the data from the + * registers before writing, if "IMF done". That code was sort of + * commented there, as the flag is always false. + */ + rc = r820t_write_reg_mask(priv, 0x08, 0, 0x3f); + if (rc < 0) + return rc; + + rc = r820t_write_reg_mask(priv, 0x09, 0, 0x3f); + + return rc; +} + +static int r820t_set_pll(struct r820t_priv *priv, u32 freq) +{ + u64 tmp64, vco_freq; + int rc, i; + u32 vco_fra; /* VCO contribution by SDM (kHz) */ + u32 vco_min = 1770000; + u32 vco_max = vco_min * 2; + u32 pll_ref; + u16 n_sdm = 2; + u16 sdm = 0; + u8 mix_div = 2; + u8 div_buf = 0; + u8 div_num = 0; + u8 ni, si, nint, vco_fine_tune, val; + u8 data[5]; + + freq = freq / 1000; /* Frequency in kHz */ + + pll_ref = priv->cfg->xtal / 1000; + + tuner_dbg("set r820t pll for frequency %d kHz = %d\n", freq, pll_ref); + + /* FIXME: this seems to be a hack - probably it can be removed */ + rc = r820t_write_reg_mask(priv, 0x10, 0x00, 0x00); + if (rc < 0) + return rc; + + /* set pll autotune = 128kHz */ + rc = r820t_write_reg_mask(priv, 0x1a, 0x00, 0x0c); + if (rc < 0) + return rc; + + /* set VCO current = 100 */ + rc = r820t_write_reg_mask(priv, 0x12, 0x80, 0xe0); + if (rc < 0) + return rc; + + /* Calculate divider */ + while (mix_div <= 64) { + if (((freq * mix_div) >= vco_min) && + ((freq * mix_div) < vco_max)) { + div_buf = mix_div; + while (div_buf > 2) { + div_buf = div_buf >> 1; + div_num++; + } + break; + } + mix_div = mix_div << 1; + } + + rc = r820_read(priv, 0x00, data, sizeof(data)); + if (rc < 0) + return rc; + + vco_fine_tune = (data[4] & 0x30) >> 4; + + if (vco_fine_tune > VCO_POWER_REF) + div_num = div_num - 1; + else if (vco_fine_tune < VCO_POWER_REF) + div_num = div_num + 1; + + rc = r820t_write_reg_mask(priv, 0x10, div_num << 5, 0xe0); + if (rc < 0) + return rc; + + vco_freq = (u64)(freq * (u64)mix_div); + + tmp64 = vco_freq; + do_div(tmp64, 2 * pll_ref); + nint = (u8)tmp64; + + tmp64 = vco_freq - ((u64)2) * pll_ref * nint; + do_div(tmp64, 1000); + vco_fra = (u16)(tmp64); + + pll_ref /= 1000; + + /* boundary spur prevention */ + if (vco_fra < pll_ref / 64) { + vco_fra = 0; + } else if (vco_fra > pll_ref * 127 / 64) { + vco_fra = 0; + nint++; + } else if ((vco_fra > pll_ref * 127 / 128) && (vco_fra < pll_ref)) { + vco_fra = pll_ref * 127 / 128; + } else if ((vco_fra > pll_ref) && (vco_fra < pll_ref * 129 / 128)) { + vco_fra = pll_ref * 129 / 128; + } + + if (nint > 63) { + tuner_info("No valid PLL values for %u kHz!\n", freq); + return -EINVAL; + } + + ni = (nint - 13) / 4; + si = nint - 4 * ni - 13; + + rc = r820t_write_reg(priv, 0x14, ni + (si << 6)); + if (rc < 0) + return rc; + + /* pw_sdm */ + if (!vco_fra) + val = 0x08; + else + val = 0x00; + + rc = r820t_write_reg_mask(priv, 0x12, val, 0x08); + if (rc < 0) + return rc; + + /* sdm calculator */ + while (vco_fra > 1) { + if (vco_fra > (2 * pll_ref / n_sdm)) { + sdm = sdm + 32768 / (n_sdm / 2); + vco_fra = vco_fra - 2 * pll_ref / n_sdm; + if (n_sdm >= 0x8000) + break; + } + n_sdm = n_sdm << 1; + } + + rc = r820t_write_reg_mask(priv, 0x16, sdm >> 8, 0x08); + if (rc < 0) + return rc; + rc = r820t_write_reg_mask(priv, 0x15, sdm & 0xff, 0x08); + if (rc < 0) + return rc; + + for (i = 0; i < 2; i++) { + /* + * FIXME: Rafael chips R620D, R828D and R828 seems to + * need 20 ms for analog TV + */ + msleep(10); + + /* Check if PLL has locked */ + rc = r820_read(priv, 0x00, data, 3); + if (rc < 0) + return rc; + if (data[2] & 0x40) + break; + + if (!i) { + /* Didn't lock. Increase VCO current */ + rc = r820t_write_reg_mask(priv, 0x12, 0x60, 0xe0); + if (rc < 0) + return rc; + } + } + + if (!(data[2] & 0x40)) { + priv->has_lock = false; + return 0; + } + + priv->has_lock = true; + tuner_dbg("tuner has lock at frequency %d kHz\n", freq); + + /* set pll autotune = 8kHz */ + rc = r820t_write_reg_mask(priv, 0x1a, 0x08, 0x08); + + return rc; +} + +static int r820t_sysfreq_sel(struct r820t_priv *priv, u32 freq, + enum v4l2_tuner_type type, + v4l2_std_id std, + u32 delsys) +{ + int rc; + u8 mixer_top, lna_top, cp_cur, div_buf_cur, lna_vth_l, mixer_vth_l; + u8 air_cable1_in, cable2_in, pre_dect, lna_discharge, filter_cur; + + tuner_dbg("adjusting tuner parameters for the standard\n"); + + switch (delsys) { + case SYS_DVBT: + if ((freq == 506000000) || (freq == 666000000) || + (freq == 818000000)) { + mixer_top = 0x14; /* mixer top:14 , top-1, low-discharge */ + lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ + cp_cur = 0x28; /* 101, 0.2 */ + div_buf_cur = 0x20; /* 10, 200u */ + } else { + mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */ + lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ + cp_cur = 0x38; /* 111, auto */ + div_buf_cur = 0x30; /* 11, 150u */ + } + lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */ + mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */ + air_cable1_in = 0x00; + cable2_in = 0x00; + pre_dect = 0x40; + lna_discharge = 14; + filter_cur = 0x40; /* 10, low */ + break; + case SYS_DVBT2: + mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */ + lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ + lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */ + mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */ + air_cable1_in = 0x00; + cable2_in = 0x00; + pre_dect = 0x40; + lna_discharge = 14; + cp_cur = 0x38; /* 111, auto */ + div_buf_cur = 0x30; /* 11, 150u */ + filter_cur = 0x40; /* 10, low */ + break; + case SYS_ISDBT: + mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */ + lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ + lna_vth_l = 0x75; /* lna vth 1.04 , vtl 0.84 */ + mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */ + air_cable1_in = 0x00; + cable2_in = 0x00; + pre_dect = 0x40; + lna_discharge = 14; + cp_cur = 0x38; /* 111, auto */ + div_buf_cur = 0x30; /* 11, 150u */ + filter_cur = 0x40; /* 10, low */ + break; + default: /* DVB-T 8M */ + mixer_top = 0x24; /* mixer top:13 , top-1, low-discharge */ + lna_top = 0xe5; /* detect bw 3, lna top:4, predet top:2 */ + lna_vth_l = 0x53; /* lna vth 0.84 , vtl 0.64 */ + mixer_vth_l = 0x75; /* mixer vth 1.04, vtl 0.84 */ + air_cable1_in = 0x00; + cable2_in = 0x00; + pre_dect = 0x40; + lna_discharge = 14; + cp_cur = 0x38; /* 111, auto */ + div_buf_cur = 0x30; /* 11, 150u */ + filter_cur = 0x40; /* 10, low */ + break; + } + + rc = r820t_write_reg_mask(priv, 0x1d, lna_top, 0xc7); + if (rc < 0) + return rc; + rc = r820t_write_reg_mask(priv, 0x1c, mixer_top, 0xf8); + if (rc < 0) + return rc; + rc = r820t_write_reg(priv, 0x0d, lna_vth_l); + if (rc < 0) + return rc; + rc = r820t_write_reg(priv, 0x0e, mixer_vth_l); + if (rc < 0) + return rc; + + /* Air-IN only for Astrometa */ + rc = r820t_write_reg_mask(priv, 0x05, air_cable1_in, 0x60); + if (rc < 0) + return rc; + rc = r820t_write_reg_mask(priv, 0x06, cable2_in, 0x08); + if (rc < 0) + return rc; + + rc = r820t_write_reg_mask(priv, 0x11, cp_cur, 0x38); + if (rc < 0) + return rc; + rc = r820t_write_reg_mask(priv, 0x17, div_buf_cur, 0x30); + if (rc < 0) + return rc; + rc = r820t_write_reg_mask(priv, 0x0a, filter_cur, 0x60); + if (rc < 0) + return rc; + /* + * Original driver initializes regs 0x05 and 0x06 with the + * same value again on this point. Probably, it is just an + * error there + */ + + /* + * Set LNA + */ + + tuner_dbg("adjusting LNA parameters\n"); + if (type != V4L2_TUNER_ANALOG_TV) { + /* LNA TOP: lowest */ + rc = r820t_write_reg_mask(priv, 0x1d, 0, 0x38); + if (rc < 0) + return rc; + + /* 0: normal mode */ + rc = r820t_write_reg_mask(priv, 0x1c, 0, 0x04); + if (rc < 0) + return rc; + + /* 0: PRE_DECT off */ + rc = r820t_write_reg_mask(priv, 0x06, 0, 0x40); + if (rc < 0) + return rc; + + /* agc clk 250hz */ + rc = r820t_write_reg_mask(priv, 0x1a, 0x30, 0x30); + if (rc < 0) + return rc; + + msleep(250); + + /* write LNA TOP = 3 */ + rc = r820t_write_reg_mask(priv, 0x1d, 0x18, 0x38); + if (rc < 0) + return rc; + + /* + * write discharge mode + * FIXME: IMHO, the mask here is wrong, but it matches + * what's there at the original driver + */ + rc = r820t_write_reg_mask(priv, 0x1c, mixer_top, 0x04); + if (rc < 0) + return rc; + + /* LNA discharge current */ + rc = r820t_write_reg_mask(priv, 0x1e, lna_discharge, 0x1f); + if (rc < 0) + return rc; + + /* agc clk 60hz */ + rc = r820t_write_reg_mask(priv, 0x1a, 0x20, 0x30); + if (rc < 0) + return rc; + } else { + /* PRE_DECT off */ + rc = r820t_write_reg_mask(priv, 0x06, 0, 0x40); + if (rc < 0) + return rc; + + /* write LNA TOP */ + rc = r820t_write_reg_mask(priv, 0x1d, lna_top, 0x38); + if (rc < 0) + return rc; + + /* + * write discharge mode + * FIXME: IMHO, the mask here is wrong, but it matches + * what's there at the original driver + */ + rc = r820t_write_reg_mask(priv, 0x1c, mixer_top, 0x04); + if (rc < 0) + return rc; + + /* LNA discharge current */ + rc = r820t_write_reg_mask(priv, 0x1e, lna_discharge, 0x1f); + if (rc < 0) + return rc; + + /* agc clk 1Khz, external det1 cap 1u */ + rc = r820t_write_reg_mask(priv, 0x1a, 0x00, 0x30); + if (rc < 0) + return rc; + + rc = r820t_write_reg_mask(priv, 0x10, 0x00, 0x04); + if (rc < 0) + return rc; + } + return 0; +} + +static int r820t_set_tv_standard(struct r820t_priv *priv, + unsigned bw, + enum v4l2_tuner_type type, + v4l2_std_id std, u32 delsys) + +{ + int rc, i; + u32 if_khz, filt_cal_lo; + u8 data[5], val; + u8 filt_gain, img_r, filt_q, hp_cor, ext_enable, loop_through; + u8 lt_att, flt_ext_widest, polyfil_cur; + bool need_calibration; + + tuner_dbg("selecting the delivery system\n"); + + if (delsys == SYS_ISDBT) { + if_khz = 4063; + filt_cal_lo = 59000; + filt_gain = 0x10; /* +3db, 6mhz on */ + img_r = 0x00; /* image negative */ + filt_q = 0x10; /* r10[4]:low q(1'b1) */ + hp_cor = 0x6a; /* 1.7m disable, +2cap, 1.25mhz */ + ext_enable = 0x40; /* r30[6], ext enable; r30[5]:0 ext at lna max */ + loop_through = 0x00; /* r5[7], lt on */ + lt_att = 0x00; /* r31[7], lt att enable */ + flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ + polyfil_cur = 0x60; /* r25[6:5]:min */ + } else { + if (bw <= 6) { + if_khz = 3570; + filt_cal_lo = 56000; /* 52000->56000 */ + filt_gain = 0x10; /* +3db, 6mhz on */ + img_r = 0x00; /* image negative */ + filt_q = 0x10; /* r10[4]:low q(1'b1) */ + hp_cor = 0x6b; /* 1.7m disable, +2cap, 1.0mhz */ + ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */ + loop_through = 0x00; /* r5[7], lt on */ + lt_att = 0x00; /* r31[7], lt att enable */ + flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ + polyfil_cur = 0x60; /* r25[6:5]:min */ + } else if (bw == 7) { + if_khz = 4070; + filt_cal_lo = 60000; + filt_gain = 0x10; /* +3db, 6mhz on */ + img_r = 0x00; /* image negative */ + filt_q = 0x10; /* r10[4]:low q(1'b1) */ + hp_cor = 0x2b; /* 1.7m disable, +1cap, 1.0mhz */ + ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */ + loop_through = 0x00; /* r5[7], lt on */ + lt_att = 0x00; /* r31[7], lt att enable */ + flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ + polyfil_cur = 0x60; /* r25[6:5]:min */ +#if 0 /* 7 MHz type 2 - nor sure why/where this is used - Perhaps Australia? */ + if_khz = 4570; + filt_cal_lo = 63000; + filt_gain = 0x10; /* +3db, 6mhz on */ + img_r = 0x00; /* image negative */ + filt_q = 0x10; /* r10[4]:low q(1'b1) */ + hp_cor = 0x2a; /* 1.7m disable, +1cap, 1.25mhz */ + ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */ + loop_through = 0x00; /* r5[7], lt on */ + lt_att = 0x00; /* r31[7], lt att enable */ + flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ + polyfil_cur = 0x60; /* r25[6:5]:min */ +#endif + } else { + if_khz = 4570; + filt_cal_lo = 68500; + filt_gain = 0x10; /* +3db, 6mhz on */ + img_r = 0x00; /* image negative */ + filt_q = 0x10; /* r10[4]:low q(1'b1) */ + hp_cor = 0x0b; /* 1.7m disable, +0cap, 1.0mhz */ + ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */ + loop_through = 0x00; /* r5[7], lt on */ + lt_att = 0x00; /* r31[7], lt att enable */ + flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ + polyfil_cur = 0x60; /* r25[6:5]:min */ + } + } + + /* Initialize the shadow registers */ + memcpy(priv->regs, r820t_init_array, sizeof(r820t_init_array)); + + /* Init Flag & Xtal_check Result */ + if (priv->imr_done) + val = 1 | priv->xtal_cap_sel << 1; + else + val = 0; + rc = r820t_write_reg_mask(priv, 0x0c, val, 0x0f); + if (rc < 0) + return rc; + + /* version */ + rc = r820t_write_reg_mask(priv, 0x13, VER_NUM, 0x3f); + if (rc < 0) + return rc; + + /* for LT Gain test */ + if (type != V4L2_TUNER_ANALOG_TV) { + rc = r820t_write_reg_mask(priv, 0x1d, 0x00, 0x38); + if (rc < 0) + return rc; + msleep(1); + } + priv->int_freq = if_khz; + + /* Check if standard changed. If so, filter calibration is needed */ + if (type != priv->type) + need_calibration = true; + else if ((type == V4L2_TUNER_ANALOG_TV) && (std != priv->std)) + need_calibration = true; + else if ((type == V4L2_TUNER_DIGITAL_TV) && + ((delsys != priv->delsys) || bw != priv->bw)) + need_calibration = true; + else + need_calibration = false; + + if (need_calibration) { + tuner_dbg("calibrating the tuner\n"); + for (i = 0; i < 2; i++) { + /* Set filt_cap */ + rc = r820t_write_reg_mask(priv, 0x0b, hp_cor, 0x60); + if (rc < 0) + return rc; + + /* set cali clk =on */ + rc = r820t_write_reg_mask(priv, 0x0f, 0x04, 0x04); + if (rc < 0) + return rc; + + /* X'tal cap 0pF for PLL */ + rc = r820t_write_reg_mask(priv, 0x10, 0x00, 0x03); + if (rc < 0) + return rc; + + rc = r820t_set_pll(priv, filt_cal_lo); + if (rc < 0 || !priv->has_lock) + return rc; + + /* Start Trigger */ + rc = r820t_write_reg_mask(priv, 0x0b, 0x10, 0x10); + if (rc < 0) + return rc; + + msleep(1); + + /* Stop Trigger */ + rc = r820t_write_reg_mask(priv, 0x0b, 0x00, 0x10); + if (rc < 0) + return rc; + + /* set cali clk =off */ + rc = r820t_write_reg_mask(priv, 0x0f, 0x00, 0x04); + if (rc < 0) + return rc; + + /* Check if calibration worked */ + rc = r820_read(priv, 0x00, data, sizeof(data)); + if (rc < 0) + return rc; + + priv->fil_cal_code = data[4] & 0x0f; + if (priv->fil_cal_code && priv->fil_cal_code != 0x0f) + break; + } + /* narrowest */ + if (priv->fil_cal_code == 0x0f) + priv->fil_cal_code = 0; + } + + rc = r820t_write_reg_mask(priv, 0x0a, + filt_q | priv->fil_cal_code, 0x1f); + if (rc < 0) + return rc; + + /* Set BW, Filter_gain, & HP corner */ + rc = r820t_write_reg_mask(priv, 0x0b, hp_cor, 0x10); + if (rc < 0) + return rc; + + + /* Set Img_R */ + rc = r820t_write_reg_mask(priv, 0x07, img_r, 0x80); + if (rc < 0) + return rc; + + /* Set filt_3dB, V6MHz */ + rc = r820t_write_reg_mask(priv, 0x06, filt_gain, 0x30); + if (rc < 0) + return rc; + + /* channel filter extension */ + rc = r820t_write_reg_mask(priv, 0x1e, ext_enable, 0x60); + if (rc < 0) + return rc; + + /* Loop through */ + rc = r820t_write_reg_mask(priv, 0x05, loop_through, 0x80); + if (rc < 0) + return rc; + + /* Loop through attenuation */ + rc = r820t_write_reg_mask(priv, 0x1f, lt_att, 0x80); + if (rc < 0) + return rc; + + /* filter extension widest */ + rc = r820t_write_reg_mask(priv, 0x0f, flt_ext_widest, 0x80); + if (rc < 0) + return rc; + + /* RF poly filter current */ + rc = r820t_write_reg_mask(priv, 0x19, polyfil_cur, 0x60); + if (rc < 0) + return rc; + + /* Store current standard. If it changes, re-calibrate the tuner */ + priv->delsys = delsys; + priv->type = type; + priv->std = std; + priv->bw = bw; + + return 0; +} + +static int generic_set_freq(struct dvb_frontend *fe, + u32 freq /* in HZ */, + unsigned bw, + enum v4l2_tuner_type type, + v4l2_std_id std, u32 delsys) +{ + struct r820t_priv *priv = fe->tuner_priv; + int rc = -EINVAL; + u32 lo_freq; + + tuner_dbg("should set frequency to %d kHz, bw %d MHz\n", + freq / 1000, bw); + + mutex_lock(&priv->lock); + + if ((type == V4L2_TUNER_ANALOG_TV) && (std == V4L2_STD_SECAM_LC)) + lo_freq = freq - priv->int_freq; + else + lo_freq = freq + priv->int_freq; + + rc = r820t_set_tv_standard(priv, bw, type, std, delsys); + if (rc < 0) + goto err; + + rc = r820t_set_mux(priv, lo_freq); + if (rc < 0) + goto err; + rc = r820t_set_pll(priv, lo_freq); + if (rc < 0 || !priv->has_lock) + goto err; + + rc = r820t_sysfreq_sel(priv, freq, type, std, delsys); +err: + mutex_unlock(&priv->lock); + + if (rc < 0) + tuner_dbg("%s: failed=%d\n", __func__, rc); + return rc; +} + +/* + * r820t standby logic + */ + +static int r820t_standby(struct r820t_priv *priv) +{ + int rc; + + rc = r820t_write_reg(priv, 0x06, 0xb1); + if (rc < 0) + return rc; + rc = r820t_write_reg(priv, 0x05, 0x03); + if (rc < 0) + return rc; + rc = r820t_write_reg(priv, 0x07, 0x3a); + if (rc < 0) + return rc; + rc = r820t_write_reg(priv, 0x08, 0x40); + if (rc < 0) + return rc; + rc = r820t_write_reg(priv, 0x09, 0xc0); + if (rc < 0) + return rc; + rc = r820t_write_reg(priv, 0x0a, 0x36); + if (rc < 0) + return rc; + rc = r820t_write_reg(priv, 0x0c, 0x35); + if (rc < 0) + return rc; + rc = r820t_write_reg(priv, 0x0f, 0x68); + if (rc < 0) + return rc; + rc = r820t_write_reg(priv, 0x11, 0x03); + if (rc < 0) + return rc; + rc = r820t_write_reg(priv, 0x17, 0xf4); + if (rc < 0) + return rc; + rc = r820t_write_reg(priv, 0x19, 0x0c); + + /* Force initial calibration */ + priv->type = -1; + + return rc; +} + +/* + * r820t device init logic + */ + +static int r820t_xtal_check(struct r820t_priv *priv) +{ + int rc, i; + u8 data[3], val; + + /* Initialize the shadow registers */ + memcpy(priv->regs, r820t_init_array, sizeof(r820t_init_array)); + + /* cap 30pF & Drive Low */ + rc = r820t_write_reg_mask(priv, 0x10, 0x0b, 0x0b); + if (rc < 0) + return rc; + + /* set pll autotune = 128kHz */ + rc = r820t_write_reg_mask(priv, 0x1a, 0x00, 0x0c); + if (rc < 0) + return rc; + + /* set manual initial reg = 111111; */ + rc = r820t_write_reg_mask(priv, 0x13, 0x7f, 0x7f); + if (rc < 0) + return rc; + + /* set auto */ + rc = r820t_write_reg_mask(priv, 0x13, 0x00, 0x40); + if (rc < 0) + return rc; + + /* Try several xtal capacitor alternatives */ + for (i = 0; i < ARRAY_SIZE(r820t_xtal_capacitor); i++) { + rc = r820t_write_reg_mask(priv, 0x10, + r820t_xtal_capacitor[i][0], 0x1b); + if (rc < 0) + return rc; + + msleep(5); + + rc = r820_read(priv, 0x00, data, sizeof(data)); + if (rc < 0) + return rc; + if ((!data[2]) & 0x40) + continue; + + val = data[2] & 0x3f; + + if (priv->cfg->xtal == 16000000 && (val > 29 || val < 23)) + break; + + if (val != 0x3f) + break; + } + + if (i == ARRAY_SIZE(r820t_xtal_capacitor)) + return -EINVAL; + + return r820t_xtal_capacitor[i][1]; +} + +/* + * r820t frontend operations and tuner attach code + */ + +static int r820t_init(struct dvb_frontend *fe) +{ + struct r820t_priv *priv = fe->tuner_priv; + int rc, i; + int xtal_cap = 0; + + tuner_dbg("%s:\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + mutex_lock(&priv->lock); + + if ((priv->cfg->rafael_chip == CHIP_R820T) || + (priv->cfg->rafael_chip == CHIP_R828S) || + (priv->cfg->rafael_chip == CHIP_R820C)) { + priv->xtal_cap_sel = XTAL_HIGH_CAP_0P; + } else { + for (i = 0; i < 3; i++) { + rc = r820t_xtal_check(priv); + if (rc < 0) + goto err; + if (!i || rc > xtal_cap) + xtal_cap = rc; + } + priv->xtal_cap_sel = xtal_cap; + } + + /* Initialize registers */ + rc = r820t_write(priv, 0x05, + r820t_init_array, sizeof(r820t_init_array)); + + mutex_unlock(&priv->lock); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return rc; +err: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + tuner_dbg("%s: failed=%d\n", __func__, rc); + return rc; +} + +static int r820t_sleep(struct dvb_frontend *fe) +{ + struct r820t_priv *priv = fe->tuner_priv; + int rc; + + tuner_dbg("%s:\n", __func__); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + mutex_lock(&priv->lock); + rc = r820t_standby(priv); + mutex_unlock(&priv->lock); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + tuner_dbg("%s: failed=%d\n", __func__, rc); + return rc; +} + +static int r820t_set_analog_freq(struct dvb_frontend *fe, + struct analog_parameters *p) +{ + struct r820t_priv *priv = fe->tuner_priv; + unsigned bw; + + tuner_dbg("%s called\n", __func__); + + /* if std is not defined, choose one */ + if (!p->std) + p->std = V4L2_STD_MN; + + if ((p->std == V4L2_STD_PAL_M) || (p->std == V4L2_STD_NTSC)) + bw = 6; + else + bw = 8; + + return generic_set_freq(fe, 62500l * p->frequency, bw, + V4L2_TUNER_ANALOG_TV, p->std, SYS_UNDEFINED); +} + +static int r820t_set_params(struct dvb_frontend *fe) +{ + struct r820t_priv *priv = fe->tuner_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int rc; + unsigned bw; + + tuner_dbg("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", + __func__, c->delivery_system, c->frequency, c->bandwidth_hz); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + bw = (c->bandwidth_hz + 500000) / 1000000; + if (!bw) + bw = 8; + + rc = generic_set_freq(fe, c->frequency, bw, + V4L2_TUNER_DIGITAL_TV, 0, c->delivery_system); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + if (rc) + tuner_dbg("%s: failed=%d\n", __func__, rc); + return rc; +} + +static int r820t_signal(struct dvb_frontend *fe, u16 *strength) +{ + struct r820t_priv *priv = fe->tuner_priv; + + if (priv->has_lock) + *strength = 0xffff; + else + *strength = 0; + + return 0; +} + +static int r820t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct r820t_priv *priv = fe->tuner_priv; + + tuner_dbg("%s:\n", __func__); + + *frequency = priv->int_freq; + + return 0; +} + +static int r820t_release(struct dvb_frontend *fe) +{ + struct r820t_priv *priv = fe->tuner_priv; + + tuner_dbg("%s:\n", __func__); + + mutex_lock(&r820t_list_mutex); + + if (priv) + hybrid_tuner_release_state(priv); + + mutex_unlock(&r820t_list_mutex); + + fe->tuner_priv = NULL; + + kfree(fe->tuner_priv); + + return 0; +} + +static const struct dvb_tuner_ops r820t_tuner_ops = { + .info = { + .name = "Rafael Micro R820T", + .frequency_min = 42000000, + .frequency_max = 1002000000, + }, + .init = r820t_init, + .release = r820t_release, + .sleep = r820t_sleep, + .set_params = r820t_set_params, + .set_analog_params = r820t_set_analog_freq, + .get_if_frequency = r820t_get_if_frequency, + .get_rf_strength = r820t_signal, +}; + +struct dvb_frontend *r820t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct r820t_config *cfg) +{ + struct r820t_priv *priv; + int rc = -ENODEV; + u8 data[5]; + int instance; + + mutex_lock(&r820t_list_mutex); + + instance = hybrid_tuner_request_state(struct r820t_priv, priv, + hybrid_tuner_instance_list, + i2c, cfg->i2c_addr, + "r820t"); + switch (instance) { + case 0: + /* memory allocation failure */ + goto err_no_gate; + break; + case 1: + /* new tuner instance */ + priv->cfg = cfg; + + mutex_init(&priv->lock); + + fe->tuner_priv = priv; + break; + case 2: + /* existing tuner instance */ + fe->tuner_priv = priv; + break; + } + + memcpy(&fe->ops.tuner_ops, &r820t_tuner_ops, sizeof(r820t_tuner_ops)); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + /* check if the tuner is there */ + rc = r820_read(priv, 0x00, data, sizeof(data)); + if (rc < 0) + goto err; + + rc = r820t_sleep(fe); + if (rc < 0) + goto err; + + tuner_info("Rafael Micro r820t successfully identified\n"); + + fe->tuner_priv = priv; + memcpy(&fe->ops.tuner_ops, &r820t_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + mutex_unlock(&r820t_list_mutex); + + return fe; +err: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + +err_no_gate: + mutex_unlock(&r820t_list_mutex); + + tuner_info("%s: failed=%d\n", __func__, rc); + r820t_release(fe); + return NULL; +} +EXPORT_SYMBOL_GPL(r820t_attach); + +MODULE_DESCRIPTION("Rafael Micro r820t silicon tuner driver"); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/tuners/r820t.h b/drivers/media/tuners/r820t.h new file mode 100644 index 000000000000..a64a7b630729 --- /dev/null +++ b/drivers/media/tuners/r820t.h @@ -0,0 +1,55 @@ +/* + * Elonics R820T silicon tuner driver + * + * Copyright (C) 2012 Antti Palosaari + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef R820T_H +#define R820T_H + +#include +#include "dvb_frontend.h" + +enum r820t_chip { + CHIP_R820T, + CHIP_R828S, + CHIP_R820C, +}; + +struct r820t_config { + u8 i2c_addr; /* 0x34 */ + + u32 xtal; + enum r820t_chip rafael_chip; + unsigned max_i2c_msg_len; +}; + +#if IS_ENABLED(CONFIG_MEDIA_TUNER_R820T) +struct dvb_frontend *r820t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct r820t_config *cfg); +#else +static inline struct dvb_frontend *r820t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + const struct r820t_config *cfg) +{ + pr_warn("%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif -- cgit v1.2.3 From 6889ab2a25cf39a048edc69b4d61884b8b4da6b0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 6 Apr 2013 09:40:11 -0300 Subject: [media] rtl28xxu: add support for Rafael Micro r820t This tuner is used on some rtl2882 dongles. Add it to the driver. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/Kconfig | 1 + drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 30 ++++++++++++++++++++++++++++++ drivers/media/usb/dvb-usb-v2/rtl28xxu.h | 1 + 3 files changed, 32 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 9aff03555464..a3c8ecf22078 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -143,6 +143,7 @@ config DVB_USB_RTL28XXU select MEDIA_TUNER_FC0013 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_E4000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_R820T if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Realtek RTL28xxU DVB USB receiver. diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 3d128a5e4794..18756a6d03d5 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -33,6 +33,7 @@ #include "e4000.h" #include "fc2580.h" #include "tua9001.h" +#include "r820t.h" DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -375,6 +376,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d) struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf}; struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf}; struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf}; + struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 5, buf}; dev_dbg(&d->udev->dev, "%s:\n", __func__); @@ -479,6 +481,14 @@ static int rtl2832u_read_config(struct dvb_usb_device *d) goto found; } + /* check R820T by reading tuner stats at I2C addr 0x1a */ + ret = rtl28xxu_ctrl_msg(d, &req_r820t); + if (ret == 0) { + priv->tuner = TUNER_RTL2832_R820T; + priv->tuner_name = "R820T"; + goto found; + } + found: dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name); @@ -589,6 +599,12 @@ static struct rtl2832_config rtl28xxu_rtl2832_e4000_config = { .tuner = TUNER_RTL2832_E4000, }; +static struct rtl2832_config rtl28xxu_rtl2832_r820t_config = { + .i2c_addr = 0x10, + .xtal = 28800000, + .tuner = TUNER_RTL2832_R820T, +}; + static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d, int cmd, int arg) { @@ -728,6 +744,9 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap) case TUNER_RTL2832_E4000: rtl2832_config = &rtl28xxu_rtl2832_e4000_config; break; + case TUNER_RTL2832_R820T: + rtl2832_config = &rtl28xxu_rtl2832_r820t_config; + break; default: dev_err(&d->udev->dev, "%s: unknown tuner=%s\n", KBUILD_MODNAME, priv->tuner_name); @@ -840,6 +859,13 @@ static const struct fc0012_config rtl2832u_fc0012_config = { .xtal_freq = FC_XTAL_28_8_MHZ, }; +static const struct r820t_config rtl2832u_r820t_config = { + .i2c_addr = 0x1a, + .xtal = 28800000, + .max_i2c_msg_len = 2, + .rafael_chip = CHIP_R820T, +}; + static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) { int ret; @@ -889,6 +915,10 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) fe = dvb_attach(tua9001_attach, adap->fe[0], &d->i2c_adap, &rtl2832u_tua9001_config); break; + case TUNER_RTL2832_R820T: + fe = dvb_attach(r820t_attach, adap->fe[0], &d->i2c_adap, + &rtl2832u_r820t_config); + break; default: fe = NULL; dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME, diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h index 2f3af2d3b6ce..533a33127289 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h @@ -82,6 +82,7 @@ enum rtl28xxu_tuner { TUNER_RTL2832_E4000, TUNER_RTL2832_TDA18272, TUNER_RTL2832_FC0013, + TUNER_RTL2832_R820T, }; struct rtl28xxu_req { -- cgit v1.2.3 From f8fde0e045aeac4417b09bef01b3ada74a4cbc80 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 7 Apr 2013 18:12:56 -0300 Subject: [media] r820t: Give a better estimation of the signal strength Instead of a binary signal strength measure, use the tuner gain to obtain a better estimation of the signal strength. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 7e02920f385a..ed9cd6569548 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -1082,6 +1082,18 @@ static int r820t_set_tv_standard(struct r820t_priv *priv, return 0; } +static int r820t_read_gain(struct r820t_priv *priv) +{ + u8 data[4]; + int rc; + + rc = r820_read(priv, 0x00, data, sizeof(data)); + if (rc < 0) + return rc; + + return ((data[3] & 0x0f) << 1) + ((data[3] & 0xf0) >> 4); +} + static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, unsigned bw, @@ -1353,11 +1365,23 @@ static int r820t_set_params(struct dvb_frontend *fe) static int r820t_signal(struct dvb_frontend *fe, u16 *strength) { struct r820t_priv *priv = fe->tuner_priv; + int rc = 0; - if (priv->has_lock) - *strength = 0xffff; - else + if (priv->has_lock) { + rc = r820t_read_gain(priv); + if (rc < 0) + return rc; + + /* A higher gain at LNA means a lower signal strength */ + *strength = (45 - rc) << 4 | 0xff; + } else { *strength = 0; + } + + tuner_dbg("%s: %s, gain=%d strength=%d\n", + __func__, + priv->has_lock ? "PLL locked" : "no signal", + rc, *strength); return 0; } -- cgit v1.2.3 From 50786ddfa8efef696ec4f72460874f3b46dc2401 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 7 Apr 2013 18:33:13 -0300 Subject: [media] r820t: Set gain mode to auto This tuner works with 2 modes: automatic gain mode and manual gain mode. Put it into automatic mode, as we currently don't have any API for manual gain adjustment. The logic to allow setting the manual mode is there, as it is just a few extra code. This way, if/when we latter add support for setting the gain mode, the code is already there. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 91 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index ed9cd6569548..0fa355d1737c 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -320,6 +320,20 @@ static int r820t_xtal_capacitor[][2] = { { 0x10, XTAL_HIGH_CAP_0P }, }; +/* + * measured with a Racal 6103E GSM test set at 928 MHz with -60 dBm + * input power, for raw results see: + * http://steve-m.de/projects/rtl-sdr/gain_measurement/r820t/ + */ + +static const int r820t_lna_gain_steps[] = { + 0, 9, 13, 40, 38, 13, 31, 22, 26, 31, 26, 14, 19, 5, 35, 13 +}; + +static const int r820t_mixer_gain_steps[] = { + 0, 5, 10, 10, 19, 9, 10, 25, 17, 10, 8, 16, 13, 6, 3, -8 +}; + /* * I2C read/write code and shadow registers logic */ @@ -1094,6 +1108,78 @@ static int r820t_read_gain(struct r820t_priv *priv) return ((data[3] & 0x0f) << 1) + ((data[3] & 0xf0) >> 4); } +static int r820t_set_gain_mode(struct r820t_priv *priv, + bool set_manual_gain, + int gain) +{ + int rc; + + if (set_manual_gain) { + int i, total_gain = 0; + uint8_t mix_index = 0, lna_index = 0; + u8 data[4]; + + /* LNA auto off */ + rc = r820t_write_reg_mask(priv, 0x05, 0x10, 0x10); + if (rc < 0) + return rc; + + /* Mixer auto off */ + rc = r820t_write_reg_mask(priv, 0x07, 0, 0x10); + if (rc < 0) + return rc; + + rc = r820_read(priv, 0x00, data, sizeof(data)); + if (rc < 0) + return rc; + + /* set fixed VGA gain for now (16.3 dB) */ + rc = r820t_write_reg_mask(priv, 0x0c, 0x08, 0x9f); + if (rc < 0) + return rc; + + for (i = 0; i < 15; i++) { + if (total_gain >= gain) + break; + + total_gain += r820t_lna_gain_steps[++lna_index]; + + if (total_gain >= gain) + break; + + total_gain += r820t_mixer_gain_steps[++mix_index]; + } + + /* set LNA gain */ + rc = r820t_write_reg_mask(priv, 0x05, lna_index, 0x0f); + if (rc < 0) + return rc; + + /* set Mixer gain */ + rc = r820t_write_reg_mask(priv, 0x07, mix_index, 0x0f); + if (rc < 0) + return rc; + } else { + /* LNA */ + rc = r820t_write_reg_mask(priv, 0x05, 0, 0xef); + if (rc < 0) + return rc; + + /* Mixer */ + rc = r820t_write_reg_mask(priv, 0x07, 0x10, 0xef); + if (rc < 0) + return rc; + + /* set fixed VGA gain for now (26.5 dB) */ + rc = r820t_write_reg_mask(priv, 0x0c, 0x0b, 0x9f); + if (rc < 0) + return rc; + } + + return 0; +} + + static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, unsigned bw, @@ -1121,6 +1207,11 @@ static int generic_set_freq(struct dvb_frontend *fe, rc = r820t_set_mux(priv, lo_freq); if (rc < 0) goto err; + + rc = r820t_set_gain_mode(priv, true, 0); + if (rc < 0) + goto err; + rc = r820t_set_pll(priv, lo_freq); if (rc < 0 || !priv->has_lock) goto err; -- cgit v1.2.3 From 9e30edd8907e5a7e92b04b1d05de5619c4a35d47 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 7 Apr 2013 18:57:15 -0300 Subject: [media] rtl28xxu: use r820t to obtain the signal strength Now that we can get the strength from r820t, use it. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 18756a6d03d5..22015fe1a0f3 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -918,6 +918,10 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap) case TUNER_RTL2832_R820T: fe = dvb_attach(r820t_attach, adap->fe[0], &d->i2c_adap, &rtl2832u_r820t_config); + + /* Use tuner to get the signal strength */ + adap->fe[0]->ops.read_signal_strength = + adap->fe[0]->ops.tuner_ops.get_rf_strength; break; default: fe = NULL; -- cgit v1.2.3 From 7a5ef30dc3363ae1ab7243397be7dd8449063999 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 7 Apr 2013 19:32:55 -0300 Subject: [media] r820t: proper lock and set the I2C gate As this tuner can be used by analog and digital parts of the driver, be sure that all ops that access the hardware will be be properly locked. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 50 +++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 0fa355d1737c..5cd8256a203e 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -1193,8 +1193,6 @@ static int generic_set_freq(struct dvb_frontend *fe, tuner_dbg("should set frequency to %d kHz, bw %d MHz\n", freq / 1000, bw); - mutex_lock(&priv->lock); - if ((type == V4L2_TUNER_ANALOG_TV) && (std == V4L2_STD_SECAM_LC)) lo_freq = freq - priv->int_freq; else @@ -1218,7 +1216,6 @@ static int generic_set_freq(struct dvb_frontend *fe, rc = r820t_sysfreq_sel(priv, freq, type, std, delsys); err: - mutex_unlock(&priv->lock); if (rc < 0) tuner_dbg("%s: failed=%d\n", __func__, rc); @@ -1335,6 +1332,8 @@ static int r820t_xtal_check(struct r820t_priv *priv) /* * r820t frontend operations and tuner attach code + * + * All driver locks and i2c control are only in this part of the code */ static int r820t_init(struct dvb_frontend *fe) @@ -1345,11 +1344,10 @@ static int r820t_init(struct dvb_frontend *fe) tuner_dbg("%s:\n", __func__); + mutex_lock(&priv->lock); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - mutex_lock(&priv->lock); - if ((priv->cfg->rafael_chip == CHIP_R820T) || (priv->cfg->rafael_chip == CHIP_R828S) || (priv->cfg->rafael_chip == CHIP_R820C)) { @@ -1369,17 +1367,13 @@ static int r820t_init(struct dvb_frontend *fe) rc = r820t_write(priv, 0x05, r820t_init_array, sizeof(r820t_init_array)); - mutex_unlock(&priv->lock); - - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 0); - - return rc; err: if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + mutex_unlock(&priv->lock); - tuner_dbg("%s: failed=%d\n", __func__, rc); + if (rc < 0) + tuner_dbg("%s: failed=%d\n", __func__, rc); return rc; } @@ -1390,15 +1384,15 @@ static int r820t_sleep(struct dvb_frontend *fe) tuner_dbg("%s:\n", __func__); + mutex_lock(&priv->lock); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - mutex_lock(&priv->lock); rc = r820t_standby(priv); - mutex_unlock(&priv->lock); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + mutex_unlock(&priv->lock); tuner_dbg("%s: failed=%d\n", __func__, rc); return rc; @@ -1409,6 +1403,7 @@ static int r820t_set_analog_freq(struct dvb_frontend *fe, { struct r820t_priv *priv = fe->tuner_priv; unsigned bw; + int rc; tuner_dbg("%s called\n", __func__); @@ -1421,8 +1416,18 @@ static int r820t_set_analog_freq(struct dvb_frontend *fe, else bw = 8; - return generic_set_freq(fe, 62500l * p->frequency, bw, - V4L2_TUNER_ANALOG_TV, p->std, SYS_UNDEFINED); + mutex_lock(&priv->lock); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + rc = generic_set_freq(fe, 62500l * p->frequency, bw, + V4L2_TUNER_ANALOG_TV, p->std, SYS_UNDEFINED); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + mutex_unlock(&priv->lock); + + return rc; } static int r820t_set_params(struct dvb_frontend *fe) @@ -1435,6 +1440,7 @@ static int r820t_set_params(struct dvb_frontend *fe) tuner_dbg("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", __func__, c->delivery_system, c->frequency, c->bandwidth_hz); + mutex_lock(&priv->lock); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); @@ -1447,6 +1453,7 @@ static int r820t_set_params(struct dvb_frontend *fe) if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + mutex_unlock(&priv->lock); if (rc) tuner_dbg("%s: failed=%d\n", __func__, rc); @@ -1458,10 +1465,14 @@ static int r820t_signal(struct dvb_frontend *fe, u16 *strength) struct r820t_priv *priv = fe->tuner_priv; int rc = 0; + mutex_lock(&priv->lock); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (priv->has_lock) { rc = r820t_read_gain(priv); if (rc < 0) - return rc; + goto err; /* A higher gain at LNA means a lower signal strength */ *strength = (45 - rc) << 4 | 0xff; @@ -1469,6 +1480,11 @@ static int r820t_signal(struct dvb_frontend *fe, u16 *strength) *strength = 0; } +err: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + mutex_unlock(&priv->lock); + tuner_dbg("%s: %s, gain=%d strength=%d\n", __func__, priv->has_lock ? "PLL locked" : "no signal", -- cgit v1.2.3 From da31934fb87dbe907d2ea77f300313f280792d8d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 7 Apr 2013 19:47:49 -0300 Subject: [media] rtl820t: Add a debug msg when PLL gets locked [ 2255.342797] r820t 3-001a: generic_set_freq: PLL locked on frequency 725476191 Hz, gain=45 Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 5cd8256a203e..1821cf192642 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -1215,6 +1215,12 @@ static int generic_set_freq(struct dvb_frontend *fe, goto err; rc = r820t_sysfreq_sel(priv, freq, type, std, delsys); + if (rc < 0) + goto err; + + tuner_dbg("%s: PLL locked on frequency %d Hz, gain=%d\n", + __func__, freq, r820t_read_gain(priv)); + err: if (rc < 0) -- cgit v1.2.3 From f60f5bcbe47d1a7c83b278740d22482a49a70269 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 9 Apr 2013 18:46:10 -0300 Subject: [media] r820t: Fix IF scale Scale used at get_if_freq and LO freq calculus is Hz. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 1821cf192642..2ecf1d2ab82f 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -975,7 +975,7 @@ static int r820t_set_tv_standard(struct r820t_priv *priv, return rc; msleep(1); } - priv->int_freq = if_khz; + priv->int_freq = if_khz * 1000; /* Check if standard changed. If so, filter calibration is needed */ if (type != priv->type) -- cgit v1.2.3 From fa4bfd2bd0548c0e5e0d931147df45157686de71 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 9 Apr 2013 18:19:50 -0300 Subject: [media] rtl2832: add code to bind r820t on it There are some init stuff to be done for each new tuner at the demod code. Add the code there for r820t. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/dvb-frontends/rtl2832.c | 76 +++++++++++++++++++++++------- drivers/media/dvb-frontends/rtl2832.h | 1 + drivers/media/dvb-frontends/rtl2832_priv.h | 28 +++++++++++ 3 files changed, 88 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 73887690b046..b6f50c7a15e6 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -432,22 +432,12 @@ static int rtl2832_init(struct dvb_frontend *fe) {DVBT_TR_THD_SET2, 0x6}, {DVBT_TRK_KC_I2, 0x5}, {DVBT_CR_THD_SET2, 0x1}, - {DVBT_SPEC_INV, 0x0}, }; dev_dbg(&priv->i2c->dev, "%s:\n", __func__); en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0); - /* - * PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22) - * / CrystalFreqHz) - */ - pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal; - pset_iffreq *= 0x400000; - pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal); - pset_iffreq = pset_iffreq & 0x3fffff; - for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) { ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs[i].reg, rtl2832_initial_regs[i].value); @@ -472,6 +462,10 @@ static int rtl2832_init(struct dvb_frontend *fe) len = ARRAY_SIZE(rtl2832_tuner_init_e4000); init = rtl2832_tuner_init_e4000; break; + case RTL2832_TUNER_R820T: + len = ARRAY_SIZE(rtl2832_tuner_init_r820t); + init = rtl2832_tuner_init_r820t; + break; default: ret = -EINVAL; goto err; @@ -483,14 +477,43 @@ static int rtl2832_init(struct dvb_frontend *fe) goto err; } - /* if frequency settings */ - ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin); - if (ret) - goto err; + /* + * if frequency settings + * Some tuners (r820t) don't initialize IF here; instead; they do it + * at set_params() + */ + if (!fe->ops.tuner_ops.get_if_frequency) { + /* + * PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22) + * / CrystalFreqHz) + */ + pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal; + pset_iffreq *= 0x400000; + pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal); + pset_iffreq = pset_iffreq & 0x3fffff; + ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin); + if (ret) + goto err; + + ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq); + if (ret) + goto err; + } - ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq); - if (ret) - goto err; + /* + * r820t NIM code does a software reset here at the demod - + * may not be needed, as there's already a software reset at set_params() + */ +#if 1 + /* soft reset */ + ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1); + if (ret) + goto err; + + ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0); + if (ret) + goto err; +#endif priv->sleeping = false; @@ -564,6 +587,25 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) if (fe->ops.tuner_ops.set_params) fe->ops.tuner_ops.set_params(fe); + /* If the frontend has get_if_frequency(), use it */ + if (fe->ops.tuner_ops.get_if_frequency) { + u32 if_freq; + u64 pset_iffreq; + + ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); + if (ret) + goto err; + + pset_iffreq = if_freq % priv->cfg.xtal; + pset_iffreq *= 0x400000; + pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal); + pset_iffreq = pset_iffreq & 0x3fffff; + + ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq); + if (ret) + goto err; + } + switch (c->bandwidth_hz) { case 6000000: i = 0; diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h index fefba0e9ba30..91b2dcf5a6ea 100644 --- a/drivers/media/dvb-frontends/rtl2832.h +++ b/drivers/media/dvb-frontends/rtl2832.h @@ -52,6 +52,7 @@ struct rtl2832_config { #define RTL2832_TUNER_FC0012 0x26 #define RTL2832_TUNER_E4000 0x27 #define RTL2832_TUNER_FC0013 0x29 +#define RTL2832_TUNER_R820T 0x2a u8 tuner; }; diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h index 7d97ce9d2193..b5f2b80092ee 100644 --- a/drivers/media/dvb-frontends/rtl2832_priv.h +++ b/drivers/media/dvb-frontends/rtl2832_priv.h @@ -267,6 +267,7 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_tua9001[] = { {DVBT_OPT_ADC_IQ, 0x1}, {DVBT_AD_AVI, 0x0}, {DVBT_AD_AVQ, 0x0}, + {DVBT_SPEC_INV, 0x0}, }; static const struct rtl2832_reg_value rtl2832_tuner_init_fc0012[] = { @@ -300,6 +301,7 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_fc0012[] = { {DVBT_GI_PGA_STATE, 0x0}, {DVBT_EN_AGC_PGA, 0x1}, {DVBT_IF_AGC_MAN, 0x0}, + {DVBT_SPEC_INV, 0x0}, }; static const struct rtl2832_reg_value rtl2832_tuner_init_e4000[] = { @@ -337,6 +339,32 @@ static const struct rtl2832_reg_value rtl2832_tuner_init_e4000[] = { {DVBT_REG_MONSEL, 0x1}, {DVBT_REG_MON, 0x1}, {DVBT_REG_4MSEL, 0x0}, + {DVBT_SPEC_INV, 0x0}, +}; + +static const struct rtl2832_reg_value rtl2832_tuner_init_r820t[] = { + {DVBT_DAGC_TRG_VAL, 0x39}, + {DVBT_AGC_TARG_VAL_0, 0x0}, + {DVBT_AGC_TARG_VAL_8_1, 0x40}, + {DVBT_AAGC_LOOP_GAIN, 0x16}, + {DVBT_LOOP_GAIN2_3_0, 0x8}, + {DVBT_LOOP_GAIN2_4, 0x1}, + {DVBT_LOOP_GAIN3, 0x18}, + {DVBT_VTOP1, 0x35}, + {DVBT_VTOP2, 0x21}, + {DVBT_VTOP3, 0x21}, + {DVBT_KRF1, 0x0}, + {DVBT_KRF2, 0x40}, + {DVBT_KRF3, 0x10}, + {DVBT_KRF4, 0x10}, + {DVBT_IF_AGC_MIN, 0x80}, + {DVBT_IF_AGC_MAX, 0x7f}, + {DVBT_RF_AGC_MIN, 0x80}, + {DVBT_RF_AGC_MAX, 0x7f}, + {DVBT_POLAR_RF_AGC, 0x0}, + {DVBT_POLAR_IF_AGC, 0x0}, + {DVBT_AD7_SETTING, 0xe9f4}, + {DVBT_SPEC_INV, 0x1}, }; #endif /* RTL2832_PRIV_H */ -- cgit v1.2.3 From a7dd065f4976b54d0e75d58f8e94066501fede76 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 9 Apr 2013 21:29:40 -0300 Subject: [media] r820t: use the right IF for the selected TV standard IF is set at r820t_set_tv_standard(). So, we can't calculate LO frequency before calling it. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 2ecf1d2ab82f..48ff6bb75f81 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -1193,15 +1193,15 @@ static int generic_set_freq(struct dvb_frontend *fe, tuner_dbg("should set frequency to %d kHz, bw %d MHz\n", freq / 1000, bw); + rc = r820t_set_tv_standard(priv, bw, type, std, delsys); + if (rc < 0) + goto err; + if ((type == V4L2_TUNER_ANALOG_TV) && (std == V4L2_STD_SECAM_LC)) lo_freq = freq - priv->int_freq; else lo_freq = freq + priv->int_freq; - rc = r820t_set_tv_standard(priv, bw, type, std, delsys); - if (rc < 0) - goto err; - rc = r820t_set_mux(priv, lo_freq); if (rc < 0) goto err; -- cgit v1.2.3 From 884655ad2e85ebcd84b10b82fca2ef8e431d4392 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 9 Apr 2013 22:16:52 -0300 Subject: [media] rtl2832: properly set en_bbin for r820t DVBT_EN_BBIN should be set on both places where IF is set. So, move it to a function and call it where needed. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/dvb-frontends/rtl2832.c | 63 +++++++++++++++++------------------ 1 file changed, 31 insertions(+), 32 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index b6f50c7a15e6..2f5a2b504932 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -380,13 +380,37 @@ err: return ret; } -static int rtl2832_init(struct dvb_frontend *fe) + +static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq) { struct rtl2832_priv *priv = fe->demodulator_priv; - int i, ret, len; - u8 en_bbin; + int ret; u64 pset_iffreq; + u8 en_bbin = (if_freq == 0 ? 0x1 : 0x0); + + /* + * PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22) + * / CrystalFreqHz) + */ + + pset_iffreq = if_freq % priv->cfg.xtal; + pset_iffreq *= 0x400000; + pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal); + pset_iffreq = pset_iffreq & 0x3fffff; + ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin); + if (ret) + return ret; + + ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq); + + return (ret); +} + +static int rtl2832_init(struct dvb_frontend *fe) +{ + struct rtl2832_priv *priv = fe->demodulator_priv; const struct rtl2832_reg_value *init; + int i, ret, len; /* initialization values for the demodulator registers */ struct rtl2832_reg_value rtl2832_initial_regs[] = { @@ -436,8 +460,6 @@ static int rtl2832_init(struct dvb_frontend *fe) dev_dbg(&priv->i2c->dev, "%s:\n", __func__); - en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0); - for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) { ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs[i].reg, rtl2832_initial_regs[i].value); @@ -477,27 +499,10 @@ static int rtl2832_init(struct dvb_frontend *fe) goto err; } - /* - * if frequency settings - * Some tuners (r820t) don't initialize IF here; instead; they do it - * at set_params() - */ if (!fe->ops.tuner_ops.get_if_frequency) { - /* - * PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22) - * / CrystalFreqHz) - */ - pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal; - pset_iffreq *= 0x400000; - pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal); - pset_iffreq = pset_iffreq & 0x3fffff; - ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin); - if (ret) - goto err; - - ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq); - if (ret) - goto err; + ret = rtl2832_set_if(fe, priv->cfg.if_dvbt); + if (ret) + goto err; } /* @@ -590,18 +595,12 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe) /* If the frontend has get_if_frequency(), use it */ if (fe->ops.tuner_ops.get_if_frequency) { u32 if_freq; - u64 pset_iffreq; ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_freq); if (ret) goto err; - pset_iffreq = if_freq % priv->cfg.xtal; - pset_iffreq *= 0x400000; - pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal); - pset_iffreq = pset_iffreq & 0x3fffff; - - ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq); + ret = rtl2832_set_if(fe, if_freq); if (ret) goto err; } -- cgit v1.2.3 From 103fe2fb2314f09d9b923c5919e70cbe66830d6d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 10 Apr 2013 07:08:17 -0300 Subject: [media] r820t: Invert bits for read ops On read, the bit order is inverted. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 48ff6bb75f81..79ab2b74bd52 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -35,8 +35,10 @@ #include #include #include -#include "tuner-i2c.h" +#include #include + +#include "tuner-i2c.h" #include "r820t.h" /* @@ -414,7 +416,7 @@ static int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val, static int r820_read(struct r820t_priv *priv, u8 reg, u8 *val, int len) { - int rc; + int rc, i; u8 *p = &priv->buf[1]; priv->buf[0] = reg; @@ -431,7 +433,8 @@ static int r820_read(struct r820t_priv *priv, u8 reg, u8 *val, int len) __func__, reg, len, len, p); /* Copy data to the output buffer */ - memcpy(val, p, len); + for (i = 0; i < len; i++) + val[i] = bitrev8(p[i]); return 0; } -- cgit v1.2.3 From 6189f80d5d6ae58b7262a0908cabf7858397711f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 10 Apr 2013 07:33:23 -0300 Subject: [media] r820t: use the second table for 7MHz The Realtek Kernel driver uses the second DVB-T 7MHz table instead of the first one. Use it as well. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 79ab2b74bd52..1880807e3e8d 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -915,6 +915,14 @@ static int r820t_set_tv_standard(struct r820t_priv *priv, flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ polyfil_cur = 0x60; /* r25[6:5]:min */ } else if (bw == 7) { +#if 0 + /* + * There are two 7 MHz tables defined on the original + * driver, but just the second one seems to be visible + * by rtl2832. Keep this one here commented, as it + * might be needed in the future + */ + if_khz = 4070; filt_cal_lo = 60000; filt_gain = 0x10; /* +3db, 6mhz on */ @@ -926,7 +934,8 @@ static int r820t_set_tv_standard(struct r820t_priv *priv, lt_att = 0x00; /* r31[7], lt att enable */ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ polyfil_cur = 0x60; /* r25[6:5]:min */ -#if 0 /* 7 MHz type 2 - nor sure why/where this is used - Perhaps Australia? */ +#endif + /* 7 MHz, second table */ if_khz = 4570; filt_cal_lo = 63000; filt_gain = 0x10; /* +3db, 6mhz on */ @@ -938,7 +947,6 @@ static int r820t_set_tv_standard(struct r820t_priv *priv, lt_att = 0x00; /* r31[7], lt att enable */ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */ polyfil_cur = 0x60; /* r25[6:5]:min */ -#endif } else { if_khz = 4570; filt_cal_lo = 68500; -- cgit v1.2.3 From 6b8c2308761029868f36d9037377806c63cf06e9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 10 Apr 2013 07:43:10 -0300 Subject: [media] r820t: Show the read data in the bit-reversed order As the driver's logic uses the bit-reversed order for read, use it as well when displaying the debug messages. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 1880807e3e8d..bb154449a2cf 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -429,13 +429,14 @@ static int r820_read(struct r820t_priv *priv, u8 reg, u8 *val, int len) return rc; return -EREMOTEIO; } - tuner_dbg("%s: i2c rd reg=%02x len=%d: %*ph\n", - __func__, reg, len, len, p); /* Copy data to the output buffer */ for (i = 0; i < len; i++) val[i] = bitrev8(p[i]); + tuner_dbg("%s: i2c rd reg=%02x len=%d: %*ph\n", + __func__, reg, len, len, val); + return 0; } -- cgit v1.2.3 From 84ddc33c20cd026871eb3585ed77badacb0fc113 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 10 Apr 2013 08:51:45 -0300 Subject: [media] r820t: add support for diplexer This is part of the original driver, and adding it doesn't hurt, so add it, to better sync the code. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 12 ++++++++++++ drivers/media/tuners/r820t.h | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index bb154449a2cf..5be4635c521d 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -101,6 +101,7 @@ struct r820t_freq_range { }; #define VCO_POWER_REF 0x02 +#define DIP_FREQ 32000000 /* * Static constants @@ -751,6 +752,17 @@ static int r820t_sysfreq_sel(struct r820t_priv *priv, u32 freq, break; } + if (priv->cfg->use_diplexer && + ((priv->cfg->rafael_chip == CHIP_R820T) || + (priv->cfg->rafael_chip == CHIP_R828S) || + (priv->cfg->rafael_chip == CHIP_R820C))) { + if (freq > DIP_FREQ) + air_cable1_in = 0x00; + else + air_cable1_in = 0x60; + cable2_in = 0x00; + } + rc = r820t_write_reg_mask(priv, 0x1d, lna_top, 0xc7); if (rc < 0) return rc; diff --git a/drivers/media/tuners/r820t.h b/drivers/media/tuners/r820t.h index a64a7b630729..949575a41d49 100644 --- a/drivers/media/tuners/r820t.h +++ b/drivers/media/tuners/r820t.h @@ -32,10 +32,10 @@ enum r820t_chip { struct r820t_config { u8 i2c_addr; /* 0x34 */ - u32 xtal; enum r820t_chip rafael_chip; unsigned max_i2c_msg_len; + bool use_diplexer; }; #if IS_ENABLED(CONFIG_MEDIA_TUNER_R820T) -- cgit v1.2.3 From 75c1819e5e42064e66d4f88a5af628a1604ad52d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 10 Apr 2013 09:04:03 -0300 Subject: [media] r820t: better report signal strength If signal is zero, shows it as a zero, not as 0xff. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 5be4635c521d..d5686e8a8bc6 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -1506,6 +1506,8 @@ static int r820t_signal(struct dvb_frontend *fe, u16 *strength) /* A higher gain at LNA means a lower signal strength */ *strength = (45 - rc) << 4 | 0xff; + if (*strength == 0xff) + *strength = 0; } else { *strength = 0; } -- cgit v1.2.3 From 8678b03428b6894d146695980f04f26af7b9b3ec Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 10 Apr 2013 10:50:50 -0300 Subject: [media] r820t: split the function that read cached regs As we'll need to retrieve cached registers, make this function explicit. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index d5686e8a8bc6..ef100ab3564d 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -402,15 +402,25 @@ static int r820t_write_reg(struct r820t_priv *priv, u8 reg, u8 val) return r820t_write(priv, reg, &val, 1); } -static int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val, - u8 bit_mask) +static int r820t_read_cache_reg(struct r820t_priv *priv, int reg) { - int r = reg - REG_SHADOW_START; + reg -= REG_SHADOW_START; - if (r >= 0 && r < NUM_REGS) - val = (priv->regs[r] & ~bit_mask) | (val & bit_mask); + if (reg >= 0 && reg < NUM_REGS) + return priv->regs[reg]; else return -EINVAL; +} + +static int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val, + u8 bit_mask) +{ + int rc = r820t_read_cache_reg(priv, reg); + + if (rc < 0) + return rc; + + val = (rc & ~bit_mask) | (val & bit_mask); return r820t_write(priv, reg, &val, 1); } -- cgit v1.2.3 From 226471a18f5458d42aac52bca62ebd8edeb37a96 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 10 Apr 2013 10:53:35 -0300 Subject: [media] r820t: fix prefix of the r820t_read() function Just cosmetic changes: all other functions are prefixed by r820t. Do the same for r820t_read(). Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index ef100ab3564d..e9367d896a07 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -425,7 +425,7 @@ static int r820t_write_reg_mask(struct r820t_priv *priv, u8 reg, u8 val, return r820t_write(priv, reg, &val, 1); } -static int r820_read(struct r820t_priv *priv, u8 reg, u8 *val, int len) +static int r820t_read(struct r820t_priv *priv, u8 reg, u8 *val, int len) { int rc, i; u8 *p = &priv->buf[1]; @@ -573,7 +573,7 @@ static int r820t_set_pll(struct r820t_priv *priv, u32 freq) mix_div = mix_div << 1; } - rc = r820_read(priv, 0x00, data, sizeof(data)); + rc = r820t_read(priv, 0x00, data, sizeof(data)); if (rc < 0) return rc; @@ -660,7 +660,7 @@ static int r820t_set_pll(struct r820t_priv *priv, u32 freq) msleep(10); /* Check if PLL has locked */ - rc = r820_read(priv, 0x00, data, 3); + rc = r820t_read(priv, 0x00, data, 3); if (rc < 0) return rc; if (data[2] & 0x40) @@ -1062,7 +1062,7 @@ static int r820t_set_tv_standard(struct r820t_priv *priv, return rc; /* Check if calibration worked */ - rc = r820_read(priv, 0x00, data, sizeof(data)); + rc = r820t_read(priv, 0x00, data, sizeof(data)); if (rc < 0) return rc; @@ -1135,7 +1135,7 @@ static int r820t_read_gain(struct r820t_priv *priv) u8 data[4]; int rc; - rc = r820_read(priv, 0x00, data, sizeof(data)); + rc = r820t_read(priv, 0x00, data, sizeof(data)); if (rc < 0) return rc; @@ -1163,7 +1163,7 @@ static int r820t_set_gain_mode(struct r820t_priv *priv, if (rc < 0) return rc; - rc = r820_read(priv, 0x00, data, sizeof(data)); + rc = r820t_read(priv, 0x00, data, sizeof(data)); if (rc < 0) return rc; @@ -1349,7 +1349,7 @@ static int r820t_xtal_check(struct r820t_priv *priv) msleep(5); - rc = r820_read(priv, 0x00, data, sizeof(data)); + rc = r820t_read(priv, 0x00, data, sizeof(data)); if (rc < 0) return rc; if ((!data[2]) & 0x40) @@ -1621,7 +1621,7 @@ struct dvb_frontend *r820t_attach(struct dvb_frontend *fe, fe->ops.i2c_gate_ctrl(fe, 1); /* check if the tuner is there */ - rc = r820_read(priv, 0x00, data, sizeof(data)); + rc = r820t_read(priv, 0x00, data, sizeof(data)); if (rc < 0) goto err; -- cgit v1.2.3 From 9cc2570a1dd74c22b4644b325257cf92d4cdb031 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 10 Apr 2013 15:48:02 -0300 Subject: [media] r820t: use usleep_range() Instead of using msleep(), use sleep_range(), as it provides a closer sleep time. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index e9367d896a07..279be4f78e7a 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -657,7 +657,7 @@ static int r820t_set_pll(struct r820t_priv *priv, u32 freq) * FIXME: Rafael chips R620D, R828D and R828 seems to * need 20 ms for analog TV */ - msleep(10); + usleep_range(10000, 11000); /* Check if PLL has locked */ rc = r820t_read(priv, 0x00, data, 3); @@ -1007,7 +1007,7 @@ static int r820t_set_tv_standard(struct r820t_priv *priv, rc = r820t_write_reg_mask(priv, 0x1d, 0x00, 0x38); if (rc < 0) return rc; - msleep(1); + usleep_range(1000, 2000); } priv->int_freq = if_khz * 1000; @@ -1049,7 +1049,7 @@ static int r820t_set_tv_standard(struct r820t_priv *priv, if (rc < 0) return rc; - msleep(1); + usleep_range(1000, 2000); /* Stop Trigger */ rc = r820t_write_reg_mask(priv, 0x0b, 0x00, 0x10); @@ -1347,7 +1347,7 @@ static int r820t_xtal_check(struct r820t_priv *priv) if (rc < 0) return rc; - msleep(5); + usleep_range(5000, 6000); rc = r820t_read(priv, 0x00, data, sizeof(data)); if (rc < 0) -- cgit v1.2.3 From d75d538899da00bdf8f152c65a99eda1ab59daa3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 10 Apr 2013 15:54:46 -0300 Subject: [media] r820t: proper initialize the PLL register The rtl-sdr library, from where this driver was initially based, doesn't use half PLL clock, but this is used on the Realtek Kernel driver. So, also do the same here. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 43 ++++++++++++++++++++++++++++--------------- drivers/media/tuners/r820t.h | 3 +++ 2 files changed, 31 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 279be4f78e7a..07d032350c1b 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -522,10 +522,12 @@ static int r820t_set_mux(struct r820t_priv *priv, u32 freq) return rc; } -static int r820t_set_pll(struct r820t_priv *priv, u32 freq) +static int r820t_set_pll(struct r820t_priv *priv, enum v4l2_tuner_type type, + u32 freq) { u64 tmp64, vco_freq; int rc, i; + unsigned sleep_time = 10000; u32 vco_fra; /* VCO contribution by SDM (kHz) */ u32 vco_min = 1770000; u32 vco_max = vco_min * 2; @@ -535,17 +537,34 @@ static int r820t_set_pll(struct r820t_priv *priv, u32 freq) u8 mix_div = 2; u8 div_buf = 0; u8 div_num = 0; + u8 refdiv2 = 0; u8 ni, si, nint, vco_fine_tune, val; u8 data[5]; - freq = freq / 1000; /* Frequency in kHz */ - + /* Frequency in kHz */ + freq = freq / 1000; pll_ref = priv->cfg->xtal / 1000; - tuner_dbg("set r820t pll for frequency %d kHz = %d\n", freq, pll_ref); + if ((priv->cfg->rafael_chip == CHIP_R620D) || + (priv->cfg->rafael_chip == CHIP_R828D) || + (priv->cfg->rafael_chip == CHIP_R828)) { + /* ref set refdiv2, reffreq = Xtal/2 on ATV application */ + if (type != V4L2_TUNER_DIGITAL_TV) { + pll_ref /= 2; + refdiv2 = 0x10; + sleep_time = 20000; + } + } else { + if (priv->cfg->xtal > 24000000) { + pll_ref /= 2; + refdiv2 = 0x10; + } + } - /* FIXME: this seems to be a hack - probably it can be removed */ - rc = r820t_write_reg_mask(priv, 0x10, 0x00, 0x00); + tuner_dbg("set r820t pll for frequency %d kHz = %d%s\n", + freq, pll_ref, refdiv2 ? " / 2" : ""); + + rc = r820t_write_reg_mask(priv, 0x10, refdiv2, 0x10); if (rc < 0) return rc; @@ -598,8 +617,6 @@ static int r820t_set_pll(struct r820t_priv *priv, u32 freq) do_div(tmp64, 1000); vco_fra = (u16)(tmp64); - pll_ref /= 1000; - /* boundary spur prevention */ if (vco_fra < pll_ref / 64) { vco_fra = 0; @@ -653,11 +670,7 @@ static int r820t_set_pll(struct r820t_priv *priv, u32 freq) return rc; for (i = 0; i < 2; i++) { - /* - * FIXME: Rafael chips R620D, R828D and R828 seems to - * need 20 ms for analog TV - */ - usleep_range(10000, 11000); + usleep_range(sleep_time, sleep_time + 1000); /* Check if PLL has locked */ rc = r820t_read(priv, 0x00, data, 3); @@ -1040,7 +1053,7 @@ static int r820t_set_tv_standard(struct r820t_priv *priv, if (rc < 0) return rc; - rc = r820t_set_pll(priv, filt_cal_lo); + rc = r820t_set_pll(priv, type, filt_cal_lo); if (rc < 0 || !priv->has_lock) return rc; @@ -1244,7 +1257,7 @@ static int generic_set_freq(struct dvb_frontend *fe, if (rc < 0) goto err; - rc = r820t_set_pll(priv, lo_freq); + rc = r820t_set_pll(priv, type, lo_freq); if (rc < 0 || !priv->has_lock) goto err; diff --git a/drivers/media/tuners/r820t.h b/drivers/media/tuners/r820t.h index 949575a41d49..4c0823b21693 100644 --- a/drivers/media/tuners/r820t.h +++ b/drivers/media/tuners/r820t.h @@ -26,6 +26,9 @@ enum r820t_chip { CHIP_R820T, + CHIP_R620D, + CHIP_R828D, + CHIP_R828, CHIP_R828S, CHIP_R820C, }; -- cgit v1.2.3 From 25cf4d462abd6d78d224b564de82dcdab7973673 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 10 Apr 2013 15:55:48 -0300 Subject: [media] r820t: add IMR calibrate code This code seems to calibrate I/Q phase and gain during the device initialization. This is done only once, and it doesn't seem to be needed to happen after resuming. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 702 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 681 insertions(+), 21 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 07d032350c1b..fa2e9ae48c98 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -47,6 +47,8 @@ */ #define REG_SHADOW_START 5 #define NUM_REGS 27 +#define NUM_IMR 5 +#define IMR_TRIAL 9 #define VER_NUM 49 @@ -66,6 +68,12 @@ enum xtal_cap_value { XTAL_HIGH_CAP_0P }; +struct r820t_sect_type { + u8 phase_y; + u8 gain_x; + u16 value; +}; + struct r820t_priv { struct list_head hybrid_tuner_instance_list; const struct r820t_config *cfg; @@ -80,6 +88,8 @@ struct r820t_priv { u8 fil_cal_code; bool imr_done; + struct r820t_sect_type imr_data[NUM_IMR]; + /* Store current mode */ u32 delsys; enum v4l2_tuner_type type; @@ -459,7 +469,7 @@ static int r820t_set_mux(struct r820t_priv *priv, u32 freq) { const struct r820t_freq_range *range; int i, rc; - u8 val; + u8 val, reg08, reg09; /* Get the proper frequency range */ freq = freq / 1000000; @@ -507,17 +517,18 @@ static int r820t_set_mux(struct r820t_priv *priv, u32 freq) if (rc < 0) return rc; - /* - * FIXME: the original driver has a logic there with preserves - * gain/phase from registers 8 and 9 reading the data from the - * registers before writing, if "IMF done". That code was sort of - * commented there, as the flag is always false. - */ - rc = r820t_write_reg_mask(priv, 0x08, 0, 0x3f); + if (priv->imr_done) { + reg08 = priv->imr_data[range->imr_mem].gain_x; + reg09 = priv->imr_data[range->imr_mem].phase_y; + } else { + reg08 = 0; + reg09 = 0; + } + rc = r820t_write_reg_mask(priv, 0x08, reg08, 0x3f); if (rc < 0) return rc; - rc = r820t_write_reg_mask(priv, 0x09, 0, 0x3f); + rc = r820t_write_reg_mask(priv, 0x09, reg09, 0x3f); return rc; } @@ -1383,24 +1394,621 @@ static int r820t_xtal_check(struct r820t_priv *priv) return r820t_xtal_capacitor[i][1]; } -/* - * r820t frontend operations and tuner attach code - * - * All driver locks and i2c control are only in this part of the code - */ +static int r820t_imr_prepare(struct r820t_priv *priv) +{ + int rc; -static int r820t_init(struct dvb_frontend *fe) + /* Initialize the shadow registers */ + memcpy(priv->regs, r820t_init_array, sizeof(r820t_init_array)); + + /* lna off (air-in off) */ + rc = r820t_write_reg_mask(priv, 0x05, 0x20, 0x20); + if (rc < 0) + return rc; + + /* mixer gain mode = manual */ + rc = r820t_write_reg_mask(priv, 0x07, 0, 0x10); + if (rc < 0) + return rc; + + /* filter corner = lowest */ + rc = r820t_write_reg_mask(priv, 0x0a, 0x0f, 0x0f); + if (rc < 0) + return rc; + + /* filter bw=+2cap, hp=5M */ + rc = r820t_write_reg_mask(priv, 0x0b, 0x60, 0x6f); + if (rc < 0) + return rc; + + /* adc=on, vga code mode, gain = 26.5dB */ + rc = r820t_write_reg_mask(priv, 0x0c, 0x0b, 0x9f); + if (rc < 0) + return rc; + + /* ring clk = on */ + rc = r820t_write_reg_mask(priv, 0x0f, 0, 0x08); + if (rc < 0) + return rc; + + /* ring power = on */ + rc = r820t_write_reg_mask(priv, 0x18, 0x10, 0x10); + if (rc < 0) + return rc; + + /* from ring = ring pll in */ + rc = r820t_write_reg_mask(priv, 0x1c, 0x02, 0x02); + if (rc < 0) + return rc; + + /* sw_pdect = det3 */ + rc = r820t_write_reg_mask(priv, 0x1e, 0x80, 0x80); + if (rc < 0) + return rc; + + /* Set filt_3dB */ + rc = r820t_write_reg_mask(priv, 0x06, 0x20, 0x20); + + return rc; +} + +static int r820t_multi_read(struct r820t_priv *priv) +{ + int rc, i; + u8 data[2], min = 0, max = 255, sum = 0; + + usleep_range(5000, 6000); + + for (i = 0; i < 6; i++) { + rc = r820t_read(priv, 0x00, data, sizeof(data)); + if (rc < 0) + return rc; + + sum += data[1]; + + if (data[1] < min) + min = data[1]; + + if (data[1] > max) + max = data[1]; + } + rc = sum - max - min; + + return rc; +} + +static int r820t_imr_cross(struct r820t_priv *priv, + struct r820t_sect_type iq_point[3], + u8 *x_direct) +{ + struct r820t_sect_type cross[5]; /* (0,0)(0,Q-1)(0,I-1)(Q-1,0)(I-1,0) */ + struct r820t_sect_type tmp; + int i, rc; + u8 reg08, reg09; + + reg08 = r820t_read_cache_reg(priv, 8) & 0xc0; + reg09 = r820t_read_cache_reg(priv, 9) & 0xc0; + + tmp.gain_x = 0; + tmp.phase_y = 0; + tmp.value = 255; + + for (i = 0; i < 5; i++) { + switch (i) { + case 0: + cross[i].gain_x = reg08; + cross[i].phase_y = reg09; + break; + case 1: + cross[i].gain_x = reg08; /* 0 */ + cross[i].phase_y = reg09 + 1; /* Q-1 */ + break; + case 2: + cross[i].gain_x = reg08; /* 0 */ + cross[i].phase_y = (reg09 | 0x20) + 1; /* I-1 */ + break; + case 3: + cross[i].gain_x = reg08 + 1; /* Q-1 */ + cross[i].phase_y = reg09; + break; + default: + cross[i].gain_x = (reg08 | 0x20) + 1; /* I-1 */ + cross[i].phase_y = reg09; + } + + rc = r820t_write_reg(priv, 0x08, cross[i].gain_x); + if (rc < 0) + return rc; + + rc = r820t_write_reg(priv, 0x09, cross[i].phase_y); + if (rc < 0) + return rc; + + rc = r820t_multi_read(priv); + if (rc < 0) + return rc; + + cross[i].value = rc; + + if (cross[i].value < tmp.value) + memcpy(&tmp, &cross[i], sizeof(tmp)); + } + + if ((tmp.phase_y & 0x1f) == 1) { /* y-direction */ + *x_direct = 0; + + iq_point[0] = cross[0]; + iq_point[1] = cross[1]; + iq_point[2] = cross[2]; + } else { /* (0,0) or x-direction */ + *x_direct = 1; + + iq_point[0] = cross[0]; + iq_point[1] = cross[3]; + iq_point[2] = cross[4]; + } + return 0; +} + +static void r820t_compre_cor(struct r820t_sect_type iq[3]) +{ + int i; + + for (i = 3; i > 0; i--) { + if (iq[0].value > iq[i - 1].value) + swap(iq[0], iq[i - 1]); + } +} + +static int r820t_compre_step(struct r820t_priv *priv, + struct r820t_sect_type iq[3], u8 reg) +{ + int rc; + struct r820t_sect_type tmp; + + /* + * Purpose: if (Gain<9 or Phase<9), Gain+1 or Phase+1 and compare + * with min value: + * new < min => update to min and continue + * new > min => Exit + */ + + /* min value already saved in iq[0] */ + tmp.phase_y = iq[0].phase_y; + tmp.gain_x = iq[0].gain_x; + + while (((tmp.gain_x & 0x1f) < IMR_TRIAL) && + ((tmp.phase_y & 0x1f) < IMR_TRIAL)) { + if (reg == 0x08) + tmp.gain_x++; + else + tmp.phase_y++; + + rc = r820t_write_reg(priv, 0x08, tmp.gain_x); + if (rc < 0) + return rc; + + rc = r820t_write_reg(priv, 0x09, tmp.phase_y); + if (rc < 0) + return rc; + + rc = r820t_multi_read(priv); + if (rc < 0) + return rc; + tmp.value = rc; + + if (tmp.value <= iq[0].value) { + iq[0].gain_x = tmp.gain_x; + iq[0].phase_y = tmp.phase_y; + iq[0].value = tmp.value; + } else { + return 0; + } + + } + + return 0; +} + +static int r820t_iq_tree(struct r820t_priv *priv, + struct r820t_sect_type iq[3], + u8 fix_val, u8 var_val, u8 fix_reg) +{ + int rc, i; + u8 tmp, var_reg; + + /* + * record IMC results by input gain/phase location then adjust + * gain or phase positive 1 step and negtive 1 step, + * both record results + */ + + if (fix_reg == 0x08) + var_reg = 0x09; + else + var_reg = 0x08; + + for (i = 0; i < 3; i++) { + rc = r820t_write_reg(priv, fix_reg, fix_val); + if (rc < 0) + return rc; + + rc = r820t_write_reg(priv, var_reg, var_val); + if (rc < 0) + return rc; + + rc = r820t_multi_read(priv); + if (rc < 0) + return rc; + iq[i].value = rc; + + if (fix_reg == 0x08) { + iq[i].gain_x = fix_val; + iq[i].phase_y = var_val; + } else { + iq[i].phase_y = fix_val; + iq[i].gain_x = var_val; + } + + if (i == 0) { /* try right-side point */ + var_val++; + } else if (i == 1) { /* try left-side point */ + /* if absolute location is 1, change I/Q direction */ + if ((var_val & 0x1f) < 0x02) { + tmp = 2 - (var_val & 0x1f); + + /* b[5]:I/Q selection. 0:Q-path, 1:I-path */ + if (var_val & 0x20) { + var_val &= 0xc0; + var_val |= tmp; + } else { + var_val |= 0x20 | tmp; + } + } else { + var_val -= 2; + } + } + } + + return 0; +} + +static int r820t_section(struct r820t_priv *priv, + struct r820t_sect_type *iq_point) +{ + int rc; + struct r820t_sect_type compare_iq[3], compare_bet[3]; + + /* Try X-1 column and save min result to compare_bet[0] */ + if (!(iq_point->gain_x & 0x1f)) + compare_iq[0].gain_x = ((iq_point->gain_x) & 0xdf) + 1; /* Q-path, Gain=1 */ + else + compare_iq[0].gain_x = iq_point->gain_x - 1; /* left point */ + compare_iq[0].phase_y = iq_point->phase_y; + + /* y-direction */ + rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, + compare_iq[0].phase_y, 0x08); + if (rc < 0) + return rc; + + r820t_compre_cor(compare_iq); + + compare_bet[0] = compare_iq[0]; + + /* Try X column and save min result to compare_bet[1] */ + compare_iq[0].gain_x = iq_point->gain_x; + compare_iq[0].phase_y = iq_point->phase_y; + + rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, + compare_iq[0].phase_y, 0x08); + if (rc < 0) + return rc; + + r820t_compre_cor(compare_iq); + + compare_bet[1] = compare_iq[0]; + + /* Try X+1 column and save min result to compare_bet[2] */ + if ((iq_point->gain_x & 0x1f) == 0x00) + compare_iq[0].gain_x = ((iq_point->gain_x) | 0x20) + 1; /* I-path, Gain=1 */ + else + compare_iq[0].gain_x = iq_point->gain_x + 1; + compare_iq[0].phase_y = iq_point->phase_y; + + rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, + compare_iq[0].phase_y, 0x08); + if (rc < 0) + return rc; + + r820t_compre_cor(compare_iq); + + compare_bet[2] = compare_iq[0]; + + r820t_compre_cor(compare_bet); + + *iq_point = compare_bet[0]; + + return 0; +} + +static int r820t_vga_adjust(struct r820t_priv *priv) +{ + int rc; + u8 vga_count; + + /* increase vga power to let image significant */ + for (vga_count = 12; vga_count < 16; vga_count++) { + rc = r820t_write_reg_mask(priv, 0x0c, vga_count, 0x0f); + if (rc < 0) + return rc; + + usleep_range(10000, 11000); + + rc = r820t_multi_read(priv); + if (rc < 0) + return rc; + + if (rc > 40 * 4) + break; + } + + return 0; +} + +static int r820t_iq(struct r820t_priv *priv, struct r820t_sect_type *iq_pont) +{ + struct r820t_sect_type compare_iq[3]; + int rc; + u8 x_direction = 0; /* 1:x, 0:y */ + u8 dir_reg, other_reg; + + r820t_vga_adjust(priv); + + rc = r820t_imr_cross(priv, compare_iq, &x_direction); + if (rc < 0) + return rc; + + if (x_direction == 1) { + dir_reg = 0x08; + other_reg = 0x09; + } else { + dir_reg = 0x09; + other_reg = 0x08; + } + + /* compare and find min of 3 points. determine i/q direction */ + r820t_compre_cor(compare_iq); + + /* increase step to find min value of this direction */ + rc = r820t_compre_step(priv, compare_iq, dir_reg); + if (rc < 0) + return rc; + + /* the other direction */ + rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, + compare_iq[0].phase_y, dir_reg); + if (rc < 0) + return rc; + + /* compare and find min of 3 points. determine i/q direction */ + r820t_compre_cor(compare_iq); + + /* increase step to find min value on this direction */ + rc = r820t_compre_step(priv, compare_iq, other_reg); + if (rc < 0) + return rc; + + /* check 3 points again */ + rc = r820t_iq_tree(priv, compare_iq, compare_iq[0].gain_x, + compare_iq[0].phase_y, other_reg); + if (rc < 0) + return rc; + + r820t_compre_cor(compare_iq); + + /* section-9 check */ + rc = r820t_section(priv, compare_iq); + + *iq_pont = compare_iq[0]; + + /* reset gain/phase control setting */ + rc = r820t_write_reg_mask(priv, 0x08, 0, 0x3f); + if (rc < 0) + return rc; + + rc = r820t_write_reg_mask(priv, 0x09, 0, 0x3f); + + return rc; +} + +static int r820t_f_imr(struct r820t_priv *priv, struct r820t_sect_type *iq_pont) +{ + int rc; + + r820t_vga_adjust(priv); + + /* + * search surrounding points from previous point + * try (x-1), (x), (x+1) columns, and find min IMR result point + */ + rc = r820t_section(priv, iq_pont); + if (rc < 0) + return rc; + + return 0; +} + +static int r820t_imr(struct r820t_priv *priv, unsigned imr_mem, bool im_flag) +{ + struct r820t_sect_type imr_point; + int rc; + u32 ring_vco, ring_freq, ring_ref; + u8 n_ring, n; + int reg18, reg19, reg1f; + + if (priv->cfg->xtal > 24000000) + ring_ref = priv->cfg->xtal / 2; + else + ring_ref = priv->cfg->xtal; + + for (n = 0; n < 16; n++) { + if ((16 + n) * 8 * ring_ref >= 3100000) { + n_ring = n; + break; + } + + /* n_ring not found */ + if (n == 15) + n_ring = n; + } + + reg18 = r820t_read_cache_reg(priv, 0x18); + reg19 = r820t_read_cache_reg(priv, 0x19); + reg1f = r820t_read_cache_reg(priv, 0x1f); + + reg18 &= 0xf0; /* set ring[3:0] */ + reg18 |= n_ring; + + ring_vco = (16 + n_ring) * 8 * ring_ref; + + reg18 &= 0xdf; /* clear ring_se23 */ + reg19 &= 0xfc; /* clear ring_seldiv */ + reg1f &= 0xfc; /* clear ring_att */ + + switch (imr_mem) { + case 0: + ring_freq = ring_vco / 48; + reg18 |= 0x20; /* ring_se23 = 1 */ + reg19 |= 0x03; /* ring_seldiv = 3 */ + reg1f |= 0x02; /* ring_att 10 */ + break; + case 1: + ring_freq = ring_vco / 16; + reg18 |= 0x00; /* ring_se23 = 0 */ + reg19 |= 0x02; /* ring_seldiv = 2 */ + reg1f |= 0x00; /* pw_ring 00 */ + break; + case 2: + ring_freq = ring_vco / 8; + reg18 |= 0x00; /* ring_se23 = 0 */ + reg19 |= 0x01; /* ring_seldiv = 1 */ + reg1f |= 0x03; /* pw_ring 11 */ + break; + case 3: + ring_freq = ring_vco / 6; + reg18 |= 0x20; /* ring_se23 = 1 */ + reg19 |= 0x00; /* ring_seldiv = 0 */ + reg1f |= 0x03; /* pw_ring 11 */ + break; + case 4: + ring_freq = ring_vco / 4; + reg18 |= 0x00; /* ring_se23 = 0 */ + reg19 |= 0x00; /* ring_seldiv = 0 */ + reg1f |= 0x01; /* pw_ring 01 */ + break; + default: + ring_freq = ring_vco / 4; + reg18 |= 0x00; /* ring_se23 = 0 */ + reg19 |= 0x00; /* ring_seldiv = 0 */ + reg1f |= 0x01; /* pw_ring 01 */ + break; + } + + + /* write pw_ring, n_ring, ringdiv2 registers */ + + /* n_ring, ring_se23 */ + rc = r820t_write_reg(priv, 0x18, reg18); + if (rc < 0) + return rc; + + /* ring_sediv */ + rc = r820t_write_reg(priv, 0x19, reg19); + if (rc < 0) + return rc; + + /* pw_ring */ + rc = r820t_write_reg(priv, 0x1f, reg1f); + if (rc < 0) + return rc; + + /* mux input freq ~ rf_in freq */ + rc = r820t_set_mux(priv, (ring_freq - 5300) * 1000); + if (rc < 0) + return rc; + + rc = r820t_set_pll(priv, V4L2_TUNER_DIGITAL_TV, + (ring_freq - 5300) * 1000); + if (!priv->has_lock) + rc = -EINVAL; + if (rc < 0) + return rc; + + if (im_flag) { + rc = r820t_iq(priv, &imr_point); + } else { + imr_point.gain_x = priv->imr_data[3].gain_x; + imr_point.phase_y = priv->imr_data[3].phase_y; + imr_point.value = priv->imr_data[3].value; + + rc = r820t_f_imr(priv, &imr_point); + } + if (rc < 0) + return rc; + + /* save IMR value */ + switch (imr_mem) { + case 0: + priv->imr_data[0].gain_x = imr_point.gain_x; + priv->imr_data[0].phase_y = imr_point.phase_y; + priv->imr_data[0].value = imr_point.value; + break; + case 1: + priv->imr_data[1].gain_x = imr_point.gain_x; + priv->imr_data[1].phase_y = imr_point.phase_y; + priv->imr_data[1].value = imr_point.value; + break; + case 2: + priv->imr_data[2].gain_x = imr_point.gain_x; + priv->imr_data[2].phase_y = imr_point.phase_y; + priv->imr_data[2].value = imr_point.value; + break; + case 3: + priv->imr_data[3].gain_x = imr_point.gain_x; + priv->imr_data[3].phase_y = imr_point.phase_y; + priv->imr_data[3].value = imr_point.value; + break; + case 4: + priv->imr_data[4].gain_x = imr_point.gain_x; + priv->imr_data[4].phase_y = imr_point.phase_y; + priv->imr_data[4].value = imr_point.value; + break; + default: + priv->imr_data[4].gain_x = imr_point.gain_x; + priv->imr_data[4].phase_y = imr_point.phase_y; + priv->imr_data[4].value = imr_point.value; + break; + } + + return 0; +} + +static int r820t_imr_callibrate(struct r820t_priv *priv) { - struct r820t_priv *priv = fe->tuner_priv; int rc, i; int xtal_cap = 0; - tuner_dbg("%s:\n", __func__); + if (priv->imr_done) + return 0; - mutex_lock(&priv->lock); - if (fe->ops.i2c_gate_ctrl) - fe->ops.i2c_gate_ctrl(fe, 1); + /* Initialize registers */ + rc = r820t_write(priv, 0x05, + r820t_init_array, sizeof(r820t_init_array)); + if (rc < 0) + return rc; + /* Detect Xtal capacitance */ if ((priv->cfg->rafael_chip == CHIP_R820T) || (priv->cfg->rafael_chip == CHIP_R828S) || (priv->cfg->rafael_chip == CHIP_R820C)) { @@ -1409,7 +2017,7 @@ static int r820t_init(struct dvb_frontend *fe) for (i = 0; i < 3; i++) { rc = r820t_xtal_check(priv); if (rc < 0) - goto err; + return rc; if (!i || rc > xtal_cap) xtal_cap = rc; } @@ -1419,6 +2027,58 @@ static int r820t_init(struct dvb_frontend *fe) /* Initialize registers */ rc = r820t_write(priv, 0x05, r820t_init_array, sizeof(r820t_init_array)); + if (rc < 0) + return rc; + + rc = r820t_imr_prepare(priv); + if (rc < 0) + return rc; + + rc = r820t_imr(priv, 3, true); + if (rc < 0) + return rc; + rc = r820t_imr(priv, 1, false); + if (rc < 0) + return rc; + rc = r820t_imr(priv, 0, false); + if (rc < 0) + return rc; + rc = r820t_imr(priv, 2, false); + if (rc < 0) + return rc; + rc = r820t_imr(priv, 4, false); + if (rc < 0) + return rc; + + priv->imr_done = true; + + return 0; +} + +/* + * r820t frontend operations and tuner attach code + * + * All driver locks and i2c control are only in this part of the code + */ + +static int r820t_init(struct dvb_frontend *fe) +{ + struct r820t_priv *priv = fe->tuner_priv; + int rc; + + tuner_dbg("%s:\n", __func__); + + mutex_lock(&priv->lock); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + rc = r820t_imr_callibrate(priv); + if (rc < 0) + goto err; + + /* Initialize registers */ + rc = r820t_write(priv, 0x05, + r820t_init_array, sizeof(r820t_init_array)); err: if (fe->ops.i2c_gate_ctrl) -- cgit v1.2.3 From 6596e88043e2c55d934f43701c3ca9860f009b06 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 10 Apr 2013 18:35:17 -0300 Subject: [media] r820t: add a commented code for GPIO Add the code to set the GPIO for this tuner. This code is currently unused, so it is kept there only for completeness. With this patch there are just two things that got left from the original driver: - At standby, there's another mode, not used by rtl2832u. Not sure if it might be needed in the future, but I suspect it is not used at all; - There is a "fast tune" mode. As nor DVB or V4L API supports it, it seems an overkill to implement it. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index fa2e9ae48c98..0125de897c8d 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -2055,6 +2055,14 @@ static int r820t_imr_callibrate(struct r820t_priv *priv) return 0; } +#if 0 +/* Not used, for now */ +static int r820t_gpio(struct r820t_priv *priv, bool enable) +{ + return r820t_write_reg_mask(priv, 0x0f, enable ? 1 : 0, 0x01); +} +#endif + /* * r820t frontend operations and tuner attach code * -- cgit v1.2.3 From 52775fd5b599c79e9a4152f75a6426bf376198dc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 11 Apr 2013 10:59:12 -0300 Subject: [media] r820t: Allow disabling IMR callibration The rtl-sdr library disabled IMR callibration. While I'm not sure yet why, it could be a good idea to add a modprobe parameter here, to allow to also disable it. There are two rationale behind it: - It helps to compare USB dumps between rtl-sdr and the Kernel module; - If rtl-sdr disabled it, perhaps there's a good reason (e. g. it might not be actually working, or it might be causing some trouble). For both cases, it seems useful to add a modprobe parameter to allow testing the device with both configurations. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 0125de897c8d..2e6a690ffb1a 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -56,6 +56,11 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable verbose debug messages"); +static int no_imr_cal; +module_param(no_imr_cal, int, 0444); +MODULE_PARM_DESC(no_imr_cal, "Disable IMR calibration at module init"); + + /* * enums and structures */ @@ -87,7 +92,8 @@ struct r820t_priv { u32 int_freq; u8 fil_cal_code; bool imr_done; - + bool has_lock; + bool init_done; struct r820t_sect_type imr_data[NUM_IMR]; /* Store current mode */ @@ -95,8 +101,6 @@ struct r820t_priv { enum v4l2_tuner_type type; v4l2_std_id std; u32 bw; /* in MHz */ - - bool has_lock; }; struct r820t_freq_range { @@ -1999,7 +2003,7 @@ static int r820t_imr_callibrate(struct r820t_priv *priv) int rc, i; int xtal_cap = 0; - if (priv->imr_done) + if (priv->init_done) return 0; /* Initialize registers */ @@ -2024,6 +2028,16 @@ static int r820t_imr_callibrate(struct r820t_priv *priv) priv->xtal_cap_sel = xtal_cap; } + /* + * Disables IMR callibration. That emulates the same behaviour + * as what is done by rtl-sdr userspace library. Useful for testing + */ + if (no_imr_cal) { + priv->init_done = true; + + return 0; + } + /* Initialize registers */ rc = r820t_write(priv, 0x05, r820t_init_array, sizeof(r820t_init_array)); @@ -2050,6 +2064,7 @@ static int r820t_imr_callibrate(struct r820t_priv *priv) if (rc < 0) return rc; + priv->init_done = true; priv->imr_done = true; return 0; -- cgit v1.2.3 From 4176e7ea8885a3cb3f5bbbf28480b421ef9b8f47 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 11 Apr 2013 13:22:21 -0300 Subject: [media] r820t: avoid rewrite all regs when not needed Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 2e6a690ffb1a..fc660f27edb3 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -2006,18 +2006,17 @@ static int r820t_imr_callibrate(struct r820t_priv *priv) if (priv->init_done) return 0; - /* Initialize registers */ - rc = r820t_write(priv, 0x05, - r820t_init_array, sizeof(r820t_init_array)); - if (rc < 0) - return rc; - /* Detect Xtal capacitance */ if ((priv->cfg->rafael_chip == CHIP_R820T) || (priv->cfg->rafael_chip == CHIP_R828S) || (priv->cfg->rafael_chip == CHIP_R820C)) { priv->xtal_cap_sel = XTAL_HIGH_CAP_0P; } else { + /* Initialize registers */ + rc = r820t_write(priv, 0x05, + r820t_init_array, sizeof(r820t_init_array)); + if (rc < 0) + return rc; for (i = 0; i < 3; i++) { rc = r820t_xtal_check(priv); if (rc < 0) -- cgit v1.2.3 From 064fd169c508ce20e35babdd82946dab7219ccc5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 11 Apr 2013 13:25:10 -0300 Subject: [media] r820t: Don't put it in standby if not initialized yet r820t_standby() can be called before r820t_init(). If that happens, just do nothing. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index fc660f27edb3..b679a3f1fb7a 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -1298,6 +1298,10 @@ static int r820t_standby(struct r820t_priv *priv) { int rc; + /* If device was not initialized yet, don't need to standby */ + if (!priv->init_done) + return 0; + rc = r820t_write_reg(priv, 0x06, 0xb1); if (rc < 0) return rc; -- cgit v1.2.3 From c0c6ed8d0479d47949e2345510b8fc8af41f7ed2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 11 Apr 2013 15:04:54 -0300 Subject: [media] r820t: fix PLL calculus There are a few errors at the PLL calculus, causing the device to use wrong values. While here, change the calculus to use 32 bits, as there's no need for 64 bits there. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index b679a3f1fb7a..f5a5fb03dfd5 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -36,7 +36,6 @@ #include #include #include -#include #include "tuner-i2c.h" #include "r820t.h" @@ -540,7 +539,7 @@ static int r820t_set_mux(struct r820t_priv *priv, u32 freq) static int r820t_set_pll(struct r820t_priv *priv, enum v4l2_tuner_type type, u32 freq) { - u64 tmp64, vco_freq; + u32 vco_freq; int rc, i; unsigned sleep_time = 10000; u32 vco_fra; /* VCO contribution by SDM (kHz) */ @@ -576,9 +575,6 @@ static int r820t_set_pll(struct r820t_priv *priv, enum v4l2_tuner_type type, } } - tuner_dbg("set r820t pll for frequency %d kHz = %d%s\n", - freq, pll_ref, refdiv2 ? " / 2" : ""); - rc = r820t_write_reg_mask(priv, 0x10, refdiv2, 0x10); if (rc < 0) return rc; @@ -622,15 +618,9 @@ static int r820t_set_pll(struct r820t_priv *priv, enum v4l2_tuner_type type, if (rc < 0) return rc; - vco_freq = (u64)(freq * (u64)mix_div); - - tmp64 = vco_freq; - do_div(tmp64, 2 * pll_ref); - nint = (u8)tmp64; - - tmp64 = vco_freq - ((u64)2) * pll_ref * nint; - do_div(tmp64, 1000); - vco_fra = (u16)(tmp64); + vco_freq = freq * mix_div; + nint = vco_freq / (2 * pll_ref); + vco_fra = vco_freq - 2 * pll_ref * nint; /* boundary spur prevention */ if (vco_fra < pll_ref / 64) { @@ -677,10 +667,13 @@ static int r820t_set_pll(struct r820t_priv *priv, enum v4l2_tuner_type type, n_sdm = n_sdm << 1; } - rc = r820t_write_reg_mask(priv, 0x16, sdm >> 8, 0x08); + tuner_dbg("freq %d kHz, pll ref %d%s, sdm=0x%04x\n", + freq, pll_ref, refdiv2 ? " / 2" : "", sdm); + + rc = r820t_write_reg(priv, 0x16, sdm >> 8); if (rc < 0) return rc; - rc = r820t_write_reg_mask(priv, 0x15, sdm & 0xff, 0x08); + rc = r820t_write_reg(priv, 0x15, sdm & 0xff); if (rc < 0) return rc; @@ -1068,7 +1061,7 @@ static int r820t_set_tv_standard(struct r820t_priv *priv, if (rc < 0) return rc; - rc = r820t_set_pll(priv, type, filt_cal_lo); + rc = r820t_set_pll(priv, type, filt_cal_lo * 1000); if (rc < 0 || !priv->has_lock) return rc; -- cgit v1.2.3 From f26588947b613925f11f5336320ff4d11b617a62 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 11 Apr 2013 15:47:53 -0300 Subject: [media] r820t: Fix hp_cor filter mask The bit mask was inverted here. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index f5a5fb03dfd5..c644e90a5907 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -1102,7 +1102,7 @@ static int r820t_set_tv_standard(struct r820t_priv *priv, return rc; /* Set BW, Filter_gain, & HP corner */ - rc = r820t_write_reg_mask(priv, 0x0b, hp_cor, 0x10); + rc = r820t_write_reg_mask(priv, 0x0b, hp_cor, 0xef); if (rc < 0) return rc; -- cgit v1.2.3 From b5e2b97b0ba474dd2abd672be320d1f1030800e8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 11 Apr 2013 15:55:27 -0300 Subject: [media] r820t: put it into automatic gain mode Currently, it is putting it on manual mode. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index c644e90a5907..e63ee9443fa6 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -1216,12 +1216,12 @@ static int r820t_set_gain_mode(struct r820t_priv *priv, return rc; } else { /* LNA */ - rc = r820t_write_reg_mask(priv, 0x05, 0, 0xef); + rc = r820t_write_reg_mask(priv, 0x05, 0, 0x10); if (rc < 0) return rc; /* Mixer */ - rc = r820t_write_reg_mask(priv, 0x07, 0x10, 0xef); + rc = r820t_write_reg_mask(priv, 0x07, 0x10, 0x10); if (rc < 0) return rc; @@ -1261,7 +1261,7 @@ static int generic_set_freq(struct dvb_frontend *fe, if (rc < 0) goto err; - rc = r820t_set_gain_mode(priv, true, 0); + rc = r820t_set_gain_mode(priv, false, 0); if (rc < 0) goto err; -- cgit v1.2.3 From c8832e8f4293b1c9fce92a92e2506572f5b11775 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 15 Apr 2013 19:44:39 -0300 Subject: [media] rtl2832: Fix IF calculus Spectrum is inverted. So, we need to invert it when calculating the value for the IF register Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/dvb-frontends/rtl2832.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 2f5a2b504932..facb84841518 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -396,7 +396,11 @@ static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq) pset_iffreq = if_freq % priv->cfg.xtal; pset_iffreq *= 0x400000; pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal); + pset_iffreq = -pset_iffreq; pset_iffreq = pset_iffreq & 0x3fffff; + dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d pset_iffreq=%08x\n", + __func__, if_freq, (unsigned)pset_iffreq); + ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin); if (ret) return ret; -- cgit v1.2.3 From dfdeac8108db5066e1adaf112adbe396ef27f0bc Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 11 Apr 2013 16:20:53 -0300 Subject: [media] r820t: disable auto gain/VGA setting On field tests, the auto gain routine is not working, nor it is used by the original driver. Let's comment it for now. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index e63ee9443fa6..8d9977919d96 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -1163,6 +1163,8 @@ static int r820t_read_gain(struct r820t_priv *priv) return ((data[3] & 0x0f) << 1) + ((data[3] & 0xf0) >> 4); } +#if 0 +/* FIXME: This routine requires more testing */ static int r820t_set_gain_mode(struct r820t_priv *priv, bool set_manual_gain, int gain) @@ -1233,7 +1235,7 @@ static int r820t_set_gain_mode(struct r820t_priv *priv, return 0; } - +#endif static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, @@ -1261,10 +1263,6 @@ static int generic_set_freq(struct dvb_frontend *fe, if (rc < 0) goto err; - rc = r820t_set_gain_mode(priv, false, 0); - if (rc < 0) - goto err; - rc = r820t_set_pll(priv, type, lo_freq); if (rc < 0 || !priv->has_lock) goto err; -- cgit v1.2.3 From 396f3659aa9decdb0acf82a36e59c20d656e19ed Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 11 Apr 2013 14:27:04 -0300 Subject: [media] r820t: Don't divide the IF by two The original Win driver doesn't do; rtl-sdr also disabled that piece of the code. Signed-off-by: Mauro Carvalho Chehab Tested-by: Antti Palosaari --- drivers/media/tuners/r820t.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 8d9977919d96..905a10615e52 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -559,6 +559,8 @@ static int r820t_set_pll(struct r820t_priv *priv, enum v4l2_tuner_type type, freq = freq / 1000; pll_ref = priv->cfg->xtal / 1000; +#if 0 + /* Doesn't exist on rtl-sdk, and on field tests, caused troubles */ if ((priv->cfg->rafael_chip == CHIP_R620D) || (priv->cfg->rafael_chip == CHIP_R828D) || (priv->cfg->rafael_chip == CHIP_R828)) { @@ -574,6 +576,7 @@ static int r820t_set_pll(struct r820t_priv *priv, enum v4l2_tuner_type type, refdiv2 = 0x10; } } +#endif rc = r820t_write_reg_mask(priv, 0x10, refdiv2, 0x10); if (rc < 0) -- cgit v1.2.3 From 82cd0b278fddc1c0bc7e187ff82fd0e273520233 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 17 Apr 2013 06:05:18 -0300 Subject: Revert "[media] v4l2: Add a V4L2 driver for SI476X MFD" As requested by Andrey Smirnov , revert this patch. This reverts commit 30bac9110455402fa8888740c6819dd3daa2666f. Conflicts: drivers/media/radio/Kconfig drivers/media/radio/radio-si476x.c Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/si476x.txt | 187 ---- drivers/media/radio/Kconfig | 17 - drivers/media/radio/Makefile | 1 - drivers/media/radio/radio-si476x.c | 1599 ---------------------------------- include/media/si476x.h | 426 --------- 5 files changed, 2230 deletions(-) delete mode 100644 Documentation/video4linux/si476x.txt delete mode 100644 drivers/media/radio/radio-si476x.c delete mode 100644 include/media/si476x.h (limited to 'drivers/media') diff --git a/Documentation/video4linux/si476x.txt b/Documentation/video4linux/si476x.txt deleted file mode 100644 index d1a08db2cbd9..000000000000 --- a/Documentation/video4linux/si476x.txt +++ /dev/null @@ -1,187 +0,0 @@ -SI476x Driver Readme ------------------------------------------------- - Copyright (C) 2013 Andrey Smirnov - -TODO for the driver ------------------------------- - -- According to the SiLabs' datasheet it is possible to update the - firmware of the radio chip in the run-time, thus bringing it to the - most recent version. Unfortunately I couldn't find any mentioning of - the said firmware update for the old chips that I tested the driver - against, so for chips like that the driver only exposes the old - functionality. - - -Parameters exposed over debugfs -------------------------------- -SI476x allow user to get multiple characteristics that can be very -useful for EoL testing/RF performance estimation, parameters that have -very little to do with V4L2 subsystem. Such parameters are exposed via -debugfs and can be accessed via regular file I/O operations. - -The drivers exposes following files: - -* /sys/kernel/debug//acf - This file contains ACF(Automatically Controlled Features) status - information. The contents of the file is binary data of the - following layout: - - Offset | Name | Description - ==================================================================== - 0x00 | blend_int | Flag, set when stereo separation has - | | crossed below the blend threshold - -------------------------------------------------------------------- - 0x01 | hblend_int | Flag, set when HiBlend cutoff - | | frequency is lower than threshold - -------------------------------------------------------------------- - 0x02 | hicut_int | Flag, set when HiCut cutoff - | | frequency is lower than threshold - -------------------------------------------------------------------- - 0x03 | chbw_int | Flag, set when channel filter - | | bandwidth is less than threshold - -------------------------------------------------------------------- - 0x04 | softmute_int | Flag indicating that softmute - | | attenuation has increased above - | | softmute threshold - -------------------------------------------------------------------- - 0x05 | smute | 0 - Audio is not soft muted - | | 1 - Audio is soft muted - -------------------------------------------------------------------- - 0x06 | smattn | Soft mute attenuation level in dB - -------------------------------------------------------------------- - 0x07 | chbw | Channel filter bandwidth in kHz - -------------------------------------------------------------------- - 0x08 | hicut | HiCut cutoff frequency in units of - | | 100Hz - -------------------------------------------------------------------- - 0x09 | hiblend | HiBlend cutoff frequency in units - | | of 100 Hz - -------------------------------------------------------------------- - 0x10 | pilot | 0 - Stereo pilot is not present - | | 1 - Stereo pilot is present - -------------------------------------------------------------------- - 0x11 | stblend | Stereo blend in % - -------------------------------------------------------------------- - - -* /sys/kernel/debug//rds_blckcnt - This file contains statistics about RDS receptions. It's binary data - has the following layout: - - Offset | Name | Description - ==================================================================== - 0x00 | expected | Number of expected RDS blocks - -------------------------------------------------------------------- - 0x02 | received | Number of received RDS blocks - -------------------------------------------------------------------- - 0x04 | uncorrectable | Number of uncorrectable RDS blocks - -------------------------------------------------------------------- - -* /sys/kernel/debug//agc - This file contains information about parameters pertaining to - AGC(Automatic Gain Control) - - The layout is: - Offset | Name | Description - ==================================================================== - 0x00 | mxhi | 0 - FM Mixer PD high threshold is - | | not tripped - | | 1 - FM Mixer PD high threshold is - | | tripped - -------------------------------------------------------------------- - 0x01 | mxlo | ditto for FM Mixer PD low - -------------------------------------------------------------------- - 0x02 | lnahi | ditto for FM LNA PD high - -------------------------------------------------------------------- - 0x03 | lnalo | ditto for FM LNA PD low - -------------------------------------------------------------------- - 0x04 | fmagc1 | FMAGC1 attenuator resistance - | | (see datasheet for more detail) - -------------------------------------------------------------------- - 0x05 | fmagc2 | ditto for FMAGC2 - -------------------------------------------------------------------- - 0x06 | pgagain | PGA gain in dB - -------------------------------------------------------------------- - 0x07 | fmwblang | FM/WB LNA Gain in dB - -------------------------------------------------------------------- - -* /sys/kernel/debug//rsq - This file contains information about parameters pertaining to - RSQ(Received Signal Quality) - - The layout is: - Offset | Name | Description - ==================================================================== - 0x00 | multhint | 0 - multipath value has not crossed - | | the Multipath high threshold - | | 1 - multipath value has crossed - | | the Multipath high threshold - -------------------------------------------------------------------- - 0x01 | multlint | ditto for Multipath low threshold - -------------------------------------------------------------------- - 0x02 | snrhint | 0 - received signal's SNR has not - | | crossed high threshold - | | 1 - received signal's SNR has - | | crossed high threshold - -------------------------------------------------------------------- - 0x03 | snrlint | ditto for low threshold - -------------------------------------------------------------------- - 0x04 | rssihint | ditto for RSSI high threshold - -------------------------------------------------------------------- - 0x05 | rssilint | ditto for RSSI low threshold - -------------------------------------------------------------------- - 0x06 | bltf | Flag indicating if seek command - | | reached/wrapped seek band limit - -------------------------------------------------------------------- - 0x07 | snr_ready | Indicates that SNR metrics is ready - -------------------------------------------------------------------- - 0x08 | rssiready | ditto for RSSI metrics - -------------------------------------------------------------------- - 0x09 | injside | 0 - Low-side injection is being used - | | 1 - High-side injection is used - -------------------------------------------------------------------- - 0x10 | afcrl | Flag indicating if AFC rails - -------------------------------------------------------------------- - 0x11 | valid | Flag indicating if channel is valid - -------------------------------------------------------------------- - 0x12 | readfreq | Current tuned frequency - -------------------------------------------------------------------- - 0x14 | freqoff | Singed frequency offset in units of - | | 2ppm - -------------------------------------------------------------------- - 0x15 | rssi | Signed value of RSSI in dBuV - -------------------------------------------------------------------- - 0x16 | snr | Signed RF SNR in dB - -------------------------------------------------------------------- - 0x17 | issi | Signed Image Strength Signal - | | indicator - -------------------------------------------------------------------- - 0x18 | lassi | Signed Low side adjacent Channel - | | Strength indicator - -------------------------------------------------------------------- - 0x19 | hassi | ditto fpr High side - -------------------------------------------------------------------- - 0x20 | mult | Multipath indicator - -------------------------------------------------------------------- - 0x21 | dev | Frequency deviation - -------------------------------------------------------------------- - 0x24 | assi | Adjascent channel SSI - -------------------------------------------------------------------- - 0x25 | usn | Ultrasonic noise indicator - -------------------------------------------------------------------- - 0x26 | pilotdev | Pilot deviation in units of 100 Hz - -------------------------------------------------------------------- - 0x27 | rdsdev | ditto for RDS - -------------------------------------------------------------------- - 0x28 | assidev | ditto for ASSI - -------------------------------------------------------------------- - 0x29 | strongdev | Frequency deviation - -------------------------------------------------------------------- - 0x30 | rdspi | RDS PI code - -------------------------------------------------------------------- - -* /sys/kernel/debug//rsq_primary - This file contains information about parameters pertaining to - RSQ(Received Signal Quality) for primary tuner only. Layout is as - the one above. diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index fef427e386c1..24e64a09884c 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -18,23 +18,6 @@ config RADIO_SI470X source "drivers/media/radio/si470x/Kconfig" -config RADIO_SI476X - tristate "Silicon Laboratories Si476x I2C FM Radio" - depends on I2C && VIDEO_V4L2 && SND && SND_SOC - select MFD_CORE - select MFD_SI476X_CORE - select SND_SOC_SI476X - ---help--- - Choose Y here if you have this FM radio chip. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux 2 API. Information on - this API and pointers to "v4l2" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-si476x. - config USB_MR800 tristate "AverMedia MR 800 USB FM radio support" depends on USB && VIDEO_V4L2 diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index 0dcdb320cfc7..303eaebdb85a 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o -obj-$(CONFIG_RADIO_SI476X) += radio-si476x.o obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_RADIO_SI470X) += si470x/ diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c deleted file mode 100644 index 9430c6a29937..000000000000 --- a/drivers/media/radio/radio-si476x.c +++ /dev/null @@ -1,1599 +0,0 @@ -/* - * drivers/media/radio/radio-si476x.c -- V4L2 driver for SI476X chips - * - * Copyright (C) 2012 Innovative Converged Devices(ICD) - * Copyright (C) 2013 Andrey Smirnov - * - * Author: Andrey Smirnov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define FM_FREQ_RANGE_LOW 64000000 -#define FM_FREQ_RANGE_HIGH 108000000 - -#define AM_FREQ_RANGE_LOW 520000 -#define AM_FREQ_RANGE_HIGH 30000000 - -#define PWRLINEFLTR (1 << 8) - -#define FREQ_MUL (10000000 / 625) - -#define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0b10000000 & (status)) - -#define DRIVER_NAME "si476x-radio" -#define DRIVER_CARD "SI476x AM/FM Receiver" - -enum si476x_freq_bands { - SI476X_BAND_FM, - SI476X_BAND_AM, -}; - -static const struct v4l2_frequency_band si476x_bands[] = { - [SI476X_BAND_FM] = { - .type = V4L2_TUNER_RADIO, - .index = SI476X_BAND_FM, - .capability = V4L2_TUNER_CAP_LOW - | V4L2_TUNER_CAP_STEREO - | V4L2_TUNER_CAP_RDS - | V4L2_TUNER_CAP_RDS_BLOCK_IO - | V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = 64 * FREQ_MUL, - .rangehigh = 108 * FREQ_MUL, - .modulation = V4L2_BAND_MODULATION_FM, - }, - [SI476X_BAND_AM] = { - .type = V4L2_TUNER_RADIO, - .index = SI476X_BAND_AM, - .capability = V4L2_TUNER_CAP_LOW - | V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = 0.52 * FREQ_MUL, - .rangehigh = 30 * FREQ_MUL, - .modulation = V4L2_BAND_MODULATION_AM, - }, -}; - -static inline bool si476x_radio_freq_is_inside_of_the_band(u32 freq, int band) -{ - return freq >= si476x_bands[band].rangelow && - freq <= si476x_bands[band].rangehigh; -} - -static inline bool si476x_radio_range_is_inside_of_the_band(u32 low, u32 high, - int band) -{ - return low >= si476x_bands[band].rangelow && - high <= si476x_bands[band].rangehigh; -} - -static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl); -static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl); - -enum phase_diversity_modes_idx { - SI476X_IDX_PHDIV_DISABLED, - SI476X_IDX_PHDIV_PRIMARY_COMBINING, - SI476X_IDX_PHDIV_PRIMARY_ANTENNA, - SI476X_IDX_PHDIV_SECONDARY_ANTENNA, - SI476X_IDX_PHDIV_SECONDARY_COMBINING, -}; - -static const char * const phase_diversity_modes[] = { - [SI476X_IDX_PHDIV_DISABLED] = "Disabled", - [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = "Primary with Secondary", - [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = "Primary Antenna", - [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = "Secondary Antenna", - [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = "Secondary with Primary", -}; - -static inline enum phase_diversity_modes_idx -si476x_phase_diversity_mode_to_idx(enum si476x_phase_diversity_mode mode) -{ - switch (mode) { - default: /* FALLTHROUGH */ - case SI476X_PHDIV_DISABLED: - return SI476X_IDX_PHDIV_DISABLED; - case SI476X_PHDIV_PRIMARY_COMBINING: - return SI476X_IDX_PHDIV_PRIMARY_COMBINING; - case SI476X_PHDIV_PRIMARY_ANTENNA: - return SI476X_IDX_PHDIV_PRIMARY_ANTENNA; - case SI476X_PHDIV_SECONDARY_ANTENNA: - return SI476X_IDX_PHDIV_SECONDARY_ANTENNA; - case SI476X_PHDIV_SECONDARY_COMBINING: - return SI476X_IDX_PHDIV_SECONDARY_COMBINING; - } -} - -static inline enum si476x_phase_diversity_mode -si476x_phase_diversity_idx_to_mode(enum phase_diversity_modes_idx idx) -{ - static const int idx_to_value[] = { - [SI476X_IDX_PHDIV_DISABLED] = SI476X_PHDIV_DISABLED, - [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = SI476X_PHDIV_PRIMARY_COMBINING, - [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = SI476X_PHDIV_PRIMARY_ANTENNA, - [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = SI476X_PHDIV_SECONDARY_ANTENNA, - [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = SI476X_PHDIV_SECONDARY_COMBINING, - }; - - return idx_to_value[idx]; -} - -static const struct v4l2_ctrl_ops si476x_ctrl_ops = { - .g_volatile_ctrl = si476x_radio_g_volatile_ctrl, - .s_ctrl = si476x_radio_s_ctrl, -}; - - -enum si476x_ctrl_idx { - SI476X_IDX_RSSI_THRESHOLD, - SI476X_IDX_SNR_THRESHOLD, - SI476X_IDX_MAX_TUNE_ERROR, - SI476X_IDX_HARMONICS_COUNT, - SI476X_IDX_DIVERSITY_MODE, - SI476X_IDX_INTERCHIP_LINK, -}; -static struct v4l2_ctrl_config si476x_ctrls[] = { - - /** - * SI476X during its station seeking(or tuning) process uses several - * parameters to detrmine if "the station" is valid: - * - * - Signal's SNR(in dBuV) must be lower than - * #V4L2_CID_SI476X_SNR_THRESHOLD - * - Signal's RSSI(in dBuV) must be greater than - * #V4L2_CID_SI476X_RSSI_THRESHOLD - * - Signal's frequency deviation(in units of 2ppm) must not be - * more than #V4L2_CID_SI476X_MAX_TUNE_ERROR - */ - [SI476X_IDX_RSSI_THRESHOLD] = { - .ops = &si476x_ctrl_ops, - .id = V4L2_CID_SI476X_RSSI_THRESHOLD, - .name = "Valid RSSI Threshold", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = -128, - .max = 127, - .step = 1, - }, - [SI476X_IDX_SNR_THRESHOLD] = { - .ops = &si476x_ctrl_ops, - .id = V4L2_CID_SI476X_SNR_THRESHOLD, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Valid SNR Threshold", - .min = -128, - .max = 127, - .step = 1, - }, - [SI476X_IDX_MAX_TUNE_ERROR] = { - .ops = &si476x_ctrl_ops, - .id = V4L2_CID_SI476X_MAX_TUNE_ERROR, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Max Tune Errors", - .min = 0, - .max = 126 * 2, - .step = 2, - }, - - /** - * #V4L2_CID_SI476X_HARMONICS_COUNT -- number of harmonics - * built-in power-line noise supression filter is to reject - * during AM-mode operation. - */ - [SI476X_IDX_HARMONICS_COUNT] = { - .ops = &si476x_ctrl_ops, - .id = V4L2_CID_SI476X_HARMONICS_COUNT, - .type = V4L2_CTRL_TYPE_INTEGER, - - .name = "Count of Harmonics to Reject", - .min = 0, - .max = 20, - .step = 1, - }, - - /** - * #V4L2_CID_SI476X_DIVERSITY_MODE -- configuration which - * two tuners working in diversity mode are to work in. - * - * - #SI476X_IDX_PHDIV_DISABLED diversity mode disabled - * - #SI476X_IDX_PHDIV_PRIMARY_COMBINING diversity mode is - * on, primary tuner's antenna is the main one. - * - #SI476X_IDX_PHDIV_PRIMARY_ANTENNA diversity mode is - * off, primary tuner's antenna is the main one. - * - #SI476X_IDX_PHDIV_SECONDARY_ANTENNA diversity mode is - * off, secondary tuner's antenna is the main one. - * - #SI476X_IDX_PHDIV_SECONDARY_COMBINING diversity mode is - * on, secondary tuner's antenna is the main one. - */ - [SI476X_IDX_DIVERSITY_MODE] = { - .ops = &si476x_ctrl_ops, - .id = V4L2_CID_SI476X_DIVERSITY_MODE, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Phase Diversity Mode", - .qmenu = phase_diversity_modes, - .min = 0, - .max = ARRAY_SIZE(phase_diversity_modes) - 1, - }, - - /** - * #V4L2_CID_SI476X_INTERCHIP_LINK -- inter-chip link in - * diversity mode indicator. Allows user to determine if two - * chips working in diversity mode have established a link - * between each other and if the system as a whole uses - * signals from both antennas to receive FM radio. - */ - [SI476X_IDX_INTERCHIP_LINK] = { - .ops = &si476x_ctrl_ops, - .id = V4L2_CID_SI476X_INTERCHIP_LINK, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, - .name = "Inter-Chip Link", - .min = 0, - .max = 1, - .step = 1, - }, -}; - -struct si476x_radio; - -/** - * struct si476x_radio_ops - vtable of tuner functions - * - * This table holds pointers to functions implementing particular - * operations depending on the mode in which the tuner chip was - * configured to start in. If the function is not supported - * corresponding element is set to #NULL. - * - * @tune_freq: Tune chip to a specific frequency - * @seek_start: Star station seeking - * @rsq_status: Get Recieved Signal Quality(RSQ) status - * @rds_blckcnt: Get recived RDS blocks count - * @phase_diversity: Change phase diversity mode of the tuner - * @phase_div_status: Get phase diversity mode status - * @acf_status: Get the status of Automatically Controlled - * Features(ACF) - * @agc_status: Get Automatic Gain Control(AGC) status - */ -struct si476x_radio_ops { - int (*tune_freq)(struct si476x_core *, struct si476x_tune_freq_args *); - int (*seek_start)(struct si476x_core *, bool, bool); - int (*rsq_status)(struct si476x_core *, struct si476x_rsq_status_args *, - struct si476x_rsq_status_report *); - int (*rds_blckcnt)(struct si476x_core *, bool, - struct si476x_rds_blockcount_report *); - - int (*phase_diversity)(struct si476x_core *, - enum si476x_phase_diversity_mode); - int (*phase_div_status)(struct si476x_core *); - int (*acf_status)(struct si476x_core *, - struct si476x_acf_status_report *); - int (*agc_status)(struct si476x_core *, - struct si476x_agc_status_report *); -}; - -/** - * struct si476x_radio - radio device - * - * @core: Pointer to underlying core device - * @videodev: Pointer to video device created by V4L2 subsystem - * @ops: Vtable of functions. See struct si476x_radio_ops for details - * @kref: Reference counter - * @core_lock: An r/w semaphore to brebvent the deletion of underlying - * core structure is the radio device is being used - */ -struct si476x_radio { - struct v4l2_device v4l2dev; - struct video_device videodev; - struct v4l2_ctrl_handler ctrl_handler; - - struct si476x_core *core; - /* This field should not be accesses unless core lock is held */ - const struct si476x_radio_ops *ops; - - struct dentry *debugfs; - u32 audmode; -}; - -static inline struct si476x_radio * -v4l2_dev_to_radio(struct v4l2_device *d) -{ - return container_of(d, struct si476x_radio, v4l2dev); -} - -static inline struct si476x_radio * -v4l2_ctrl_handler_to_radio(struct v4l2_ctrl_handler *d) -{ - return container_of(d, struct si476x_radio, ctrl_handler); -} - -/* - * si476x_vidioc_querycap - query device capabilities - */ -static int si476x_radio_querycap(struct file *file, void *priv, - struct v4l2_capability *capability) -{ - struct si476x_radio *radio = video_drvdata(file); - - strlcpy(capability->driver, radio->v4l2dev.name, - sizeof(capability->driver)); - strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); - snprintf(capability->bus_info, sizeof(capability->bus_info), - "platform:%s", radio->v4l2dev.name); - - capability->device_caps = V4L2_CAP_TUNER - | V4L2_CAP_RADIO - | V4L2_CAP_HW_FREQ_SEEK; - - si476x_core_lock(radio->core); - if (!si476x_core_is_a_secondary_tuner(radio->core)) - capability->device_caps |= V4L2_CAP_RDS_CAPTURE - | V4L2_CAP_READWRITE; - si476x_core_unlock(radio->core); - - capability->capabilities = capability->device_caps - | V4L2_CAP_DEVICE_CAPS; - return 0; -} - -static int si476x_radio_enum_freq_bands(struct file *file, void *priv, - struct v4l2_frequency_band *band) -{ - int err; - struct si476x_radio *radio = video_drvdata(file); - - if (band->tuner != 0) - return -EINVAL; - - switch (radio->core->chip_id) { - /* AM/FM tuners -- all bands are supported */ - case SI476X_CHIP_SI4761: - case SI476X_CHIP_SI4764: - if (band->index < ARRAY_SIZE(si476x_bands)) { - *band = si476x_bands[band->index]; - err = 0; - } else { - err = -EINVAL; - } - break; - /* FM companion tuner chips -- only FM bands are - * supported */ - case SI476X_CHIP_SI4768: - if (band->index == SI476X_BAND_FM) { - *band = si476x_bands[band->index]; - err = 0; - } else { - err = -EINVAL; - } - break; - default: - err = -EINVAL; - } - - return err; -} - -static int si476x_radio_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) -{ - int err; - struct si476x_rsq_status_report report; - struct si476x_radio *radio = video_drvdata(file); - - struct si476x_rsq_status_args args = { - .primary = false, - .rsqack = false, - .attune = false, - .cancel = false, - .stcack = false, - }; - - if (tuner->index != 0) - return -EINVAL; - - tuner->type = V4L2_TUNER_RADIO; - tuner->capability = V4L2_TUNER_CAP_LOW /* Measure frequencies - * in multiples of - * 62.5 Hz */ - | V4L2_TUNER_CAP_STEREO - | V4L2_TUNER_CAP_HWSEEK_BOUNDED - | V4L2_TUNER_CAP_HWSEEK_WRAP - | V4L2_TUNER_CAP_HWSEEK_PROG_LIM; - - si476x_core_lock(radio->core); - - if (si476x_core_is_a_secondary_tuner(radio->core)) { - strlcpy(tuner->name, "FM (secondary)", sizeof(tuner->name)); - tuner->rxsubchans = 0; - tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; - } else if (si476x_core_has_am(radio->core)) { - if (si476x_core_is_a_primary_tuner(radio->core)) - strlcpy(tuner->name, "AM/FM (primary)", - sizeof(tuner->name)); - else - strlcpy(tuner->name, "AM/FM", sizeof(tuner->name)); - - tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO - | V4L2_TUNER_SUB_RDS; - tuner->capability |= V4L2_TUNER_CAP_RDS - | V4L2_TUNER_CAP_RDS_BLOCK_IO - | V4L2_TUNER_CAP_FREQ_BANDS; - - tuner->rangelow = si476x_bands[SI476X_BAND_AM].rangelow; - } else { - strlcpy(tuner->name, "FM", sizeof(tuner->name)); - tuner->rxsubchans = V4L2_TUNER_SUB_RDS; - tuner->capability |= V4L2_TUNER_CAP_RDS - | V4L2_TUNER_CAP_RDS_BLOCK_IO - | V4L2_TUNER_CAP_FREQ_BANDS; - tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; - } - - tuner->audmode = radio->audmode; - - tuner->afc = 1; - tuner->rangehigh = si476x_bands[SI476X_BAND_FM].rangehigh; - - err = radio->ops->rsq_status(radio->core, - &args, &report); - if (err < 0) { - tuner->signal = 0; - } else { - /* - * tuner->signal value range: 0x0000 .. 0xFFFF, - * report.rssi: -128 .. 127 - */ - tuner->signal = (report.rssi + 128) * 257; - } - si476x_core_unlock(radio->core); - - return err; -} - -static int si476x_radio_s_tuner(struct file *file, void *priv, - const struct v4l2_tuner *tuner) -{ - struct si476x_radio *radio = video_drvdata(file); - - if (tuner->index != 0) - return -EINVAL; - - if (tuner->audmode == V4L2_TUNER_MODE_MONO || - tuner->audmode == V4L2_TUNER_MODE_STEREO) - radio->audmode = tuner->audmode; - else - radio->audmode = V4L2_TUNER_MODE_STEREO; - - return 0; -} - -static int si476x_radio_init_vtable(struct si476x_radio *radio, - enum si476x_func func) -{ - static const struct si476x_radio_ops fm_ops = { - .tune_freq = si476x_core_cmd_fm_tune_freq, - .seek_start = si476x_core_cmd_fm_seek_start, - .rsq_status = si476x_core_cmd_fm_rsq_status, - .rds_blckcnt = si476x_core_cmd_fm_rds_blockcount, - .phase_diversity = si476x_core_cmd_fm_phase_diversity, - .phase_div_status = si476x_core_cmd_fm_phase_div_status, - .acf_status = si476x_core_cmd_fm_acf_status, - .agc_status = si476x_core_cmd_agc_status, - }; - - static const struct si476x_radio_ops am_ops = { - .tune_freq = si476x_core_cmd_am_tune_freq, - .seek_start = si476x_core_cmd_am_seek_start, - .rsq_status = si476x_core_cmd_am_rsq_status, - .rds_blckcnt = NULL, - .phase_diversity = NULL, - .phase_div_status = NULL, - .acf_status = si476x_core_cmd_am_acf_status, - .agc_status = NULL, - }; - - switch (func) { - case SI476X_FUNC_FM_RECEIVER: - radio->ops = &fm_ops; - return 0; - - case SI476X_FUNC_AM_RECEIVER: - radio->ops = &am_ops; - return 0; - default: - WARN(1, "Unexpected tuner function value\n"); - return -EINVAL; - } -} - -static int si476x_radio_pretune(struct si476x_radio *radio, - enum si476x_func func) -{ - int retval; - - struct si476x_tune_freq_args args = { - .zifsr = false, - .hd = false, - .injside = SI476X_INJSIDE_AUTO, - .tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE, - .smoothmetrics = SI476X_SM_INITIALIZE_AUDIO, - .antcap = 0, - }; - - switch (func) { - case SI476X_FUNC_FM_RECEIVER: - args.freq = v4l2_to_si476x(radio->core, - 92 * FREQ_MUL); - retval = radio->ops->tune_freq(radio->core, &args); - break; - case SI476X_FUNC_AM_RECEIVER: - args.freq = v4l2_to_si476x(radio->core, - 0.6 * FREQ_MUL); - retval = radio->ops->tune_freq(radio->core, &args); - break; - default: - WARN(1, "Unexpected tuner function value\n"); - retval = -EINVAL; - } - - return retval; -} -static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio, - enum si476x_func func) -{ - int err; - - /* regcache_mark_dirty(radio->core->regmap); */ - err = regcache_sync_region(radio->core->regmap, - SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE, - SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT); - if (err < 0) - return err; - - err = regcache_sync_region(radio->core->regmap, - SI476X_PROP_AUDIO_DEEMPHASIS, - SI476X_PROP_AUDIO_PWR_LINE_FILTER); - if (err < 0) - return err; - - err = regcache_sync_region(radio->core->regmap, - SI476X_PROP_INT_CTL_ENABLE, - SI476X_PROP_INT_CTL_ENABLE); - if (err < 0) - return err; - - /* - * Is there any point in restoring SNR and the like - * when switching between AM/FM? - */ - err = regcache_sync_region(radio->core->regmap, - SI476X_PROP_VALID_MAX_TUNE_ERROR, - SI476X_PROP_VALID_MAX_TUNE_ERROR); - if (err < 0) - return err; - - err = regcache_sync_region(radio->core->regmap, - SI476X_PROP_VALID_SNR_THRESHOLD, - SI476X_PROP_VALID_RSSI_THRESHOLD); - if (err < 0) - return err; - - if (func == SI476X_FUNC_FM_RECEIVER) { - if (si476x_core_has_diversity(radio->core)) { - err = si476x_core_cmd_fm_phase_diversity(radio->core, - radio->core->diversity_mode); - if (err < 0) - return err; - } - - err = regcache_sync_region(radio->core->regmap, - SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, - SI476X_PROP_FM_RDS_CONFIG); - if (err < 0) - return err; - } - - return si476x_radio_init_vtable(radio, func); - -} - -static int si476x_radio_change_func(struct si476x_radio *radio, - enum si476x_func func) -{ - int err; - bool soft; - /* - * Since power/up down is a very time consuming operation, - * try to avoid doing it if the requested mode matches the one - * the tuner is in - */ - if (func == radio->core->power_up_parameters.func) - return 0; - - soft = true; - err = si476x_core_stop(radio->core, soft); - if (err < 0) { - /* - * OK, if the chip does not want to play nice let's - * try to reset it in more brutal way - */ - soft = false; - err = si476x_core_stop(radio->core, soft); - if (err < 0) - return err; - } - /* - Set the desired radio tuner function - */ - radio->core->power_up_parameters.func = func; - - err = si476x_core_start(radio->core, soft); - if (err < 0) - return err; - - /* - * No need to do the rest of manipulations for the bootlader - * mode - */ - if (func != SI476X_FUNC_FM_RECEIVER && - func != SI476X_FUNC_AM_RECEIVER) - return err; - - return si476x_radio_do_post_powerup_init(radio, func); -} - -static int si476x_radio_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - int err; - struct si476x_radio *radio = video_drvdata(file); - - if (f->tuner != 0 || - f->type != V4L2_TUNER_RADIO) - return -EINVAL; - - si476x_core_lock(radio->core); - - if (radio->ops->rsq_status) { - struct si476x_rsq_status_report report; - struct si476x_rsq_status_args args = { - .primary = false, - .rsqack = false, - .attune = true, - .cancel = false, - .stcack = false, - }; - - err = radio->ops->rsq_status(radio->core, &args, &report); - if (!err) - f->frequency = si476x_to_v4l2(radio->core, - report.readfreq); - } else { - err = -EINVAL; - } - - si476x_core_unlock(radio->core); - - return err; -} - -static int si476x_radio_s_frequency(struct file *file, void *priv, - const struct v4l2_frequency *f) -{ - int err; - u32 freq = f->frequency; - struct si476x_tune_freq_args args; - struct si476x_radio *radio = video_drvdata(file); - - const u32 midrange = (si476x_bands[SI476X_BAND_AM].rangehigh + - si476x_bands[SI476X_BAND_FM].rangelow) / 2; - const int band = (freq > midrange) ? - SI476X_BAND_FM : SI476X_BAND_AM; - const enum si476x_func func = (band == SI476X_BAND_AM) ? - SI476X_FUNC_AM_RECEIVER : SI476X_FUNC_FM_RECEIVER; - - if (f->tuner != 0 || - f->type != V4L2_TUNER_RADIO) - return -EINVAL; - - si476x_core_lock(radio->core); - - freq = clamp(freq, - si476x_bands[band].rangelow, - si476x_bands[band].rangehigh); - - if (si476x_radio_freq_is_inside_of_the_band(freq, - SI476X_BAND_AM) && - (!si476x_core_has_am(radio->core) || - si476x_core_is_a_secondary_tuner(radio->core))) { - err = -EINVAL; - goto unlock; - } - - err = si476x_radio_change_func(radio, func); - if (err < 0) - goto unlock; - - args.zifsr = false; - args.hd = false; - args.injside = SI476X_INJSIDE_AUTO; - args.freq = v4l2_to_si476x(radio->core, freq); - args.tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE; - args.smoothmetrics = SI476X_SM_INITIALIZE_AUDIO; - args.antcap = 0; - - err = radio->ops->tune_freq(radio->core, &args); - -unlock: - si476x_core_unlock(radio->core); - return err; -} - -static int si476x_radio_s_hw_freq_seek(struct file *file, void *priv, - const struct v4l2_hw_freq_seek *seek) -{ - int err; - enum si476x_func func; - u32 rangelow, rangehigh; - struct si476x_radio *radio = video_drvdata(file); - - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - - if (seek->tuner != 0 || - seek->type != V4L2_TUNER_RADIO) - return -EINVAL; - - si476x_core_lock(radio->core); - - if (!seek->rangelow) { - err = regmap_read(radio->core->regmap, - SI476X_PROP_SEEK_BAND_BOTTOM, - &rangelow); - if (!err) - rangelow = si476x_to_v4l2(radio->core, rangelow); - else - goto unlock; - } - if (!seek->rangehigh) { - err = regmap_read(radio->core->regmap, - SI476X_PROP_SEEK_BAND_TOP, - &rangehigh); - if (!err) - rangehigh = si476x_to_v4l2(radio->core, rangehigh); - else - goto unlock; - } - - if (rangelow > rangehigh) { - err = -EINVAL; - goto unlock; - } - - if (si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, - SI476X_BAND_FM)) { - func = SI476X_FUNC_FM_RECEIVER; - - } else if (si476x_core_has_am(radio->core) && - si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, - SI476X_BAND_AM)) { - func = SI476X_FUNC_AM_RECEIVER; - } else { - err = -EINVAL; - goto unlock; - } - - err = si476x_radio_change_func(radio, func); - if (err < 0) - goto unlock; - - if (seek->rangehigh) { - err = regmap_write(radio->core->regmap, - SI476X_PROP_SEEK_BAND_TOP, - v4l2_to_si476x(radio->core, - seek->rangehigh)); - if (err) - goto unlock; - } - if (seek->rangelow) { - err = regmap_write(radio->core->regmap, - SI476X_PROP_SEEK_BAND_BOTTOM, - v4l2_to_si476x(radio->core, - seek->rangelow)); - if (err) - goto unlock; - } - if (seek->spacing) { - err = regmap_write(radio->core->regmap, - SI476X_PROP_SEEK_FREQUENCY_SPACING, - v4l2_to_si476x(radio->core, - seek->spacing)); - if (err) - goto unlock; - } - - err = radio->ops->seek_start(radio->core, - seek->seek_upward, - seek->wrap_around); -unlock: - si476x_core_unlock(radio->core); - - - - return err; -} - -static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - int retval; - struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); - - si476x_core_lock(radio->core); - - switch (ctrl->id) { - case V4L2_CID_SI476X_INTERCHIP_LINK: - if (si476x_core_has_diversity(radio->core)) { - if (radio->ops->phase_diversity) { - retval = radio->ops->phase_div_status(radio->core); - if (retval < 0) - break; - - ctrl->val = !!SI476X_PHDIV_STATUS_LINK_LOCKED(retval); - retval = 0; - break; - } else { - retval = -ENOTTY; - break; - } - } - retval = -EINVAL; - break; - default: - retval = -EINVAL; - break; - } - si476x_core_unlock(radio->core); - return retval; - -} - -static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl) -{ - int retval; - enum si476x_phase_diversity_mode mode; - struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); - - si476x_core_lock(radio->core); - - switch (ctrl->id) { - case V4L2_CID_SI476X_HARMONICS_COUNT: - retval = regmap_update_bits(radio->core->regmap, - SI476X_PROP_AUDIO_PWR_LINE_FILTER, - SI476X_PROP_PWR_HARMONICS_MASK, - ctrl->val); - break; - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (ctrl->val) { - case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: - retval = regmap_update_bits(radio->core->regmap, - SI476X_PROP_AUDIO_PWR_LINE_FILTER, - SI476X_PROP_PWR_ENABLE_MASK, - 0); - break; - case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: - retval = regmap_update_bits(radio->core->regmap, - SI476X_PROP_AUDIO_PWR_LINE_FILTER, - SI476X_PROP_PWR_GRID_MASK, - SI476X_PROP_PWR_GRID_50HZ); - break; - case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: - retval = regmap_update_bits(radio->core->regmap, - SI476X_PROP_AUDIO_PWR_LINE_FILTER, - SI476X_PROP_PWR_GRID_MASK, - SI476X_PROP_PWR_GRID_60HZ); - break; - default: - retval = -EINVAL; - break; - } - break; - case V4L2_CID_SI476X_RSSI_THRESHOLD: - retval = regmap_write(radio->core->regmap, - SI476X_PROP_VALID_RSSI_THRESHOLD, - ctrl->val); - break; - case V4L2_CID_SI476X_SNR_THRESHOLD: - retval = regmap_write(radio->core->regmap, - SI476X_PROP_VALID_SNR_THRESHOLD, - ctrl->val); - break; - case V4L2_CID_SI476X_MAX_TUNE_ERROR: - retval = regmap_write(radio->core->regmap, - SI476X_PROP_VALID_MAX_TUNE_ERROR, - ctrl->val); - break; - case V4L2_CID_RDS_RECEPTION: - /* - * It looks like RDS related properties are - * inaccesable when tuner is in AM mode, so cache the - * changes - */ - if (si476x_core_is_in_am_receiver_mode(radio->core)) - regcache_cache_only(radio->core->regmap, true); - - if (ctrl->val) { - retval = regmap_write(radio->core->regmap, - SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT, - radio->core->rds_fifo_depth); - if (retval < 0) - break; - - if (radio->core->client->irq) { - retval = regmap_write(radio->core->regmap, - SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, - SI476X_RDSRECV); - if (retval < 0) - break; - } - - /* Drain RDS FIFO before enabling RDS processing */ - retval = si476x_core_cmd_fm_rds_status(radio->core, - false, - true, - true, - NULL); - if (retval < 0) - break; - - retval = regmap_update_bits(radio->core->regmap, - SI476X_PROP_FM_RDS_CONFIG, - SI476X_PROP_RDSEN_MASK, - SI476X_PROP_RDSEN); - } else { - retval = regmap_update_bits(radio->core->regmap, - SI476X_PROP_FM_RDS_CONFIG, - SI476X_PROP_RDSEN_MASK, - !SI476X_PROP_RDSEN); - } - - if (si476x_core_is_in_am_receiver_mode(radio->core)) - regcache_cache_only(radio->core->regmap, false); - break; - case V4L2_CID_TUNE_DEEMPHASIS: - retval = regmap_write(radio->core->regmap, - SI476X_PROP_AUDIO_DEEMPHASIS, - ctrl->val); - break; - - case V4L2_CID_SI476X_DIVERSITY_MODE: - mode = si476x_phase_diversity_idx_to_mode(ctrl->val); - - if (mode == radio->core->diversity_mode) { - retval = 0; - break; - } - - if (si476x_core_is_in_am_receiver_mode(radio->core)) { - /* - * Diversity cannot be configured while tuner - * is in AM mode so save the changes and carry on. - */ - radio->core->diversity_mode = mode; - retval = 0; - } else { - retval = radio->ops->phase_diversity(radio->core, mode); - if (!retval) - radio->core->diversity_mode = mode; - } - break; - - default: - retval = -EINVAL; - break; - } - - si476x_core_unlock(radio->core); - - return retval; -} - -static int si476x_radio_g_chip_ident(struct file *file, void *fh, - struct v4l2_dbg_chip_ident *chip) -{ - if (chip->match.type == V4L2_CHIP_MATCH_HOST && - v4l2_chip_match_host(&chip->match)) - return 0; - return -EINVAL; -} - - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int si476x_radio_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - int err; - unsigned int value; - struct si476x_radio *radio = video_drvdata(file); - - si476x_core_lock(radio->core); - reg->size = 2; - err = regmap_read(radio->core->regmap, - (unsigned int)reg->reg, &value); - reg->val = value; - si476x_core_unlock(radio->core); - - return err; -} -static int si476x_radio_s_register(struct file *file, void *fh, - const struct v4l2_dbg_register *reg) -{ - - int err; - struct si476x_radio *radio = video_drvdata(file); - - si476x_core_lock(radio->core); - err = regmap_write(radio->core->regmap, - (unsigned int)reg->reg, - (unsigned int)reg->val); - si476x_core_unlock(radio->core); - - return err; -} -#endif - -static int si476x_radio_fops_open(struct file *file) -{ - struct si476x_radio *radio = video_drvdata(file); - int err; - - err = v4l2_fh_open(file); - if (err) - return err; - - if (v4l2_fh_is_singular_file(file)) { - si476x_core_lock(radio->core); - err = si476x_core_set_power_state(radio->core, - SI476X_POWER_UP_FULL); - if (err < 0) - goto done; - - err = si476x_radio_do_post_powerup_init(radio, - radio->core->power_up_parameters.func); - if (err < 0) - goto power_down; - - err = si476x_radio_pretune(radio, - radio->core->power_up_parameters.func); - if (err < 0) - goto power_down; - - si476x_core_unlock(radio->core); - /*Must be done after si476x_core_unlock to prevent a deadlock*/ - v4l2_ctrl_handler_setup(&radio->ctrl_handler); - } - - return err; - -power_down: - si476x_core_set_power_state(radio->core, - SI476X_POWER_DOWN); -done: - si476x_core_unlock(radio->core); - v4l2_fh_release(file); - - return err; -} - -static int si476x_radio_fops_release(struct file *file) -{ - int err; - struct si476x_radio *radio = video_drvdata(file); - - if (v4l2_fh_is_singular_file(file) && - atomic_read(&radio->core->is_alive)) - si476x_core_set_power_state(radio->core, - SI476X_POWER_DOWN); - - err = v4l2_fh_release(file); - - return err; -} - -static ssize_t si476x_radio_fops_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - ssize_t rval; - size_t fifo_len; - unsigned int copied; - - struct si476x_radio *radio = video_drvdata(file); - - /* block if no new data available */ - if (kfifo_is_empty(&radio->core->rds_fifo)) { - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; - - rval = wait_event_interruptible(radio->core->rds_read_queue, - (!kfifo_is_empty(&radio->core->rds_fifo) || - !atomic_read(&radio->core->is_alive))); - if (rval < 0) - return -EINTR; - - if (!atomic_read(&radio->core->is_alive)) - return -ENODEV; - } - - fifo_len = kfifo_len(&radio->core->rds_fifo); - - if (kfifo_to_user(&radio->core->rds_fifo, buf, - min(fifo_len, count), - &copied) != 0) { - dev_warn(&radio->videodev.dev, - "Error during FIFO to userspace copy\n"); - rval = -EIO; - } else { - rval = (ssize_t)copied; - } - - return rval; -} - -static unsigned int si476x_radio_fops_poll(struct file *file, - struct poll_table_struct *pts) -{ - struct si476x_radio *radio = video_drvdata(file); - unsigned long req_events = poll_requested_events(pts); - unsigned int err = v4l2_ctrl_poll(file, pts); - - if (req_events & (POLLIN | POLLRDNORM)) { - if (atomic_read(&radio->core->is_alive)) - poll_wait(file, &radio->core->rds_read_queue, pts); - - if (!atomic_read(&radio->core->is_alive)) - err = POLLHUP; - - if (!kfifo_is_empty(&radio->core->rds_fifo)) - err = POLLIN | POLLRDNORM; - } - - return err; -} - -static const struct v4l2_file_operations si476x_fops = { - .owner = THIS_MODULE, - .read = si476x_radio_fops_read, - .poll = si476x_radio_fops_poll, - .unlocked_ioctl = video_ioctl2, - .open = si476x_radio_fops_open, - .release = si476x_radio_fops_release, -}; - - -static const struct v4l2_ioctl_ops si4761_ioctl_ops = { - .vidioc_querycap = si476x_radio_querycap, - .vidioc_g_tuner = si476x_radio_g_tuner, - .vidioc_s_tuner = si476x_radio_s_tuner, - - .vidioc_g_frequency = si476x_radio_g_frequency, - .vidioc_s_frequency = si476x_radio_s_frequency, - .vidioc_s_hw_freq_seek = si476x_radio_s_hw_freq_seek, - .vidioc_enum_freq_bands = si476x_radio_enum_freq_bands, - - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - - .vidioc_g_chip_ident = si476x_radio_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = si476x_radio_g_register, - .vidioc_s_register = si476x_radio_s_register, -#endif -}; - - -static const struct video_device si476x_viddev_template = { - .fops = &si476x_fops, - .name = DRIVER_NAME, - .release = video_device_release_empty, -}; - - - -static ssize_t si476x_radio_read_acf_blob(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - int err; - struct si476x_radio *radio = file->private_data; - struct si476x_acf_status_report report; - - si476x_core_lock(radio->core); - if (radio->ops->acf_status) - err = radio->ops->acf_status(radio->core, &report); - else - err = -ENOENT; - si476x_core_unlock(radio->core); - - if (err < 0) - return err; - - return simple_read_from_buffer(user_buf, count, ppos, &report, - sizeof(report)); -} - -static const struct file_operations radio_acf_fops = { - .open = simple_open, - .llseek = default_llseek, - .read = si476x_radio_read_acf_blob, -}; - -static ssize_t si476x_radio_read_rds_blckcnt_blob(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - int err; - struct si476x_radio *radio = file->private_data; - struct si476x_rds_blockcount_report report; - - si476x_core_lock(radio->core); - if (radio->ops->rds_blckcnt) - err = radio->ops->rds_blckcnt(radio->core, true, - &report); - else - err = -ENOENT; - si476x_core_unlock(radio->core); - - if (err < 0) - return err; - - return simple_read_from_buffer(user_buf, count, ppos, &report, - sizeof(report)); -} - -static const struct file_operations radio_rds_blckcnt_fops = { - .open = simple_open, - .llseek = default_llseek, - .read = si476x_radio_read_rds_blckcnt_blob, -}; - -static ssize_t si476x_radio_read_agc_blob(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - int err; - struct si476x_radio *radio = file->private_data; - struct si476x_agc_status_report report; - - si476x_core_lock(radio->core); - if (radio->ops->rds_blckcnt) - err = radio->ops->agc_status(radio->core, &report); - else - err = -ENOENT; - si476x_core_unlock(radio->core); - - if (err < 0) - return err; - - return simple_read_from_buffer(user_buf, count, ppos, &report, - sizeof(report)); -} - -static const struct file_operations radio_agc_fops = { - .open = simple_open, - .llseek = default_llseek, - .read = si476x_radio_read_agc_blob, -}; - -static ssize_t si476x_radio_read_rsq_blob(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - int err; - struct si476x_radio *radio = file->private_data; - struct si476x_rsq_status_report report; - struct si476x_rsq_status_args args = { - .primary = false, - .rsqack = false, - .attune = false, - .cancel = false, - .stcack = false, - }; - - si476x_core_lock(radio->core); - if (radio->ops->rds_blckcnt) - err = radio->ops->rsq_status(radio->core, &args, &report); - else - err = -ENOENT; - si476x_core_unlock(radio->core); - - if (err < 0) - return err; - - return simple_read_from_buffer(user_buf, count, ppos, &report, - sizeof(report)); -} - -static const struct file_operations radio_rsq_fops = { - .open = simple_open, - .llseek = default_llseek, - .read = si476x_radio_read_rsq_blob, -}; - -static ssize_t si476x_radio_read_rsq_primary_blob(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - int err; - struct si476x_radio *radio = file->private_data; - struct si476x_rsq_status_report report; - struct si476x_rsq_status_args args = { - .primary = true, - .rsqack = false, - .attune = false, - .cancel = false, - .stcack = false, - }; - - si476x_core_lock(radio->core); - if (radio->ops->rds_blckcnt) - err = radio->ops->rsq_status(radio->core, &args, &report); - else - err = -ENOENT; - si476x_core_unlock(radio->core); - - if (err < 0) - return err; - - return simple_read_from_buffer(user_buf, count, ppos, &report, - sizeof(report)); -} - -static const struct file_operations radio_rsq_primary_fops = { - .open = simple_open, - .llseek = default_llseek, - .read = si476x_radio_read_rsq_primary_blob, -}; - - -static int si476x_radio_init_debugfs(struct si476x_radio *radio) -{ - struct dentry *dentry; - int ret; - - dentry = debugfs_create_dir(dev_name(radio->v4l2dev.dev), NULL); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto exit; - } - radio->debugfs = dentry; - - dentry = debugfs_create_file("acf", S_IRUGO, - radio->debugfs, radio, &radio_acf_fops); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto cleanup; - } - - dentry = debugfs_create_file("rds_blckcnt", S_IRUGO, - radio->debugfs, radio, - &radio_rds_blckcnt_fops); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto cleanup; - } - - dentry = debugfs_create_file("agc", S_IRUGO, - radio->debugfs, radio, &radio_agc_fops); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto cleanup; - } - - dentry = debugfs_create_file("rsq", S_IRUGO, - radio->debugfs, radio, &radio_rsq_fops); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto cleanup; - } - - dentry = debugfs_create_file("rsq_primary", S_IRUGO, - radio->debugfs, radio, - &radio_rsq_primary_fops); - if (IS_ERR(dentry)) { - ret = PTR_ERR(dentry); - goto cleanup; - } - - return 0; -cleanup: - debugfs_remove_recursive(radio->debugfs); -exit: - return ret; -} - - -static int si476x_radio_add_new_custom(struct si476x_radio *radio, - enum si476x_ctrl_idx idx) -{ - int rval; - struct v4l2_ctrl *ctrl; - - ctrl = v4l2_ctrl_new_custom(&radio->ctrl_handler, - &si476x_ctrls[idx], - NULL); - rval = radio->ctrl_handler.error; - if (ctrl == NULL && rval) - dev_err(radio->v4l2dev.dev, - "Could not initialize '%s' control %d\n", - si476x_ctrls[idx].name, rval); - - return rval; -} - -static int si476x_radio_probe(struct platform_device *pdev) -{ - int rval; - struct si476x_radio *radio; - struct v4l2_ctrl *ctrl; - - static atomic_t instance = ATOMIC_INIT(0); - - radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL); - if (!radio) - return -ENOMEM; - - radio->core = i2c_mfd_cell_to_core(&pdev->dev); - - v4l2_device_set_name(&radio->v4l2dev, DRIVER_NAME, &instance); - - rval = v4l2_device_register(&pdev->dev, &radio->v4l2dev); - if (rval) { - dev_err(&pdev->dev, "Cannot register v4l2_device.\n"); - return rval; - } - - memcpy(&radio->videodev, &si476x_viddev_template, - sizeof(struct video_device)); - - radio->videodev.v4l2_dev = &radio->v4l2dev; - radio->videodev.ioctl_ops = &si4761_ioctl_ops; - - video_set_drvdata(&radio->videodev, radio); - platform_set_drvdata(pdev, radio); - - set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags); - - radio->v4l2dev.ctrl_handler = &radio->ctrl_handler; - v4l2_ctrl_handler_init(&radio->ctrl_handler, - 1 + ARRAY_SIZE(si476x_ctrls)); - - if (si476x_core_has_am(radio->core)) { - ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, - &si476x_ctrl_ops, - V4L2_CID_POWER_LINE_FREQUENCY, - V4L2_CID_POWER_LINE_FREQUENCY_60HZ, - 0, 0); - rval = radio->ctrl_handler.error; - if (ctrl == NULL && rval) { - dev_err(&pdev->dev, "Could not initialize V4L2_CID_POWER_LINE_FREQUENCY control %d\n", - rval); - goto exit; - } - - rval = si476x_radio_add_new_custom(radio, - SI476X_IDX_HARMONICS_COUNT); - if (rval < 0) - goto exit; - } - - rval = si476x_radio_add_new_custom(radio, SI476X_IDX_RSSI_THRESHOLD); - if (rval < 0) - goto exit; - - rval = si476x_radio_add_new_custom(radio, SI476X_IDX_SNR_THRESHOLD); - if (rval < 0) - goto exit; - - rval = si476x_radio_add_new_custom(radio, SI476X_IDX_MAX_TUNE_ERROR); - if (rval < 0) - goto exit; - - ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, - &si476x_ctrl_ops, - V4L2_CID_TUNE_DEEMPHASIS, - V4L2_DEEMPHASIS_75_uS, 0, 0); - rval = radio->ctrl_handler.error; - if (ctrl == NULL && rval) { - dev_err(&pdev->dev, "Could not initialize V4L2_CID_TUNE_DEEMPHASIS control %d\n", - rval); - goto exit; - } - - ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &si476x_ctrl_ops, - V4L2_CID_RDS_RECEPTION, - 0, 1, 1, 1); - rval = radio->ctrl_handler.error; - if (ctrl == NULL && rval) { - dev_err(&pdev->dev, "Could not initialize V4L2_CID_RDS_RECEPTION control %d\n", - rval); - goto exit; - } - - if (si476x_core_has_diversity(radio->core)) { - si476x_ctrls[SI476X_IDX_DIVERSITY_MODE].def = - si476x_phase_diversity_mode_to_idx(radio->core->diversity_mode); - si476x_radio_add_new_custom(radio, SI476X_IDX_DIVERSITY_MODE); - if (rval < 0) - goto exit; - - si476x_radio_add_new_custom(radio, SI476X_IDX_INTERCHIP_LINK); - if (rval < 0) - goto exit; - } - - /* register video device */ - rval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, -1); - if (rval < 0) { - dev_err(&pdev->dev, "Could not register video device\n"); - goto exit; - } - - rval = si476x_radio_init_debugfs(radio); - if (rval < 0) { - dev_err(&pdev->dev, "Could not creat debugfs interface\n"); - goto exit; - } - - return 0; -exit: - v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); - return rval; -} - -static int si476x_radio_remove(struct platform_device *pdev) -{ - struct si476x_radio *radio = platform_get_drvdata(pdev); - - v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); - video_unregister_device(&radio->videodev); - v4l2_device_unregister(&radio->v4l2dev); - debugfs_remove_recursive(radio->debugfs); - - return 0; -} - -MODULE_ALIAS("platform:si476x-radio"); - -static struct platform_driver si476x_radio_driver = { - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, - .probe = si476x_radio_probe, - .remove = si476x_radio_remove, -}; -module_platform_driver(si476x_radio_driver); - -MODULE_AUTHOR("Andrey Smirnov "); -MODULE_DESCRIPTION("Driver for Si4761/64/68 AM/FM Radio MFD Cell"); -MODULE_LICENSE("GPL"); diff --git a/include/media/si476x.h b/include/media/si476x.h deleted file mode 100644 index beb6433d6958..000000000000 --- a/include/media/si476x.h +++ /dev/null @@ -1,426 +0,0 @@ -/* - * include/media/si476x.h -- Common definitions for si476x driver - * - * Copyright (C) 2012 Innovative Converged Devices(ICD) - * Copyright (C) 2013 Andrey Smirnov - * - * Author: Andrey Smirnov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -#ifndef SI476X_H -#define SI476X_H - -#include -#include - -struct si476x_device; - -/* It is possible to select one of the four adresses using pins A0 - * and A1 on SI476x */ -#define SI476X_I2C_ADDR_1 0x60 -#define SI476X_I2C_ADDR_2 0x61 -#define SI476X_I2C_ADDR_3 0x62 -#define SI476X_I2C_ADDR_4 0x63 - -enum si476x_iqclk_config { - SI476X_IQCLK_NOOP = 0, - SI476X_IQCLK_TRISTATE = 1, - SI476X_IQCLK_IQ = 21, -}; -enum si476x_iqfs_config { - SI476X_IQFS_NOOP = 0, - SI476X_IQFS_TRISTATE = 1, - SI476X_IQFS_IQ = 21, -}; -enum si476x_iout_config { - SI476X_IOUT_NOOP = 0, - SI476X_IOUT_TRISTATE = 1, - SI476X_IOUT_OUTPUT = 22, -}; -enum si476x_qout_config { - SI476X_QOUT_NOOP = 0, - SI476X_QOUT_TRISTATE = 1, - SI476X_QOUT_OUTPUT = 22, -}; - -enum si476x_dclk_config { - SI476X_DCLK_NOOP = 0, - SI476X_DCLK_TRISTATE = 1, - SI476X_DCLK_DAUDIO = 10, -}; - -enum si476x_dfs_config { - SI476X_DFS_NOOP = 0, - SI476X_DFS_TRISTATE = 1, - SI476X_DFS_DAUDIO = 10, -}; - -enum si476x_dout_config { - SI476X_DOUT_NOOP = 0, - SI476X_DOUT_TRISTATE = 1, - SI476X_DOUT_I2S_OUTPUT = 12, - SI476X_DOUT_I2S_INPUT = 13, -}; - -enum si476x_xout_config { - SI476X_XOUT_NOOP = 0, - SI476X_XOUT_TRISTATE = 1, - SI476X_XOUT_I2S_INPUT = 13, - SI476X_XOUT_MODE_SELECT = 23, -}; - - -enum si476x_icin_config { - SI476X_ICIN_NOOP = 0, - SI476X_ICIN_TRISTATE = 1, - SI476X_ICIN_GPO1_HIGH = 2, - SI476X_ICIN_GPO1_LOW = 3, - SI476X_ICIN_IC_LINK = 30, -}; - -enum si476x_icip_config { - SI476X_ICIP_NOOP = 0, - SI476X_ICIP_TRISTATE = 1, - SI476X_ICIP_GPO2_HIGH = 2, - SI476X_ICIP_GPO2_LOW = 3, - SI476X_ICIP_IC_LINK = 30, -}; - -enum si476x_icon_config { - SI476X_ICON_NOOP = 0, - SI476X_ICON_TRISTATE = 1, - SI476X_ICON_I2S = 10, - SI476X_ICON_IC_LINK = 30, -}; - -enum si476x_icop_config { - SI476X_ICOP_NOOP = 0, - SI476X_ICOP_TRISTATE = 1, - SI476X_ICOP_I2S = 10, - SI476X_ICOP_IC_LINK = 30, -}; - - -enum si476x_lrout_config { - SI476X_LROUT_NOOP = 0, - SI476X_LROUT_TRISTATE = 1, - SI476X_LROUT_AUDIO = 2, - SI476X_LROUT_MPX = 3, -}; - - -enum si476x_intb_config { - SI476X_INTB_NOOP = 0, - SI476X_INTB_TRISTATE = 1, - SI476X_INTB_DAUDIO = 10, - SI476X_INTB_IRQ = 40, -}; - -enum si476x_a1_config { - SI476X_A1_NOOP = 0, - SI476X_A1_TRISTATE = 1, - SI476X_A1_IRQ = 40, -}; - -enum si476x_part_revisions { - SI476X_REVISION_A10 = 0, - SI476X_REVISION_A20 = 1, - SI476X_REVISION_A30 = 2, -}; - -struct si476x_pinmux { - enum si476x_dclk_config dclk; - enum si476x_dfs_config dfs; - enum si476x_dout_config dout; - enum si476x_xout_config xout; - - enum si476x_iqclk_config iqclk; - enum si476x_iqfs_config iqfs; - enum si476x_iout_config iout; - enum si476x_qout_config qout; - - enum si476x_icin_config icin; - enum si476x_icip_config icip; - enum si476x_icon_config icon; - enum si476x_icop_config icop; - - enum si476x_lrout_config lrout; - - enum si476x_intb_config intb; - enum si476x_a1_config a1; -}; - -/** - * enum si476x_phase_diversity_mode - possbile phase diversity modes - * for SI4764/5/6/7 chips. - * - * @SI476X_PHDIV_DISABLED: Phase diversity feature is - * disabled. - * @SI476X_PHDIV_PRIMARY_COMBINING: Tuner works as a primary tuner - * in combination with a - * secondary one. - * @SI476X_PHDIV_PRIMARY_ANTENNA: Tuner works as a primary tuner - * using only its own antenna. - * @SI476X_PHDIV_SECONDARY_ANTENNA: Tuner works as a primary tuner - * usning seconary tuner's antenna. - * @SI476X_PHDIV_SECONDARY_COMBINING: Tuner works as a secondary - * tuner in combination with the - * primary one. - */ -enum si476x_phase_diversity_mode { - SI476X_PHDIV_DISABLED = 0, - SI476X_PHDIV_PRIMARY_COMBINING = 1, - SI476X_PHDIV_PRIMARY_ANTENNA = 2, - SI476X_PHDIV_SECONDARY_ANTENNA = 3, - SI476X_PHDIV_SECONDARY_COMBINING = 5, -}; - -enum si476x_ibias6x { - SI476X_IBIAS6X_OTHER = 0, - SI476X_IBIAS6X_RCVR1_NON_4MHZ_CLK = 1, -}; - -enum si476x_xstart { - SI476X_XSTART_MULTIPLE_TUNER = 0x11, - SI476X_XSTART_NORMAL = 0x77, -}; - -enum si476x_freq { - SI476X_FREQ_4_MHZ = 0, - SI476X_FREQ_37P209375_MHZ = 1, - SI476X_FREQ_36P4_MHZ = 2, - SI476X_FREQ_37P8_MHZ = 3, -}; - -enum si476x_xmode { - SI476X_XMODE_CRYSTAL_RCVR1 = 1, - SI476X_XMODE_EXT_CLOCK = 2, - SI476X_XMODE_CRYSTAL_RCVR2_3 = 3, -}; - -enum si476x_xbiashc { - SI476X_XBIASHC_SINGLE_RECEIVER = 0, - SI476X_XBIASHC_MULTIPLE_RECEIVER = 1, -}; - -enum si476x_xbias { - SI476X_XBIAS_RCVR2_3 = 0, - SI476X_XBIAS_4MHZ_RCVR1 = 3, - SI476X_XBIAS_RCVR1 = 7, -}; - -enum si476x_func { - SI476X_FUNC_BOOTLOADER = 0, - SI476X_FUNC_FM_RECEIVER = 1, - SI476X_FUNC_AM_RECEIVER = 2, - SI476X_FUNC_WB_RECEIVER = 3, -}; - - -/** - * @xcload: Selects the amount of additional on-chip capacitance to - * be connected between XTAL1 and gnd and between XTAL2 and - * GND. One half of the capacitance value shown here is the - * additional load capacitance presented to the xtal. The - * minimum step size is 0.277 pF. Recommended value is 0x28 - * but it will be layout dependent. Range is 0–0x3F i.e. - * (0–16.33 pF) - * @ctsien: enable CTSINT(interrupt request when CTS condition - * arises) when set - * @intsel: when set A1 pin becomes the interrupt pin; otherwise, - * INTB is the interrupt pin - * @func: selects the boot function of the device. I.e. - * SI476X_BOOTLOADER - Boot loader - * SI476X_FM_RECEIVER - FM receiver - * SI476X_AM_RECEIVER - AM receiver - * SI476X_WB_RECEIVER - Weatherband receiver - * @freq: oscillator's crystal frequency: - * SI476X_XTAL_37P209375_MHZ - 37.209375 Mhz - * SI476X_XTAL_36P4_MHZ - 36.4 Mhz - * SI476X_XTAL_37P8_MHZ - 37.8 Mhz - */ -struct si476x_power_up_args { - enum si476x_ibias6x ibias6x; - enum si476x_xstart xstart; - u8 xcload; - bool fastboot; - enum si476x_xbiashc xbiashc; - enum si476x_xbias xbias; - enum si476x_func func; - enum si476x_freq freq; - enum si476x_xmode xmode; -}; - - -enum si476x_ctrl_id { - V4L2_CID_SI476X_RSSI_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 1), - V4L2_CID_SI476X_SNR_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 2), - V4L2_CID_SI476X_MAX_TUNE_ERROR = (V4L2_CID_USER_SI476X_BASE + 3), - V4L2_CID_SI476X_HARMONICS_COUNT = (V4L2_CID_USER_SI476X_BASE + 4), - V4L2_CID_SI476X_DIVERSITY_MODE = (V4L2_CID_USER_SI476X_BASE + 5), - V4L2_CID_SI476X_INTERCHIP_LINK = (V4L2_CID_USER_SI476X_BASE + 6), -}; - -/* - * Platform dependent definition - */ -struct si476x_platform_data { - int gpio_reset; /* < 0 if not used */ - - struct si476x_power_up_args power_up_parameters; - enum si476x_phase_diversity_mode diversity_mode; - - struct si476x_pinmux pinmux; -}; - -/** - * struct si476x_rsq_status - structure containing received signal - * quality - * @multhint: Multipath Detect High. - * true - Indicatedes that the value is below - * FM_RSQ_MULTIPATH_HIGH_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_MULTIPATH_HIGH_THRESHOLD - * @multlint: Multipath Detect Low. - * true - Indicatedes that the value is below - * FM_RSQ_MULTIPATH_LOW_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_MULTIPATH_LOW_THRESHOLD - * @snrhint: SNR Detect High. - * true - Indicatedes that the value is below - * FM_RSQ_SNR_HIGH_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_SNR_HIGH_THRESHOLD - * @snrlint: SNR Detect Low. - * true - Indicatedes that the value is below - * FM_RSQ_SNR_LOW_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_SNR_LOW_THRESHOLD - * @rssihint: RSSI Detect High. - * true - Indicatedes that the value is below - * FM_RSQ_RSSI_HIGH_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_RSSI_HIGH_THRESHOLD - * @rssilint: RSSI Detect Low. - * true - Indicatedes that the value is below - * FM_RSQ_RSSI_LOW_THRESHOLD - * false - Indicatedes that the value is above - * FM_RSQ_RSSI_LOW_THRESHOLD - * @bltf: Band Limit. - * Set if seek command hits the band limit or wrapped to - * the original frequency. - * @snr_ready: SNR measurement in progress. - * @rssiready: RSSI measurement in progress. - * @afcrl: Set if FREQOFF >= MAX_TUNE_ERROR - * @valid: Set if the channel is valid - * rssi < FM_VALID_RSSI_THRESHOLD - * snr < FM_VALID_SNR_THRESHOLD - * tune_error < FM_VALID_MAX_TUNE_ERROR - * @readfreq: Current tuned frequency. - * @freqoff: Signed frequency offset. - * @rssi: Received Signal Strength Indicator(dBuV). - * @snr: RF SNR Indicator(dB). - * @lassi: - * @hassi: Low/High side Adjacent(100 kHz) Channel Strength Indicator - * @mult: Multipath indicator - * @dev: Who knows? But values may vary. - * @readantcap: Antenna tuning capacity value. - * @assi: Adjacent Channel(+/- 200kHz) Strength Indicator - * @usn: Ultrasonic Noise Inticator in -DBFS - */ -struct si476x_rsq_status_report { - __u8 multhint, multlint; - __u8 snrhint, snrlint; - __u8 rssihint, rssilint; - __u8 bltf; - __u8 snr_ready; - __u8 rssiready; - __u8 injside; - __u8 afcrl; - __u8 valid; - - __u16 readfreq; - __s8 freqoff; - __s8 rssi; - __s8 snr; - __s8 issi; - __s8 lassi, hassi; - __s8 mult; - __u8 dev; - __u16 readantcap; - __s8 assi; - __s8 usn; - - __u8 pilotdev; - __u8 rdsdev; - __u8 assidev; - __u8 strongdev; - __u16 rdspi; -} __packed; - -/** - * si476x_acf_status_report - ACF report results - * - * @blend_int: If set, indicates that stereo separation has crossed - * below the blend threshold as set by FM_ACF_BLEND_THRESHOLD - * @hblend_int: If set, indicates that HiBlend cutoff frequency is - * lower than threshold as set by FM_ACF_HBLEND_THRESHOLD - * @hicut_int: If set, indicates that HiCut cutoff frequency is lower - * than the threshold set by ACF_ - - */ -struct si476x_acf_status_report { - __u8 blend_int; - __u8 hblend_int; - __u8 hicut_int; - __u8 chbw_int; - __u8 softmute_int; - __u8 smute; - __u8 smattn; - __u8 chbw; - __u8 hicut; - __u8 hiblend; - __u8 pilot; - __u8 stblend; -} __packed; - -enum si476x_fmagc { - SI476X_FMAGC_10K_OHM = 0, - SI476X_FMAGC_800_OHM = 1, - SI476X_FMAGC_400_OHM = 2, - SI476X_FMAGC_200_OHM = 4, - SI476X_FMAGC_100_OHM = 8, - SI476X_FMAGC_50_OHM = 16, - SI476X_FMAGC_25_OHM = 32, - SI476X_FMAGC_12P5_OHM = 64, - SI476X_FMAGC_6P25_OHM = 128, -}; - -struct si476x_agc_status_report { - __u8 mxhi; - __u8 mxlo; - __u8 lnahi; - __u8 lnalo; - __u8 fmagc1; - __u8 fmagc2; - __u8 pgagain; - __u8 fmwblang; -} __packed; - -struct si476x_rds_blockcount_report { - __u16 expected; - __u16 received; - __u16 uncorrectable; -} __packed; - -#endif /* SI476X_H*/ -- cgit v1.2.3 From b879a9c2a755d4ddf9e685258de6435710fd2f03 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Thu, 18 Apr 2013 20:46:08 -0300 Subject: [media] v4l2: Add a V4L2 driver for SI476X MFD This commit adds a driver that exposes all the radio related functionality of the Si476x series of chips via the V4L2 subsystem. [mchehab@redhat.com: change it to depends on MFD_SI476X_CORE instead of selecting it; vidioc_s_register now uses const struct] Acked-by: Hans Verkuil Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/si476x.txt | 187 ++++ drivers/media/radio/Kconfig | 16 + drivers/media/radio/Makefile | 1 + drivers/media/radio/radio-si476x.c | 1599 ++++++++++++++++++++++++++++++++++ include/media/si476x.h | 37 + 5 files changed, 1840 insertions(+) create mode 100644 Documentation/video4linux/si476x.txt create mode 100644 drivers/media/radio/radio-si476x.c create mode 100644 include/media/si476x.h (limited to 'drivers/media') diff --git a/Documentation/video4linux/si476x.txt b/Documentation/video4linux/si476x.txt new file mode 100644 index 000000000000..d1a08db2cbd9 --- /dev/null +++ b/Documentation/video4linux/si476x.txt @@ -0,0 +1,187 @@ +SI476x Driver Readme +------------------------------------------------ + Copyright (C) 2013 Andrey Smirnov + +TODO for the driver +------------------------------ + +- According to the SiLabs' datasheet it is possible to update the + firmware of the radio chip in the run-time, thus bringing it to the + most recent version. Unfortunately I couldn't find any mentioning of + the said firmware update for the old chips that I tested the driver + against, so for chips like that the driver only exposes the old + functionality. + + +Parameters exposed over debugfs +------------------------------- +SI476x allow user to get multiple characteristics that can be very +useful for EoL testing/RF performance estimation, parameters that have +very little to do with V4L2 subsystem. Such parameters are exposed via +debugfs and can be accessed via regular file I/O operations. + +The drivers exposes following files: + +* /sys/kernel/debug//acf + This file contains ACF(Automatically Controlled Features) status + information. The contents of the file is binary data of the + following layout: + + Offset | Name | Description + ==================================================================== + 0x00 | blend_int | Flag, set when stereo separation has + | | crossed below the blend threshold + -------------------------------------------------------------------- + 0x01 | hblend_int | Flag, set when HiBlend cutoff + | | frequency is lower than threshold + -------------------------------------------------------------------- + 0x02 | hicut_int | Flag, set when HiCut cutoff + | | frequency is lower than threshold + -------------------------------------------------------------------- + 0x03 | chbw_int | Flag, set when channel filter + | | bandwidth is less than threshold + -------------------------------------------------------------------- + 0x04 | softmute_int | Flag indicating that softmute + | | attenuation has increased above + | | softmute threshold + -------------------------------------------------------------------- + 0x05 | smute | 0 - Audio is not soft muted + | | 1 - Audio is soft muted + -------------------------------------------------------------------- + 0x06 | smattn | Soft mute attenuation level in dB + -------------------------------------------------------------------- + 0x07 | chbw | Channel filter bandwidth in kHz + -------------------------------------------------------------------- + 0x08 | hicut | HiCut cutoff frequency in units of + | | 100Hz + -------------------------------------------------------------------- + 0x09 | hiblend | HiBlend cutoff frequency in units + | | of 100 Hz + -------------------------------------------------------------------- + 0x10 | pilot | 0 - Stereo pilot is not present + | | 1 - Stereo pilot is present + -------------------------------------------------------------------- + 0x11 | stblend | Stereo blend in % + -------------------------------------------------------------------- + + +* /sys/kernel/debug//rds_blckcnt + This file contains statistics about RDS receptions. It's binary data + has the following layout: + + Offset | Name | Description + ==================================================================== + 0x00 | expected | Number of expected RDS blocks + -------------------------------------------------------------------- + 0x02 | received | Number of received RDS blocks + -------------------------------------------------------------------- + 0x04 | uncorrectable | Number of uncorrectable RDS blocks + -------------------------------------------------------------------- + +* /sys/kernel/debug//agc + This file contains information about parameters pertaining to + AGC(Automatic Gain Control) + + The layout is: + Offset | Name | Description + ==================================================================== + 0x00 | mxhi | 0 - FM Mixer PD high threshold is + | | not tripped + | | 1 - FM Mixer PD high threshold is + | | tripped + -------------------------------------------------------------------- + 0x01 | mxlo | ditto for FM Mixer PD low + -------------------------------------------------------------------- + 0x02 | lnahi | ditto for FM LNA PD high + -------------------------------------------------------------------- + 0x03 | lnalo | ditto for FM LNA PD low + -------------------------------------------------------------------- + 0x04 | fmagc1 | FMAGC1 attenuator resistance + | | (see datasheet for more detail) + -------------------------------------------------------------------- + 0x05 | fmagc2 | ditto for FMAGC2 + -------------------------------------------------------------------- + 0x06 | pgagain | PGA gain in dB + -------------------------------------------------------------------- + 0x07 | fmwblang | FM/WB LNA Gain in dB + -------------------------------------------------------------------- + +* /sys/kernel/debug//rsq + This file contains information about parameters pertaining to + RSQ(Received Signal Quality) + + The layout is: + Offset | Name | Description + ==================================================================== + 0x00 | multhint | 0 - multipath value has not crossed + | | the Multipath high threshold + | | 1 - multipath value has crossed + | | the Multipath high threshold + -------------------------------------------------------------------- + 0x01 | multlint | ditto for Multipath low threshold + -------------------------------------------------------------------- + 0x02 | snrhint | 0 - received signal's SNR has not + | | crossed high threshold + | | 1 - received signal's SNR has + | | crossed high threshold + -------------------------------------------------------------------- + 0x03 | snrlint | ditto for low threshold + -------------------------------------------------------------------- + 0x04 | rssihint | ditto for RSSI high threshold + -------------------------------------------------------------------- + 0x05 | rssilint | ditto for RSSI low threshold + -------------------------------------------------------------------- + 0x06 | bltf | Flag indicating if seek command + | | reached/wrapped seek band limit + -------------------------------------------------------------------- + 0x07 | snr_ready | Indicates that SNR metrics is ready + -------------------------------------------------------------------- + 0x08 | rssiready | ditto for RSSI metrics + -------------------------------------------------------------------- + 0x09 | injside | 0 - Low-side injection is being used + | | 1 - High-side injection is used + -------------------------------------------------------------------- + 0x10 | afcrl | Flag indicating if AFC rails + -------------------------------------------------------------------- + 0x11 | valid | Flag indicating if channel is valid + -------------------------------------------------------------------- + 0x12 | readfreq | Current tuned frequency + -------------------------------------------------------------------- + 0x14 | freqoff | Singed frequency offset in units of + | | 2ppm + -------------------------------------------------------------------- + 0x15 | rssi | Signed value of RSSI in dBuV + -------------------------------------------------------------------- + 0x16 | snr | Signed RF SNR in dB + -------------------------------------------------------------------- + 0x17 | issi | Signed Image Strength Signal + | | indicator + -------------------------------------------------------------------- + 0x18 | lassi | Signed Low side adjacent Channel + | | Strength indicator + -------------------------------------------------------------------- + 0x19 | hassi | ditto fpr High side + -------------------------------------------------------------------- + 0x20 | mult | Multipath indicator + -------------------------------------------------------------------- + 0x21 | dev | Frequency deviation + -------------------------------------------------------------------- + 0x24 | assi | Adjascent channel SSI + -------------------------------------------------------------------- + 0x25 | usn | Ultrasonic noise indicator + -------------------------------------------------------------------- + 0x26 | pilotdev | Pilot deviation in units of 100 Hz + -------------------------------------------------------------------- + 0x27 | rdsdev | ditto for RDS + -------------------------------------------------------------------- + 0x28 | assidev | ditto for ASSI + -------------------------------------------------------------------- + 0x29 | strongdev | Frequency deviation + -------------------------------------------------------------------- + 0x30 | rdspi | RDS PI code + -------------------------------------------------------------------- + +* /sys/kernel/debug//rsq_primary + This file contains information about parameters pertaining to + RSQ(Received Signal Quality) for primary tuner only. Layout is as + the one above. diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 24e64a09884c..c0beee2fa37c 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -18,6 +18,22 @@ config RADIO_SI470X source "drivers/media/radio/si470x/Kconfig" +config RADIO_SI476X + tristate "Silicon Laboratories Si476x I2C FM Radio" + depends on I2C && VIDEO_V4L2 + depends on MFD_SI476X_CORE + select SND_SOC_SI476X + ---help--- + Choose Y here if you have this FM radio chip. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux 2 API. Information on + this API and pointers to "v4l2" programs may be found at + . + + To compile this driver as a module, choose M here: the + module will be called radio-si476x. + config USB_MR800 tristate "AverMedia MR 800 USB FM radio support" depends on USB && VIDEO_V4L2 diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index 303eaebdb85a..0dcdb320cfc7 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o +obj-$(CONFIG_RADIO_SI476X) += radio-si476x.o obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o obj-$(CONFIG_USB_DSBR) += dsbr100.o obj-$(CONFIG_RADIO_SI470X) += si470x/ diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c new file mode 100644 index 000000000000..9430c6a29937 --- /dev/null +++ b/drivers/media/radio/radio-si476x.c @@ -0,0 +1,1599 @@ +/* + * drivers/media/radio/radio-si476x.c -- V4L2 driver for SI476X chips + * + * Copyright (C) 2012 Innovative Converged Devices(ICD) + * Copyright (C) 2013 Andrey Smirnov + * + * Author: Andrey Smirnov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define FM_FREQ_RANGE_LOW 64000000 +#define FM_FREQ_RANGE_HIGH 108000000 + +#define AM_FREQ_RANGE_LOW 520000 +#define AM_FREQ_RANGE_HIGH 30000000 + +#define PWRLINEFLTR (1 << 8) + +#define FREQ_MUL (10000000 / 625) + +#define SI476X_PHDIV_STATUS_LINK_LOCKED(status) (0b10000000 & (status)) + +#define DRIVER_NAME "si476x-radio" +#define DRIVER_CARD "SI476x AM/FM Receiver" + +enum si476x_freq_bands { + SI476X_BAND_FM, + SI476X_BAND_AM, +}; + +static const struct v4l2_frequency_band si476x_bands[] = { + [SI476X_BAND_FM] = { + .type = V4L2_TUNER_RADIO, + .index = SI476X_BAND_FM, + .capability = V4L2_TUNER_CAP_LOW + | V4L2_TUNER_CAP_STEREO + | V4L2_TUNER_CAP_RDS + | V4L2_TUNER_CAP_RDS_BLOCK_IO + | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 64 * FREQ_MUL, + .rangehigh = 108 * FREQ_MUL, + .modulation = V4L2_BAND_MODULATION_FM, + }, + [SI476X_BAND_AM] = { + .type = V4L2_TUNER_RADIO, + .index = SI476X_BAND_AM, + .capability = V4L2_TUNER_CAP_LOW + | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 0.52 * FREQ_MUL, + .rangehigh = 30 * FREQ_MUL, + .modulation = V4L2_BAND_MODULATION_AM, + }, +}; + +static inline bool si476x_radio_freq_is_inside_of_the_band(u32 freq, int band) +{ + return freq >= si476x_bands[band].rangelow && + freq <= si476x_bands[band].rangehigh; +} + +static inline bool si476x_radio_range_is_inside_of_the_band(u32 low, u32 high, + int band) +{ + return low >= si476x_bands[band].rangelow && + high <= si476x_bands[band].rangehigh; +} + +static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl); +static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl); + +enum phase_diversity_modes_idx { + SI476X_IDX_PHDIV_DISABLED, + SI476X_IDX_PHDIV_PRIMARY_COMBINING, + SI476X_IDX_PHDIV_PRIMARY_ANTENNA, + SI476X_IDX_PHDIV_SECONDARY_ANTENNA, + SI476X_IDX_PHDIV_SECONDARY_COMBINING, +}; + +static const char * const phase_diversity_modes[] = { + [SI476X_IDX_PHDIV_DISABLED] = "Disabled", + [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = "Primary with Secondary", + [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = "Primary Antenna", + [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = "Secondary Antenna", + [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = "Secondary with Primary", +}; + +static inline enum phase_diversity_modes_idx +si476x_phase_diversity_mode_to_idx(enum si476x_phase_diversity_mode mode) +{ + switch (mode) { + default: /* FALLTHROUGH */ + case SI476X_PHDIV_DISABLED: + return SI476X_IDX_PHDIV_DISABLED; + case SI476X_PHDIV_PRIMARY_COMBINING: + return SI476X_IDX_PHDIV_PRIMARY_COMBINING; + case SI476X_PHDIV_PRIMARY_ANTENNA: + return SI476X_IDX_PHDIV_PRIMARY_ANTENNA; + case SI476X_PHDIV_SECONDARY_ANTENNA: + return SI476X_IDX_PHDIV_SECONDARY_ANTENNA; + case SI476X_PHDIV_SECONDARY_COMBINING: + return SI476X_IDX_PHDIV_SECONDARY_COMBINING; + } +} + +static inline enum si476x_phase_diversity_mode +si476x_phase_diversity_idx_to_mode(enum phase_diversity_modes_idx idx) +{ + static const int idx_to_value[] = { + [SI476X_IDX_PHDIV_DISABLED] = SI476X_PHDIV_DISABLED, + [SI476X_IDX_PHDIV_PRIMARY_COMBINING] = SI476X_PHDIV_PRIMARY_COMBINING, + [SI476X_IDX_PHDIV_PRIMARY_ANTENNA] = SI476X_PHDIV_PRIMARY_ANTENNA, + [SI476X_IDX_PHDIV_SECONDARY_ANTENNA] = SI476X_PHDIV_SECONDARY_ANTENNA, + [SI476X_IDX_PHDIV_SECONDARY_COMBINING] = SI476X_PHDIV_SECONDARY_COMBINING, + }; + + return idx_to_value[idx]; +} + +static const struct v4l2_ctrl_ops si476x_ctrl_ops = { + .g_volatile_ctrl = si476x_radio_g_volatile_ctrl, + .s_ctrl = si476x_radio_s_ctrl, +}; + + +enum si476x_ctrl_idx { + SI476X_IDX_RSSI_THRESHOLD, + SI476X_IDX_SNR_THRESHOLD, + SI476X_IDX_MAX_TUNE_ERROR, + SI476X_IDX_HARMONICS_COUNT, + SI476X_IDX_DIVERSITY_MODE, + SI476X_IDX_INTERCHIP_LINK, +}; +static struct v4l2_ctrl_config si476x_ctrls[] = { + + /** + * SI476X during its station seeking(or tuning) process uses several + * parameters to detrmine if "the station" is valid: + * + * - Signal's SNR(in dBuV) must be lower than + * #V4L2_CID_SI476X_SNR_THRESHOLD + * - Signal's RSSI(in dBuV) must be greater than + * #V4L2_CID_SI476X_RSSI_THRESHOLD + * - Signal's frequency deviation(in units of 2ppm) must not be + * more than #V4L2_CID_SI476X_MAX_TUNE_ERROR + */ + [SI476X_IDX_RSSI_THRESHOLD] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_RSSI_THRESHOLD, + .name = "Valid RSSI Threshold", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = -128, + .max = 127, + .step = 1, + }, + [SI476X_IDX_SNR_THRESHOLD] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_SNR_THRESHOLD, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Valid SNR Threshold", + .min = -128, + .max = 127, + .step = 1, + }, + [SI476X_IDX_MAX_TUNE_ERROR] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_MAX_TUNE_ERROR, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Max Tune Errors", + .min = 0, + .max = 126 * 2, + .step = 2, + }, + + /** + * #V4L2_CID_SI476X_HARMONICS_COUNT -- number of harmonics + * built-in power-line noise supression filter is to reject + * during AM-mode operation. + */ + [SI476X_IDX_HARMONICS_COUNT] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_HARMONICS_COUNT, + .type = V4L2_CTRL_TYPE_INTEGER, + + .name = "Count of Harmonics to Reject", + .min = 0, + .max = 20, + .step = 1, + }, + + /** + * #V4L2_CID_SI476X_DIVERSITY_MODE -- configuration which + * two tuners working in diversity mode are to work in. + * + * - #SI476X_IDX_PHDIV_DISABLED diversity mode disabled + * - #SI476X_IDX_PHDIV_PRIMARY_COMBINING diversity mode is + * on, primary tuner's antenna is the main one. + * - #SI476X_IDX_PHDIV_PRIMARY_ANTENNA diversity mode is + * off, primary tuner's antenna is the main one. + * - #SI476X_IDX_PHDIV_SECONDARY_ANTENNA diversity mode is + * off, secondary tuner's antenna is the main one. + * - #SI476X_IDX_PHDIV_SECONDARY_COMBINING diversity mode is + * on, secondary tuner's antenna is the main one. + */ + [SI476X_IDX_DIVERSITY_MODE] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_DIVERSITY_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Phase Diversity Mode", + .qmenu = phase_diversity_modes, + .min = 0, + .max = ARRAY_SIZE(phase_diversity_modes) - 1, + }, + + /** + * #V4L2_CID_SI476X_INTERCHIP_LINK -- inter-chip link in + * diversity mode indicator. Allows user to determine if two + * chips working in diversity mode have established a link + * between each other and if the system as a whole uses + * signals from both antennas to receive FM radio. + */ + [SI476X_IDX_INTERCHIP_LINK] = { + .ops = &si476x_ctrl_ops, + .id = V4L2_CID_SI476X_INTERCHIP_LINK, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE, + .name = "Inter-Chip Link", + .min = 0, + .max = 1, + .step = 1, + }, +}; + +struct si476x_radio; + +/** + * struct si476x_radio_ops - vtable of tuner functions + * + * This table holds pointers to functions implementing particular + * operations depending on the mode in which the tuner chip was + * configured to start in. If the function is not supported + * corresponding element is set to #NULL. + * + * @tune_freq: Tune chip to a specific frequency + * @seek_start: Star station seeking + * @rsq_status: Get Recieved Signal Quality(RSQ) status + * @rds_blckcnt: Get recived RDS blocks count + * @phase_diversity: Change phase diversity mode of the tuner + * @phase_div_status: Get phase diversity mode status + * @acf_status: Get the status of Automatically Controlled + * Features(ACF) + * @agc_status: Get Automatic Gain Control(AGC) status + */ +struct si476x_radio_ops { + int (*tune_freq)(struct si476x_core *, struct si476x_tune_freq_args *); + int (*seek_start)(struct si476x_core *, bool, bool); + int (*rsq_status)(struct si476x_core *, struct si476x_rsq_status_args *, + struct si476x_rsq_status_report *); + int (*rds_blckcnt)(struct si476x_core *, bool, + struct si476x_rds_blockcount_report *); + + int (*phase_diversity)(struct si476x_core *, + enum si476x_phase_diversity_mode); + int (*phase_div_status)(struct si476x_core *); + int (*acf_status)(struct si476x_core *, + struct si476x_acf_status_report *); + int (*agc_status)(struct si476x_core *, + struct si476x_agc_status_report *); +}; + +/** + * struct si476x_radio - radio device + * + * @core: Pointer to underlying core device + * @videodev: Pointer to video device created by V4L2 subsystem + * @ops: Vtable of functions. See struct si476x_radio_ops for details + * @kref: Reference counter + * @core_lock: An r/w semaphore to brebvent the deletion of underlying + * core structure is the radio device is being used + */ +struct si476x_radio { + struct v4l2_device v4l2dev; + struct video_device videodev; + struct v4l2_ctrl_handler ctrl_handler; + + struct si476x_core *core; + /* This field should not be accesses unless core lock is held */ + const struct si476x_radio_ops *ops; + + struct dentry *debugfs; + u32 audmode; +}; + +static inline struct si476x_radio * +v4l2_dev_to_radio(struct v4l2_device *d) +{ + return container_of(d, struct si476x_radio, v4l2dev); +} + +static inline struct si476x_radio * +v4l2_ctrl_handler_to_radio(struct v4l2_ctrl_handler *d) +{ + return container_of(d, struct si476x_radio, ctrl_handler); +} + +/* + * si476x_vidioc_querycap - query device capabilities + */ +static int si476x_radio_querycap(struct file *file, void *priv, + struct v4l2_capability *capability) +{ + struct si476x_radio *radio = video_drvdata(file); + + strlcpy(capability->driver, radio->v4l2dev.name, + sizeof(capability->driver)); + strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); + snprintf(capability->bus_info, sizeof(capability->bus_info), + "platform:%s", radio->v4l2dev.name); + + capability->device_caps = V4L2_CAP_TUNER + | V4L2_CAP_RADIO + | V4L2_CAP_HW_FREQ_SEEK; + + si476x_core_lock(radio->core); + if (!si476x_core_is_a_secondary_tuner(radio->core)) + capability->device_caps |= V4L2_CAP_RDS_CAPTURE + | V4L2_CAP_READWRITE; + si476x_core_unlock(radio->core); + + capability->capabilities = capability->device_caps + | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int si476x_radio_enum_freq_bands(struct file *file, void *priv, + struct v4l2_frequency_band *band) +{ + int err; + struct si476x_radio *radio = video_drvdata(file); + + if (band->tuner != 0) + return -EINVAL; + + switch (radio->core->chip_id) { + /* AM/FM tuners -- all bands are supported */ + case SI476X_CHIP_SI4761: + case SI476X_CHIP_SI4764: + if (band->index < ARRAY_SIZE(si476x_bands)) { + *band = si476x_bands[band->index]; + err = 0; + } else { + err = -EINVAL; + } + break; + /* FM companion tuner chips -- only FM bands are + * supported */ + case SI476X_CHIP_SI4768: + if (band->index == SI476X_BAND_FM) { + *band = si476x_bands[band->index]; + err = 0; + } else { + err = -EINVAL; + } + break; + default: + err = -EINVAL; + } + + return err; +} + +static int si476x_radio_g_tuner(struct file *file, void *priv, + struct v4l2_tuner *tuner) +{ + int err; + struct si476x_rsq_status_report report; + struct si476x_radio *radio = video_drvdata(file); + + struct si476x_rsq_status_args args = { + .primary = false, + .rsqack = false, + .attune = false, + .cancel = false, + .stcack = false, + }; + + if (tuner->index != 0) + return -EINVAL; + + tuner->type = V4L2_TUNER_RADIO; + tuner->capability = V4L2_TUNER_CAP_LOW /* Measure frequencies + * in multiples of + * 62.5 Hz */ + | V4L2_TUNER_CAP_STEREO + | V4L2_TUNER_CAP_HWSEEK_BOUNDED + | V4L2_TUNER_CAP_HWSEEK_WRAP + | V4L2_TUNER_CAP_HWSEEK_PROG_LIM; + + si476x_core_lock(radio->core); + + if (si476x_core_is_a_secondary_tuner(radio->core)) { + strlcpy(tuner->name, "FM (secondary)", sizeof(tuner->name)); + tuner->rxsubchans = 0; + tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; + } else if (si476x_core_has_am(radio->core)) { + if (si476x_core_is_a_primary_tuner(radio->core)) + strlcpy(tuner->name, "AM/FM (primary)", + sizeof(tuner->name)); + else + strlcpy(tuner->name, "AM/FM", sizeof(tuner->name)); + + tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO + | V4L2_TUNER_SUB_RDS; + tuner->capability |= V4L2_TUNER_CAP_RDS + | V4L2_TUNER_CAP_RDS_BLOCK_IO + | V4L2_TUNER_CAP_FREQ_BANDS; + + tuner->rangelow = si476x_bands[SI476X_BAND_AM].rangelow; + } else { + strlcpy(tuner->name, "FM", sizeof(tuner->name)); + tuner->rxsubchans = V4L2_TUNER_SUB_RDS; + tuner->capability |= V4L2_TUNER_CAP_RDS + | V4L2_TUNER_CAP_RDS_BLOCK_IO + | V4L2_TUNER_CAP_FREQ_BANDS; + tuner->rangelow = si476x_bands[SI476X_BAND_FM].rangelow; + } + + tuner->audmode = radio->audmode; + + tuner->afc = 1; + tuner->rangehigh = si476x_bands[SI476X_BAND_FM].rangehigh; + + err = radio->ops->rsq_status(radio->core, + &args, &report); + if (err < 0) { + tuner->signal = 0; + } else { + /* + * tuner->signal value range: 0x0000 .. 0xFFFF, + * report.rssi: -128 .. 127 + */ + tuner->signal = (report.rssi + 128) * 257; + } + si476x_core_unlock(radio->core); + + return err; +} + +static int si476x_radio_s_tuner(struct file *file, void *priv, + const struct v4l2_tuner *tuner) +{ + struct si476x_radio *radio = video_drvdata(file); + + if (tuner->index != 0) + return -EINVAL; + + if (tuner->audmode == V4L2_TUNER_MODE_MONO || + tuner->audmode == V4L2_TUNER_MODE_STEREO) + radio->audmode = tuner->audmode; + else + radio->audmode = V4L2_TUNER_MODE_STEREO; + + return 0; +} + +static int si476x_radio_init_vtable(struct si476x_radio *radio, + enum si476x_func func) +{ + static const struct si476x_radio_ops fm_ops = { + .tune_freq = si476x_core_cmd_fm_tune_freq, + .seek_start = si476x_core_cmd_fm_seek_start, + .rsq_status = si476x_core_cmd_fm_rsq_status, + .rds_blckcnt = si476x_core_cmd_fm_rds_blockcount, + .phase_diversity = si476x_core_cmd_fm_phase_diversity, + .phase_div_status = si476x_core_cmd_fm_phase_div_status, + .acf_status = si476x_core_cmd_fm_acf_status, + .agc_status = si476x_core_cmd_agc_status, + }; + + static const struct si476x_radio_ops am_ops = { + .tune_freq = si476x_core_cmd_am_tune_freq, + .seek_start = si476x_core_cmd_am_seek_start, + .rsq_status = si476x_core_cmd_am_rsq_status, + .rds_blckcnt = NULL, + .phase_diversity = NULL, + .phase_div_status = NULL, + .acf_status = si476x_core_cmd_am_acf_status, + .agc_status = NULL, + }; + + switch (func) { + case SI476X_FUNC_FM_RECEIVER: + radio->ops = &fm_ops; + return 0; + + case SI476X_FUNC_AM_RECEIVER: + radio->ops = &am_ops; + return 0; + default: + WARN(1, "Unexpected tuner function value\n"); + return -EINVAL; + } +} + +static int si476x_radio_pretune(struct si476x_radio *radio, + enum si476x_func func) +{ + int retval; + + struct si476x_tune_freq_args args = { + .zifsr = false, + .hd = false, + .injside = SI476X_INJSIDE_AUTO, + .tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE, + .smoothmetrics = SI476X_SM_INITIALIZE_AUDIO, + .antcap = 0, + }; + + switch (func) { + case SI476X_FUNC_FM_RECEIVER: + args.freq = v4l2_to_si476x(radio->core, + 92 * FREQ_MUL); + retval = radio->ops->tune_freq(radio->core, &args); + break; + case SI476X_FUNC_AM_RECEIVER: + args.freq = v4l2_to_si476x(radio->core, + 0.6 * FREQ_MUL); + retval = radio->ops->tune_freq(radio->core, &args); + break; + default: + WARN(1, "Unexpected tuner function value\n"); + retval = -EINVAL; + } + + return retval; +} +static int si476x_radio_do_post_powerup_init(struct si476x_radio *radio, + enum si476x_func func) +{ + int err; + + /* regcache_mark_dirty(radio->core->regmap); */ + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE, + SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT); + if (err < 0) + return err; + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_AUDIO_DEEMPHASIS, + SI476X_PROP_AUDIO_PWR_LINE_FILTER); + if (err < 0) + return err; + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_INT_CTL_ENABLE, + SI476X_PROP_INT_CTL_ENABLE); + if (err < 0) + return err; + + /* + * Is there any point in restoring SNR and the like + * when switching between AM/FM? + */ + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_VALID_MAX_TUNE_ERROR, + SI476X_PROP_VALID_MAX_TUNE_ERROR); + if (err < 0) + return err; + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_VALID_SNR_THRESHOLD, + SI476X_PROP_VALID_RSSI_THRESHOLD); + if (err < 0) + return err; + + if (func == SI476X_FUNC_FM_RECEIVER) { + if (si476x_core_has_diversity(radio->core)) { + err = si476x_core_cmd_fm_phase_diversity(radio->core, + radio->core->diversity_mode); + if (err < 0) + return err; + } + + err = regcache_sync_region(radio->core->regmap, + SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, + SI476X_PROP_FM_RDS_CONFIG); + if (err < 0) + return err; + } + + return si476x_radio_init_vtable(radio, func); + +} + +static int si476x_radio_change_func(struct si476x_radio *radio, + enum si476x_func func) +{ + int err; + bool soft; + /* + * Since power/up down is a very time consuming operation, + * try to avoid doing it if the requested mode matches the one + * the tuner is in + */ + if (func == radio->core->power_up_parameters.func) + return 0; + + soft = true; + err = si476x_core_stop(radio->core, soft); + if (err < 0) { + /* + * OK, if the chip does not want to play nice let's + * try to reset it in more brutal way + */ + soft = false; + err = si476x_core_stop(radio->core, soft); + if (err < 0) + return err; + } + /* + Set the desired radio tuner function + */ + radio->core->power_up_parameters.func = func; + + err = si476x_core_start(radio->core, soft); + if (err < 0) + return err; + + /* + * No need to do the rest of manipulations for the bootlader + * mode + */ + if (func != SI476X_FUNC_FM_RECEIVER && + func != SI476X_FUNC_AM_RECEIVER) + return err; + + return si476x_radio_do_post_powerup_init(radio, func); +} + +static int si476x_radio_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + int err; + struct si476x_radio *radio = video_drvdata(file); + + if (f->tuner != 0 || + f->type != V4L2_TUNER_RADIO) + return -EINVAL; + + si476x_core_lock(radio->core); + + if (radio->ops->rsq_status) { + struct si476x_rsq_status_report report; + struct si476x_rsq_status_args args = { + .primary = false, + .rsqack = false, + .attune = true, + .cancel = false, + .stcack = false, + }; + + err = radio->ops->rsq_status(radio->core, &args, &report); + if (!err) + f->frequency = si476x_to_v4l2(radio->core, + report.readfreq); + } else { + err = -EINVAL; + } + + si476x_core_unlock(radio->core); + + return err; +} + +static int si476x_radio_s_frequency(struct file *file, void *priv, + const struct v4l2_frequency *f) +{ + int err; + u32 freq = f->frequency; + struct si476x_tune_freq_args args; + struct si476x_radio *radio = video_drvdata(file); + + const u32 midrange = (si476x_bands[SI476X_BAND_AM].rangehigh + + si476x_bands[SI476X_BAND_FM].rangelow) / 2; + const int band = (freq > midrange) ? + SI476X_BAND_FM : SI476X_BAND_AM; + const enum si476x_func func = (band == SI476X_BAND_AM) ? + SI476X_FUNC_AM_RECEIVER : SI476X_FUNC_FM_RECEIVER; + + if (f->tuner != 0 || + f->type != V4L2_TUNER_RADIO) + return -EINVAL; + + si476x_core_lock(radio->core); + + freq = clamp(freq, + si476x_bands[band].rangelow, + si476x_bands[band].rangehigh); + + if (si476x_radio_freq_is_inside_of_the_band(freq, + SI476X_BAND_AM) && + (!si476x_core_has_am(radio->core) || + si476x_core_is_a_secondary_tuner(radio->core))) { + err = -EINVAL; + goto unlock; + } + + err = si476x_radio_change_func(radio, func); + if (err < 0) + goto unlock; + + args.zifsr = false; + args.hd = false; + args.injside = SI476X_INJSIDE_AUTO; + args.freq = v4l2_to_si476x(radio->core, freq); + args.tunemode = SI476X_TM_VALIDATED_NORMAL_TUNE; + args.smoothmetrics = SI476X_SM_INITIALIZE_AUDIO; + args.antcap = 0; + + err = radio->ops->tune_freq(radio->core, &args); + +unlock: + si476x_core_unlock(radio->core); + return err; +} + +static int si476x_radio_s_hw_freq_seek(struct file *file, void *priv, + const struct v4l2_hw_freq_seek *seek) +{ + int err; + enum si476x_func func; + u32 rangelow, rangehigh; + struct si476x_radio *radio = video_drvdata(file); + + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + if (seek->tuner != 0 || + seek->type != V4L2_TUNER_RADIO) + return -EINVAL; + + si476x_core_lock(radio->core); + + if (!seek->rangelow) { + err = regmap_read(radio->core->regmap, + SI476X_PROP_SEEK_BAND_BOTTOM, + &rangelow); + if (!err) + rangelow = si476x_to_v4l2(radio->core, rangelow); + else + goto unlock; + } + if (!seek->rangehigh) { + err = regmap_read(radio->core->regmap, + SI476X_PROP_SEEK_BAND_TOP, + &rangehigh); + if (!err) + rangehigh = si476x_to_v4l2(radio->core, rangehigh); + else + goto unlock; + } + + if (rangelow > rangehigh) { + err = -EINVAL; + goto unlock; + } + + if (si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, + SI476X_BAND_FM)) { + func = SI476X_FUNC_FM_RECEIVER; + + } else if (si476x_core_has_am(radio->core) && + si476x_radio_range_is_inside_of_the_band(rangelow, rangehigh, + SI476X_BAND_AM)) { + func = SI476X_FUNC_AM_RECEIVER; + } else { + err = -EINVAL; + goto unlock; + } + + err = si476x_radio_change_func(radio, func); + if (err < 0) + goto unlock; + + if (seek->rangehigh) { + err = regmap_write(radio->core->regmap, + SI476X_PROP_SEEK_BAND_TOP, + v4l2_to_si476x(radio->core, + seek->rangehigh)); + if (err) + goto unlock; + } + if (seek->rangelow) { + err = regmap_write(radio->core->regmap, + SI476X_PROP_SEEK_BAND_BOTTOM, + v4l2_to_si476x(radio->core, + seek->rangelow)); + if (err) + goto unlock; + } + if (seek->spacing) { + err = regmap_write(radio->core->regmap, + SI476X_PROP_SEEK_FREQUENCY_SPACING, + v4l2_to_si476x(radio->core, + seek->spacing)); + if (err) + goto unlock; + } + + err = radio->ops->seek_start(radio->core, + seek->seek_upward, + seek->wrap_around); +unlock: + si476x_core_unlock(radio->core); + + + + return err; +} + +static int si476x_radio_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + int retval; + struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); + + si476x_core_lock(radio->core); + + switch (ctrl->id) { + case V4L2_CID_SI476X_INTERCHIP_LINK: + if (si476x_core_has_diversity(radio->core)) { + if (radio->ops->phase_diversity) { + retval = radio->ops->phase_div_status(radio->core); + if (retval < 0) + break; + + ctrl->val = !!SI476X_PHDIV_STATUS_LINK_LOCKED(retval); + retval = 0; + break; + } else { + retval = -ENOTTY; + break; + } + } + retval = -EINVAL; + break; + default: + retval = -EINVAL; + break; + } + si476x_core_unlock(radio->core); + return retval; + +} + +static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl) +{ + int retval; + enum si476x_phase_diversity_mode mode; + struct si476x_radio *radio = v4l2_ctrl_handler_to_radio(ctrl->handler); + + si476x_core_lock(radio->core); + + switch (ctrl->id) { + case V4L2_CID_SI476X_HARMONICS_COUNT: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_HARMONICS_MASK, + ctrl->val); + break; + case V4L2_CID_POWER_LINE_FREQUENCY: + switch (ctrl->val) { + case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_ENABLE_MASK, + 0); + break; + case V4L2_CID_POWER_LINE_FREQUENCY_50HZ: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_GRID_MASK, + SI476X_PROP_PWR_GRID_50HZ); + break; + case V4L2_CID_POWER_LINE_FREQUENCY_60HZ: + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_AUDIO_PWR_LINE_FILTER, + SI476X_PROP_PWR_GRID_MASK, + SI476X_PROP_PWR_GRID_60HZ); + break; + default: + retval = -EINVAL; + break; + } + break; + case V4L2_CID_SI476X_RSSI_THRESHOLD: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_VALID_RSSI_THRESHOLD, + ctrl->val); + break; + case V4L2_CID_SI476X_SNR_THRESHOLD: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_VALID_SNR_THRESHOLD, + ctrl->val); + break; + case V4L2_CID_SI476X_MAX_TUNE_ERROR: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_VALID_MAX_TUNE_ERROR, + ctrl->val); + break; + case V4L2_CID_RDS_RECEPTION: + /* + * It looks like RDS related properties are + * inaccesable when tuner is in AM mode, so cache the + * changes + */ + if (si476x_core_is_in_am_receiver_mode(radio->core)) + regcache_cache_only(radio->core->regmap, true); + + if (ctrl->val) { + retval = regmap_write(radio->core->regmap, + SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT, + radio->core->rds_fifo_depth); + if (retval < 0) + break; + + if (radio->core->client->irq) { + retval = regmap_write(radio->core->regmap, + SI476X_PROP_FM_RDS_INTERRUPT_SOURCE, + SI476X_RDSRECV); + if (retval < 0) + break; + } + + /* Drain RDS FIFO before enabling RDS processing */ + retval = si476x_core_cmd_fm_rds_status(radio->core, + false, + true, + true, + NULL); + if (retval < 0) + break; + + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_FM_RDS_CONFIG, + SI476X_PROP_RDSEN_MASK, + SI476X_PROP_RDSEN); + } else { + retval = regmap_update_bits(radio->core->regmap, + SI476X_PROP_FM_RDS_CONFIG, + SI476X_PROP_RDSEN_MASK, + !SI476X_PROP_RDSEN); + } + + if (si476x_core_is_in_am_receiver_mode(radio->core)) + regcache_cache_only(radio->core->regmap, false); + break; + case V4L2_CID_TUNE_DEEMPHASIS: + retval = regmap_write(radio->core->regmap, + SI476X_PROP_AUDIO_DEEMPHASIS, + ctrl->val); + break; + + case V4L2_CID_SI476X_DIVERSITY_MODE: + mode = si476x_phase_diversity_idx_to_mode(ctrl->val); + + if (mode == radio->core->diversity_mode) { + retval = 0; + break; + } + + if (si476x_core_is_in_am_receiver_mode(radio->core)) { + /* + * Diversity cannot be configured while tuner + * is in AM mode so save the changes and carry on. + */ + radio->core->diversity_mode = mode; + retval = 0; + } else { + retval = radio->ops->phase_diversity(radio->core, mode); + if (!retval) + radio->core->diversity_mode = mode; + } + break; + + default: + retval = -EINVAL; + break; + } + + si476x_core_unlock(radio->core); + + return retval; +} + +static int si476x_radio_g_chip_ident(struct file *file, void *fh, + struct v4l2_dbg_chip_ident *chip) +{ + if (chip->match.type == V4L2_CHIP_MATCH_HOST && + v4l2_chip_match_host(&chip->match)) + return 0; + return -EINVAL; +} + + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int si476x_radio_g_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg) +{ + int err; + unsigned int value; + struct si476x_radio *radio = video_drvdata(file); + + si476x_core_lock(radio->core); + reg->size = 2; + err = regmap_read(radio->core->regmap, + (unsigned int)reg->reg, &value); + reg->val = value; + si476x_core_unlock(radio->core); + + return err; +} +static int si476x_radio_s_register(struct file *file, void *fh, + const struct v4l2_dbg_register *reg) +{ + + int err; + struct si476x_radio *radio = video_drvdata(file); + + si476x_core_lock(radio->core); + err = regmap_write(radio->core->regmap, + (unsigned int)reg->reg, + (unsigned int)reg->val); + si476x_core_unlock(radio->core); + + return err; +} +#endif + +static int si476x_radio_fops_open(struct file *file) +{ + struct si476x_radio *radio = video_drvdata(file); + int err; + + err = v4l2_fh_open(file); + if (err) + return err; + + if (v4l2_fh_is_singular_file(file)) { + si476x_core_lock(radio->core); + err = si476x_core_set_power_state(radio->core, + SI476X_POWER_UP_FULL); + if (err < 0) + goto done; + + err = si476x_radio_do_post_powerup_init(radio, + radio->core->power_up_parameters.func); + if (err < 0) + goto power_down; + + err = si476x_radio_pretune(radio, + radio->core->power_up_parameters.func); + if (err < 0) + goto power_down; + + si476x_core_unlock(radio->core); + /*Must be done after si476x_core_unlock to prevent a deadlock*/ + v4l2_ctrl_handler_setup(&radio->ctrl_handler); + } + + return err; + +power_down: + si476x_core_set_power_state(radio->core, + SI476X_POWER_DOWN); +done: + si476x_core_unlock(radio->core); + v4l2_fh_release(file); + + return err; +} + +static int si476x_radio_fops_release(struct file *file) +{ + int err; + struct si476x_radio *radio = video_drvdata(file); + + if (v4l2_fh_is_singular_file(file) && + atomic_read(&radio->core->is_alive)) + si476x_core_set_power_state(radio->core, + SI476X_POWER_DOWN); + + err = v4l2_fh_release(file); + + return err; +} + +static ssize_t si476x_radio_fops_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t rval; + size_t fifo_len; + unsigned int copied; + + struct si476x_radio *radio = video_drvdata(file); + + /* block if no new data available */ + if (kfifo_is_empty(&radio->core->rds_fifo)) { + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + + rval = wait_event_interruptible(radio->core->rds_read_queue, + (!kfifo_is_empty(&radio->core->rds_fifo) || + !atomic_read(&radio->core->is_alive))); + if (rval < 0) + return -EINTR; + + if (!atomic_read(&radio->core->is_alive)) + return -ENODEV; + } + + fifo_len = kfifo_len(&radio->core->rds_fifo); + + if (kfifo_to_user(&radio->core->rds_fifo, buf, + min(fifo_len, count), + &copied) != 0) { + dev_warn(&radio->videodev.dev, + "Error during FIFO to userspace copy\n"); + rval = -EIO; + } else { + rval = (ssize_t)copied; + } + + return rval; +} + +static unsigned int si476x_radio_fops_poll(struct file *file, + struct poll_table_struct *pts) +{ + struct si476x_radio *radio = video_drvdata(file); + unsigned long req_events = poll_requested_events(pts); + unsigned int err = v4l2_ctrl_poll(file, pts); + + if (req_events & (POLLIN | POLLRDNORM)) { + if (atomic_read(&radio->core->is_alive)) + poll_wait(file, &radio->core->rds_read_queue, pts); + + if (!atomic_read(&radio->core->is_alive)) + err = POLLHUP; + + if (!kfifo_is_empty(&radio->core->rds_fifo)) + err = POLLIN | POLLRDNORM; + } + + return err; +} + +static const struct v4l2_file_operations si476x_fops = { + .owner = THIS_MODULE, + .read = si476x_radio_fops_read, + .poll = si476x_radio_fops_poll, + .unlocked_ioctl = video_ioctl2, + .open = si476x_radio_fops_open, + .release = si476x_radio_fops_release, +}; + + +static const struct v4l2_ioctl_ops si4761_ioctl_ops = { + .vidioc_querycap = si476x_radio_querycap, + .vidioc_g_tuner = si476x_radio_g_tuner, + .vidioc_s_tuner = si476x_radio_s_tuner, + + .vidioc_g_frequency = si476x_radio_g_frequency, + .vidioc_s_frequency = si476x_radio_s_frequency, + .vidioc_s_hw_freq_seek = si476x_radio_s_hw_freq_seek, + .vidioc_enum_freq_bands = si476x_radio_enum_freq_bands, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_g_chip_ident = si476x_radio_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = si476x_radio_g_register, + .vidioc_s_register = si476x_radio_s_register, +#endif +}; + + +static const struct video_device si476x_viddev_template = { + .fops = &si476x_fops, + .name = DRIVER_NAME, + .release = video_device_release_empty, +}; + + + +static ssize_t si476x_radio_read_acf_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_acf_status_report report; + + si476x_core_lock(radio->core); + if (radio->ops->acf_status) + err = radio->ops->acf_status(radio->core, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_acf_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_acf_blob, +}; + +static ssize_t si476x_radio_read_rds_blckcnt_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_rds_blockcount_report report; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->rds_blckcnt(radio->core, true, + &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_rds_blckcnt_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_rds_blckcnt_blob, +}; + +static ssize_t si476x_radio_read_agc_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_agc_status_report report; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->agc_status(radio->core, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_agc_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_agc_blob, +}; + +static ssize_t si476x_radio_read_rsq_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_rsq_status_report report; + struct si476x_rsq_status_args args = { + .primary = false, + .rsqack = false, + .attune = false, + .cancel = false, + .stcack = false, + }; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->rsq_status(radio->core, &args, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_rsq_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_rsq_blob, +}; + +static ssize_t si476x_radio_read_rsq_primary_blob(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + int err; + struct si476x_radio *radio = file->private_data; + struct si476x_rsq_status_report report; + struct si476x_rsq_status_args args = { + .primary = true, + .rsqack = false, + .attune = false, + .cancel = false, + .stcack = false, + }; + + si476x_core_lock(radio->core); + if (radio->ops->rds_blckcnt) + err = radio->ops->rsq_status(radio->core, &args, &report); + else + err = -ENOENT; + si476x_core_unlock(radio->core); + + if (err < 0) + return err; + + return simple_read_from_buffer(user_buf, count, ppos, &report, + sizeof(report)); +} + +static const struct file_operations radio_rsq_primary_fops = { + .open = simple_open, + .llseek = default_llseek, + .read = si476x_radio_read_rsq_primary_blob, +}; + + +static int si476x_radio_init_debugfs(struct si476x_radio *radio) +{ + struct dentry *dentry; + int ret; + + dentry = debugfs_create_dir(dev_name(radio->v4l2dev.dev), NULL); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto exit; + } + radio->debugfs = dentry; + + dentry = debugfs_create_file("acf", S_IRUGO, + radio->debugfs, radio, &radio_acf_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("rds_blckcnt", S_IRUGO, + radio->debugfs, radio, + &radio_rds_blckcnt_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("agc", S_IRUGO, + radio->debugfs, radio, &radio_agc_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("rsq", S_IRUGO, + radio->debugfs, radio, &radio_rsq_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + dentry = debugfs_create_file("rsq_primary", S_IRUGO, + radio->debugfs, radio, + &radio_rsq_primary_fops); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto cleanup; + } + + return 0; +cleanup: + debugfs_remove_recursive(radio->debugfs); +exit: + return ret; +} + + +static int si476x_radio_add_new_custom(struct si476x_radio *radio, + enum si476x_ctrl_idx idx) +{ + int rval; + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_new_custom(&radio->ctrl_handler, + &si476x_ctrls[idx], + NULL); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) + dev_err(radio->v4l2dev.dev, + "Could not initialize '%s' control %d\n", + si476x_ctrls[idx].name, rval); + + return rval; +} + +static int si476x_radio_probe(struct platform_device *pdev) +{ + int rval; + struct si476x_radio *radio; + struct v4l2_ctrl *ctrl; + + static atomic_t instance = ATOMIC_INIT(0); + + radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL); + if (!radio) + return -ENOMEM; + + radio->core = i2c_mfd_cell_to_core(&pdev->dev); + + v4l2_device_set_name(&radio->v4l2dev, DRIVER_NAME, &instance); + + rval = v4l2_device_register(&pdev->dev, &radio->v4l2dev); + if (rval) { + dev_err(&pdev->dev, "Cannot register v4l2_device.\n"); + return rval; + } + + memcpy(&radio->videodev, &si476x_viddev_template, + sizeof(struct video_device)); + + radio->videodev.v4l2_dev = &radio->v4l2dev; + radio->videodev.ioctl_ops = &si4761_ioctl_ops; + + video_set_drvdata(&radio->videodev, radio); + platform_set_drvdata(pdev, radio); + + set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags); + + radio->v4l2dev.ctrl_handler = &radio->ctrl_handler; + v4l2_ctrl_handler_init(&radio->ctrl_handler, + 1 + ARRAY_SIZE(si476x_ctrls)); + + if (si476x_core_has_am(radio->core)) { + ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, + &si476x_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, + 0, 0); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) { + dev_err(&pdev->dev, "Could not initialize V4L2_CID_POWER_LINE_FREQUENCY control %d\n", + rval); + goto exit; + } + + rval = si476x_radio_add_new_custom(radio, + SI476X_IDX_HARMONICS_COUNT); + if (rval < 0) + goto exit; + } + + rval = si476x_radio_add_new_custom(radio, SI476X_IDX_RSSI_THRESHOLD); + if (rval < 0) + goto exit; + + rval = si476x_radio_add_new_custom(radio, SI476X_IDX_SNR_THRESHOLD); + if (rval < 0) + goto exit; + + rval = si476x_radio_add_new_custom(radio, SI476X_IDX_MAX_TUNE_ERROR); + if (rval < 0) + goto exit; + + ctrl = v4l2_ctrl_new_std_menu(&radio->ctrl_handler, + &si476x_ctrl_ops, + V4L2_CID_TUNE_DEEMPHASIS, + V4L2_DEEMPHASIS_75_uS, 0, 0); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) { + dev_err(&pdev->dev, "Could not initialize V4L2_CID_TUNE_DEEMPHASIS control %d\n", + rval); + goto exit; + } + + ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &si476x_ctrl_ops, + V4L2_CID_RDS_RECEPTION, + 0, 1, 1, 1); + rval = radio->ctrl_handler.error; + if (ctrl == NULL && rval) { + dev_err(&pdev->dev, "Could not initialize V4L2_CID_RDS_RECEPTION control %d\n", + rval); + goto exit; + } + + if (si476x_core_has_diversity(radio->core)) { + si476x_ctrls[SI476X_IDX_DIVERSITY_MODE].def = + si476x_phase_diversity_mode_to_idx(radio->core->diversity_mode); + si476x_radio_add_new_custom(radio, SI476X_IDX_DIVERSITY_MODE); + if (rval < 0) + goto exit; + + si476x_radio_add_new_custom(radio, SI476X_IDX_INTERCHIP_LINK); + if (rval < 0) + goto exit; + } + + /* register video device */ + rval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, -1); + if (rval < 0) { + dev_err(&pdev->dev, "Could not register video device\n"); + goto exit; + } + + rval = si476x_radio_init_debugfs(radio); + if (rval < 0) { + dev_err(&pdev->dev, "Could not creat debugfs interface\n"); + goto exit; + } + + return 0; +exit: + v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); + return rval; +} + +static int si476x_radio_remove(struct platform_device *pdev) +{ + struct si476x_radio *radio = platform_get_drvdata(pdev); + + v4l2_ctrl_handler_free(radio->videodev.ctrl_handler); + video_unregister_device(&radio->videodev); + v4l2_device_unregister(&radio->v4l2dev); + debugfs_remove_recursive(radio->debugfs); + + return 0; +} + +MODULE_ALIAS("platform:si476x-radio"); + +static struct platform_driver si476x_radio_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = si476x_radio_probe, + .remove = si476x_radio_remove, +}; +module_platform_driver(si476x_radio_driver); + +MODULE_AUTHOR("Andrey Smirnov "); +MODULE_DESCRIPTION("Driver for Si4761/64/68 AM/FM Radio MFD Cell"); +MODULE_LICENSE("GPL"); diff --git a/include/media/si476x.h b/include/media/si476x.h new file mode 100644 index 000000000000..e02e241e2d22 --- /dev/null +++ b/include/media/si476x.h @@ -0,0 +1,37 @@ +/* + * include/media/si476x.h -- Common definitions for si476x driver + * + * Copyright (C) 2012 Innovative Converged Devices(ICD) + * Copyright (C) 2013 Andrey Smirnov + * + * Author: Andrey Smirnov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#ifndef SI476X_H +#define SI476X_H + +#include +#include + +#include + +enum si476x_ctrl_id { + V4L2_CID_SI476X_RSSI_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 1), + V4L2_CID_SI476X_SNR_THRESHOLD = (V4L2_CID_USER_SI476X_BASE + 2), + V4L2_CID_SI476X_MAX_TUNE_ERROR = (V4L2_CID_USER_SI476X_BASE + 3), + V4L2_CID_SI476X_HARMONICS_COUNT = (V4L2_CID_USER_SI476X_BASE + 4), + V4L2_CID_SI476X_DIVERSITY_MODE = (V4L2_CID_USER_SI476X_BASE + 5), + V4L2_CID_SI476X_INTERCHIP_LINK = (V4L2_CID_USER_SI476X_BASE + 6), +}; + +#endif /* SI476X_H*/ -- cgit v1.2.3 From 71867976466b48462f65992d3d6198e5f2888bbf Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 17 Apr 2013 08:18:30 -0300 Subject: [media] lg2160: dubious one-bit signed bitfield Sparse complains that these are "dubious one-bit signed bitfields" and the comment says it was intended to be 1 and 0 instead of -1 and 0. Signed-off-by: Dan Carpenter Signed-off-by: Michael Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/lg2160.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/lg2160.h b/drivers/media/dvb-frontends/lg2160.h index a5f036824d68..194a07a78dc1 100644 --- a/drivers/media/dvb-frontends/lg2160.h +++ b/drivers/media/dvb-frontends/lg2160.h @@ -57,10 +57,10 @@ struct lg2160_config { u16 if_khz; /* disable i2c repeater - 0:repeater enabled 1:repeater disabled */ - int deny_i2c_rptr:1; + unsigned int deny_i2c_rptr:1; /* spectral inversion - 0:disabled 1:enabled */ - int spectral_inversion:1; + unsigned int spectral_inversion:1; unsigned int output_if; enum lg2160_spi_clock spi_clock; -- cgit v1.2.3 From 5ddfbbb9ca2e74d4b392ccef675641babba6b7f8 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 13 Apr 2013 18:52:04 -0300 Subject: [media] cx88: Fix unsafe locking in suspend-resume Legacy PCI suspend-resume handlers are called with interrupts enabled. But cx8800_suspend/cx8800_resume and cx8802_suspend_common/cx8802_resume_common use spin_lock/spin_unlock functions to acquire dev->slock, while the same lock is acquired in the corresponding irq-handlers: cx8800_irq and cx8802_irq. That means a deadlock is possible if an interrupt happens while suspend or resume owns the lock. The patch replaces spin_lock/spin_unlock with spin_lock_irqsave/spin_unlock_irqrestore. Found by Linux Driver Verification project (linuxtesting.org). [mchehab@redhat.com: Fix CodingStyle] Signed-off-by: Alexey Khoroshilov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-mpeg.c | 10 ++++++---- drivers/media/pci/cx88/cx88-video.c | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index c9d3182f79d5..2d3507eb4897 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -532,16 +532,17 @@ static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; + unsigned long flags; /* stop mpeg dma */ - spin_lock(&dev->slock); + spin_lock_irqsave(&dev->slock, flags); if (!list_empty(&dev->mpegq.active)) { dprintk( 2, "suspend\n" ); printk("%s: suspend mpeg\n", core->name); cx8802_stop_dma(dev); del_timer(&dev->mpegq.timeout); } - spin_unlock(&dev->slock); + spin_unlock_irqrestore(&dev->slock, flags); /* FIXME -- shutdown device */ cx88_shutdown(dev->core); @@ -558,6 +559,7 @@ static int cx8802_resume_common(struct pci_dev *pci_dev) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; + unsigned long flags; int err; if (dev->state.disabled) { @@ -584,12 +586,12 @@ static int cx8802_resume_common(struct pci_dev *pci_dev) cx88_reset(dev->core); /* restart video+vbi capture */ - spin_lock(&dev->slock); + spin_lock_irqsave(&dev->slock, flags); if (!list_empty(&dev->mpegq.active)) { printk("%s: resume mpeg\n", core->name); cx8802_restart_queue(dev,&dev->mpegq); } - spin_unlock(&dev->slock); + spin_unlock_irqrestore(&dev->slock, flags); return 0; } diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index e3f6181d1044..1b00615fd395 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1954,9 +1954,10 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) { struct cx8800_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; + unsigned long flags; /* stop video+vbi capture */ - spin_lock(&dev->slock); + spin_lock_irqsave(&dev->slock, flags); if (!list_empty(&dev->vidq.active)) { printk("%s/0: suspend video\n", core->name); stop_video_dma(dev); @@ -1967,7 +1968,7 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) cx8800_stop_vbi_dma(dev); del_timer(&dev->vbiq.timeout); } - spin_unlock(&dev->slock); + spin_unlock_irqrestore(&dev->slock, flags); if (core->ir) cx88_ir_stop(core); @@ -1986,6 +1987,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) { struct cx8800_dev *dev = pci_get_drvdata(pci_dev); struct cx88_core *core = dev->core; + unsigned long flags; int err; if (dev->state.disabled) { @@ -2016,7 +2018,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) cx_set(MO_PCI_INTMSK, core->pci_irqmask); /* restart video+vbi capture */ - spin_lock(&dev->slock); + spin_lock_irqsave(&dev->slock, flags); if (!list_empty(&dev->vidq.active)) { printk("%s/0: resume video\n", core->name); restart_video_queue(dev,&dev->vidq); @@ -2025,7 +2027,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) printk("%s/0: resume vbi\n", core->name); cx8800_restart_vbi_queue(dev,&dev->vbiq); } - spin_unlock(&dev->slock); + spin_unlock_irqrestore(&dev->slock, flags); return 0; } -- cgit v1.2.3 From 1552fb344d5ddd5178e8774a31fdb08765c668e1 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Fri, 19 Apr 2013 17:09:46 -0300 Subject: [media] em28xx: add a missing le16_to_cpu conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 61ff5d69 "em28xx: improve em2710/em2820 distinction" missed the le16_to_cpu conversion of the USB vendor ID. Signed-off-by: Frank Schäfer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index cc63f1963de5..d2ed67825993 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2910,7 +2910,8 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, break; case CHIP_ID_EM2820: chip_name = "em2710/2820"; - if (dev->udev->descriptor.idVendor == 0xeb1a) { + if (le16_to_cpu(dev->udev->descriptor.idVendor) + == 0xeb1a) { __le16 idProd = dev->udev->descriptor.idProduct; if (le16_to_cpu(idProd) == 0x2710) chip_name = "em2710"; -- cgit v1.2.3 From 173a64cb3fcff1993b2aa8113e53fd379f6a968f Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Mon, 22 Apr 2013 12:45:52 -0300 Subject: [media] dib8000: enhancement The intend of this patch is to improve the support of the dib8000. Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib8000.c | 2239 +++++++++++++++----------- drivers/media/dvb-frontends/dib8000.h | 6 +- drivers/media/dvb-frontends/dibx000_common.h | 3 +- drivers/media/usb/dvb-usb/dib0700_devices.c | 2 +- 4 files changed, 1323 insertions(+), 927 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 1f3bcb5a1de8..1d719cce8995 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -23,8 +23,8 @@ #define LAYER_B 2 #define LAYER_C 3 -#define FE_CALLBACK_TIME_NEVER 0xffffffff #define MAX_NUMBER_OF_FRONTENDS 6 +/* #define DIB8000_AGC_FREEZE */ static int debug; module_param(debug, int, 0644); @@ -32,8 +32,6 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); #define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0) -#define FE_STATUS_TUNE_FAILED 0 - struct i2c_device { struct i2c_adapter *adap; u8 addr; @@ -42,6 +40,23 @@ struct i2c_device { struct mutex *i2c_buffer_lock; }; +enum param_loop_step { + LOOP_TUNE_1, + LOOP_TUNE_2 +}; + +enum dib8000_autosearch_step { + AS_START = 0, + AS_SEARCHING_FFT, + AS_SEARCHING_GUARD, + AS_DONE = 100, +}; + +enum timeout_mode { + SYMBOL_DEPENDENT_OFF = 0, + SYMBOL_DEPENDENT_ON, +}; + struct dib8000_state { struct dib8000_config cfg; @@ -72,7 +87,7 @@ struct dib8000_state { u16 revision; u8 isdbt_cfg_loaded; enum frontend_tune_state tune_state; - u32 status; + s32 status; struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS]; @@ -85,6 +100,30 @@ struct dib8000_state { u16 tuner_enable; struct i2c_adapter dib8096p_tuner_adap; + u16 current_demod_bw; + + u16 seg_mask; + u16 seg_diff_mask; + u16 mode; + u8 layer_b_nb_seg; + u8 layer_c_nb_seg; + + u8 channel_parameters_set; + u16 autosearch_state; + u16 found_nfft; + u16 found_guard; + u8 subchannel; + u8 symbol_duration; + u32 timeout; + u8 longest_intlv_layer; + u16 output_mode; + +#ifdef DIB8000_AGC_FREEZE + u16 agc1_max; + u16 agc1_min; + u16 agc2_max; + u16 agc2_min; +#endif }; enum dib8000_power_mode { @@ -338,9 +377,9 @@ static void dib8000_set_acquisition_mode(struct dib8000_state *state) static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode) { struct dib8000_state *state = fe->demodulator_priv; - u16 outreg, fifo_threshold, smo_mode, sram = 0x0205; /* by default SDRAM deintlv is enabled */ + state->output_mode = mode; outreg = 0; fifo_threshold = 1792; smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); @@ -399,8 +438,9 @@ static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode) static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff) { struct dib8000_state *state = fe->demodulator_priv; - u16 sync_wait = dib8000_read_word(state, 273) & 0xfff0; + u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0; + dprintk("set diversity input to %i", onoff); if (!state->differential_constellation) { dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1 dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2 @@ -424,6 +464,13 @@ static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff) dib8000_write_word(state, 271, 1); break; } + + if (state->revision == 0x8002) { + tmp = dib8000_read_word(state, 903); + dib8000_write_word(state, 903, tmp & ~(1 << 3)); + msleep(30); + dib8000_write_word(state, 903, tmp | (1 << 3)); + } return 0; } @@ -468,27 +515,6 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow dib8000_write_word(state, 1280, reg_1280); } -static int dib8000_init_sdram(struct dib8000_state *state) -{ - u16 reg = 0; - dprintk("Init sdram"); - - reg = dib8000_read_word(state, 274)&0xfff0; - /* P_dintlv_delay_ram = 7 because of MobileSdram */ - dib8000_write_word(state, 274, reg | 0x7); - - dib8000_write_word(state, 1803, (7<<2)); - - reg = dib8000_read_word(state, 1280); - /* force restart P_restart_sdram */ - dib8000_write_word(state, 1280, reg | (1<<2)); - - /* release restart P_restart_sdram */ - dib8000_write_word(state, 1280, reg); - - return 0; -} - static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_states no) { int ret = 0; @@ -584,18 +610,23 @@ static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw) static int dib8000_sad_calib(struct dib8000_state *state) { + u8 sad_sel = 3; + if (state->revision == 0x8090) { - dprintk("%s: the sad calibration is not needed for the dib8096P", - __func__); - return 0; - } - /* internal */ - dib8000_write_word(state, 923, (0 << 1) | (0 << 0)); - dib8000_write_word(state, 924, 776); // 0.625*3.3 / 4096 + dib8000_write_word(state, 922, (sad_sel << 2)); + dib8000_write_word(state, 923, 2048); + + dib8000_write_word(state, 922, (sad_sel << 2) | 0x1); + dib8000_write_word(state, 922, (sad_sel << 2)); + } else { + /* internal */ + dib8000_write_word(state, 923, (0 << 1) | (0 << 0)); + dib8000_write_word(state, 924, 776); - /* do the calibration */ - dib8000_write_word(state, 923, (1 << 0)); - dib8000_write_word(state, 923, (0 << 0)); + /* do the calibration */ + dib8000_write_word(state, 923, (1 << 0)); + dib8000_write_word(state, 923, (0 << 0)); + } msleep(1); return 0; @@ -609,8 +640,8 @@ int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) state->wbd_ref = value; return dib8000_write_word(state, 106, value); } - EXPORT_SYMBOL(dib8000_set_wbd_ref); + static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw) { dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25); @@ -685,20 +716,23 @@ static void dib8000_reset_pll(struct dib8000_state *state) } int dib8000_update_pll(struct dvb_frontend *fe, - struct dibx000_bandwidth_config *pll) + struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio) { struct dib8000_state *state = fe->demodulator_priv; u16 reg_1857, reg_1856 = dib8000_read_word(state, 1856); - u8 loopdiv, prediv; + u8 loopdiv, prediv, oldprediv = state->cfg.pll->pll_prediv ; u32 internal, xtal; /* get back old values */ prediv = reg_1856 & 0x3f; loopdiv = (reg_1856 >> 6) & 0x3f; - if ((pll != NULL) && (pll->pll_prediv != prediv || - pll->pll_ratio != loopdiv)) { - dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio); + if ((pll == NULL) || (pll->pll_prediv == prediv && + pll->pll_ratio == loopdiv)) + return -EINVAL; + + dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio); + if (state->revision == 0x8090) { reg_1856 &= 0xf000; reg_1857 = dib8000_read_word(state, 1857); /* disable PLL */ @@ -729,10 +763,33 @@ int dib8000_update_pll(struct dvb_frontend *fe, reg_1856 = dib8000_read_word(state, 1856); dprintk("PLL Updated with prediv = %d and loopdiv = %d", reg_1856&0x3f, (reg_1856>>6)&0x3f); + } else { + if (bw != state->current_demod_bw) { + /** Bandwidth change => force PLL update **/ + dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv); + + if (state->cfg.pll->pll_prediv != oldprediv) { + /** Full PLL change only if prediv is changed **/ + + /** full update => bypass and reconfigure **/ + dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio); + dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */ + dib8000_reset_pll(state); + dib8000_write_word(state, 898, 0x0004); /* sad */ + } else + ratio = state->cfg.pll->pll_ratio; - return 0; - } - return -EINVAL; + state->current_demod_bw = bw; + } + + if (ratio != 0) { + /** ratio update => only change ratio **/ + dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio); + dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */ + } +} + + return 0; } EXPORT_SYMBOL(dib8000_update_pll); @@ -928,7 +985,7 @@ static int dib8000_reset(struct dvb_frontend *fe) dib8000_set_power_mode(state, DIB8000_POWER_ALL); /* always leave the VBG voltage on - it consumes almost nothing but takes a long time to start */ - dib8000_set_adc_state(state, DIBX000_VBG_ENABLE); + dib8000_set_adc_state(state, DIBX000_ADC_OFF); /* restart all parts */ dib8000_write_word(state, 770, 0xffff); @@ -992,12 +1049,11 @@ static int dib8000_reset(struct dvb_frontend *fe) l = *n++; } } - if (state->revision != 0x8090) - dib8000_write_word(state, 903, (0 << 4) | 2); + state->isdbt_cfg_loaded = 0; //div_cfg override for special configs - if (state->cfg.div_cfg != 0) + if ((state->revision != 8090) && (state->cfg.div_cfg != 0)) dib8000_write_word(state, 903, state->cfg.div_cfg); /* unforce divstr regardless whether i2c enumeration was done or not */ @@ -1006,10 +1062,12 @@ static int dib8000_reset(struct dvb_frontend *fe) dib8000_set_bandwidth(fe, 6000); dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON); - if (state->revision != 0x8090) { - dib8000_sad_calib(state); + dib8000_sad_calib(state); + if (state->revision != 0x8090) dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF); - } + + /* ber_rs_len = 3 */ + dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY); @@ -1441,6 +1499,7 @@ static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode) u8 prefer_mpeg_mux_use = 1; int ret = 0; + state->output_mode = mode; dib8096p_host_bus_drive(state, 1); fifo_threshold = 1792; @@ -1879,782 +1938,637 @@ static const u16 adc_target_16dB[11] = { }; static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 }; -static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching) +static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation) { - u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0; - u8 guard, crate, constellation, timeI; - u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff; // All 13 segments enabled - const s16 *ncoeff = NULL, *ana_fe; - u16 tmcc_pow = 0; - u16 coff_pow = 0x2800; - u16 init_prbs = 0xfff; - u16 ana_gain = 0; - - if (state->revision == 0x8090) - dib8000_init_sdram(state); - - if (state->ber_monitored_layer != LAYER_ALL) - dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer); - else - dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60); - - i = dib8000_read_word(state, 26) & 1; // P_dds_invspec - dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion^i); - - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { - //compute new dds_freq for the seg and adjust prbs - int seg_offset = - state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx - - (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) - - (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2); - int clk = state->cfg.pll->internal; - u32 segtodds = ((u32) (430 << 23) / clk) << 3; // segtodds = SegBW / Fclk * pow(2,26) - int dds_offset = seg_offset * segtodds; - int new_dds, sub_channel; - if ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) - dds_offset -= (int)(segtodds / 2); - - if (state->cfg.pll->ifreq == 0) { - if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) { - dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1); - new_dds = dds_offset; - } else - new_dds = dds_offset; - - // We shift tuning frequency if the wanted segment is : - // - the segment of center frequency with an odd total number of segments - // - the segment to the left of center frequency with an even total number of segments - // - the segment to the right of center frequency with an even total number of segments - if ((state->fe[0]->dtv_property_cache.delivery_system == SYS_ISDBT) - && (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) - && (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) - && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == - ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) - || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) - && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2))) - || (((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) == 0) - && (state->fe[0]->dtv_property_cache.isdbt_sb_segment_idx == - ((state->fe[0]->dtv_property_cache.isdbt_sb_segment_count / 2) + 1))) - )) { - new_dds -= ((u32) (850 << 22) / clk) << 4; // new_dds = 850 (freq shift in KHz) / Fclk * pow(2,26) - } - } else { - if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) - new_dds = state->cfg.pll->ifreq - dds_offset; - else - new_dds = state->cfg.pll->ifreq + dds_offset; - } - dib8000_write_word(state, 27, (u16) ((new_dds >> 16) & 0x01ff)); - dib8000_write_word(state, 28, (u16) (new_dds & 0xffff)); - if (state->fe[0]->dtv_property_cache.isdbt_sb_segment_count % 2) - sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset) + 1) % 41) / 3; - else - sub_channel = ((state->fe[0]->dtv_property_cache.isdbt_sb_subchannel + (3 * seg_offset)) % 41) / 3; - sub_channel -= 6; - - if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K - || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) { - dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); //adp_pass =1 - dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); //pha3_force_pha_shift = 1 - } else { - dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); //adp_pass =0 - dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); //pha3_force_pha_shift = 0 - } - - switch (state->fe[0]->dtv_property_cache.transmission_mode) { - case TRANSMISSION_MODE_2K: - switch (sub_channel) { - case -6: - init_prbs = 0x0; - break; // 41, 0, 1 - case -5: - init_prbs = 0x423; - break; // 02~04 - case -4: - init_prbs = 0x9; - break; // 05~07 - case -3: - init_prbs = 0x5C7; - break; // 08~10 - case -2: - init_prbs = 0x7A6; - break; // 11~13 - case -1: - init_prbs = 0x3D8; - break; // 14~16 - case 0: - init_prbs = 0x527; - break; // 17~19 - case 1: - init_prbs = 0x7FF; - break; // 20~22 - case 2: - init_prbs = 0x79B; - break; // 23~25 - case 3: - init_prbs = 0x3D6; - break; // 26~28 - case 4: - init_prbs = 0x3A2; - break; // 29~31 - case 5: - init_prbs = 0x53B; - break; // 32~34 - case 6: - init_prbs = 0x2F4; - break; // 35~37 - default: - case 7: - init_prbs = 0x213; - break; // 38~40 - } - break; - - case TRANSMISSION_MODE_4K: - switch (sub_channel) { - case -6: - init_prbs = 0x0; - break; // 41, 0, 1 - case -5: - init_prbs = 0x208; - break; // 02~04 - case -4: - init_prbs = 0xC3; - break; // 05~07 - case -3: - init_prbs = 0x7B9; - break; // 08~10 - case -2: - init_prbs = 0x423; - break; // 11~13 - case -1: - init_prbs = 0x5C7; - break; // 14~16 - case 0: - init_prbs = 0x3D8; - break; // 17~19 - case 1: - init_prbs = 0x7FF; - break; // 20~22 - case 2: - init_prbs = 0x3D6; - break; // 23~25 - case 3: - init_prbs = 0x53B; - break; // 26~28 - case 4: - init_prbs = 0x213; - break; // 29~31 - case 5: - init_prbs = 0x29; - break; // 32~34 - case 6: - init_prbs = 0xD0; - break; // 35~37 - default: - case 7: - init_prbs = 0x48E; - break; // 38~40 - } - break; - - default: - case TRANSMISSION_MODE_8K: - switch (sub_channel) { - case -6: - init_prbs = 0x0; - break; // 41, 0, 1 - case -5: - init_prbs = 0x740; - break; // 02~04 - case -4: - init_prbs = 0x069; - break; // 05~07 - case -3: - init_prbs = 0x7DD; - break; // 08~10 - case -2: - init_prbs = 0x208; - break; // 11~13 - case -1: - init_prbs = 0x7B9; - break; // 14~16 - case 0: - init_prbs = 0x5C7; - break; // 17~19 - case 1: - init_prbs = 0x7FF; - break; // 20~22 - case 2: - init_prbs = 0x53B; - break; // 23~25 - case 3: - init_prbs = 0x29; - break; // 26~28 - case 4: - init_prbs = 0x48E; - break; // 29~31 - case 5: - init_prbs = 0x4C4; - break; // 32~34 - case 6: - init_prbs = 0x367; - break; // 33~37 - default: - case 7: - init_prbs = 0x684; - break; // 38~40 - } - break; - } - } else { - dib8000_write_word(state, 27, (u16) ((state->cfg.pll->ifreq >> 16) & 0x01ff)); - dib8000_write_word(state, 28, (u16) (state->cfg.pll->ifreq & 0xffff)); - dib8000_write_word(state, 26, (u16) ((state->cfg.pll->ifreq >> 25) & 0x0003)); - } - /*P_mode == ?? */ - dib8000_write_word(state, 10, (seq << 4)); - // dib8000_write_word(state, 287, (dib8000_read_word(state, 287) & 0xe000) | 0x1000); - - switch (state->fe[0]->dtv_property_cache.guard_interval) { - case GUARD_INTERVAL_1_32: - guard = 0; - break; - case GUARD_INTERVAL_1_16: - guard = 1; - break; - case GUARD_INTERVAL_1_8: - guard = 2; - break; - case GUARD_INTERVAL_1_4: - default: - guard = 3; - break; - } - - dib8000_write_word(state, 1, (init_prbs << 2) | (guard & 0x3)); // ADDR 1 + u8 cr, constellation, time_intlv; - max_constellation = DQPSK; - for (i = 0; i < 3; i++) { - switch (state->fe[0]->dtv_property_cache.layer[i].modulation) { - case DQPSK: + switch (state->fe[0]->dtv_property_cache.layer[layer_index].modulation) { + case DQPSK: constellation = 0; break; - case QPSK: + case QPSK: constellation = 1; break; - case QAM_16: + case QAM_16: constellation = 2; break; - case QAM_64: - default: + case QAM_64: + default: constellation = 3; break; - } + } - switch (state->fe[0]->dtv_property_cache.layer[i].fec) { - case FEC_1_2: - crate = 1; + switch (state->fe[0]->dtv_property_cache.layer[layer_index].fec) { + case FEC_1_2: + cr = 1; break; - case FEC_2_3: - crate = 2; + case FEC_2_3: + cr = 2; break; - case FEC_3_4: - crate = 3; + case FEC_3_4: + cr = 3; break; - case FEC_5_6: - crate = 5; + case FEC_5_6: + cr = 5; break; - case FEC_7_8: - default: - crate = 7; + case FEC_7_8: + default: + cr = 7; break; - } + } - if ((state->fe[0]->dtv_property_cache.layer[i].interleaving > 0) && - ((state->fe[0]->dtv_property_cache.layer[i].interleaving <= 3) || - (state->fe[0]->dtv_property_cache.layer[i].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1)) - ) - timeI = state->fe[0]->dtv_property_cache.layer[i].interleaving; - else - timeI = 0; - dib8000_write_word(state, 2 + i, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[i].segment_count & 0xf) << 6) | - (crate << 3) | timeI); - if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) { - switch (max_constellation) { - case DQPSK: - case QPSK: - if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_16 || - state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64) - max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation; + if ((state->fe[0]->dtv_property_cache.layer[layer_index].interleaving > 0) && ((state->fe[0]->dtv_property_cache.layer[layer_index].interleaving <= 3) || (state->fe[0]->dtv_property_cache.layer[layer_index].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1))) + time_intlv = state->fe[0]->dtv_property_cache.layer[layer_index].interleaving; + else + time_intlv = 0; + + dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv); + if (state->fe[0]->dtv_property_cache.layer[layer_index].segment_count > 0) { + switch (max_constellation) { + case DQPSK: + case QPSK: + if (state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_16 || state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_64) + max_constellation = state->fe[0]->dtv_property_cache.layer[layer_index].modulation; break; - case QAM_16: - if (state->fe[0]->dtv_property_cache.layer[i].modulation == QAM_64) - max_constellation = state->fe[0]->dtv_property_cache.layer[i].modulation; + case QAM_16: + if (state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_64) + max_constellation = state->fe[0]->dtv_property_cache.layer[layer_index].modulation; break; - } } } - mode = fft_to_mode(state); + return max_constellation; +} + +static const u16 adp_Q64[4] = {0x0148, 0xfff0, 0x00a4, 0xfff8}; /* P_adp_regul_cnt 0.04, P_adp_noise_cnt -0.002, P_adp_regul_ext 0.02, P_adp_noise_ext -0.001 */ +static const u16 adp_Q16[4] = {0x023d, 0xffdf, 0x00a4, 0xfff0}; /* P_adp_regul_cnt 0.07, P_adp_noise_cnt -0.004, P_adp_regul_ext 0.02, P_adp_noise_ext -0.002 */ +static const u16 adp_Qdefault[4] = {0x099a, 0xffae, 0x0333, 0xfff8}; /* P_adp_regul_cnt 0.3, P_adp_noise_cnt -0.01, P_adp_regul_ext 0.1, P_adp_noise_ext -0.002 */ +static u16 dib8000_adp_fine_tune(struct dib8000_state *state, u16 max_constellation) +{ + u16 i, ana_gain = 0; + const u16 *adp; + + /* channel estimation fine configuration */ + switch (max_constellation) { + case QAM_64: + ana_gain = 0x7; + adp = &adp_Q64[0]; + break; + case QAM_16: + ana_gain = 0x7; + adp = &adp_Q16[0]; + break; + default: + ana_gain = 0; + adp = &adp_Qdefault[0]; + break; + } + + for (i = 0; i < 4; i++) + dib8000_write_word(state, 215 + i, adp[i]); - //dib8000_write_word(state, 5, 13); /*p_last_seg = 13*/ + return ana_gain; +} - dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | - ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache. - isdbt_sb_mode & 1) << 4)); +static void dib8000_update_ana_gain(struct dib8000_state *state, u16 ana_gain) +{ + u16 i; - dprintk("mode = %d ; guard = %d", mode, state->fe[0]->dtv_property_cache.guard_interval); + dib8000_write_word(state, 116, ana_gain); - /* signal optimization parameter */ + /* update ADC target depending on ana_gain */ + if (ana_gain) { /* set -16dB ADC target for ana_gain=-1 */ + for (i = 0; i < 10; i++) + dib8000_write_word(state, 80 + i, adc_target_16dB[i]); + } else { /* set -22dB ADC target for ana_gain=0 */ + for (i = 0; i < 10; i++) + dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355); + } +} - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) { - seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0]; - for (i = 1; i < 3; i++) - nbseg_diff += - (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count; - for (i = 0; i < nbseg_diff; i++) - seg_diff_mask |= 1 << permu_seg[i + 1]; - } else { - for (i = 0; i < 3; i++) - nbseg_diff += - (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count; - for (i = 0; i < nbseg_diff; i++) - seg_diff_mask |= 1 << permu_seg[i]; +static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *ana_fe) +{ + u16 mode = 0; + + if (state->isdbt_cfg_loaded == 0) + for (mode = 0; mode < 24; mode++) + dib8000_write_word(state, 117 + mode, ana_fe[mode]); +} + +static const u16 lut_prbs_2k[14] = { + 0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213 +}; +static const u16 lut_prbs_4k[14] = { + 0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E +}; +static const u16 lut_prbs_8k[14] = { + 0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684 +}; + +static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel) +{ + int sub_channel_prbs_group = 0; + + sub_channel_prbs_group = (subchannel / 3) + 1; + dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]); + + switch (state->fe[0]->dtv_property_cache.transmission_mode) { + case TRANSMISSION_MODE_2K: + return lut_prbs_2k[sub_channel_prbs_group]; + case TRANSMISSION_MODE_4K: + return lut_prbs_4k[sub_channel_prbs_group]; + default: + case TRANSMISSION_MODE_8K: + return lut_prbs_8k[sub_channel_prbs_group]; } - dprintk("nbseg_diff = %X (%d)", seg_diff_mask, seg_diff_mask); +} - state->differential_constellation = (seg_diff_mask != 0); - if (state->revision != 0x8090) - dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); - else - dib8096p_set_diversity_in(state->fe[0], state->diversity_onoff); +static void dib8000_set_13seg_channel(struct dib8000_state *state) +{ + u16 i; + u16 coff_pow = 0x2800; + + state->seg_mask = 0x1fff; /* All 13 segments enabled */ - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) - seg_mask13 = 0x00E0; - else // 1-segment - seg_mask13 = 0x0040; - } else - seg_mask13 = 0x1fff; + /* ---- COFF ---- Carloff, the most robust --- */ + if (state->isdbt_cfg_loaded == 0) { /* if not Sound Broadcasting mode : put default values for 13 segments */ + dib8000_write_word(state, 180, (16 << 6) | 9); + dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2); + coff_pow = 0x2800; + for (i = 0; i < 6; i++) + dib8000_write_word(state, 181+i, coff_pow); - // WRITE: Mode & Diff mask - dib8000_write_word(state, 0, (mode << 13) | seg_diff_mask); + /* P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1 */ + /* P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1 */ + dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1); - if ((seg_diff_mask) || (state->fe[0]->dtv_property_cache.isdbt_sb_mode)) - dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200); - else - dib8000_write_word(state, 268, (2 << 9) | 39); //init value + /* P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 */ + dib8000_write_word(state, 340, (8 << 6) | (6 << 0)); + /* P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 */ + dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); + + dib8000_write_word(state, 228, 0); /* default value */ + dib8000_write_word(state, 265, 31); /* default value */ + dib8000_write_word(state, 205, 0x200f); /* init value */ + } + + /* + * make the cpil_coff_lock more robust but slower p_coff_winlen + * 6bits; p_coff_thres_lock 6bits (for coff lock if needed) + */ + + if (state->cfg.pll->ifreq == 0) + dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */ - // ---- SMALL ---- - // P_small_seg_diff - dib8000_write_word(state, 352, seg_diff_mask); // ADDR 352 + dib8000_load_ana_fe_coefs(state, ana_fe_coeff_13seg); +} + +static void dib8000_set_subchannel_prbs(struct dib8000_state *state, u16 init_prbs) +{ + u16 reg_1; + + reg_1 = dib8000_read_word(state, 1); + dib8000_write_word(state, 1, (init_prbs << 2) | (reg_1 & 0x3)); /* ADDR 1 */ +} + +static void dib8000_small_fine_tune(struct dib8000_state *state) +{ + u16 i; + const s16 *ncoeff; - dib8000_write_word(state, 353, seg_mask13); // ADDR 353 + dib8000_write_word(state, 352, state->seg_diff_mask); + dib8000_write_word(state, 353, state->seg_mask); -/* // P_small_narrow_band=0, P_small_last_seg=13, P_small_offset_num_car=5 */ + /* P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 */ + dib8000_write_word(state, 351, (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5); - // ---- SMALL ---- - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { + /* ---- SMALL ---- */ switch (state->fe[0]->dtv_property_cache.transmission_mode) { case TRANSMISSION_MODE_2K: - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) - ncoeff = coeff_2k_sb_1seg_dqpsk; - else // QPSK or QAM - ncoeff = coeff_2k_sb_1seg; - } else { // 3-segments - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) - ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk; - else // QPSK or QAM on external segments - ncoeff = coeff_2k_sb_3seg_0dqpsk; - } else { // QPSK or QAM on central segment - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) - ncoeff = coeff_2k_sb_3seg_1dqpsk; - else // QPSK or QAM on external segments - ncoeff = coeff_2k_sb_3seg; + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */ + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */ + ncoeff = coeff_2k_sb_1seg_dqpsk; + else /* QPSK or QAM */ + ncoeff = coeff_2k_sb_1seg; + } else { /* 3-segments */ + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */ + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */ + ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk; + else /* QPSK or QAM on external segments */ + ncoeff = coeff_2k_sb_3seg_0dqpsk; + } else { /* QPSK or QAM on central segment */ + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */ + ncoeff = coeff_2k_sb_3seg_1dqpsk; + else /* QPSK or QAM on external segments */ + ncoeff = coeff_2k_sb_3seg; + } } - } - break; - + break; case TRANSMISSION_MODE_4K: - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) - ncoeff = coeff_4k_sb_1seg_dqpsk; - else // QPSK or QAM - ncoeff = coeff_4k_sb_1seg; - } else { // 3-segments - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { - ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk; - } else { // QPSK or QAM on external segments - ncoeff = coeff_4k_sb_3seg_0dqpsk; + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */ + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */ + ncoeff = coeff_4k_sb_1seg_dqpsk; + else /* QPSK or QAM */ + ncoeff = coeff_4k_sb_1seg; + } else { /* 3-segments */ + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */ + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */ + ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk; + else /* QPSK or QAM on external segments */ + ncoeff = coeff_4k_sb_3seg_0dqpsk; + } else { /* QPSK or QAM on central segment */ + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */ + ncoeff = coeff_4k_sb_3seg_1dqpsk; + else /* QPSK or QAM on external segments */ + ncoeff = coeff_4k_sb_3seg; } - } else { // QPSK or QAM on central segment - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { - ncoeff = coeff_4k_sb_3seg_1dqpsk; - } else // QPSK or QAM on external segments - ncoeff = coeff_4k_sb_3seg; } - } - break; - + break; case TRANSMISSION_MODE_AUTO: case TRANSMISSION_MODE_8K: default: - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) - ncoeff = coeff_8k_sb_1seg_dqpsk; - else // QPSK or QAM - ncoeff = coeff_8k_sb_1seg; - } else { // 3-segments - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { - ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk; - } else { // QPSK or QAM on external segments - ncoeff = coeff_8k_sb_3seg_0dqpsk; + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */ + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */ + ncoeff = coeff_8k_sb_1seg_dqpsk; + else /* QPSK or QAM */ + ncoeff = coeff_8k_sb_1seg; + } else { /* 3-segments */ + if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */ + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */ + ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk; + else /* QPSK or QAM on external segments */ + ncoeff = coeff_8k_sb_3seg_0dqpsk; + } else { /* QPSK or QAM on central segment */ + if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */ + ncoeff = coeff_8k_sb_3seg_1dqpsk; + else /* QPSK or QAM on external segments */ + ncoeff = coeff_8k_sb_3seg; } - } else { // QPSK or QAM on central segment - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) { - ncoeff = coeff_8k_sb_3seg_1dqpsk; - } else // QPSK or QAM on external segments - ncoeff = coeff_8k_sb_3seg; } - } - break; + break; } + for (i = 0; i < 8; i++) dib8000_write_word(state, 343 + i, ncoeff[i]); } +} - // P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 - dib8000_write_word(state, 351, - (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5); +static const u16 coff_thres_1seg[3] = {300, 150, 80}; +static const u16 coff_thres_3seg[3] = {350, 300, 250}; +static void dib8000_set_sb_channel(struct dib8000_state *state) +{ + const u16 *coff; + u16 i; - // ---- COFF ---- - // Carloff, the most robust - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { + if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) { + dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */ + dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */ + } else { + dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); /* adp_pass =0 */ + dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */ + } - // P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64 - // P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 - dib8000_write_word(state, 187, - (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2) - | 0x3); + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) /* 3-segments */ + state->seg_mask = 0x00E0; + else /* 1-segment */ + state->seg_mask = 0x0040; -/* // P_small_coef_ext_enable = 1 */ -/* dib8000_write_word(state, 351, dib8000_read_word(state, 351) | 0x200); */ + dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200); - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { + /* ---- COFF ---- Carloff, the most robust --- */ + /* P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64, P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 */ + dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2) | 0x3); - // P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width= (P_mode == 3) , P_coff_one_seg_sym= (P_mode-1) - if (mode == 3) - dib8000_write_word(state, 180, 0x1fcf | ((mode - 1) << 14)); - else - dib8000_write_word(state, 180, 0x0fcf | ((mode - 1) << 14)); - // P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1, - // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4 - dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4); - // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 - dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); - // P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 - dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); - - // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k - dib8000_write_word(state, 181, 300); - dib8000_write_word(state, 182, 150); - dib8000_write_word(state, 183, 80); - dib8000_write_word(state, 184, 300); - dib8000_write_word(state, 185, 150); - dib8000_write_word(state, 186, 80); - } else { // Sound Broadcasting mode 3 seg - // P_coff_one_seg_sym= 1, P_coff_one_seg_width= 1, P_coff_winlen=63, P_coff_thres_lock=15 - /* if (mode == 3) */ - /* dib8000_write_word(state, 180, 0x2fca | ((0) << 14)); */ - /* else */ - /* dib8000_write_word(state, 180, 0x2fca | ((1) << 14)); */ - dib8000_write_word(state, 180, 0x1fcf | (1 << 14)); - - // P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1, - // P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4 - dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4); - // P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 - dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); - //P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 - dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); - - // P_coff_corthres_8k, 4k, 2k and P_coff_cpilthres_8k, 4k, 2k - dib8000_write_word(state, 181, 350); - dib8000_write_word(state, 182, 300); - dib8000_write_word(state, 183, 250); - dib8000_write_word(state, 184, 350); - dib8000_write_word(state, 185, 300); - dib8000_write_word(state, 186, 250); - } + dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */ + dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));/* P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 */ - } else if (state->isdbt_cfg_loaded == 0) { // if not Sound Broadcasting mode : put default values for 13 segments - dib8000_write_word(state, 180, (16 << 6) | 9); - dib8000_write_word(state, 187, (4 << 12) | (8 << 5) | 0x2); - coff_pow = 0x2800; - for (i = 0; i < 6; i++) - dib8000_write_word(state, 181 + i, coff_pow); + /* Sound Broadcasting mode 1 seg */ + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { + /* P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width = (P_mode == 3) , P_coff_one_seg_sym = (P_mode-1) */ + if (state->mode == 3) + dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14)); + else + dib8000_write_word(state, 180, 0x0fcf | ((state->mode - 1) << 14)); - // P_ctrl_corm_thres4pre_freq_inh=1, P_ctrl_pre_freq_mode_sat=1, - // P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 3, P_pre_freq_win_len=1 - dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (3 << 5) | 1); + /* P_ctrl_corm_thres4pre_freq_inh=1,P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 5, P_pre_freq_win_len=4 */ + dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (5 << 5) | 4); + coff = &coff_thres_1seg[0]; + } else { /* Sound Broadcasting mode 3 seg */ + dib8000_write_word(state, 180, 0x1fcf | (1 << 14)); + /* P_ctrl_corm_thres4pre_freq_inh = 1, P_ctrl_pre_freq_mode_sat=1, P_ctrl_pre_freq_inh=0, P_ctrl_pre_freq_step = 4, P_pre_freq_win_len=4 */ + dib8000_write_word(state, 338, (1 << 12) | (1 << 10) | (0 << 9) | (4 << 5) | 4); + coff = &coff_thres_3seg[0]; + } - // P_ctrl_pre_freq_win_len=8, P_ctrl_pre_freq_thres_lockin=6 - dib8000_write_word(state, 340, (8 << 6) | (6 << 0)); - // P_ctrl_pre_freq_thres_lockout=4, P_small_use_tmcc/ac/cp=1 - dib8000_write_word(state, 341, (4 << 3) | (1 << 2) | (1 << 1) | (1 << 0)); + dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */ + dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */ + + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0 && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) + dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */ + + /* Write COFF thres */ + for (i = 0 ; i < 3; i++) { + dib8000_write_word(state, 181+i, coff[i]); + dib8000_write_word(state, 184+i, coff[i]); } - // ---- FFT ---- - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 && state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) - dib8000_write_word(state, 178, 64); // P_fft_powrange=64 - else - dib8000_write_word(state, 178, 32); // P_fft_powrange=32 - /* make the cpil_coff_lock more robust but slower p_coff_winlen + /* + * make the cpil_coff_lock more robust but slower p_coff_winlen * 6bits; p_coff_thres_lock 6bits (for coff lock if needed) */ - /* if ( ( nbseg_diff>0)&&(nbseg_diff<13)) - dib8000_write_word(state, 187, (dib8000_read_word(state, 187) & 0xfffb) | (1 << 3)); */ - - dib8000_write_word(state, 189, ~seg_mask13 | seg_diff_mask); /* P_lmod4_seg_inh */ - dib8000_write_word(state, 192, ~seg_mask13 | seg_diff_mask); /* P_pha3_seg_inh */ - dib8000_write_word(state, 225, ~seg_mask13 | seg_diff_mask); /* P_tac_seg_inh */ - if ((!state->fe[0]->dtv_property_cache.isdbt_sb_mode) && (state->cfg.pll->ifreq == 0)) - dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask | 0x40); /* P_equal_noise_seg_inh */ - else - dib8000_write_word(state, 266, ~seg_mask13 | seg_diff_mask); /* P_equal_noise_seg_inh */ - dib8000_write_word(state, 287, ~seg_mask13 | 0x1000); /* P_tmcc_seg_inh */ - //dib8000_write_word(state, 288, ~seg_mask13 | seg_diff_mask); /* P_tmcc_seg_eq_inh */ - if (!autosearching) - dib8000_write_word(state, 288, (~seg_mask13 | seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */ - else - dib8000_write_word(state, 288, 0x1fff); //disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. - dprintk("287 = %X (%d)", ~seg_mask13 | 0x1000, ~seg_mask13 | 0x1000); - - dib8000_write_word(state, 211, seg_mask13 & (~seg_diff_mask)); /* P_des_seg_enabled */ - - /* offset loop parameters */ - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) - /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */ - dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x40); - - else // Sound Broadcasting mode 3 seg - /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x80 */ - dib8000_write_word(state, 32, ((10 - mode) << 12) | (6 << 8) | 0x60); - } else - // TODO in 13 seg, timf_alpha can always be the same or not ? - /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */ - dib8000_write_word(state, 32, ((9 - mode) << 12) | (6 << 8) | 0x80); - - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) - /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (11-P_mode) */ - dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (10 - mode)); - - else // Sound Broadcasting mode 3 seg - /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */ - dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (9 - mode)); - } else - /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */ - dib8000_write_word(state, 37, (3 << 5) | (0 << 4) | (8 - mode)); - /* P_dvsy_sync_wait - reuse mode */ - switch (state->fe[0]->dtv_property_cache.transmission_mode) { - case TRANSMISSION_MODE_8K: - mode = 256; - break; - case TRANSMISSION_MODE_4K: - mode = 128; - break; - default: - case TRANSMISSION_MODE_2K: - mode = 64; - break; - } - if (state->cfg.diversity_delay == 0) - mode = (mode * (1 << (guard)) * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo + dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */ + + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) + dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */ else - mode = (mode * (1 << (guard)) * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for DVSY-fifo - mode <<= 4; - dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | mode); + dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */ +} - /* channel estimation fine configuration */ - switch (max_constellation) { - case QAM_64: - ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB - coeff[0] = 0x0148; /* P_adp_regul_cnt 0.04 */ - coeff[1] = 0xfff0; /* P_adp_noise_cnt -0.002 */ - coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ - coeff[3] = 0xfff8; /* P_adp_noise_ext -0.001 */ - //if (!state->cfg.hostbus_diversity) //if diversity, we should prehaps use the configuration of the max_constallation -1 - break; - case QAM_16: - ana_gain = 0x7; // -1 : avoid def_est saturation when ADC target is -16dB - coeff[0] = 0x023d; /* P_adp_regul_cnt 0.07 */ - coeff[1] = 0xffdf; /* P_adp_noise_cnt -0.004 */ - coeff[2] = 0x00a4; /* P_adp_regul_ext 0.02 */ - coeff[3] = 0xfff0; /* P_adp_noise_ext -0.002 */ - //if (!((state->cfg.hostbus_diversity) && (max_constellation == QAM_16))) - break; - default: - ana_gain = 0; // 0 : goes along with ADC target at -22dB to keep good mobile performance and lock at sensitivity level - coeff[0] = 0x099a; /* P_adp_regul_cnt 0.3 */ - coeff[1] = 0xffae; /* P_adp_noise_cnt -0.01 */ - coeff[2] = 0x0333; /* P_adp_regul_ext 0.1 */ - coeff[3] = 0xfff8; /* P_adp_noise_ext -0.002 */ - break; - } - for (mode = 0; mode < 4; mode++) - dib8000_write_word(state, 215 + mode, coeff[mode]); +static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq, u8 autosearching) +{ + u16 p_cfr_left_edge = 0, p_cfr_right_edge = 0; + u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ; + u16 max_constellation = DQPSK; + int init_prbs; - // update ana_gain depending on max constellation - dib8000_write_word(state, 116, ana_gain); - // update ADC target depending on ana_gain - if (ana_gain) { // set -16dB ADC target for ana_gain=-1 - for (i = 0; i < 10; i++) - dib8000_write_word(state, 80 + i, adc_target_16dB[i]); - } else { // set -22dB ADC target for ana_gain=0 - for (i = 0; i < 10; i++) - dib8000_write_word(state, 80 + i, adc_target_16dB[i] - 355); + /* P_mode */ + dib8000_write_word(state, 10, (seq << 4)); + + /* init mode */ + state->mode = fft_to_mode(state); + + /* set guard */ + tmp = dib8000_read_word(state, 1); + dib8000_write_word(state, 1, (tmp&0xfffc) | (state->fe[0]->dtv_property_cache.guard_interval & 0x3)); + + dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.isdbt_sb_mode & 1) << 4)); + + /* signal optimization parameter */ + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) { + state->seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0]; + for (i = 1; i < 3; i++) + nbseg_diff += (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count; + for (i = 0; i < nbseg_diff; i++) + state->seg_diff_mask |= 1 << permu_seg[i+1]; + } else { + for (i = 0; i < 3; i++) + nbseg_diff += (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count; + for (i = 0; i < nbseg_diff; i++) + state->seg_diff_mask |= 1 << permu_seg[i]; + } + + if (state->seg_diff_mask) + dib8000_write_word(state, 268, (dib8000_read_word(state, 268) & 0xF9FF) | 0x0200); + else + dib8000_write_word(state, 268, (2 << 9) | 39); /*init value */ + + for (i = 0; i < 3; i++) + max_constellation = dib8000_set_layer(state, i, max_constellation); + if (autosearching == 0) { + state->layer_b_nb_seg = state->fe[0]->dtv_property_cache.layer[1].segment_count; + state->layer_c_nb_seg = state->fe[0]->dtv_property_cache.layer[2].segment_count; } - // ---- ANA_FE ---- + /* WRITE: Mode & Diff mask */ + dib8000_write_word(state, 0, (state->mode << 13) | state->seg_diff_mask); + + state->differential_constellation = (state->seg_diff_mask != 0); + + /* channel estimation fine configuration */ + ana_gain = dib8000_adp_fine_tune(state, max_constellation); + + /* update ana_gain depending on max constellation */ + dib8000_update_ana_gain(state, ana_gain); + + /* ---- ANA_FE ---- */ + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) /* 3-segments */ + dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg); + else + dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */ + + /* TSB or ISDBT ? apply it now */ if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) - ana_fe = ana_fe_coeff_3seg; - else // 1-segment - ana_fe = ana_fe_coeff_1seg; - } else - ana_fe = ana_fe_coeff_13seg; - - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1 || state->isdbt_cfg_loaded == 0) - for (mode = 0; mode < 24; mode++) - dib8000_write_word(state, 117 + mode, ana_fe[mode]); + dib8000_set_sb_channel(state); + if (state->fe[0]->dtv_property_cache.isdbt_sb_subchannel != -1) + init_prbs = dib8000_get_init_prbs(state, state->fe[0]->dtv_property_cache.isdbt_sb_subchannel); + else + init_prbs = 0; + } else { + dib8000_set_13seg_channel(state); + init_prbs = 0xfff; + } + + /* SMALL */ + dib8000_small_fine_tune(state); + + dib8000_set_subchannel_prbs(state, init_prbs); - // ---- CHAN_BLK ---- + /* ---- CHAN_BLK ---- */ for (i = 0; i < 13; i++) { - if ((((~seg_diff_mask) >> i) & 1) == 1) { - P_cfr_left_edge += (1 << i) * ((i == 0) || ((((seg_mask13 & (~seg_diff_mask)) >> (i - 1)) & 1) == 0)); - P_cfr_right_edge += (1 << i) * ((i == 12) || ((((seg_mask13 & (~seg_diff_mask)) >> (i + 1)) & 1) == 0)); + if ((((~state->seg_diff_mask) >> i) & 1) == 1) { + p_cfr_left_edge += (1 << i) * ((i == 0) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i - 1)) & 1) == 0)); + p_cfr_right_edge += (1 << i) * ((i == 12) || ((((state->seg_mask & (~state->seg_diff_mask)) >> (i + 1)) & 1) == 0)); } } - dib8000_write_word(state, 222, P_cfr_left_edge); // P_cfr_left_edge - dib8000_write_word(state, 223, P_cfr_right_edge); // P_cfr_right_edge - // "P_cspu_left_edge" not used => do not care - // "P_cspu_right_edge" not used => do not care - - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - dib8000_write_word(state, 228, 1); // P_2d_mode_byp=1 - dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); // P_cspu_win_cut = 0 - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0 - && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) { - //dib8000_write_word(state, 219, dib8000_read_word(state, 219) & 0xfffe); // P_adp_pass = 0 - dib8000_write_word(state, 265, 15); // P_equal_noise_sel = 15 - } - } else if (state->isdbt_cfg_loaded == 0) { - dib8000_write_word(state, 228, 0); // default value - dib8000_write_word(state, 265, 31); // default value - dib8000_write_word(state, 205, 0x200f); // init value - } - // ---- TMCC ---- + dib8000_write_word(state, 222, p_cfr_left_edge); /* p_cfr_left_edge */ + dib8000_write_word(state, 223, p_cfr_right_edge); /* p_cfr_right_edge */ + /* "P_cspu_left_edge" & "P_cspu_right_edge" not used => do not care */ + + dib8000_write_word(state, 189, ~state->seg_mask | state->seg_diff_mask); /* P_lmod4_seg_inh */ + dib8000_write_word(state, 192, ~state->seg_mask | state->seg_diff_mask); /* P_pha3_seg_inh */ + dib8000_write_word(state, 225, ~state->seg_mask | state->seg_diff_mask); /* P_tac_seg_inh */ + + if (!autosearching) + dib8000_write_word(state, 288, (~state->seg_mask | state->seg_diff_mask) & 0x1fff); /* P_tmcc_seg_eq_inh */ + else + dib8000_write_word(state, 288, 0x1fff); /*disable equalisation of the tmcc when autosearch to be able to find the DQPSK channels. */ + + dib8000_write_word(state, 211, state->seg_mask & (~state->seg_diff_mask)); /* P_des_seg_enabled */ + dib8000_write_word(state, 287, ~state->seg_mask | 0x1000); /* P_tmcc_seg_inh */ + + dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */ + + /* ---- TMCC ---- */ for (i = 0; i < 3; i++) - tmcc_pow += - (((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count); - // Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); - // Threshold is set at 1/4 of max power. - tmcc_pow *= (1 << (9 - 2)); - - dib8000_write_word(state, 290, tmcc_pow); // P_tmcc_dec_thres_2k - dib8000_write_word(state, 291, tmcc_pow); // P_tmcc_dec_thres_4k - dib8000_write_word(state, 292, tmcc_pow); // P_tmcc_dec_thres_8k - //dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); - // ---- PHA3 ---- + tmcc_pow += (((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count) ; + + /* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */ + /* Threshold is set at 1/4 of max power. */ + tmcc_pow *= (1 << (9-2)); + dib8000_write_word(state, 290, tmcc_pow); /* P_tmcc_dec_thres_2k */ + dib8000_write_word(state, 291, tmcc_pow); /* P_tmcc_dec_thres_4k */ + dib8000_write_word(state, 292, tmcc_pow); /* P_tmcc_dec_thres_8k */ + /*dib8000_write_word(state, 287, (1 << 13) | 0x1000 ); */ + /* ---- PHA3 ---- */ if (state->isdbt_cfg_loaded == 0) - dib8000_write_word(state, 250, 3285); /*p_2d_hspeed_thr0 */ + dib8000_write_word(state, 250, 3285); /* p_2d_hspeed_thr0 */ - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) - state->isdbt_cfg_loaded = 0; - else - state->isdbt_cfg_loaded = 1; + state->isdbt_cfg_loaded = 0; +} + +u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal, u32 wait0_ms, u32 wait1_ms, u32 wait2_ms) +{ + u32 value; + u16 reg = 11; /* P_search_end0 start addr */ + for (reg = 11; reg < 16; reg += 2) { + if (reg == 11) { + if (state->revision == 0x8090) + value = internal * wait1_ms; /* P_search_end0 wait time */ + else + value = internal * wait0_ms; /* P_search_end0 wait time */ + } else if (reg == 13) + value = internal * wait1_ms; /* P_search_end0 wait time */ + else if (reg == 15) + value = internal * wait2_ms; /* P_search_end0 wait time */ + dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff)); + dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff)); + } + return value; } static int dib8000_autosearch_start(struct dvb_frontend *fe) { - u8 factor; - u32 value; struct dib8000_state *state = fe->demodulator_priv; + u8 slist = 0; + u32 value, internal = state->cfg.pll->internal; - int slist = 0; + if (state->revision == 0x8090) + internal = dib8000_read32(state, 23) / 1000; - state->fe[0]->dtv_property_cache.inversion = 0; - if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode) - state->fe[0]->dtv_property_cache.layer[0].segment_count = 13; - state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64; - state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3; - state->fe[0]->dtv_property_cache.layer[0].interleaving = 0; + if (state->autosearch_state == AS_SEARCHING_FFT) { + dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */ + dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */ - //choose the right list, in sb, always do everything - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { + dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x1fff) | (0 << 13) | (1 << 15)); /* P_mode = 0, P_restart_search=1 */ + dib8000_write_word(state, 1, (dib8000_read_word(state, 1) & 0xfffc) | 0); /* P_guard = 0 */ + dib8000_write_word(state, 6, 0); /* P_lock0_mask = 0 */ + dib8000_write_word(state, 7, 0); /* P_lock1_mask = 0 */ + dib8000_write_word(state, 8, 0); /* P_lock2_mask = 0 */ + dib8000_write_word(state, 10, (dib8000_read_word(state, 10) & 0x200) | (16 << 4) | (0 << 0)); /* P_search_list=16, P_search_maxtrial=0 */ + + if (state->revision == 0x8090) + value = dib8000_wait_lock(state, internal, 10, 10, 10); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ + else + value = dib8000_wait_lock(state, internal, 20, 20, 20); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ + + dib8000_write_word(state, 17, 0); + dib8000_write_word(state, 18, 200); /* P_search_rstst = 200 */ + dib8000_write_word(state, 19, 0); + dib8000_write_word(state, 20, 400); /* P_search_rstend = 400 */ + dib8000_write_word(state, 21, (value >> 16) & 0xffff); /* P_search_checkst */ + dib8000_write_word(state, 22, value & 0xffff); + + if (state->revision == 0x8090) + dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (0 << 8)); /* P_corm_alpha = 0 */ + else + dib8000_write_word(state, 32, (dib8000_read_word(state, 32) & 0xf0ff) | (9 << 8)); /* P_corm_alpha = 3 */ + dib8000_write_word(state, 355, 2); /* P_search_param_max = 2 */ + + /* P_search_param_select = (1 | 1<<4 | 1 << 8) */ + dib8000_write_word(state, 356, 0); + dib8000_write_word(state, 357, 0x111); + + dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */ + dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */ + dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */ + } else if (state->autosearch_state == AS_SEARCHING_GUARD) { state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; - slist = 7; - dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); + state->fe[0]->dtv_property_cache.inversion = 0; + state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64; + state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3; + state->fe[0]->dtv_property_cache.layer[0].interleaving = 0; + state->fe[0]->dtv_property_cache.layer[0].segment_count = 13; + + slist = 16; + state->fe[0]->dtv_property_cache.transmission_mode = state->found_nfft; + + dib8000_set_isdbt_common_channel(state, slist, 1); + + /* set lock_mask values */ + dib8000_write_word(state, 6, 0x4); + if (state->revision == 0x8090) + dib8000_write_word(state, 7, ((1 << 12) | (1 << 11) | (1 << 10)));/* tmcc_dec_lock, tmcc_sync_lock, tmcc_data_lock, tmcc_bch_uncor */ + else + dib8000_write_word(state, 7, 0x8); + dib8000_write_word(state, 8, 0x1000); + + /* set lock_mask wait time values */ + if (state->revision == 0x8090) + dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ + else + dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ + + dib8000_write_word(state, 355, 3); /* P_search_param_max = 3 */ + + /* P_search_param_select = 0xf; look for the 4 different guard intervals */ + dib8000_write_word(state, 356, 0); + dib8000_write_word(state, 357, 0xf); + + value = dib8000_read_word(state, 0); + dib8000_write_word(state, 0, (u16)((1 << 15) | value)); + dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */ + dib8000_write_word(state, 0, (u16)value); } else { - if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) { - if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { - slist = 7; - dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 to have autosearch start ok with mode2 - } else - slist = 3; + state->fe[0]->dtv_property_cache.inversion = 0; + state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64; + state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3; + state->fe[0]->dtv_property_cache.layer[0].interleaving = 0; + state->fe[0]->dtv_property_cache.layer[0].segment_count = 13; + if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode) + state->fe[0]->dtv_property_cache.layer[0].segment_count = 13; + + /* choose the right list, in sb, always do everything */ + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { + slist = 7; + dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); } else { - if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { - slist = 2; - dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 - } else - slist = 0; + if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) { + if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; + slist = 7; + dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 to have autosearch start ok with mode2 */ + } else { + state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; + slist = 3; + } + } else { + if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { + state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; + slist = 2; + dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 */ + } else + slist = 0; + } } + dprintk("Using list for autosearch : %d", slist); - if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) - state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; - if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) - state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; - - dprintk("using list for autosearch : %d", slist); - dib8000_set_channel(state, (unsigned char)slist, 1); - //dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); // P_mode = 1 + dib8000_set_isdbt_common_channel(state, slist, 1); - factor = 1; - - //set lock_mask values + /* set lock_mask values */ dib8000_write_word(state, 6, 0x4); - dib8000_write_word(state, 7, 0x8); + if (state->revision == 0x8090) + dib8000_write_word(state, 7, (1 << 12) | (1 << 11) | (1 << 10)); + else + dib8000_write_word(state, 7, 0x8); dib8000_write_word(state, 8, 0x1000); - //set lock_mask wait time values - value = 50 * state->cfg.pll->internal * factor; - dib8000_write_word(state, 11, (u16) ((value >> 16) & 0xffff)); // lock0 wait time - dib8000_write_word(state, 12, (u16) (value & 0xffff)); // lock0 wait time - value = 100 * state->cfg.pll->internal * factor; - dib8000_write_word(state, 13, (u16) ((value >> 16) & 0xffff)); // lock1 wait time - dib8000_write_word(state, 14, (u16) (value & 0xffff)); // lock1 wait time - value = 1000 * state->cfg.pll->internal * factor; - dib8000_write_word(state, 15, (u16) ((value >> 16) & 0xffff)); // lock2 wait time - dib8000_write_word(state, 16, (u16) (value & 0xffff)); // lock2 wait time + /* set lock_mask wait time values */ + if (state->revision == 0x8090) + dib8000_wait_lock(state, internal, 50, 200, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ + else + dib8000_wait_lock(state, internal, 50, 100, 1000); /* time in ms configure P_search_end0 P_search_end1 P_search_end2 */ value = dib8000_read_word(state, 0); - dib8000_write_word(state, 0, (u16) ((1 << 15) | value)); - dib8000_read_word(state, 1284); // reset the INT. n_irq_pending - dib8000_write_word(state, 0, (u16) value); - + dib8000_write_word(state, 0, (u16)((1 << 15) | value)); + dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */ + dib8000_write_word(state, 0, (u16)value); } - return 0; } @@ -2663,96 +2577,623 @@ static int dib8000_autosearch_irq(struct dvb_frontend *fe) struct dib8000_state *state = fe->demodulator_priv; u16 irq_pending = dib8000_read_word(state, 1284); - if (irq_pending & 0x1) { // failed - dprintk("dib8000_autosearch_irq failed"); - return 1; - } + if (state->autosearch_state == AS_SEARCHING_FFT) { + if (irq_pending & 0x1) { + dprintk("dib8000_autosearch_irq: max correlation result available"); + return 3; + } + } else { + if (irq_pending & 0x1) { /* failed */ + dprintk("dib8000_autosearch_irq failed"); + return 1; + } - if (irq_pending & 0x2) { // succeeded - dprintk("dib8000_autosearch_irq succeeded"); - return 2; + if (irq_pending & 0x2) { /* succeeded */ + dprintk("dib8000_autosearch_irq succeeded"); + return 2; + } } return 0; // still pending } -static int dib8000_tune(struct dvb_frontend *fe) +static void dib8000_viterbi_state(struct dib8000_state *state, u8 onoff) { - struct dib8000_state *state = fe->demodulator_priv; - int ret = 0; - u16 lock, value, mode; + u16 tmp; - // we are already tuned - just resuming from suspend - if (state == NULL) - return -EINVAL; + tmp = dib8000_read_word(state, 771); + if (onoff) /* start P_restart_chd : channel_decoder */ + dib8000_write_word(state, 771, tmp & 0xfffd); + else /* stop P_restart_chd : channel_decoder */ + dib8000_write_word(state, 771, tmp | (1<<1)); +} - mode = fft_to_mode(state); +static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz) +{ + s16 unit_khz_dds_val; + u32 abs_offset_khz = ABS(offset_khz); + u32 dds = state->cfg.pll->ifreq & 0x1ffffff; + u8 invert = !!(state->cfg.pll->ifreq & (1 << 25)); + u8 ratio; - dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000); - dib8000_set_channel(state, 0, 0); + if (state->revision == 0x8090) { + ratio = 4; + unit_khz_dds_val = (1<<26) / (dib8000_read32(state, 23) / 1000); + if (offset_khz < 0) + dds = (1 << 26) - (abs_offset_khz * unit_khz_dds_val); + else + dds = (abs_offset_khz * unit_khz_dds_val); - // restart demod - ret |= dib8000_write_word(state, 770, 0x4000); - ret |= dib8000_write_word(state, 770, 0x0000); - msleep(45); + if (invert) + dds = (1<<26) - dds; + } else { + ratio = 2; + unit_khz_dds_val = (u16) (67108864 / state->cfg.pll->internal); - /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3 */ - /* ret |= dib8000_write_word(state, 29, (0 << 9) | (4 << 5) | (0 << 4) | (3 << 0) ); workaround inh_isi stays at 1 */ + if (offset_khz < 0) + unit_khz_dds_val *= -1; - // never achieved a lock before - wait for timfreq to update - if (state->timf == 0) { - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) - msleep(300); - else // Sound Broadcasting mode 3 seg - msleep(500); - } else // 13 seg - msleep(200); + /* IF tuner */ + if (invert) + dds -= abs_offset_khz * unit_khz_dds_val; + else + dds += abs_offset_khz * unit_khz_dds_val; } - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { - /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40 alpha to check on board */ - dib8000_write_word(state, 32, ((13 - mode) << 12) | (6 << 8) | 0x40); - //dib8000_write_word(state, 32, (8 << 12) | (6 << 8) | 0x80); + dprintk("setting a DDS frequency offset of %c%dkHz", invert ? '-' : ' ', dds / unit_khz_dds_val); - /* P_ctrl_sfreq_step= (12-P_mode) P_ctrl_sfreq_inh =0 P_ctrl_pha_off_max */ - ret |= dib8000_write_word(state, 37, (12 - mode) | ((5 + mode) << 5)); + if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) { + /* Max dds offset is the half of the demod freq */ + dib8000_write_word(state, 26, invert); + dib8000_write_word(state, 27, (u16)(dds >> 16) & 0x1ff); + dib8000_write_word(state, 28, (u16)(dds & 0xffff)); + } +} - } else { // Sound Broadcasting mode 3 seg +static void dib8000_set_frequency_offset(struct dib8000_state *state) +{ + int i; + u32 current_rf; + int total_dds_offset_khz; + + if (state->fe[0]->ops.tuner_ops.get_frequency) + state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], ¤t_rf); + else + current_rf = state->fe[0]->dtv_property_cache.frequency; + current_rf /= 1000; + total_dds_offset_khz = (int)current_rf - (int)state->fe[0]->dtv_property_cache.frequency / 1000; + + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { + state->subchannel = state->fe[0]->dtv_property_cache.isdbt_sb_subchannel; - /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 alpha to check on board */ - dib8000_write_word(state, 32, ((12 - mode) << 12) | (6 << 8) | 0x60); + i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */ + dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion ^ i); - ret |= dib8000_write_word(state, 37, (11 - mode) | ((5 + mode) << 5)); + if (state->cfg.pll->ifreq == 0) { /* low if tuner */ + if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) + dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1); + } else { + if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) + total_dds_offset_khz *= -1; } + } + + dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d", state->fe[0]->dtv_property_cache.frequency - current_rf, state->fe[0]->dtv_property_cache.frequency, current_rf, total_dds_offset_khz); + + /* apply dds offset now */ + dib8000_set_dds(state, total_dds_offset_khz); +} + +static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 }; +u32 dib8000_get_symbol_duration(struct dib8000_state *state) +{ + u16 i; + + switch (state->fe[0]->dtv_property_cache.transmission_mode) { + case TRANSMISSION_MODE_2K: + i = 0; + break; + case TRANSMISSION_MODE_4K: + i = 2; + break; + default: + case TRANSMISSION_MODE_AUTO: + case TRANSMISSION_MODE_8K: + i = 1; + break; + } - } else { // 13 seg - /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 alpha to check on board */ - dib8000_write_word(state, 32, ((11 - mode) << 12) | (6 << 8) | 0x80); + return (LUT_isdbt_symbol_duration[i] / (state->fe[0]->dtv_property_cache.bandwidth_hz / 1000)) + 1; +} - ret |= dib8000_write_word(state, 37, (10 - mode) | ((5 + mode) << 5)); +static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step) +{ + u16 reg_32 = 0, reg_37 = 0; + switch (loop_step) { + case LOOP_TUNE_1: + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { + reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */ + reg_37 = (3 << 5) | (0 << 4) | (10 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */ + } else { /* Sound Broadcasting mode 3 seg */ + reg_32 = ((10 - state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (10-P_mode), P_corm_alpha=6, P_corm_thres=0x60 */ + reg_37 = (3 << 5) | (0 << 4) | (9 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (9-P_mode) */ + } + } else { /* 13-seg start conf offset loop parameters */ + reg_32 = ((9 - state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = (9-P_mode, P_corm_alpha=6, P_corm_thres=0x80 */ + reg_37 = (3 << 5) | (0 << 4) | (8 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = 9 */ + } + break; + case LOOP_TUNE_2: + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { + if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* Sound Broadcasting mode 1 seg */ + reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/ + reg_37 = (12-state->mode) | ((5 + state->mode) << 5); + } else { /* Sound Broadcasting mode 3 seg */ + reg_32 = ((12-state->mode) << 12) | (6 << 8) | 0x60; /* P_timf_alpha = (12-P_mode) , P_corm_alpha=6, P_corm_thres=0x60 */ + reg_37 = (11-state->mode) | ((5 + state->mode) << 5); + } + } else { /* 13 seg */ + reg_32 = ((11-state->mode) << 12) | (6 << 8) | 0x80; /* P_timf_alpha = 8 , P_corm_alpha=6, P_corm_thres=0x80 */ + reg_37 = ((5+state->mode) << 5) | (10 - state->mode); + } + break; } + dib8000_write_word(state, 32, reg_32); + dib8000_write_word(state, 37, reg_37); +} - // we achieved a coff_cpil_lock - it's time to update the timf - if (state->revision != 0x8090) - lock = dib8000_read_word(state, 568); +static void dib8000_demod_restart(struct dib8000_state *state) +{ + dib8000_write_word(state, 770, 0x4000); + dib8000_write_word(state, 770, 0x0000); + return; +} + +static void dib8000_set_sync_wait(struct dib8000_state *state) +{ + u16 sync_wait = 64; + + /* P_dvsy_sync_wait - reuse mode */ + switch (state->fe[0]->dtv_property_cache.transmission_mode) { + case TRANSMISSION_MODE_8K: + sync_wait = 256; + break; + case TRANSMISSION_MODE_4K: + sync_wait = 128; + break; + default: + case TRANSMISSION_MODE_2K: + sync_wait = 64; + break; + } + + if (state->cfg.diversity_delay == 0) + sync_wait = (sync_wait * (1 << (state->fe[0]->dtv_property_cache.guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */ + else + sync_wait = (sync_wait * (1 << (state->fe[0]->dtv_property_cache.guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */ + + dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4)); +} + +static u32 dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode) +{ + if (mode == SYMBOL_DEPENDENT_ON) + return systime() + (delay * state->symbol_duration); else - lock = dib8000_read_word(state, 570); - if ((lock >> 11) & 0x1) - dib8000_update_timf(state); + return systime() + delay; +} - //now that tune is finished, lock0 should lock on fec_mpeg to output this lock on MP_LOCK. It's changed in autosearch start - dib8000_write_word(state, 6, 0x200); +static s32 dib8000_get_status(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + return state->status; +} - if (state->revision == 0x8002) { - value = dib8000_read_word(state, 903); - dib8000_write_word(state, 903, value & ~(1 << 3)); - msleep(1); - dib8000_write_word(state, 903, value | (1 << 3)); +enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + return state->tune_state; +} +EXPORT_SYMBOL(dib8000_get_tune_state); + +int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) +{ + struct dib8000_state *state = fe->demodulator_priv; + + state->tune_state = tune_state; + return 0; +} +EXPORT_SYMBOL(dib8000_set_tune_state); + +static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + + state->status = FE_STATUS_TUNE_PENDING; + state->tune_state = CT_DEMOD_START; + return 0; +} + +static u16 dib8000_read_lock(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + + if (state->revision == 0x8090) + return dib8000_read_word(state, 570); + return dib8000_read_word(state, 568); +} + +static int dib8090p_init_sdram(struct dib8000_state *state) +{ + u16 reg = 0; + dprintk("init sdram"); + + reg = dib8000_read_word(state, 274) & 0xfff0; + dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */ + + dib8000_write_word(state, 1803, (7 << 2)); + + reg = dib8000_read_word(state, 1280); + dib8000_write_word(state, 1280, reg | (1 << 2)); /* force restart P_restart_sdram */ + dib8000_write_word(state, 1280, reg); /* release restart P_restart_sdram */ + + return 0; +} + +static int dib8000_tune(struct dvb_frontend *fe) +{ + struct dib8000_state *state = fe->demodulator_priv; + enum frontend_tune_state *tune_state = &state->tune_state; + + u16 locks, deeper_interleaver = 0, i; + int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */ + + u32 *timeout = &state->timeout; + u32 now = systime(); +#ifdef DIB8000_AGC_FREEZE + u16 agc1, agc2; +#endif + + u32 corm[4] = {0, 0, 0, 0}; + u8 find_index, max_value; + +#if 0 + if (*tune_state < CT_DEMOD_STOP) + dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u systime = %u", state->channel_parameters_set, *tune_state, state->autosearch_state, now); +#endif + + switch (*tune_state) { + case CT_DEMOD_START: /* 30 */ + if (state->revision == 0x8090) + dib8090p_init_sdram(state); + state->status = FE_STATUS_TUNE_PENDING; + if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) || + (state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) || + (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) || + (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) || + (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) && + (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) && + (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) && + ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) || + (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) || + (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) && + (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) && + (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) && + ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) || + (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) || + (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) && + (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) && + (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) && + ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) || + (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) || + (((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) || + ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) && + ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) || + ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) && + ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) + state->channel_parameters_set = 0; /* auto search */ + else + state->channel_parameters_set = 1; /* channel parameters are known */ + + dib8000_viterbi_state(state, 0); /* force chan dec in restart */ + + /* Layer monit */ + dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60); + + dib8000_set_frequency_offset(state); + dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000); + + if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */ +#ifdef DIB8000_AGC_FREEZE + if (state->revision != 0x8090) { + state->agc1_max = dib8000_read_word(state, 108); + state->agc1_min = dib8000_read_word(state, 109); + state->agc2_max = dib8000_read_word(state, 110); + state->agc2_min = dib8000_read_word(state, 111); + agc1 = dib8000_read_word(state, 388); + agc2 = dib8000_read_word(state, 389); + dib8000_write_word(state, 108, agc1); + dib8000_write_word(state, 109, agc1); + dib8000_write_word(state, 110, agc2); + dib8000_write_word(state, 111, agc2); + } +#endif + state->autosearch_state = AS_SEARCHING_FFT; + state->found_nfft = TRANSMISSION_MODE_AUTO; + state->found_guard = GUARD_INTERVAL_AUTO; + *tune_state = CT_DEMOD_SEARCH_NEXT; + } else { /* we already know the channel struct so TUNE only ! */ + state->autosearch_state = AS_DONE; + *tune_state = CT_DEMOD_STEP_3; + } + state->symbol_duration = dib8000_get_symbol_duration(state); + break; + + case CT_DEMOD_SEARCH_NEXT: /* 51 */ + dib8000_autosearch_start(fe); + if (state->revision == 0x8090) + ret = 50; + else + ret = 15; + *tune_state = CT_DEMOD_STEP_1; + break; + + case CT_DEMOD_STEP_1: /* 31 */ + switch (dib8000_autosearch_irq(fe)) { + case 1: /* fail */ + state->status = FE_STATUS_TUNE_FAILED; + state->autosearch_state = AS_DONE; + *tune_state = CT_DEMOD_STOP; /* else we are done here */ + break; + case 2: /* Succes */ + state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */ + *tune_state = CT_DEMOD_STEP_3; + if (state->autosearch_state == AS_SEARCHING_GUARD) + *tune_state = CT_DEMOD_STEP_2; + else + state->autosearch_state = AS_DONE; + break; + case 3: /* Autosearch FFT max correlation endded */ + *tune_state = CT_DEMOD_STEP_2; + break; + } + break; + + case CT_DEMOD_STEP_2: + switch (state->autosearch_state) { + case AS_SEARCHING_FFT: + /* searching for the correct FFT */ + if (state->revision == 0x8090) { + corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597)); + corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599)); + corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601)); + } else { + corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595)); + corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597)); + corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599)); + } + /* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */ + + max_value = 0; + for (find_index = 1 ; find_index < 3 ; find_index++) { + if (corm[max_value] < corm[find_index]) + max_value = find_index ; + } + + switch (max_value) { + case 0: + state->found_nfft = TRANSMISSION_MODE_2K; + break; + case 1: + state->found_nfft = TRANSMISSION_MODE_4K; + break; + case 2: + default: + state->found_nfft = TRANSMISSION_MODE_8K; + break; + } + /* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */ + + *tune_state = CT_DEMOD_SEARCH_NEXT; + state->autosearch_state = AS_SEARCHING_GUARD; + if (state->revision == 0x8090) + ret = 50; + else + ret = 10; + break; + case AS_SEARCHING_GUARD: + /* searching for the correct guard interval */ + if (state->revision == 0x8090) + state->found_guard = dib8000_read_word(state, 572) & 0x3; + else + state->found_guard = dib8000_read_word(state, 570) & 0x3; + /* dprintk("guard interval found=%i", state->found_guard); */ + + *tune_state = CT_DEMOD_STEP_3; + break; + default: + /* the demod should never be in this state */ + state->status = FE_STATUS_TUNE_FAILED; + state->autosearch_state = AS_DONE; + *tune_state = CT_DEMOD_STOP; /* else we are done here */ + break; + } + break; + + case CT_DEMOD_STEP_3: /* 33 */ + state->symbol_duration = dib8000_get_symbol_duration(state); + dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1); + dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */ + *tune_state = CT_DEMOD_STEP_4; + break; + + case CT_DEMOD_STEP_4: /* (34) */ + dib8000_demod_restart(state); + + dib8000_set_sync_wait(state); + dib8000_set_diversity_in(state->fe[0], state->diversity_onoff); + + locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */ + /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this lenght to lock */ + *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON); + *tune_state = CT_DEMOD_STEP_5; + break; + + case CT_DEMOD_STEP_5: /* (35) */ + locks = dib8000_read_lock(fe); + if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */ + dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */ + if (!state->differential_constellation) { + /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */ + *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON); + *tune_state = CT_DEMOD_STEP_7; + } else { + *tune_state = CT_DEMOD_STEP_8; + } + } else if (now > *timeout) { + *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */ + } + break; + + case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */ + if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) { + /* if there is a diversity fe in input and this fe is has not already failled : wait here until this this fe has succedeed or failled */ + if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */ + *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */ + else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */ + *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */ + dib8000_viterbi_state(state, 1); /* start viterbi chandec */ + dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); + state->status = FE_STATUS_TUNE_FAILED; + } + } else { + dib8000_viterbi_state(state, 1); /* start viterbi chandec */ + dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); + *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */ + state->status = FE_STATUS_TUNE_FAILED; + } + break; + + case CT_DEMOD_STEP_7: /* 37 */ + locks = dib8000_read_lock(fe); + if (locks & (1<<10)) { /* lmod4_lock */ + ret = 14; /* wait for 14 symbols */ + *tune_state = CT_DEMOD_STEP_8; + } else if (now > *timeout) + *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */ + break; + + case CT_DEMOD_STEP_8: /* 38 */ + dib8000_viterbi_state(state, 1); /* start viterbi chandec */ + dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); + + /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/ + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode && state->fe[0]->dtv_property_cache.isdbt_sb_subchannel == -1 && !state->differential_constellation) { + state->subchannel = 0; + *tune_state = CT_DEMOD_STEP_11; + } else { + *tune_state = CT_DEMOD_STEP_9; + state->status = FE_STATUS_LOCKED; + } + break; + + case CT_DEMOD_STEP_9: /* 39 */ + if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */ + /* defines timeout for mpeg lock depending on interleaver lenght of longest layer */ + for (i = 0; i < 3; i++) { + if (state->fe[0]->dtv_property_cache.layer[i].interleaving >= deeper_interleaver) { + dprintk("layer%i: time interleaver = %d ", i, state->fe[0]->dtv_property_cache.layer[i].interleaving); + if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) { /* valid layer */ + deeper_interleaver = state->fe[0]->dtv_property_cache.layer[0].interleaving; + state->longest_intlv_layer = i; + } + } + } + + if (deeper_interleaver == 0) + locks = 2; /* locks is the tmp local variable name */ + else if (deeper_interleaver == 3) + locks = 8; + else + locks = 2 * deeper_interleaver; + + if (state->diversity_onoff != 0) /* because of diversity sync */ + locks *= 2; + + *timeout = now + (2000 * locks); /* give the mpeg lock 800ms if sram is present */ + dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %d", deeper_interleaver, state->longest_intlv_layer, locks, *timeout); + + *tune_state = CT_DEMOD_STEP_10; + } else + *tune_state = CT_DEMOD_STOP; + break; + + case CT_DEMOD_STEP_10: /* 40 */ + locks = dib8000_read_lock(fe); + if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */ + dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1); + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode && state->fe[0]->dtv_property_cache.isdbt_sb_subchannel == -1 && !state->differential_constellation) + /* signal to the upper layer, that there was a channel found and the parameters can be read */ + state->status = FE_STATUS_DEMOD_SUCCESS; + else + state->status = FE_STATUS_DATA_LOCKED; + *tune_state = CT_DEMOD_STOP; + } else if (now > *timeout) { + if (state->fe[0]->dtv_property_cache.isdbt_sb_mode && state->fe[0]->dtv_property_cache.isdbt_sb_subchannel == -1 && !state->differential_constellation) { /* continue to try init prbs autosearch */ + state->subchannel += 3; + *tune_state = CT_DEMOD_STEP_11; + } else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */ + if (locks & (0x7<<5)) { + dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1); + state->status = FE_STATUS_DATA_LOCKED; + } else + state->status = FE_STATUS_TUNE_FAILED; + *tune_state = CT_DEMOD_STOP; + } + } + break; + + case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */ + if (state->subchannel <= 41) { + dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel)); + *tune_state = CT_DEMOD_STEP_9; + } else { + *tune_state = CT_DEMOD_STOP; + state->status = FE_STATUS_TUNE_FAILED; + } + break; + + default: + break; + } + + /* tuning is finished - cleanup the demod */ + switch (*tune_state) { + case CT_DEMOD_STOP: /* (42) */ +#ifdef DIB8000_AGC_FREEZE + if ((state->revision != 0x8090) && (state->agc1_max != 0)) { + dib8000_write_word(state, 108, state->agc1_max); + dib8000_write_word(state, 109, state->agc1_min); + dib8000_write_word(state, 110, state->agc2_max); + dib8000_write_word(state, 111, state->agc2_min); + state->agc1_max = 0; + state->agc1_min = 0; + state->agc2_max = 0; + state->agc2_min = 0; + } +#endif + ret = FE_CALLBACK_TIME_NEVER; + break; + default: + break; } + if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3)) + return ret * state->symbol_duration; + if ((ret > 0) && (ret < state->symbol_duration)) + return state->symbol_duration; /* at least one symbol */ return ret; } @@ -2767,7 +3208,7 @@ static int dib8000_wakeup(struct dvb_frontend *fe) if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) dprintk("could not start Slow ADC"); - if (state->revision != 0x8090) + if (state->revision == 0x8090) dib8000_sad_calib(state); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { @@ -2797,21 +3238,6 @@ static int dib8000_sleep(struct dvb_frontend *fe) return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF); } -enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe) -{ - struct dib8000_state *state = fe->demodulator_priv; - return state->tune_state; -} -EXPORT_SYMBOL(dib8000_get_tune_state); - -int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) -{ - struct dib8000_state *state = fe->demodulator_priv; - state->tune_state = tune_state; - return 0; -} -EXPORT_SYMBOL(dib8000_set_tune_state); - static int dib8000_get_frontend(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; @@ -2961,10 +3387,9 @@ static int dib8000_get_frontend(struct dvb_frontend *fe) static int dib8000_set_frontend(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; - u8 nbr_pending, exit_condition, index_frontend; - s8 index_frontend_success = -1; - int time, ret; - int time_slave = FE_CALLBACK_TIME_NEVER; + int l, i, active, time, ret, time_slave = FE_CALLBACK_TIME_NEVER; + u8 exit_condition, index_frontend; + u32 delay, callback_time; if (state->fe[0]->dtv_property_cache.frequency == 0) { dprintk("dib8000: must at least specify frequency "); @@ -2981,18 +3406,36 @@ static int dib8000_set_frontend(struct dvb_frontend *fe) state->fe[index_frontend]->dtv_property_cache.delivery_system = SYS_ISDBT; memcpy(&state->fe[index_frontend]->dtv_property_cache, &fe->dtv_property_cache, sizeof(struct dtv_frontend_properties)); - if (state->revision != 0x8090) - dib8000_set_output_mode(state->fe[index_frontend], - OUTMODE_HIGH_Z); - else - dib8096p_set_output_mode(state->fe[index_frontend], - OUTMODE_HIGH_Z); + /* set output mode and diversity input */ + if (state->revision != 0x8090) { + dib8000_set_diversity_in(state->fe[index_frontend], 1); + if (index_frontend != 0) + dib8000_set_output_mode(state->fe[index_frontend], + OUTMODE_DIVERSITY); + else + dib8000_set_output_mode(state->fe[0], OUTMODE_HIGH_Z); + } else { + dib8096p_set_diversity_in(state->fe[index_frontend], 1); + if (index_frontend != 0) + dib8096p_set_output_mode(state->fe[index_frontend], + OUTMODE_DIVERSITY); + else + dib8096p_set_output_mode(state->fe[0], OUTMODE_HIGH_Z); + } + + /* tune the tuner */ if (state->fe[index_frontend]->ops.tuner_ops.set_params) state->fe[index_frontend]->ops.tuner_ops.set_params(state->fe[index_frontend]); dib8000_set_tune_state(state->fe[index_frontend], CT_AGC_START); } + /* turn off the diversity of the last chip */ + if (state->revision != 0x8090) + dib8000_set_diversity_in(state->fe[index_frontend - 1], 0); + else + dib8096p_set_diversity_in(state->fe[index_frontend - 1], 0); + /* start up the AGC */ do { time = dib8000_agc_startup(state->fe[0]); @@ -3019,139 +3462,88 @@ static int dib8000_set_frontend(struct dvb_frontend *fe) for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) dib8000_set_tune_state(state->fe[index_frontend], CT_DEMOD_START); - if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) || - (state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) || - (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) || - (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) || - (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) && - (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) && - (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) && - ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) || - (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) || - (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) && - (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) && - (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) && - ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) || - (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) || - (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) && - (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) && - (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) && - ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) || - (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) || - (((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) || - ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) && - ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) || - ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) && - ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) { - int i = 100; - u8 found = 0; - u8 tune_failed = 0; - + active = 1; + do { + callback_time = FE_CALLBACK_TIME_NEVER; for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - dib8000_set_bandwidth(state->fe[index_frontend], fe->dtv_property_cache.bandwidth_hz / 1000); - dib8000_autosearch_start(state->fe[index_frontend]); - } - - do { - msleep(20); - nbr_pending = 0; - exit_condition = 0; /* 0: tune pending; 1: tune failed; 2:tune success */ - for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { - if (((tune_failed >> index_frontend) & 0x1) == 0) { - found = dib8000_autosearch_irq(state->fe[index_frontend]); - switch (found) { - case 0: /* tune pending */ - nbr_pending++; - break; - case 2: - dprintk("autosearch succeed on the frontend%i", index_frontend); - exit_condition = 2; - index_frontend_success = index_frontend; - break; - default: - dprintk("unhandled autosearch result"); - case 1: - tune_failed |= (1 << index_frontend); - dprintk("autosearch failed for the frontend%i", index_frontend); - break; + delay = dib8000_tune(state->fe[index_frontend]); + if (delay != FE_CALLBACK_TIME_NEVER) + delay += systime(); + + /* we are in autosearch */ + if (state->channel_parameters_set == 0) { /* searching */ + if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) { + dprintk("autosearch succeeded on fe%i", index_frontend); + dib8000_get_frontend(state->fe[index_frontend]); /* we read the channel parameters from the frontend which was successful */ + state->channel_parameters_set = 1; + + for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) { + if (l != index_frontend) { /* and for all frontend except the successful one */ + dib8000_tune_restart_from_demod(state->fe[l]); + + state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode; + state->fe[l]->dtv_property_cache.inversion = state->fe[index_frontend]->dtv_property_cache.inversion; + state->fe[l]->dtv_property_cache.transmission_mode = state->fe[index_frontend]->dtv_property_cache.transmission_mode; + state->fe[l]->dtv_property_cache.guard_interval = state->fe[index_frontend]->dtv_property_cache.guard_interval; + state->fe[l]->dtv_property_cache.isdbt_partial_reception = state->fe[index_frontend]->dtv_property_cache.isdbt_partial_reception; + for (i = 0; i < 3; i++) { + state->fe[l]->dtv_property_cache.layer[i].segment_count = state->fe[index_frontend]->dtv_property_cache.layer[i].segment_count; + state->fe[l]->dtv_property_cache.layer[i].interleaving = state->fe[index_frontend]->dtv_property_cache.layer[i].interleaving; + state->fe[l]->dtv_property_cache.layer[i].fec = state->fe[index_frontend]->dtv_property_cache.layer[i].fec; + state->fe[l]->dtv_property_cache.layer[i].modulation = state->fe[index_frontend]->dtv_property_cache.layer[i].modulation; + } + + } } } } - - /* if all tune are done and no success, exit: tune failed */ - if ((nbr_pending == 0) && (exit_condition == 0)) - exit_condition = 1; - } while ((exit_condition == 0) && i--); - - if (exit_condition == 1) { /* tune failed */ - dprintk("tune failed"); - return 0; + if (delay < callback_time) + callback_time = delay; + } + /* tuning is done when the master frontend is done (failed or success) */ + if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED || + dib8000_get_status(state->fe[0]) == FE_STATUS_LOCKED || + dib8000_get_status(state->fe[0]) == FE_STATUS_DATA_LOCKED) { + active = 0; + /* we need to wait for all frontends to be finished */ + for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { + if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_DEMOD_STOP) + active = 1; + } + if (active == 0) + dprintk("tuning done with status %d", dib8000_get_status(state->fe[0])); } - dprintk("tune success on frontend%i", index_frontend_success); - - dib8000_get_frontend(fe); - } + if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) { + dprintk("strange callback time something went wrong"); + active = 0; + } - for (index_frontend = 0, ret = 0; (ret >= 0) && (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) - ret = dib8000_tune(state->fe[index_frontend]); + while ((active == 1) && (systime() < callback_time)) + msleep(100); + } while (active); - /* set output mode and diversity input */ - if (state->revision != 0x8090) { + /* set output mode */ + if (state->revision != 0x8090) dib8000_set_output_mode(state->fe[0], state->cfg.output_mode); - for (index_frontend = 1; - (index_frontend < MAX_NUMBER_OF_FRONTENDS) && - (state->fe[index_frontend] != NULL); - index_frontend++) { - dib8000_set_output_mode(state->fe[index_frontend], - OUTMODE_DIVERSITY); - dib8000_set_diversity_in(state->fe[index_frontend-1], 1); - } - - /* turn off the diversity of the last chip */ - dib8000_set_diversity_in(state->fe[index_frontend-1], 0); - } else { + else { dib8096p_set_output_mode(state->fe[0], state->cfg.output_mode); if (state->cfg.enMpegOutput == 0) { dib8096p_setDibTxMux(state, MPEG_ON_DIBTX); dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); } - for (index_frontend = 1; - (index_frontend < MAX_NUMBER_OF_FRONTENDS) && - (state->fe[index_frontend] != NULL); - index_frontend++) { - dib8096p_set_output_mode(state->fe[index_frontend], - OUTMODE_DIVERSITY); - dib8096p_set_diversity_in(state->fe[index_frontend-1], 1); - } - - /* turn off the diversity of the last chip */ - dib8096p_set_diversity_in(state->fe[index_frontend-1], 0); } return ret; } -static u16 dib8000_read_lock(struct dvb_frontend *fe) -{ - struct dib8000_state *state = fe->demodulator_priv; - - if (state->revision == 0x8090) - return dib8000_read_word(state, 570); - return dib8000_read_word(state, 568); -} - static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat) { struct dib8000_state *state = fe->demodulator_priv; u16 lock_slave = 0, lock; u8 index_frontend; - if (state->revision == 0x8090) - lock = dib8000_read_word(state, 570); - else - lock = dib8000_read_word(state, 568); - + lock = dib8000_read_lock(fe); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) lock_slave |= dib8000_read_lock(state->fe[index_frontend]); @@ -3545,10 +3937,11 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s dib8000_reset(fe); dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & ~0x60) | (3 << 5)); /* ber_rs_len = 3 */ + state->current_demod_bw = 6000; return fe; - error: +error: kfree(state); return NULL; } diff --git a/drivers/media/dvb-frontends/dib8000.h b/drivers/media/dvb-frontends/dib8000.h index 9e7a2b170d55..b8c11e52c512 100644 --- a/drivers/media/dvb-frontends/dib8000.h +++ b/drivers/media/dvb-frontends/dib8000.h @@ -33,6 +33,8 @@ struct dib8000_config { u8 output_mode; u8 refclksel; u8 enMpegOutput:1; + + struct dibx000_bandwidth_config *plltable; }; #define DEFAULT_DIB8000_I2C_ADDRESS 18 @@ -58,7 +60,7 @@ extern int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ); extern u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf); extern int dib8000_update_pll(struct dvb_frontend *fe, - struct dibx000_bandwidth_config *pll); + struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio); extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave); extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe); extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index); @@ -147,7 +149,7 @@ static inline u32 dib8000_ctrl_timf(struct dvb_frontend *fe, return 0; } static inline int dib8000_update_pll(struct dvb_frontend *fe, - struct dibx000_bandwidth_config *pll) + struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; diff --git a/drivers/media/dvb-frontends/dibx000_common.h b/drivers/media/dvb-frontends/dibx000_common.h index 5f484881d7b1..b538e0555c95 100644 --- a/drivers/media/dvb-frontends/dibx000_common.h +++ b/drivers/media/dvb-frontends/dibx000_common.h @@ -193,7 +193,8 @@ enum frontend_tune_state { CT_DEMOD_STEP_8, CT_DEMOD_STEP_9, CT_DEMOD_STEP_10, - CT_DEMOD_SEARCH_NEXT = 41, + CT_DEMOD_STEP_11, + CT_DEMOD_SEARCH_NEXT = 51, CT_DEMOD_STEP_LOCKED, CT_DEMOD_STOP, diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 11798426fa88..5a4175ef3524 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -1850,7 +1850,7 @@ static int dib8096p_agc_startup(struct dvb_frontend *fe) if ((adc_table->freq != 0xffffffff) && better_sampling_freq) { pll.pll_ratio = adc_table->pll_loopdiv; pll.pll_prediv = adc_table->pll_prediv; - dib8000_update_pll(fe, &pll); + dib8000_update_pll(fe, &pll, fe->dtv_property_cache.bandwidth_hz / 1000, 0); dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc_table->timf); } return 0; -- cgit v1.2.3 From 6fe1099c7aecc54ebf2fcf8e3af2225cd7bfa550 Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Mon, 31 Dec 2012 09:23:26 -0300 Subject: [media] dib7000p: enhancement The intend of this patch is to improve the support of the dib7000p. It is now possible to set the minimum value for the AGC1. Also, the driver takes into account the frequency offset introduced in the tuned frequency. Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib7000p.c | 17 ++++++++++++++++- drivers/media/dvb-frontends/dib7000p.h | 7 +++++++ 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index 3e1eefada0e8..effb87f773b0 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -429,6 +429,13 @@ int dib7000p_get_agc_values(struct dvb_frontend *fe, } EXPORT_SYMBOL(dib7000p_get_agc_values); +int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v) +{ + struct dib7000p_state *state = fe->demodulator_priv; + return dib7000p_write_word(state, 108, v); +} +EXPORT_SYMBOL(dib7000p_set_agc1_min); + static void dib7000p_reset_pll(struct dib7000p_state *state) { struct dibx000_bandwidth_config *bw = &state->cfg.bw[0]; @@ -821,6 +828,7 @@ static int dib7000p_agc_startup(struct dvb_frontend *demod) u8 agc_split; u16 reg; u32 upd_demod_gain_period = 0x1000; + s32 frequency_offset = 0; switch (state->agc_state) { case 0: @@ -841,7 +849,14 @@ static int dib7000p_agc_startup(struct dvb_frontend *demod) if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency / 1000)) != 0) return -1; - dib7000p_set_dds(state, 0); + if (demod->ops.tuner_ops.get_frequency) { + u32 frequency_tuner; + + demod->ops.tuner_ops.get_frequency(demod, &frequency_tuner); + frequency_offset = (s32)frequency_tuner / 1000 - ch->frequency / 1000; + } + + dib7000p_set_dds(state, frequency_offset); ret = 7; (*agc_state)++; break; diff --git a/drivers/media/dvb-frontends/dib7000p.h b/drivers/media/dvb-frontends/dib7000p.h index cf5e77956a1f..d08cdff59bdf 100644 --- a/drivers/media/dvb-frontends/dib7000p.h +++ b/drivers/media/dvb-frontends/dib7000p.h @@ -63,6 +63,7 @@ extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe); extern int dib7090_slave_reset(struct dvb_frontend *fe); extern int dib7000p_get_agc_values(struct dvb_frontend *fe, u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd); +extern int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v); #else static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg) { @@ -154,6 +155,12 @@ static inline int dib7000p_get_agc_values(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; } + +static inline int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} #endif #endif -- cgit v1.2.3 From aedabf7a5402cd46df6ca33e87d77762c08599b0 Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Mon, 31 Dec 2012 10:38:44 -0300 Subject: [media] dib0090: enhancement The intend of this patch is to improve the support of the dib0090 tuner. The ramp tables have been updated. Also some minor enhancements has been added (EFUSE and reset). Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib0090.c | 438 ++++++++++++++++------------------ 1 file changed, 212 insertions(+), 226 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index d9fe60b4be48..f9916b8434b7 100644 --- a/drivers/media/dvb-frontends/dib0090.c +++ b/drivers/media/dvb-frontends/dib0090.c @@ -528,20 +528,19 @@ static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_ u16 PllCfg, i, v; HARD_RESET(state); - dib0090_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL); - dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */ + if (cfg->in_soc) + return; - if (!cfg->in_soc) { - /* adcClkOutRatio=8->7, release reset */ - dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0); - if (cfg->clkoutdrive != 0) - dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8) - | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0)); - else - dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8) - | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0)); - } + dib0090_write_reg(state, 0x1b, EN_DIGCLK | EN_PLL | EN_CRYSTAL); /* PLL, DIG_CLK and CRYSTAL remain */ + /* adcClkOutRatio=8->7, release reset */ + dib0090_write_reg(state, 0x20, ((cfg->io.adc_clock_ratio - 1) << 11) | (0 << 10) | (1 << 9) | (1 << 8) | (0 << 4) | 0); + if (cfg->clkoutdrive != 0) + dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8) + | (cfg->clkoutdrive << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0)); + else + dib0090_write_reg(state, 0x23, (0 << 15) | ((!cfg->analog_output) << 14) | (2 << 10) | (1 << 9) | (0 << 8) + | (7 << 5) | (cfg->clkouttobamse << 4) | (0 << 2) | (0)); /* Read Pll current config * */ PllCfg = dib0090_read_reg(state, 0x21); @@ -694,192 +693,174 @@ void dib0090_dcc_freq(struct dvb_frontend *fe, u8 fast) EXPORT_SYMBOL(dib0090_dcc_freq); static const u16 bb_ramp_pwm_normal_socs[] = { - 550, /* max BB gain in 10th of dB */ - (1 << 9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */ + 550, /* max BB gain in 10th of dB */ + (1<<9) | 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */ 440, - (4 << 9) | 0, /* BB_RAMP3 = 26dB */ - (0 << 9) | 208, /* BB_RAMP4 */ - (4 << 9) | 208, /* BB_RAMP5 = 29dB */ - (0 << 9) | 440, /* BB_RAMP6 */ + (4 << 9) | 0, /* BB_RAMP3 = 26dB */ + (0 << 9) | 208, /* BB_RAMP4 */ + (4 << 9) | 208, /* BB_RAMP5 = 29dB */ + (0 << 9) | 440, /* BB_RAMP6 */ }; -static const u16 rf_ramp_pwm_cband_7090[] = { - 280, /* max RF gain in 10th of dB */ - 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ - 504, /* ramp_max = maximum X used on the ramp */ - (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */ - (0 << 10) | 504, /* RF_RAMP6, LNA 1 */ - (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */ - (0 << 10) | 364, /* RF_RAMP8, LNA 2 */ - (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */ - (0 << 10) | 228, /* GAIN_4_2, LNA 3 */ - (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ - (0 << 10) | 109, /* RF_RAMP4, LNA 4 */ +static const u16 rf_ramp_pwm_cband_7090p[] = { + 280, /* max RF gain in 10th of dB */ + 18, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 504, /* ramp_max = maximum X used on the ramp */ + (29 << 10) | 364, /* RF_RAMP5, LNA 1 = 8dB */ + (0 << 10) | 504, /* RF_RAMP6, LNA 1 */ + (60 << 10) | 228, /* RF_RAMP7, LNA 2 = 7.7dB */ + (0 << 10) | 364, /* RF_RAMP8, LNA 2 */ + (34 << 10) | 109, /* GAIN_4_1, LNA 3 = 6.8dB */ + (0 << 10) | 228, /* GAIN_4_2, LNA 3 */ + (37 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ + (0 << 10) | 109, /* RF_RAMP4, LNA 4 */ }; -static const uint16_t rf_ramp_pwm_cband_7090e_sensitivity[] = { - 186, - 40, - 746, - (10 << 10) | 345, - (0 << 10) | 746, - (0 << 10) | 0, - (0 << 10) | 0, - (28 << 10) | 200, - (0 << 10) | 345, - (20 << 10) | 0, - (0 << 10) | 200, +static const u16 rf_ramp_pwm_cband_7090e_sensitivity[] = { + 186, /* max RF gain in 10th of dB */ + 40, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 746, /* ramp_max = maximum X used on the ramp */ + (10 << 10) | 345, /* RF_RAMP5, LNA 1 = 10dB */ + (0 << 10) | 746, /* RF_RAMP6, LNA 1 */ + (0 << 10) | 0, /* RF_RAMP7, LNA 2 = 0 dB */ + (0 << 10) | 0, /* RF_RAMP8, LNA 2 */ + (28 << 10) | 200, /* GAIN_4_1, LNA 3 = 6.8dB */ /* 3.61 dB */ + (0 << 10) | 345, /* GAIN_4_2, LNA 3 */ + (20 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ /* 4.96 dB */ + (0 << 10) | 200, /* RF_RAMP4, LNA 4 */ }; -static const uint16_t rf_ramp_pwm_cband_7090e_aci[] = { - 86, - 40, - 345, - (0 << 10) | 0, - (0 << 10) | 0, - (0 << 10) | 0, - (0 << 10) | 0, - (28 << 10) | 200, - (0 << 10) | 345, - (20 << 10) | 0, - (0 << 10) | 200, +static const u16 rf_ramp_pwm_cband_7090e_aci[] = { + 86, /* max RF gain in 10th of dB */ + 40, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 345, /* ramp_max = maximum X used on the ramp */ + (0 << 10) | 0, /* RF_RAMP5, LNA 1 = 8dB */ /* 7.47 dB */ + (0 << 10) | 0, /* RF_RAMP6, LNA 1 */ + (0 << 10) | 0, /* RF_RAMP7, LNA 2 = 0 dB */ + (0 << 10) | 0, /* RF_RAMP8, LNA 2 */ + (28 << 10) | 200, /* GAIN_4_1, LNA 3 = 6.8dB */ /* 3.61 dB */ + (0 << 10) | 345, /* GAIN_4_2, LNA 3 */ + (20 << 10) | 0, /* RF_RAMP3, LNA 4 = 6.2dB */ /* 4.96 dB */ + (0 << 10) | 200, /* RF_RAMP4, LNA 4 */ }; static const u16 rf_ramp_pwm_cband_8090[] = { - 345, /* max RF gain in 10th of dB */ - 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ - 1000, /* ramp_max = maximum X used on the ramp */ - (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */ - (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */ - (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */ - (0 << 10) | 772, /* RF_RAMP6, LNA 2 */ - (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */ - (0 << 10) | 496, /* RF_RAMP8, LNA 3 */ - (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */ - (0 << 10) | 200, /* GAIN_4_2, LNA 4 */ + 345, /* max RF gain in 10th of dB */ + 29, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 1000, /* ramp_max = maximum X used on the ramp */ + (35 << 10) | 772, /* RF_RAMP3, LNA 1 = 8dB */ + (0 << 10) | 1000, /* RF_RAMP4, LNA 1 */ + (58 << 10) | 496, /* RF_RAMP5, LNA 2 = 9.5dB */ + (0 << 10) | 772, /* RF_RAMP6, LNA 2 */ + (27 << 10) | 200, /* RF_RAMP7, LNA 3 = 10.5dB */ + (0 << 10) | 496, /* RF_RAMP8, LNA 3 */ + (40 << 10) | 0, /* GAIN_4_1, LNA 4 = 7dB */ + (0 << 10) | 200, /* GAIN_4_2, LNA 4 */ }; static const u16 rf_ramp_pwm_uhf_7090[] = { - 407, /* max RF gain in 10th of dB */ - 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ - 529, /* ramp_max = maximum X used on the ramp */ - (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */ - (0 << 10) | 176, /* RF_RAMP4, LNA 1 */ - (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */ - (0 << 10) | 529, /* RF_RAMP6, LNA 2 */ - (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */ - (0 << 10) | 400, /* RF_RAMP8, LNA 3 */ - (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */ - (0 << 10) | 316, /* GAIN_4_2, LNA 4 */ + 407, /* max RF gain in 10th of dB */ + 13, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 529, /* ramp_max = maximum X used on the ramp */ + (23 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */ + (0 << 10) | 176, /* RF_RAMP4, LNA 1 */ + (63 << 10) | 400, /* RF_RAMP5, LNA 2 = 8dB */ + (0 << 10) | 529, /* RF_RAMP6, LNA 2 */ + (48 << 10) | 316, /* RF_RAMP7, LNA 3 = 6.8dB */ + (0 << 10) | 400, /* RF_RAMP8, LNA 3 */ + (29 << 10) | 176, /* GAIN_4_1, LNA 4 = 11.5dB */ + (0 << 10) | 316, /* GAIN_4_2, LNA 4 */ }; static const u16 rf_ramp_pwm_uhf_8090[] = { - 388, /* max RF gain in 10th of dB */ - 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ - 1008, /* ramp_max = maximum X used on the ramp */ - (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */ - (0 << 10) | 369, /* RF_RAMP4, LNA 1 */ - (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */ - (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */ - (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */ - (0 << 10) | 809, /* RF_RAMP8, LNA 3 */ - (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */ - (0 << 10) | 659, /* GAIN_4_2, LNA 4 */ + 388, /* max RF gain in 10th of dB */ + 26, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 1008, /* ramp_max = maximum X used on the ramp */ + (11 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.7dB */ + (0 << 10) | 369, /* RF_RAMP4, LNA 1 */ + (41 << 10) | 809, /* RF_RAMP5, LNA 2 = 8dB */ + (0 << 10) | 1008, /* RF_RAMP6, LNA 2 */ + (27 << 10) | 659, /* RF_RAMP7, LNA 3 = 6dB */ + (0 << 10) | 809, /* RF_RAMP8, LNA 3 */ + (14 << 10) | 369, /* GAIN_4_1, LNA 4 = 11.5dB */ + (0 << 10) | 659, /* GAIN_4_2, LNA 4 */ }; -static const u16 rf_ramp_pwm_cband[] = { - 0, /* max RF gain in 10th of dB */ - 0, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ - 0, /* ramp_max = maximum X used on the ramp */ - (0 << 10) | 0, /* 0x2c, LNA 1 = 0dB */ - (0 << 10) | 0, /* 0x2d, LNA 1 */ - (0 << 10) | 0, /* 0x2e, LNA 2 = 0dB */ - (0 << 10) | 0, /* 0x2f, LNA 2 */ - (0 << 10) | 0, /* 0x30, LNA 3 = 0dB */ - (0 << 10) | 0, /* 0x31, LNA 3 */ - (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */ - (0 << 10) | 0, /* GAIN_4_2, LNA 4 */ -}; - -static const u16 rf_ramp_vhf[] = { - 412, /* max RF gain in 10th of dB */ - 132, 307, 127, /* LNA1, 13.2dB */ - 105, 412, 255, /* LNA2, 10.5dB */ - 50, 50, 127, /* LNA3, 5dB */ - 125, 175, 127, /* LNA4, 12.5dB */ - 0, 0, 127, /* CBAND, 0dB */ -}; - -static const u16 rf_ramp_uhf[] = { - 412, /* max RF gain in 10th of dB */ - 132, 307, 127, /* LNA1 : total gain = 13.2dB, point on the ramp where this amp is full gain, value to write to get full gain */ - 105, 412, 255, /* LNA2 : 10.5 dB */ - 50, 50, 127, /* LNA3 : 5.0 dB */ - 125, 175, 127, /* LNA4 : 12.5 dB */ - 0, 0, 127, /* CBAND : 0.0 dB */ +/* GENERAL PWM ramp definition for all other Krosus */ +static const u16 bb_ramp_pwm_normal[] = { + 500, /* max BB gain in 10th of dB */ + 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */ + 400, + (2 << 9) | 0, /* BB_RAMP3 = 21dB */ + (0 << 9) | 168, /* BB_RAMP4 */ + (2 << 9) | 168, /* BB_RAMP5 = 29dB */ + (0 << 9) | 400, /* BB_RAMP6 */ }; -static const u16 rf_ramp_cband_broadmatching[] = /* for p1G only */ -{ - 314, /* Calibrated at 200MHz order has been changed g4-g3-g2-g1 */ - 84, 314, 127, /* LNA1 */ - 80, 230, 255, /* LNA2 */ - 80, 150, 127, /* LNA3 It was measured 12dB, do not lock if 120 */ - 70, 70, 127, /* LNA4 */ - 0, 0, 127, /* CBAND */ +static const u16 bb_ramp_pwm_boost[] = { + 550, /* max BB gain in 10th of dB */ + 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> BB_RAMP2 */ + 440, + (2 << 9) | 0, /* BB_RAMP3 = 26dB */ + (0 << 9) | 208, /* BB_RAMP4 */ + (2 << 9) | 208, /* BB_RAMP5 = 29dB */ + (0 << 9) | 440, /* BB_RAMP6 */ }; -static const u16 rf_ramp_cband[] = { - 332, /* max RF gain in 10th of dB */ - 132, 252, 127, /* LNA1, dB */ - 80, 332, 255, /* LNA2, dB */ - 0, 0, 127, /* LNA3, dB */ - 0, 0, 127, /* LNA4, dB */ - 120, 120, 127, /* LT1 CBAND */ +static const u16 rf_ramp_pwm_cband[] = { + 314, /* max RF gain in 10th of dB */ + 33, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 1023, /* ramp_max = maximum X used on the ramp */ + (8 << 10) | 743, /* RF_RAMP3, LNA 1 = 0dB */ + (0 << 10) | 1023, /* RF_RAMP4, LNA 1 */ + (15 << 10) | 469, /* RF_RAMP5, LNA 2 = 0dB */ + (0 << 10) | 742, /* RF_RAMP6, LNA 2 */ + (9 << 10) | 234, /* RF_RAMP7, LNA 3 = 0dB */ + (0 << 10) | 468, /* RF_RAMP8, LNA 3 */ + (9 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */ + (0 << 10) | 233, /* GAIN_4_2, LNA 4 */ }; static const u16 rf_ramp_pwm_vhf[] = { - 404, /* max RF gain in 10th of dB */ - 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ - 1011, /* ramp_max = maximum X used on the ramp */ - (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */ - (0 << 10) | 756, /* 0x2d, LNA 1 */ - (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */ - (0 << 10) | 1011, /* 0x2f, LNA 2 */ - (16 << 10) | 290, /* 0x30, LNA 3 = 5dB */ - (0 << 10) | 417, /* 0x31, LNA 3 */ - (7 << 10) | 0, /* GAIN_4_1, LNA 4 = 12.5dB */ - (0 << 10) | 290, /* GAIN_4_2, LNA 4 */ + 398, /* max RF gain in 10th of dB */ + 24, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 954, /* ramp_max = maximum X used on the ramp */ + (7 << 10) | 0, /* RF_RAMP3, LNA 1 = 13.2dB */ + (0 << 10) | 290, /* RF_RAMP4, LNA 1 */ + (16 << 10) | 699, /* RF_RAMP5, LNA 2 = 10.5dB */ + (0 << 10) | 954, /* RF_RAMP6, LNA 2 */ + (17 << 10) | 580, /* RF_RAMP7, LNA 3 = 5dB */ + (0 << 10) | 699, /* RF_RAMP8, LNA 3 */ + (7 << 10) | 290, /* GAIN_4_1, LNA 4 = 12.5dB */ + (0 << 10) | 580, /* GAIN_4_2, LNA 4 */ }; static const u16 rf_ramp_pwm_uhf[] = { - 404, /* max RF gain in 10th of dB */ - 25, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x2b */ - 1011, /* ramp_max = maximum X used on the ramp */ - (6 << 10) | 417, /* 0x2c, LNA 1 = 13.2dB */ - (0 << 10) | 756, /* 0x2d, LNA 1 */ - (16 << 10) | 756, /* 0x2e, LNA 2 = 10.5dB */ - (0 << 10) | 1011, /* 0x2f, LNA 2 */ - (16 << 10) | 0, /* 0x30, LNA 3 = 5dB */ - (0 << 10) | 127, /* 0x31, LNA 3 */ - (7 << 10) | 127, /* GAIN_4_1, LNA 4 = 12.5dB */ - (0 << 10) | 417, /* GAIN_4_2, LNA 4 */ + 398, /* max RF gain in 10th of dB */ + 24, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 954, /* ramp_max = maximum X used on the ramp */ + (7 << 10) | 0, /* RF_RAMP3, LNA 1 = 13.2dB */ + (0 << 10) | 290, /* RF_RAMP4, LNA 1 */ + (16 << 10) | 699, /* RF_RAMP5, LNA 2 = 10.5dB */ + (0 << 10) | 954, /* RF_RAMP6, LNA 2 */ + (17 << 10) | 580, /* RF_RAMP7, LNA 3 = 5dB */ + (0 << 10) | 699, /* RF_RAMP8, LNA 3 */ + (7 << 10) | 290, /* GAIN_4_1, LNA 4 = 12.5dB */ + (0 << 10) | 580, /* GAIN_4_2, LNA 4 */ }; -static const u16 bb_ramp_boost[] = { - 550, /* max BB gain in 10th of dB */ - 260, 260, 26, /* BB1, 26dB */ - 290, 550, 29, /* BB2, 29dB */ -}; - -static const u16 bb_ramp_pwm_normal[] = { - 500, /* max RF gain in 10th of dB */ - 8, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> 0x34 */ - 400, - (2 << 9) | 0, /* 0x35 = 21dB */ - (0 << 9) | 168, /* 0x36 */ - (2 << 9) | 168, /* 0x37 = 29dB */ - (0 << 9) | 400, /* 0x38 */ +static const u16 rf_ramp_pwm_sband[] = { + 253, /* max RF gain in 10th of dB */ + 38, /* ramp_slope = 1dB of gain -> clock_ticks_per_db = clk_khz / ramp_slope -> RF_RAMP2 */ + 961, + (4 << 10) | 0, /* RF_RAMP3, LNA 1 = 14.1dB */ + (0 << 10) | 508, /* RF_RAMP4, LNA 1 */ + (9 << 10) | 508, /* RF_RAMP5, LNA 2 = 11.2dB */ + (0 << 10) | 961, /* RF_RAMP6, LNA 2 */ + (0 << 10) | 0, /* RF_RAMP7, LNA 3 = 0dB */ + (0 << 10) | 0, /* RF_RAMP8, LNA 3 */ + (0 << 10) | 0, /* GAIN_4_1, LNA 4 = 0dB */ + (0 << 10) | 0, /* GAIN_4_2, LNA 4 */ }; struct slope { @@ -1089,70 +1070,69 @@ static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg) void dib0090_pwm_gain_reset(struct dvb_frontend *fe) { struct dib0090_state *state = fe->tuner_priv; - /* reset the AGC */ + u16 *bb_ramp = (u16 *)&bb_ramp_pwm_normal; /* default baseband config */ + u16 *rf_ramp = NULL; + u8 en_pwm_rf_mux = 1; + /* reset the AGC */ if (state->config->use_pwm_agc) { -#ifdef CONFIG_BAND_SBAND - if (state->current_band == BAND_SBAND) { - dib0090_set_rframp_pwm(state, rf_ramp_pwm_sband); - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_boost); - } else -#endif -#ifdef CONFIG_BAND_CBAND if (state->current_band == BAND_CBAND) { if (state->identity.in_soc) { - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); + bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs; if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1) - dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_8090); - else if (state->identity.version == SOC_7090_P1G_11R1 - || state->identity.version == SOC_7090_P1G_21R1) { + rf_ramp = (u16 *)&rf_ramp_pwm_cband_8090; + else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) { if (state->config->is_dib7090e) { if (state->rf_ramp == NULL) - dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090e_sensitivity); + rf_ramp = (u16 *)&rf_ramp_pwm_cband_7090e_sensitivity; else - dib0090_set_rframp_pwm(state, state->rf_ramp); + rf_ramp = (u16 *)state->rf_ramp; } else - dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband_7090); + rf_ramp = (u16 *)&rf_ramp_pwm_cband_7090p; } - } else { - dib0090_set_rframp_pwm(state, rf_ramp_pwm_cband); - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); - } + } else + rf_ramp = (u16 *)&rf_ramp_pwm_cband; } else -#endif -#ifdef CONFIG_BAND_VHF - if (state->current_band == BAND_VHF) { - if (state->identity.in_soc) { - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); - } else { - dib0090_set_rframp_pwm(state, rf_ramp_pwm_vhf); - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); + + if (state->current_band == BAND_VHF) { + if (state->identity.in_soc) { + bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs; + /* rf_ramp = &rf_ramp_pwm_vhf_socs; */ /* TODO */ + } else + rf_ramp = (u16 *)&rf_ramp_pwm_vhf; + } else if (state->current_band == BAND_UHF) { + if (state->identity.in_soc) { + bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs; + if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1) + rf_ramp = (u16 *)&rf_ramp_pwm_uhf_8090; + else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) + rf_ramp = (u16 *)&rf_ramp_pwm_uhf_7090; + } else + rf_ramp = (u16 *)&rf_ramp_pwm_uhf; } + if (rf_ramp) + dib0090_set_rframp_pwm(state, rf_ramp); + dib0090_set_bbramp_pwm(state, bb_ramp); + + /* activate the ramp generator using PWM control */ + dprintk("ramp RF gain = %d BAND = %s version = %d", state->rf_ramp[0], (state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND", state->identity.version & 0x1f); + + if ((state->rf_ramp[0] == 0) || (state->current_band == BAND_CBAND && (state->identity.version & 0x1f) <= P1D_E_F)) { + dprintk("DE-Engage mux for direct gain reg control"); + en_pwm_rf_mux = 0; } else -#endif - { - if (state->identity.in_soc) { - if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1) - dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_8090); - else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) - dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf_7090); - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal_socs); - } else { - dib0090_set_rframp_pwm(state, rf_ramp_pwm_uhf); - dib0090_set_bbramp_pwm(state, bb_ramp_pwm_normal); - } - } + dprintk("Engage mux for PWM control"); - if (state->rf_ramp[0] != 0) - dib0090_write_reg(state, 0x32, (3 << 11)); - else - dib0090_write_reg(state, 0x32, (0 << 11)); + dib0090_write_reg(state, 0x32, (en_pwm_rf_mux << 12) | (en_pwm_rf_mux << 11)); - dib0090_write_reg(state, 0x04, 0x03); - dib0090_write_reg(state, 0x39, (1 << 10)); + /* Set fast servo cutoff to start AGC; 0 = 1KHz ; 1 = 50Hz ; 2 = 150Hz ; 3 = 50KHz ; 4 = servo fast*/ + if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) + dib0090_write_reg(state, 0x04, 3); + else + dib0090_write_reg(state, 0x04, 1); + dib0090_write_reg(state, 0x39, (1 << 10)); /* 0 gain by default */ } } - EXPORT_SYMBOL(dib0090_pwm_gain_reset); void dib0090_set_dc_servo(struct dvb_frontend *fe, u8 DC_servo_cutoff) @@ -1193,22 +1173,22 @@ int dib0090_gain_control(struct dvb_frontend *fe) #endif #ifdef CONFIG_BAND_VHF if (state->current_band == BAND_VHF && !state->identity.p1g) { - dib0090_set_rframp(state, rf_ramp_vhf); - dib0090_set_bbramp(state, bb_ramp_boost); + dib0090_set_rframp(state, rf_ramp_pwm_vhf); + dib0090_set_bbramp(state, bb_ramp_pwm_normal); } else #endif #ifdef CONFIG_BAND_CBAND if (state->current_band == BAND_CBAND && !state->identity.p1g) { - dib0090_set_rframp(state, rf_ramp_cband); - dib0090_set_bbramp(state, bb_ramp_boost); + dib0090_set_rframp(state, rf_ramp_pwm_cband); + dib0090_set_bbramp(state, bb_ramp_pwm_normal); } else #endif if ((state->current_band == BAND_CBAND || state->current_band == BAND_VHF) && state->identity.p1g) { - dib0090_set_rframp(state, rf_ramp_cband_broadmatching); - dib0090_set_bbramp(state, bb_ramp_boost); + dib0090_set_rframp(state, rf_ramp_pwm_cband_7090p); + dib0090_set_bbramp(state, bb_ramp_pwm_normal_socs); } else { - dib0090_set_rframp(state, rf_ramp_uhf); - dib0090_set_bbramp(state, bb_ramp_boost); + dib0090_set_rframp(state, rf_ramp_pwm_uhf); + dib0090_set_bbramp(state, bb_ramp_pwm_normal); } dib0090_write_reg(state, 0x32, 0); @@ -1553,14 +1533,20 @@ static void dib0090_set_EFUSE(struct dib0090_state *state) if ((c >= CAP_VALUE_MAX) || (c <= CAP_VALUE_MIN)) c = 32; + else + c += 14; if ((h >= HR_MAX) || (h <= HR_MIN)) h = 34; if ((n >= POLY_MAX) || (n <= POLY_MIN)) n = 3; - dib0090_write_reg(state, 0x13, (h << 10)) ; - e2 = (n<<11) | ((h>>2)<<6) | (c); - dib0090_write_reg(state, 0x2, e2) ; /* Load the BB_2 */ + if ((c >= CAP_VALUE_MIN) && (c <= CAP_VALUE_MAX) + && (h >= HR_MIN) && (h <= HR_MAX) + && (n >= POLY_MIN) && (n <= POLY_MAX)) { + dib0090_write_reg(state, 0x13, (h << 10)); + e2 = (n << 11) | ((h >> 2)<<6) | c; + dib0090_write_reg(state, 0x2, e2); /* Load the BB_2 */ + } } } -- cgit v1.2.3 From 5e9c85d983375fd84a4ba98b34f8fc38d4ec8766 Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Mon, 31 Dec 2012 10:17:44 -0300 Subject: [media] dib8096: enhancement The intend of this patch is to improve the support of the dib8096. The PLL parameters are not automatically computed. The limit to set/unset external diode for attenuation has been updated. The TFE8096P board is using the new I2C API. Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dib0700_devices.c | 208 +++++++++++++++++++++++----- 1 file changed, 175 insertions(+), 33 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 5a4175ef3524..d0916c88d9c1 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -1431,13 +1431,22 @@ static int dib8090_get_adc_power(struct dvb_frontend *fe) return dib8000_get_adc_power(fe, 1); } +static void dib8090_agc_control(struct dvb_frontend *fe, u8 restart) +{ + deb_info("AGC control callback: %i\n", restart); + dib0090_dcc_freq(fe, restart); + + if (restart == 0) /* before AGC startup */ + dib0090_set_dc_servo(fe, 1); +} + static struct dib8000_config dib809x_dib8000_config[2] = { { .output_mpeg2_in_188_bytes = 1, .agc_config_count = 2, .agc = dib8090_agc_config, - .agc_control = dib0090_dcc_freq, + .agc_control = dib8090_agc_control, .pll = &dib8090_pll_config_12mhz, .tuner_is_baseband = 1, @@ -1456,7 +1465,7 @@ static struct dib8000_config dib809x_dib8000_config[2] = { .agc_config_count = 2, .agc = dib8090_agc_config, - .agc_control = dib0090_dcc_freq, + .agc_control = dib8090_agc_control, .pll = &dib8090_pll_config_12mhz, .tuner_is_baseband = 1, @@ -1504,28 +1513,89 @@ static struct dib0090_config dib809x_dib0090_config = { .fref_clock_ratio = 6, }; +static u8 dib8090_compute_pll_parameters(struct dvb_frontend *fe) +{ + u8 optimal_pll_ratio = 20; + u32 freq_adc, ratio, rest, max = 0; + u8 pll_ratio; + + for (pll_ratio = 17; pll_ratio <= 20; pll_ratio++) { + freq_adc = 12 * pll_ratio * (1 << 8) / 16; + ratio = ((fe->dtv_property_cache.frequency / 1000) * (1 << 8) / 1000) / freq_adc; + rest = ((fe->dtv_property_cache.frequency / 1000) * (1 << 8) / 1000) - ratio * freq_adc; + + if (rest > freq_adc / 2) + rest = freq_adc - rest; + deb_info("PLL ratio=%i rest=%i\n", pll_ratio, rest); + if ((rest > max) && (rest > 717)) { + optimal_pll_ratio = pll_ratio; + max = rest; + } + } + deb_info("optimal PLL ratio=%i\n", optimal_pll_ratio); + + return optimal_pll_ratio; +} + static int dib8096_set_param_override(struct dvb_frontend *fe) { - struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dvb_usb_adapter *adap = fe->dvb->priv; struct dib0700_adapter_state *state = adap->priv; - u8 band = BAND_OF_FREQUENCY(p->frequency/1000); - u16 target; + u8 pll_ratio, band = BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000); + u16 target, ltgain, rf_gain_limit; + u32 timf; int ret = 0; enum frontend_tune_state tune_state = CT_SHUTDOWN; - u16 ltgain, rf_gain_limit; + + switch (band) { + default: + deb_info("Warning : Rf frequency (%iHz) is not in the supported range, using VHF switch ", fe->dtv_property_cache.frequency); + case BAND_VHF: + dib8000_set_gpio(fe, 3, 0, 1); + break; + case BAND_UHF: + dib8000_set_gpio(fe, 3, 0, 0); + break; + } ret = state->set_param_save(fe); if (ret < 0) return ret; - target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2; - dib8000_set_wbd_ref(fe, target); + if (fe->dtv_property_cache.bandwidth_hz != 6000000) { + deb_info("only 6MHz bandwidth is supported\n"); + return -EINVAL; + } + /** Update PLL if needed ratio **/ + dib8000_update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, 0); + + /** Get optimize PLL ratio to remove spurious **/ + pll_ratio = dib8090_compute_pll_parameters(fe); + if (pll_ratio == 17) + timf = 21387946; + else if (pll_ratio == 18) + timf = 20199727; + else if (pll_ratio == 19) + timf = 19136583; + else + timf = 18179756; + + /** Update ratio **/ + dib8000_update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, pll_ratio); + + dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, timf); + + if (band != BAND_CBAND) { + /* dib0090_get_wbd_target is returning any possible temperature compensated wbd-target */ + target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2; + dib8000_set_wbd_ref(fe, target); + } if (band == BAND_CBAND) { deb_info("tuning in CBAND - soft-AGC startup\n"); dib0090_set_tune_state(fe, CT_AGC_START); + do { ret = dib0090_gain_control(fe); msleep(ret); @@ -1534,14 +1604,17 @@ static int dib8096_set_param_override(struct dvb_frontend *fe) dib8000_set_gpio(fe, 6, 0, 1); else if (tune_state == CT_AGC_STEP_1) { dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain); - if (rf_gain_limit == 0) + if (rf_gain_limit < 2000) /* activate the external attenuator in case of very high input power */ dib8000_set_gpio(fe, 6, 0, 0); } } while (tune_state < CT_AGC_STOP); + + deb_info("switching to PWM AGC\n"); dib0090_pwm_gain_reset(fe); dib8000_pwm_agc_reset(fe); dib8000_set_tune_state(fe, CT_DEMOD_START); } else { + /* for everything else than CBAND we are using standard AGC */ deb_info("not tuning in CBAND - standard AGC startup\n"); dib0090_pwm_gain_reset(fe); } @@ -1814,21 +1887,92 @@ struct dibx090p_adc { u32 pll_prediv; /* New loopdiv */ }; -struct dibx090p_adc dib8090p_adc_tab[] = { - { 50000, 17043521, 16, 3}, /* 64 MHz */ - {878000, 20199729, 9, 1}, /* 60 MHz */ - {0xffffffff, 0, 0, 0}, /* 60 MHz */ +struct dibx090p_best_adc { + u32 timf; + u32 pll_loopdiv; + u32 pll_prediv; }; +static int dib8096p_get_best_sampling(struct dvb_frontend *fe, struct dibx090p_best_adc *adc) +{ + u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1; + u16 xtal = 12000; + u16 fcp_min = 1900; /* PLL, Minimum Frequency of phase comparator (KHz) */ + u16 fcp_max = 20000; /* PLL, Maximum Frequency of phase comparator (KHz) */ + u32 fmem_max = 140000; /* 140MHz max SDRAM freq */ + u32 fdem_min = 66000; + u32 fcp = 0, fs = 0, fdem = 0, fmem = 0; + u32 harmonic_id = 0; + + adc->timf = 0; + adc->pll_loopdiv = loopdiv; + adc->pll_prediv = prediv; + + deb_info("bandwidth = %d", fe->dtv_property_cache.bandwidth_hz); + + /* Find Min and Max prediv */ + while ((xtal / max_prediv) >= fcp_min) + max_prediv++; + + max_prediv--; + min_prediv = max_prediv; + while ((xtal / min_prediv) <= fcp_max) { + min_prediv--; + if (min_prediv == 1) + break; + } + deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv); + + min_prediv = 1; + + for (prediv = min_prediv; prediv < max_prediv; prediv++) { + fcp = xtal / prediv; + if (fcp > fcp_min && fcp < fcp_max) { + for (loopdiv = 1; loopdiv < 64; loopdiv++) { + fmem = ((xtal/prediv) * loopdiv); + fdem = fmem / 2; + fs = fdem / 4; + + /* test min/max system restrictions */ + if ((fdem >= fdem_min) && (fmem <= fmem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz / 1000)) { + spur = 0; + /* test fs harmonics positions */ + for (harmonic_id = (fe->dtv_property_cache.frequency / (1000 * fs)); harmonic_id <= ((fe->dtv_property_cache.frequency / (1000 * fs)) + 1); harmonic_id++) { + if (((fs * harmonic_id) >= (fe->dtv_property_cache.frequency / 1000 - (fe->dtv_property_cache.bandwidth_hz / 2000))) && ((fs * harmonic_id) <= (fe->dtv_property_cache.frequency / 1000 + (fe->dtv_property_cache.bandwidth_hz / 2000)))) { + spur = 1; + break; + } + } + + if (!spur) { + adc->pll_loopdiv = loopdiv; + adc->pll_prediv = prediv; + adc->timf = (4260880253U / fdem) * (1 << 8); + adc->timf += ((4260880253U % fdem) << 8) / fdem; + + deb_info("RF %6d; BW %6d; Xtal %6d; Fmem %6d; Fdem %6d; Fs %6d; Prediv %2d; Loopdiv %2d; Timf %8d;", fe->dtv_property_cache.frequency, fe->dtv_property_cache.bandwidth_hz, xtal, fmem, fdem, fs, prediv, loopdiv, adc->timf); + break; + } + } + } + } + if (!spur) + break; + } + + if (adc->pll_loopdiv == 0 && adc->pll_prediv == 0) + return -EINVAL; + return 0; +} + static int dib8096p_agc_startup(struct dvb_frontend *fe) { - struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dvb_usb_adapter *adap = fe->dvb->priv; struct dib0700_adapter_state *state = adap->priv; struct dibx000_bandwidth_config pll; + struct dibx090p_best_adc adc; u16 target; - int better_sampling_freq = 0, ret; - struct dibx090p_adc *adc_table = &dib8090p_adc_tab[0]; + int ret; ret = state->set_param_save(fe); if (ret < 0) @@ -1841,23 +1985,27 @@ static int dib8096p_agc_startup(struct dvb_frontend *fe) target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2; dib8000_set_wbd_ref(fe, target); + if (dib8096p_get_best_sampling(fe, &adc) == 0) { + pll.pll_ratio = adc.pll_loopdiv; + pll.pll_prediv = adc.pll_prediv; - while (p->frequency / 1000 > adc_table->freq) { - better_sampling_freq = 1; - adc_table++; - } - - if ((adc_table->freq != 0xffffffff) && better_sampling_freq) { - pll.pll_ratio = adc_table->pll_loopdiv; - pll.pll_prediv = adc_table->pll_prediv; + dib0700_set_i2c_speed(adap->dev, 200); dib8000_update_pll(fe, &pll, fe->dtv_property_cache.bandwidth_hz / 1000, 0); - dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc_table->timf); + dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf); + dib0700_set_i2c_speed(adap->dev, 1000); } return 0; } static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap) { + struct dib0700_state *st = adap->dev->priv; + u32 fw_version; + + dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL); + if (fw_version >= 0x10200) + st->fw_use_new_i2c_api = 1; + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(20); dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); @@ -2242,13 +2390,7 @@ static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap) } /* NIM7090 */ -struct dib7090p_best_adc { - u32 timf; - u32 pll_loopdiv; - u32 pll_prediv; -}; - -static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_best_adc *adc) +static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dibx090p_best_adc *adc) { u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1; @@ -2327,7 +2469,7 @@ static int dib7090_agc_startup(struct dvb_frontend *fe) struct dib0700_adapter_state *state = adap->priv; struct dibx000_bandwidth_config pll; u16 target; - struct dib7090p_best_adc adc; + struct dibx090p_best_adc adc; int ret; ret = state->set_param_save(fe); -- cgit v1.2.3 From f45f513a9325b52a5f3e26ee8d15471e8b692947 Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Mon, 31 Dec 2012 09:47:10 -0300 Subject: [media] dib7090p: remove the support for the dib7090E The intend of this patch is to remove the support for the dib7090E. The DiB7090E-package has never left prototype state and never made it to mass-prod-state. Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb-usb-ids.h | 3 +- drivers/media/usb/dvb-usb/dib0700_devices.c | 233 ++++------------------------ 2 files changed, 29 insertions(+), 207 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index 399e1042d351..335a8f4695b4 100644 --- a/drivers/media/dvb-core/dvb-usb-ids.h +++ b/drivers/media/dvb-core/dvb-usb-ids.h @@ -124,8 +124,7 @@ #define USB_PID_DIBCOM_STK7770P 0x1e80 #define USB_PID_DIBCOM_NIM7090 0x1bb2 #define USB_PID_DIBCOM_TFE7090PVR 0x1bb4 -#define USB_PID_DIBCOM_TFE7090E 0x1bb7 -#define USB_PID_DIBCOM_TFE7790E 0x1e6e +#define USB_PID_DIBCOM_TFE7790P 0x1e6e #define USB_PID_DIBCOM_NIM9090M 0x2383 #define USB_PID_DIBCOM_NIM9090MD 0x2384 #define USB_PID_DPOSH_M9206_COLD 0x9206 diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index d0916c88d9c1..d8077f15e536 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -2499,36 +2499,16 @@ static int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) return 0; } -static int dib7090e_update_lna(struct dvb_frontend *fe, u16 agc_global) +static int tfe7790p_update_lna(struct dvb_frontend *fe, u16 agc_global) { - u16 agc1 = 0, agc2, wbd = 0, wbd_target, wbd_offset, threshold_agc1; - s16 wbd_delta; + deb_info("update LNA: agc global=%i", agc_global); - if ((fe->dtv_property_cache.frequency) < 400000000) - threshold_agc1 = 25000; - else - threshold_agc1 = 30000; - - wbd_target = (dib0090_get_wbd_target(fe)*8+1)/2; - wbd_offset = dib0090_get_wbd_offset(fe); - dib7000p_get_agc_values(fe, NULL, &agc1, &agc2, &wbd); - wbd_delta = (s16)wbd - (((s16)wbd_offset+10)*4) ; - - deb_info("update lna, agc_global=%d agc1=%d agc2=%d", - agc_global, agc1, agc2); - deb_info("update lna, wbd=%d wbd target=%d wbd offset=%d wbd delta=%d", - wbd, wbd_target, wbd_offset, wbd_delta); - - if ((agc1 < threshold_agc1) && (wbd_delta > 0)) { - dib0090_set_switch(fe, 1, 1, 1); - dib0090_set_vga(fe, 0); - dib0090_update_rframp_7090(fe, 0); - dib0090_update_tuning_table_7090(fe, 0); + if (agc_global < 25000) { + dib7000p_set_gpio(fe, 8, 0, 0); + dib7000p_set_agc1_min(fe, 0); } else { - dib0090_set_vga(fe, 1); - dib0090_update_rframp_7090(fe, 1); - dib0090_update_tuning_table_7090(fe, 1); - dib0090_set_switch(fe, 0, 0, 0); + dib7000p_set_gpio(fe, 8, 0, 1); + dib7000p_set_agc1_min(fe, 32768); } return 0; @@ -2542,15 +2522,6 @@ static struct dib0090_wbd_slope dib7090_wbd_table[] = { { 0xFFFF, 0, 0, 0, 0, 0}, }; -static struct dib0090_wbd_slope dib7090e_wbd_table[] = { - { 380, 81, 850, 64, 540, 4}, - { 700, 51, 866, 21, 320, 4}, - { 860, 48, 666, 18, 330, 6}, - {1700, 0, 250, 0, 100, 6}, - {2600, 0, 250, 0, 100, 6}, - { 0xFFFF, 0, 0, 0, 0, 0}, -}; - static struct dibx000_agc_config dib7090_agc_config[2] = { { .band_caps = BAND_UHF, @@ -2729,34 +2700,6 @@ static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = { } }; -static struct dib7000p_config tfe7090e_dib7000p_config = { - .output_mpeg2_in_188_bytes = 1, - .hostbus_diversity = 1, - .tuner_is_baseband = 1, - .update_lna = dib7090e_update_lna, - - .agc_config_count = 2, - .agc = dib7090_agc_config, - - .bw = &dib7090_clock_config_12_mhz, - - .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS, - .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES, - .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, - - .pwm_freq_div = 0, - - .agc_control = dib7090_agc_restart, - - .spur_protect = 0, - .disable_sample_and_hold = 0, - .enable_current_mirror = 0, - .diversity_delay = 0, - - .output_mode = OUTMODE_MPEG2_FIFO, - .enMpegOutput = 1, -}; - static const struct dib0090_config nim7090_dib0090_config = { .io.clock_khz = 12000, .io.pll_bypass = 0, @@ -2791,47 +2734,11 @@ static const struct dib0090_config nim7090_dib0090_config = { .in_soc = 1, }; -static const struct dib0090_config tfe7090e_dib0090_config = { - .io.clock_khz = 12000, - .io.pll_bypass = 0, - .io.pll_range = 0, - .io.pll_prediv = 3, - .io.pll_loopdiv = 6, - .io.adc_clock_ratio = 0, - .io.pll_int_loop_filt = 0, - .reset = dib7090_tuner_sleep, - .sleep = dib7090_tuner_sleep, - - .freq_offset_khz_uhf = 0, - .freq_offset_khz_vhf = 0, - - .get_adc_power = dib7090_get_adc_power, - - .clkouttobamse = 1, - .analog_output = 0, - - .wbd_vhf_offset = 0, - .wbd_cband_offset = 0, - .use_pwm_agc = 1, - .clkoutdrive = 0, - - .fref_clock_ratio = 0, - - .wbd = dib7090e_wbd_table, - - .ls_cfg_pad_drv = 0, - .data_tx_drv = 0, - .low_if = NULL, - .in_soc = 1, - .force_cband_input = 1, - .is_dib7090e = 1, -}; - -static struct dib7000p_config tfe7790e_dib7000p_config = { +static struct dib7000p_config tfe7790p_dib7000p_config = { .output_mpeg2_in_188_bytes = 1, .hostbus_diversity = 1, .tuner_is_baseband = 1, - .update_lna = dib7090e_update_lna, + .update_lna = tfe7790p_update_lna, .agc_config_count = 2, .agc = dib7090_agc_config, @@ -2855,7 +2762,7 @@ static struct dib7000p_config tfe7790e_dib7000p_config = { .enMpegOutput = 1, }; -static const struct dib0090_config tfe7790e_dib0090_config = { +static const struct dib0090_config tfe7790p_dib0090_config = { .io.clock_khz = 12000, .io.pll_bypass = 0, .io.pll_range = 0, @@ -2881,14 +2788,14 @@ static const struct dib0090_config tfe7790e_dib0090_config = { .fref_clock_ratio = 0, - .wbd = dib7090e_wbd_table, + .wbd = dib7090_wbd_table, .ls_cfg_pad_drv = 0, .data_tx_drv = 0, .low_if = NULL, .in_soc = 1, - .force_cband_input = 1, - .is_dib7090e = 1, + .force_cband_input = 0, + .is_dib7090e = 0, .force_crystal_mode = 1, }; @@ -3084,37 +2991,11 @@ static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap) return 0; } -static int tfe7090e_frontend_attach(struct dvb_usb_adapter *adap) -{ - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); - - msleep(20); - dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); - msleep(20); - dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, - 1, 0x10, &tfe7090e_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", - __func__); - return -ENODEV; - } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, - 0x80, &tfe7090e_dib7000p_config); - - return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; -} - -static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap) +static int tfe7790p_frontend_attach(struct dvb_usb_adapter *adap) { struct dib0700_state *st = adap->dev->priv; - /* The TFE7790E requires the dib0700 to not be in master mode */ + /* The TFE7790P requires the dib0700 to not be in master mode */ st->disable_streaming_master_mode = 1; dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); @@ -3130,42 +3011,25 @@ static int tfe7790e_frontend_attach(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, - 1, 0x10, &tfe7790e_dib7000p_config) != 0) { + 1, 0x10, &tfe7790p_dib7000p_config) != 0) { err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); return -ENODEV; } adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, - 0x80, &tfe7790e_dib7000p_config); + 0x80, &tfe7790p_dib7000p_config); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } -static int tfe7790e_tuner_attach(struct dvb_usb_adapter *adap) -{ - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = - dib7090_get_i2c_tuner(adap->fe_adap[0].fe); - - if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, - &tfe7790e_dib0090_config) == NULL) - return -ENODEV; - - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); - - st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; - adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; - return 0; -} - -static int tfe7090e_tuner_attach(struct dvb_usb_adapter *adap) +static int tfe7790p_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe); if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, - &tfe7090e_dib0090_config) == NULL) + &tfe7790p_dib0090_config) == NULL) return -ENODEV; dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); @@ -3708,10 +3572,9 @@ struct usb_device_id dib0700_usb_id_table[] = { /* 75 */{ USB_DEVICE(USB_VID_MEDION, USB_PID_CREATIX_CTX1921) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E) }, { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E_SE) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090E) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790E) }, -/* 80 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) }, - { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790P) }, + { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) }, +/* 80 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -4022,7 +3885,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { { NULL }, }, { "Elgato EyeTV DTT rev. 2", - { &dib0700_usb_id_table[81], NULL }, + { &dib0700_usb_id_table[80], NULL }, { NULL }, }, }, @@ -4839,48 +4702,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .pid_filter_count = 32, .pid_filter = stk70x0p_pid_filter, .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = tfe7090e_frontend_attach, - .tuner_attach = tfe7090e_tuner_attach, - - DIB0700_DEFAULT_STREAMING_CONFIG(0x02), - } }, - - .size_of_priv = - sizeof(struct dib0700_adapter_state), - }, - }, - - .num_device_descs = 1, - .devices = { - { "DiBcom TFE7090E reference design", - { &dib0700_usb_id_table[78], NULL }, - { NULL }, - }, - }, - - .rc.core = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .module_name = "dib0700", - .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_BIT_RC5 | - RC_BIT_RC6_MCE | - RC_BIT_NEC, - .change_protocol = dib0700_change_protocol, - }, - }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, - .num_adapters = 1, - .adapter = { - { - .num_frontends = 1, - .fe = {{ - .caps = DVB_USB_ADAP_HAS_PID_FILTER | - DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF, - .pid_filter_count = 32, - .pid_filter = stk70x0p_pid_filter, - .pid_filter_ctrl = stk70x0p_pid_filter_ctrl, - .frontend_attach = tfe7790e_frontend_attach, - .tuner_attach = tfe7790e_tuner_attach, + .frontend_attach = tfe7790p_frontend_attach, + .tuner_attach = tfe7790p_tuner_attach, DIB0700_DEFAULT_STREAMING_CONFIG(0x03), } }, @@ -4892,8 +4715,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { - { "DiBcom TFE7790E reference design", - { &dib0700_usb_id_table[79], NULL }, + { "DiBcom TFE7790P reference design", + { &dib0700_usb_id_table[78], NULL }, { NULL }, }, }, @@ -4934,7 +4757,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { { "DiBcom TFE8096P reference design", - { &dib0700_usb_id_table[80], NULL }, + { &dib0700_usb_id_table[79], NULL }, { NULL }, }, }, -- cgit v1.2.3 From 59501bb792c66b85fb7fdbd740e788e3afc70bbd Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Mon, 31 Dec 2012 09:51:17 -0300 Subject: [media] dib7090p: improve the support of the dib7090 and dib7790 The intend of this patch is to improve the support of the dib7090 and dib7790. The AGC1 min value is set to 32768 by default. The actual AGC1 min and the external attenuation are controled depending on the received RF level. Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dib0700_devices.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index d8077f15e536..f08136052f9c 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -2541,7 +2541,7 @@ static struct dibx000_agc_config dib7090_agc_config[2] = { .wbd_alpha = 5, .agc1_max = 65535, - .agc1_min = 0, + .agc1_min = 32768, .agc2_max = 65535, .agc2_min = 0, @@ -2618,7 +2618,7 @@ static struct dib7000p_config nim7090_dib7000p_config = { .output_mpeg2_in_188_bytes = 1, .hostbus_diversity = 1, .tuner_is_baseband = 1, - .update_lna = NULL, + .update_lna = tfe7790p_update_lna, /* GPIO used is the same as TFE7790 */ .agc_config_count = 2, .agc = dib7090_agc_config, @@ -2642,12 +2642,26 @@ static struct dib7000p_config nim7090_dib7000p_config = { .enMpegOutput = 1, }; +static int tfe7090p_pvr_update_lna(struct dvb_frontend *fe, u16 agc_global) +{ + deb_info("TFE7090P-PVR update LNA: agc global=%i", agc_global); + if (agc_global < 25000) { + dib7000p_set_gpio(fe, 5, 0, 0); + dib7000p_set_agc1_min(fe, 0); + } else { + dib7000p_set_gpio(fe, 5, 0, 1); + dib7000p_set_agc1_min(fe, 32768); + } + + return 0; +} + static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = { { .output_mpeg2_in_188_bytes = 1, .hostbus_diversity = 1, .tuner_is_baseband = 1, - .update_lna = NULL, + .update_lna = tfe7090p_pvr_update_lna, .agc_config_count = 2, .agc = dib7090_agc_config, @@ -2674,7 +2688,7 @@ static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = { .output_mpeg2_in_188_bytes = 1, .hostbus_diversity = 1, .tuner_is_baseband = 1, - .update_lna = NULL, + .update_lna = tfe7090p_pvr_update_lna, .agc_config_count = 2, .agc = dib7090_agc_config, -- cgit v1.2.3 From c06ca8f92b0b23dfd209fea27d71046c9c776910 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sun, 21 Apr 2013 07:10:03 -0300 Subject: [media] media: info leak in media_device_enum_entities() The last part of the "u_ent.name" buffer isn't cleared so it still has uninitialized stack memory. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 99b80b6f7f67..1957c0df08fd 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -102,9 +102,12 @@ static long media_device_enum_entities(struct media_device *mdev, return -EINVAL; u_ent.id = ent->id; - u_ent.name[0] = '\0'; - if (ent->name) - strlcpy(u_ent.name, ent->name, sizeof(u_ent.name)); + if (ent->name) { + strncpy(u_ent.name, ent->name, sizeof(u_ent.name)); + u_ent.name[sizeof(u_ent.name) - 1] = '\0'; + } else { + memset(u_ent.name, 0, sizeof(u_ent.name)); + } u_ent.type = ent->type; u_ent.revision = ent->revision; u_ent.flags = ent->flags; -- cgit v1.2.3 From f7d141b312702d33449809b823894c486e6d9770 Mon Sep 17 00:00:00 2001 From: Kevin Baradon Date: Mon, 22 Apr 2013 16:09:44 -0300 Subject: [media] imon: Use large delays earlier send_packet() is used during initialization, before send_packet_delay is set. So, move ictx->send_packet_delay to happen earlier. [mchehab@redhat.com: fold two patches into one to make git history clearer] Signed-off-by: Kevin Baradon Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index b8f9f85a11c9..624fd33d7086 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -2093,7 +2093,8 @@ static bool imon_find_endpoints(struct imon_context *ictx, } -static struct imon_context *imon_init_intf0(struct usb_interface *intf) +static struct imon_context *imon_init_intf0(struct usb_interface *intf, + const struct usb_device_id *id) { struct imon_context *ictx; struct urb *rx_urb; @@ -2133,6 +2134,10 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf) ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor); ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct); + /* default send_packet delay is 5ms but some devices need more */ + ictx->send_packet_delay = id->driver_info & IMON_NEED_20MS_PKT_DELAY ? + 20 : 5; + ret = -ENODEV; iface_desc = intf->cur_altsetting; if (!imon_find_endpoints(ictx, iface_desc)) { @@ -2311,7 +2316,7 @@ static int imon_probe(struct usb_interface *interface, first_if_ctx = usb_get_intfdata(first_if); if (ifnum == 0) { - ictx = imon_init_intf0(interface); + ictx = imon_init_intf0(interface, id); if (!ictx) { pr_err("failed to initialize context!\n"); ret = -ENODEV; @@ -2329,10 +2334,6 @@ static int imon_probe(struct usb_interface *interface, } - /* default send_packet delay is 5ms but some devices need more */ - ictx->send_packet_delay = id->driver_info & IMON_NEED_20MS_PKT_DELAY ? - 20 : 5; - usb_set_intfdata(interface, ictx); if (ifnum == 0) { -- cgit v1.2.3 From 7d54ba0e37130edda335e7f373f193014ede2a12 Mon Sep 17 00:00:00 2001 From: Kevin Baradon Date: Mon, 22 Apr 2013 16:09:45 -0300 Subject: [media] media/rc/imon.c: do not try to register 2nd intf if 1st intf failed This bug could be triggered if 1st interface configuration fails: Apr 8 18:20:30 homeserver kernel: usb 5-1: new low-speed USB device number 2 using ohci_hcd Apr 8 18:20:30 homeserver kernel: input: iMON Panel, Knob and Mouse(15c2:0036) as /devices/pci0000:00/0000:00:13.0/usb5/5-1/5-1:1.0/input/input2 Apr 8 18:20:30 homeserver kernel: Registered IR keymap rc-imon-pad Apr 8 18:20:30 homeserver kernel: input: iMON Remote (15c2:0036) as /devices/pci0000:00/0000:00:13.0/usb5/5-1/5-1:1.0/rc/rc0/input3 Apr 8 18:20:30 homeserver kernel: rc0: iMON Remote (15c2:0036) as /devices/pci0000:00/0000:00:13.0/usb5/5-1/5-1:1.0/rc/rc0 Apr 8 18:20:30 homeserver kernel: imon:send_packet: packet tx failed (-32) Apr 8 18:20:30 homeserver kernel: imon 5-1:1.0: remote input dev register failed Apr 8 18:20:30 homeserver kernel: imon 5-1:1.0: imon_init_intf0: rc device setup failed Apr 8 18:20:30 homeserver kernel: imon 5-1:1.0: unable to initialize intf0, err 0 Apr 8 18:20:30 homeserver kernel: imon:imon_probe: failed to initialize context! Apr 8 18:20:30 homeserver kernel: imon 5-1:1.0: unable to register, err -19 Apr 8 18:20:30 homeserver kernel: BUG: unable to handle kernel NULL pointer dereference at 00000014 Apr 8 18:20:30 homeserver kernel: IP: [] mutex_lock+0xc/0x30 Apr 8 18:20:30 homeserver kernel: *pde = 00000000 Apr 8 18:20:30 homeserver kernel: Oops: 0002 [#1] PREEMPT SMP Apr 8 18:20:30 homeserver kernel: Modules linked in: Apr 8 18:20:30 homeserver kernel: Pid: 367, comm: khubd Not tainted 3.8.3-htpc-00002-g79b1403 #23 Unknow Unknow/RS780-SB700 Apr 8 18:20:30 homeserver kernel: EIP: 0060:[] EFLAGS: 00010296 CPU: 1 Apr 8 18:20:30 homeserver kernel: EIP is at mutex_lock+0xc/0x30 Apr 8 18:20:30 homeserver kernel: EAX: 00000014 EBX: 00000014 ECX: 00000000 EDX: f590e480 Apr 8 18:20:30 homeserver kernel: ESI: f5deac00 EDI: f590e480 EBP: f5f3ee00 ESP: f6577c28 Apr 8 18:20:30 homeserver kernel: DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 Apr 8 18:20:30 homeserver kernel: CR0: 8005003b CR2: 00000014 CR3: 0081b000 CR4: 000007d0 Apr 8 18:20:30 homeserver kernel: DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 Apr 8 18:20:30 homeserver kernel: DR6: ffff0ff0 DR7: 00000400 Apr 8 18:20:30 homeserver kernel: Process khubd (pid: 367, ti=f6576000 task=f649ea00 task.ti=f6576000) Apr 8 18:20:30 homeserver kernel: Stack: Apr 8 18:20:30 homeserver kernel: 00000000 f5deac00 c0448de4 f59714c0 f5deac64 c03b8ad2 f6577c90 00000004 Apr 8 18:20:30 homeserver kernel: f649ea00 c0205142 f6779820 a1ff7f08 f5deac00 00000001 f5f3ee1c 00000014 Apr 8 18:20:30 homeserver kernel: 00000004 00000202 15c20036 c07a03e8 fffee0ca f6795c00 f5f3ee1c f5deac00 Apr 8 18:20:30 homeserver kernel: Call Trace: Apr 8 18:20:30 homeserver kernel: [] ? imon_probe+0x494/0xde0 Apr 8 18:20:30 homeserver kernel: [] ? rpm_resume+0xb2/0x4f0 Apr 8 18:20:30 homeserver kernel: [] ? sysfs_addrm_finish+0x12/0x90 Apr 8 18:20:30 homeserver kernel: [] ? usb_probe_interface+0x169/0x240 Apr 8 18:20:30 homeserver kernel: [] ? __driver_attach+0x80/0x80 Apr 8 18:20:30 homeserver kernel: [] ? __driver_attach+0x80/0x80 Apr 8 18:20:30 homeserver kernel: [] ? driver_probe_device+0x54/0x1e0 Apr 8 18:20:30 homeserver kernel: [] ? usb_device_match+0x4e/0x80 Apr 8 18:20:30 homeserver kernel: [] ? bus_for_each_drv+0x34/0x70 Apr 8 18:20:30 homeserver kernel: [] ? device_attach+0x7b/0x90 Apr 8 18:20:30 homeserver kernel: [] ? __driver_attach+0x80/0x80 Apr 8 18:20:30 homeserver kernel: [] ? bus_probe_device+0x5f/0x80 Apr 8 18:20:30 homeserver kernel: [] ? device_add+0x567/0x610 Apr 8 18:20:30 homeserver kernel: [] ? usb_create_ep_devs+0x7c/0xd0 Apr 8 18:20:30 homeserver kernel: [] ? create_intf_ep_devs+0x47/0x70 Apr 8 18:20:30 homeserver kernel: [] ? usb_set_configuration+0x454/0x750 Apr 8 18:20:30 homeserver kernel: [] ? __driver_attach+0x80/0x80 Apr 8 18:20:30 homeserver kernel: [] ? generic_probe+0x2a/0x80 Apr 8 18:20:30 homeserver kernel: [] ? __driver_attach+0x80/0x80 Apr 8 18:20:30 homeserver kernel: [] ? sysfs_create_link+0xf/0x20 Apr 8 18:20:30 homeserver kernel: [] ? usb_probe_device+0x1b/0x40 Apr 8 18:20:30 homeserver kernel: [] ? driver_probe_device+0x54/0x1e0 Apr 8 18:20:30 homeserver kernel: [] ? bus_for_each_drv+0x34/0x70 Apr 8 18:20:30 homeserver kernel: [] ? device_attach+0x7b/0x90 Apr 8 18:20:30 homeserver kernel: [] ? __driver_attach+0x80/0x80 Apr 8 18:20:30 homeserver kernel: [] ? bus_probe_device+0x5f/0x80 Apr 8 18:20:30 homeserver kernel: [] ? device_add+0x567/0x610 Apr 8 18:20:30 homeserver kernel: [] ? usb_new_device+0x12f/0x1e0 Apr 8 18:20:30 homeserver kernel: [] ? hub_thread+0x458/0x1230 Apr 8 18:20:30 homeserver kernel: [] ? dequeue_task_fair+0x9f/0xc0 Apr 8 18:20:30 homeserver kernel: [] ? release_task+0x1d2/0x330 Apr 8 18:20:30 homeserver kernel: [] ? abort_exclusive_wait+0x90/0x90 Apr 8 18:20:30 homeserver kernel: [] ? usb_remote_wakeup+0x40/0x40 Apr 8 18:20:30 homeserver kernel: [] ? kthread+0x92/0xa0 Apr 8 18:20:30 homeserver kernel: [] ? ret_from_kernel_thread+0x1b/0x28 Apr 8 18:20:30 homeserver kernel: [] ? kthread_freezable_should_stop+0x50/0x50 Apr 8 18:20:30 homeserver kernel: Code: 89 04 24 89 f0 e8 05 ff ff ff 8b 5c 24 24 8b 74 24 28 8b 7c 24 2c 8b 6c 24 30 83 c4 34 c3 00 83 ec 08 89 1c 24 89 74 24 04 89 c3 ff 08 79 05 e8 ca 03 00 00 64 a1 70 d6 80 c0 8b 74 24 04 89 Apr 8 18:20:30 homeserver kernel: EIP: [] mutex_lock+0xc/0x30 SS:ESP 0068:f6577c28 Apr 8 18:20:30 homeserver kernel: CR2: 0000000000000014 Apr 8 18:20:30 homeserver kernel: ---[ end trace df134132c967205c ]--- Signed-off-by: Kevin Baradon Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 624fd33d7086..3af7bb6c9f30 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -2324,7 +2324,14 @@ static int imon_probe(struct usb_interface *interface, } } else { - /* this is the secondary interface on the device */ + /* this is the secondary interface on the device */ + + /* fail early if first intf failed to register */ + if (!first_if_ctx) { + ret = -ENODEV; + goto fail; + } + ictx = imon_init_intf1(interface, first_if_ctx); if (!ictx) { pr_err("failed to attach to context!\n"); -- cgit v1.2.3 From 5f3f254f7c138a22a544b80ce2c14a3fc4ed711e Mon Sep 17 00:00:00 2001 From: Kevin Baradon Date: Mon, 22 Apr 2013 16:09:46 -0300 Subject: [media] media/rc/imon.c: kill urb when send_packet() is interrupted This avoids: Apr 12 23:52:16 homeserver kernel: imon:send_packet: task interrupted Apr 12 23:52:16 homeserver kernel: ------------[ cut here ]------------ Apr 12 23:52:16 homeserver kernel: WARNING: at drivers/usb/core/urb.c:327 usb_submit_urb+0x353/0x370() Apr 12 23:52:16 homeserver kernel: Hardware name: Unknow Apr 12 23:52:16 homeserver kernel: URB f64b6f00 submitted while active Apr 12 23:52:16 homeserver kernel: Modules linked in: Apr 12 23:52:16 homeserver kernel: Pid: 3154, comm: LCDd Not tainted 3.8.6-htpc-00005-g9e6fc5e #26 Apr 12 23:52:16 homeserver kernel: Call Trace: Apr 12 23:52:16 homeserver kernel: [] ? warn_slowpath_common+0x78/0xb0 Apr 12 23:52:16 homeserver kernel: [] ? usb_submit_urb+0x353/0x370 Apr 12 23:52:16 homeserver kernel: [] ? usb_submit_urb+0x353/0x370 Apr 12 23:52:16 homeserver kernel: [] ? imon_ir_change_protocol+0x150/0x150 Apr 12 23:52:16 homeserver kernel: [] ? warn_slowpath_fmt+0x33/0x40 Apr 12 23:52:16 homeserver kernel: [] ? usb_submit_urb+0x353/0x370 Apr 12 23:52:16 homeserver kernel: [] ? send_packet+0x97/0x270 Apr 12 23:52:16 homeserver kernel: [] ? send_packet+0x12e/0x270 Apr 12 23:52:16 homeserver kernel: [] ? do_nanosleep+0xa3/0xd0 Apr 12 23:52:16 homeserver kernel: [] ? vfd_write+0xae/0x250 Apr 12 23:52:16 homeserver kernel: [] ? lcd_write+0x180/0x180 Apr 12 23:52:16 homeserver kernel: [] ? vfs_write+0x89/0x140 Apr 12 23:52:16 homeserver kernel: [] ? sys_write+0x4a/0x90 Apr 12 23:52:16 homeserver kernel: [] ? sysenter_do_call+0x12/0x26 Apr 12 23:52:16 homeserver kernel: ---[ end trace a0b6f0fcfd2f9a1d ]--- Apr 12 23:52:16 homeserver kernel: imon:send_packet: error submitting urb(-16) Apr 12 23:52:16 homeserver kernel: imon:vfd_write: send packet #3 failed Apr 12 23:52:16 homeserver kernel: imon:send_packet: error submitting urb(-16) Apr 12 23:52:16 homeserver kernel: imon:vfd_write: send packet #0 failed Signed-off-by: Kevin Baradon Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 3af7bb6c9f30..72e3fa652481 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -528,8 +528,10 @@ static int send_packet(struct imon_context *ictx) mutex_unlock(&ictx->lock); retval = wait_for_completion_interruptible( &ictx->tx.finished); - if (retval) + if (retval) { + usb_kill_urb(ictx->tx_urb); pr_err_ratelimited("task interrupted\n"); + } mutex_lock(&ictx->lock); retval = ictx->tx.status; -- cgit v1.2.3 From 38c602b8ed4ddb73c9274df1af33a6f6f7db26e1 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 16 Apr 2013 03:02:19 -0300 Subject: [media] exynos4-is: Fix potential null pointer dereferencing If fimc->drv_data is NULL, then fimc->drv_data->num_entities would cause NULL pointer dereferencing. Hence remove it from print statement. Signed-off-by: Sachin Kamat Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index f25807d7bc8a..a8eaad0fc612 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -955,8 +955,8 @@ static int fimc_probe(struct platform_device *pdev) } if (!fimc->drv_data || fimc->id >= fimc->drv_data->num_entities || fimc->id < 0) { - dev_err(dev, "Invalid driver data or device id (%d/%d)\n", - fimc->id, fimc->drv_data->num_entities); + dev_err(dev, "Invalid driver data or device id (%d)\n", + fimc->id); return -EINVAL; } if (!dev->of_node) -- cgit v1.2.3 From 068b16b638070611272cf60da821cd70b2a267b3 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 16 Apr 2013 03:02:20 -0300 Subject: [media] exynos4-is: Convert index variable to signed index variable is used to check the validity of the data by testing for negative values. Hence make it signed. Signed-off-by: Sachin Kamat Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-core.h | 2 +- drivers/media/platform/exynos4-is/fimc-lite.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h index d2fe162485a3..953b074d542f 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.h +++ b/drivers/media/platform/exynos4-is/fimc-core.h @@ -425,7 +425,7 @@ struct fimc_dev { struct regmap *sysreg; const struct fimc_variant *variant; const struct fimc_drvdata *drv_data; - u16 id; + int id; struct clk *clock[MAX_FIMC_CLOCKS]; void __iomem *regs; wait_queue_head_t irq_queue; diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index 71fed5129e30..47da5e049247 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -140,7 +140,7 @@ struct fimc_lite { struct v4l2_subdev *sensor; struct v4l2_ctrl_handler ctrl_handler; struct v4l2_ctrl *test_pattern; - u32 index; + int index; struct fimc_pipeline pipeline; const struct fimc_pipeline_ops *pipeline_ops; -- cgit v1.2.3 From 0c2224ee0e480001eab6fd31e7d12b6d80745926 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 17 Apr 2013 15:03:34 -0300 Subject: [media] s5c73m3: Fix remove() callback to free requested resources Make sure v4l2_device_unregister_subdev() is called for both: oif and sensor subdev and both media entities are freed on driver removal. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/s5c73m3/s5c73m3-core.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index b353c50a6881..ce8fcf22253a 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -1668,13 +1668,17 @@ out_err1: static int s5c73m3_remove(struct i2c_client *client) { - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); + struct v4l2_subdev *oif_sd = i2c_get_clientdata(client); + struct s5c73m3 *state = oif_sd_to_s5c73m3(oif_sd); + struct v4l2_subdev *sensor_sd = &state->sensor_sd; - v4l2_device_unregister_subdev(sd); + v4l2_device_unregister_subdev(oif_sd); - v4l2_ctrl_handler_free(sd->ctrl_handler); - media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(oif_sd->ctrl_handler); + media_entity_cleanup(&oif_sd->entity); + + v4l2_device_unregister_subdev(sensor_sd); + media_entity_cleanup(&sensor_sd->entity); s5c73m3_unregister_spi_driver(state); s5c73m3_free_gpios(state); -- cgit v1.2.3 From a5ad1dbe226324f2d1ee51cf3337d0d855faa076 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 18 Apr 2013 14:34:05 -0300 Subject: [media] s5c73m3: Add missing subdev .unregistered callback This is needed to free any resources requested in the .registered subdev op. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/s5c73m3/s5c73m3-core.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index ce8fcf22253a..cb52438e53ac 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -1457,6 +1457,12 @@ static int s5c73m3_oif_registered(struct v4l2_subdev *sd) return ret; } +static void s5c73m3_oif_unregistered(struct v4l2_subdev *sd) +{ + struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); + v4l2_device_unregister_subdev(&state->sensor_sd); +} + static const struct v4l2_subdev_internal_ops s5c73m3_internal_ops = { .open = s5c73m3_open, }; @@ -1474,6 +1480,7 @@ static const struct v4l2_subdev_ops s5c73m3_subdev_ops = { static const struct v4l2_subdev_internal_ops oif_internal_ops = { .registered = s5c73m3_oif_registered, + .unregistered = s5c73m3_oif_unregistered, .open = s5c73m3_oif_open, }; -- cgit v1.2.3 From 861a51fd40757b7a0912a103e5014366621be6e7 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 16 Apr 2013 13:15:25 -0300 Subject: [media] exynos4-is: Remove redundant MODULE_DEVICE_TABLE entries Remove unneeded MODULE_DEVICE_TABLE(of,...) instances from files that are linked into same module. This fixes following error when building as a module: LD [M] drivers/media/platform/exynos4-is/s5p-fimc.o drivers/media/platform/exynos4-is/fimc-is-sensor.o: In function `.LANCHOR1': fimc-is-sensor.c:(.rodata+0x48): multiple definition of `__mod_of_device_table' drivers/media/platform/exynos4-is/fimc-is.o:fimc-is.c:(.rodata+0x174): first defined here drivers/media/platform/exynos4-is/fimc-is-i2c.o:(.rodata+0x5c): multiple definition of `__mod_of_device_table' drivers/media/platform/exynos4-is/fimc-is.o:fimc-is.c:(.rodata+0x174): first defined here make[4]: *** [drivers/media/platform/exynos4-is/exynos-fimc-is.o] Error 1 Also remove exporting fimc_is_(un)register_i2c_driver functions, it is not needed since these functions should be called only from our module. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is-i2c.c | 3 --- drivers/media/platform/exynos4-is/fimc-is-sensor.c | 1 - 2 files changed, 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/exynos4-is/fimc-is-i2c.c index 1ec6b3c6a62a..c397777d7cbb 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-i2c.c +++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.c @@ -103,7 +103,6 @@ static const struct of_device_id fimc_is_i2c_of_match[] = { { .compatible = FIMC_IS_I2C_COMPATIBLE }, { }, }; -MODULE_DEVICE_TABLE(of, fimc_is_i2c_of_match); static struct platform_driver fimc_is_i2c_driver = { .probe = fimc_is_i2c_probe, @@ -120,10 +119,8 @@ int fimc_is_register_i2c_driver(void) { return platform_driver_register(&fimc_is_i2c_driver); } -EXPORT_SYMBOL(fimc_is_register_i2c_driver); void fimc_is_unregister_i2c_driver(void) { platform_driver_unregister(&fimc_is_i2c_driver); } -EXPORT_SYMBOL(fimc_is_unregister_i2c_driver); diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.c b/drivers/media/platform/exynos4-is/fimc-is-sensor.c index 02b27190d2ae..6b3ea54269dd 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-sensor.c +++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.c @@ -294,7 +294,6 @@ static const struct of_device_id fimc_is_sensor_of_match[] = { }, { } }; -MODULE_DEVICE_TABLE(of, fimc_is_sensor_of_match); static struct i2c_driver fimc_is_sensor_driver = { .driver = { -- cgit v1.2.3 From 5a66561f426d4a10bce077ba90ab127e6a27ac3d Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 18 Apr 2013 08:49:54 -0300 Subject: [media] exynos4-is: Fix initialization of subdev 'flags' field Ensure the value of struct v4l2_subdev::flags field as set in v4l2_subdev_init() is preserved when initializing it in the subdev drivers. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-capture.c | 2 +- drivers/media/platform/exynos4-is/fimc-isp.c | 2 +- drivers/media/platform/exynos4-is/fimc-lite.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 72c516af40f6..558c528d9ce1 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -1869,7 +1869,7 @@ int fimc_initialize_capture_subdev(struct fimc_dev *fimc) int ret; v4l2_subdev_init(sd, &fimc_subdev_ops); - sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->id); fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK_CAM].flags = MEDIA_PAD_FL_SINK; diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index 3b9a6642a491..d63947f7b302 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.c +++ b/drivers/media/platform/exynos4-is/fimc-isp.c @@ -621,7 +621,7 @@ int fimc_isp_subdev_create(struct fimc_isp *isp) v4l2_subdev_init(sd, &fimc_is_subdev_ops); sd->grp_id = GRP_ID_FIMC_IS; - sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; snprintf(sd->name, sizeof(sd->name), "FIMC-IS-ISP"); isp->subdev_pads[FIMC_ISP_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 661d0d148cb5..7ecf4e7ff5fc 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -1377,7 +1377,7 @@ static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc) int ret; v4l2_subdev_init(sd, &fimc_lite_subdev_ops); - sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; snprintf(sd->name, sizeof(sd->name), "FIMC-LITE.%d", fimc->index); fimc->subdev_pads[FLITE_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; -- cgit v1.2.3 From b2afa23669ffb30173c010ccab1f6d1d4d0c82fb Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 18 Apr 2013 08:55:23 -0300 Subject: [media] exynos4-is: Fix regulator/gpio resource releasing on the driver removal Remove regulator_bulk_free() calls as devm_regulator_bulk_get() function is used to get the regulators so those will be freed automatically while the driver is removed. Missing gpio free is fixed by requesting a gpio with the devm_* API. All that is done now in the I2C client driver remove() callback is the media entity cleanup call. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is-sensor.c | 26 +++++++--------------- 1 file changed, 8 insertions(+), 18 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.c b/drivers/media/platform/exynos4-is/fimc-is-sensor.c index 6b3ea54269dd..035fa147de7f 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-sensor.c +++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.c @@ -216,7 +216,8 @@ static int fimc_is_sensor_probe(struct i2c_client *client, gpio = of_get_gpio_flags(dev->of_node, 0, NULL); if (gpio_is_valid(gpio)) { - ret = gpio_request_one(gpio, GPIOF_OUT_INIT_LOW, DRIVER_NAME); + ret = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_LOW, + DRIVER_NAME); if (ret < 0) return ret; } @@ -228,13 +229,11 @@ static int fimc_is_sensor_probe(struct i2c_client *client, ret = devm_regulator_bulk_get(&client->dev, SENSOR_NUM_SUPPLIES, sensor->supplies); if (ret < 0) - goto err_gpio; + return ret; of_id = of_match_node(fimc_is_sensor_of_match, dev->of_node); - if (!of_id) { - ret = -ENODEV; - goto err_reg; - } + if (!of_id) + return -ENODEV; sensor->drvdata = of_id->data; sensor->dev = dev; @@ -251,28 +250,19 @@ static int fimc_is_sensor_probe(struct i2c_client *client, sensor->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_init(&sd->entity, 1, &sensor->pad, 0); if (ret < 0) - goto err_reg; + return ret; v4l2_set_subdevdata(sd, sensor); pm_runtime_no_callbacks(dev); pm_runtime_enable(dev); - return 0; -err_reg: - regulator_bulk_free(SENSOR_NUM_SUPPLIES, sensor->supplies); -err_gpio: - if (gpio_is_valid(sensor->gpio_reset)) - gpio_free(sensor->gpio_reset); return ret; } static int fimc_is_sensor_remove(struct i2c_client *client) { - struct fimc_is_sensor *sensor; - - regulator_bulk_free(SENSOR_NUM_SUPPLIES, sensor->supplies); - media_entity_cleanup(&sensor->subdev.entity); - + struct v4l2_subdev *sd = i2c_get_clientdata(client); + media_entity_cleanup(&sd->entity); return 0; } -- cgit v1.2.3 From 1bc515ac6e60c6437422c98fb3be89b3b0802286 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 18 Apr 2013 09:00:45 -0300 Subject: [media] exynos4-is: Don't overwrite subdevdata in the fimc-is sensor driver It's an I2C client driver and it must not overwrite the struct v4l2_subdev dev_priv field, which is used by the v4l2 core to store a pointer to struct i2c_client. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is-sensor.c | 8 +------- drivers/media/platform/exynos4-is/fimc-is-sensor.h | 6 ++++++ drivers/media/platform/exynos4-is/fimc-is.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.c b/drivers/media/platform/exynos4-is/fimc-is-sensor.c index 035fa147de7f..6647421e5d3a 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-sensor.c +++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.c @@ -40,11 +40,6 @@ static const struct v4l2_mbus_framefmt fimc_is_sensor_formats[] = { } }; -static struct fimc_is_sensor *sd_to_fimc_is_sensor(struct v4l2_subdev *sd) -{ - return container_of(sd, struct fimc_is_sensor, subdev); -} - static const struct v4l2_mbus_framefmt *find_sensor_format( struct v4l2_mbus_framefmt *mf) { @@ -147,7 +142,7 @@ static const struct v4l2_subdev_internal_ops fimc_is_sensor_sd_internal_ops = { static int fimc_is_sensor_s_power(struct v4l2_subdev *sd, int on) { - struct fimc_is_sensor *sensor = v4l2_get_subdevdata(sd); + struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd); int gpio = sensor->gpio_reset; int ret; @@ -252,7 +247,6 @@ static int fimc_is_sensor_probe(struct i2c_client *client, if (ret < 0) return ret; - v4l2_set_subdevdata(sd, sensor); pm_runtime_no_callbacks(dev); pm_runtime_enable(dev); diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.h b/drivers/media/platform/exynos4-is/fimc-is-sensor.h index 50b8e4d59d62..6036d49a6c68 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-sensor.h +++ b/drivers/media/platform/exynos4-is/fimc-is-sensor.h @@ -77,6 +77,12 @@ struct fimc_is_sensor { struct v4l2_mbus_framefmt format; }; +static inline +struct fimc_is_sensor *sd_to_fimc_is_sensor(struct v4l2_subdev *sd) +{ + return container_of(sd, struct fimc_is_sensor, subdev); +} + int fimc_is_register_sensor_driver(void); void fimc_is_unregister_sensor_driver(void); diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 3c81c882bfd1..c4049d44e687 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -220,7 +220,7 @@ static int fimc_is_register_subdevs(struct fimc_is *is) if (WARN_ON(is->sensor)) continue; - is->sensor = v4l2_get_subdevdata(sd); + is->sensor = sd_to_fimc_is_sensor(sd); if (fimc_is_parse_sensor_config(is->sensor, child)) { dev_warn(&is->pdev->dev, "DT parse error: %s\n", -- cgit v1.2.3 From e41a35cb4be81a56664c52c94ddbdb740dca4f63 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 18 Apr 2013 09:05:54 -0300 Subject: [media] exynos4-is: Unregister fimc-is subdevs from the media device properly Add missing v4l2_device_unregister_subdev() call for the FIMC-IS subdevs (currently there is only the FIMC-IS-ISP subdev) so corresponding resources are properly freed upon the media device driver module removal. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyugmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/media-dev.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 1dbd55422706..a371ee5e857a 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -823,6 +823,10 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd) fimc_md_unregister_sensor(fmd->sensor[i].subdev); fmd->sensor[i].subdev = NULL; } + + if (fmd->fimc_is) + v4l2_device_unregister_subdev(&fmd->fimc_is->isp.subdev); + v4l2_info(&fmd->v4l2_dev, "Unregistered all entities\n"); } -- cgit v1.2.3 From a59ed48f0c35b47e3cf22fa90678d51e77118b56 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 18 Apr 2013 13:40:42 -0300 Subject: [media] exynos4-is: Set fimc-lite subdev owner module The FIMC-LITE.n subdevs have currently sd->owner field not set, the exynos-fimc-lite module can be removed at any time, regardless it is in use by other modules. When this module is unloaded the kernel can crash easily by accessing video or media device nodes. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-lite.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 7ecf4e7ff5fc..14bb7bc8adbe 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -1399,6 +1399,7 @@ static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc) sd->ctrl_handler = handler; sd->internal_ops = &fimc_lite_subdev_internal_ops; sd->entity.ops = &fimc_lite_subdev_media_ops; + sd->owner = THIS_MODULE; v4l2_set_subdevdata(sd, fimc); return 0; -- cgit v1.2.3 From 11551ca3b68bf7549ff87390fe6dbc805977563a Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 18 Apr 2013 13:49:23 -0300 Subject: [media] exynos4-is: Remove redundant module_put() for MIPI-CSIS module Currently there is unbalanced module_put() on the s5p-csis module which prevents it from being unloaded. The subdev's owner module has reference count decremented in v4l2_device_unregister_subdev() so just remove this erroneous call. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/media-dev.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index a371ee5e857a..15ef8f28239b 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -814,7 +814,6 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd) if (fmd->csis[i].sd == NULL) continue; v4l2_device_unregister_subdev(fmd->csis[i].sd); - module_put(fmd->csis[i].sd->owner); fmd->csis[i].sd = NULL; } for (i = 0; i < fmd->num_sensors; i++) { -- cgit v1.2.3 From 450f5f54758a26173c50950172c00eb192f8a22c Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 18 Apr 2013 14:10:02 -0300 Subject: [media] exynos4-is: Remove debugfs entries properly Ensure both debugfs: fimc_is directory and the fw_log file are properly removed in the driver cleanup sequence. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index c4049d44e687..ca72b02022ad 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -766,7 +766,7 @@ static const struct file_operations fimc_is_debugfs_fops = { static void fimc_is_debugfs_remove(struct fimc_is *is) { - debugfs_remove(is->debugfs_entry); + debugfs_remove_recursive(is->debugfs_entry); is->debugfs_entry = NULL; } -- cgit v1.2.3 From 0e30c7e1f1a162d0c2026cdc5ad4f0f0a7332fc6 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 18 Apr 2013 14:18:22 -0300 Subject: [media] exynos4-is: Change function call order in fimc_is_module_exit() Due to hardware dependencies (clocks/power domain) the I2C bus controller needs to be unregistered before fimc-is. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index ca72b02022ad..5e890776d164 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -995,9 +995,9 @@ err_sens: static void fimc_is_module_exit(void) { - platform_driver_unregister(&fimc_is_driver); - fimc_is_unregister_i2c_driver(); fimc_is_unregister_sensor_driver(); + fimc_is_unregister_i2c_driver(); + platform_driver_unregister(&fimc_is_driver); } module_init(fimc_is_module_init); -- cgit v1.2.3 From b34f51fad396484e2bc102dcf95807b9990c3265 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 18 Apr 2013 14:26:19 -0300 Subject: [media] exynos4-is: Fix runtime PM handling on fimc-is probe error path Ensure there is no unbalanced pm_runtime_put(). Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-is.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 5e890776d164..47c6363d04e2 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.c +++ b/drivers/media/platform/exynos4-is/fimc-is.c @@ -847,16 +847,17 @@ static int fimc_is_probe(struct platform_device *pdev) goto err_irq; ret = fimc_is_setup_clocks(is); + pm_runtime_put_sync(dev); + if (ret < 0) goto err_irq; - pm_runtime_put_sync(dev); is->clk_init = true; is->alloc_ctx = vb2_dma_contig_init_ctx(dev); if (IS_ERR(is->alloc_ctx)) { ret = PTR_ERR(is->alloc_ctx); - goto err_pm; + goto err_irq; } /* * Register FIMC-IS V4L2 subdevs to this driver. The video nodes @@ -885,8 +886,6 @@ err_sd: fimc_is_unregister_subdevs(is); err_irq: free_irq(is->irq, is); -err_pm: - pm_runtime_put(dev); err_clk: fimc_is_put_clocks(is); return ret; -- cgit v1.2.3 From d68b44e088caf0176cf80e7539750569d6e71ed8 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 17 Apr 2013 23:18:19 -0300 Subject: [media] s5p-mfc: fix error return code in s5p_mfc_probe() Fix to return a negative error code from the error handling case instead of 0, as returned elsewhere in this function. Signed-off-by: Wei Yongjun Acked-by: Kamil Debski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index e810b1abf40e..a5853fa59531 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1110,7 +1110,8 @@ static int s5p_mfc_probe(struct platform_device *pdev) } if (pdev->dev.of_node) { - if (s5p_mfc_alloc_memdevs(dev) < 0) + ret = s5p_mfc_alloc_memdevs(dev); + if (ret < 0) goto err_res; } else { dev->mem_dev_l = device_find_child(&dev->plat_dev->dev, -- cgit v1.2.3 From aceb59ed3438dcb2f5c90e2f62f0f9edde4091d2 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 23 Apr 2013 11:36:04 -0300 Subject: [media] exynos4-is: Fix driver name reported in vidioc_querycap Originally struct v4l2_capability driver and card name was filled with name of the platform device. After switching to the device tree the device names have changed and now are 4 different driver names reported, depending on the video device opened. So instead of e.g. "exynos4-fimc" there is now one of: 11800000.fimc, 11810000.fimc, 11820000.fimc, 11830000.fimc. Fix this by using dev->driver_name, rather than platform device name. A common vidioc_querycap function is created for both M2M and capture video node. This fixes any breakage at user space should any application/library rely on the driver's name. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-capture.c | 11 ++++------- drivers/media/platform/exynos4-is/fimc-core.c | 13 ++++++++++++- drivers/media/platform/exynos4-is/fimc-core.h | 4 +++- drivers/media/platform/exynos4-is/fimc-m2m.c | 12 +++++------- 4 files changed, 24 insertions(+), 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 558c528d9ce1..528f41369364 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -742,16 +742,13 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx, /* * The video node ioctl operations */ -static int fimc_vidioc_querycap_capture(struct file *file, void *priv, +static int fimc_cap_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct fimc_dev *fimc = video_drvdata(file); - strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1); - strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1); - cap->bus_info[0] = 0; - cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE; - + __fimc_vidioc_querycap(&fimc->pdev->dev, cap, V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE_MPLANE); return 0; } @@ -1375,7 +1372,7 @@ static int fimc_cap_s_selection(struct file *file, void *fh, } static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { - .vidioc_querycap = fimc_vidioc_querycap_capture, + .vidioc_querycap = fimc_cap_querycap, .vidioc_enum_fmt_vid_cap_mplane = fimc_cap_enum_fmt_mplane, .vidioc_try_fmt_vid_cap_mplane = fimc_cap_try_fmt_mplane, diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index a8eaad0fc612..379a5e9d52a7 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -213,6 +213,17 @@ struct fimc_fmt *fimc_get_format(unsigned int index) return &fimc_formats[index]; } +void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap, + unsigned int caps) +{ + strlcpy(cap->driver, dev->driver->name, sizeof(cap->driver)); + strlcpy(cap->card, dev->driver->name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", dev_name(dev)); + cap->device_caps = caps; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; +} + int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh, int dw, int dh, int rotation) { @@ -1283,7 +1294,7 @@ static struct platform_driver fimc_driver = { .id_table = fimc_driver_ids, .driver = { .of_match_table = fimc_of_match, - .name = FIMC_MODULE_NAME, + .name = FIMC_DRIVER_NAME, .owner = THIS_MODULE, .pm = &fimc_pm_ops, } diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h index 953b074d542f..539a3f71c16a 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.h +++ b/drivers/media/platform/exynos4-is/fimc-core.h @@ -35,7 +35,7 @@ /* Time to wait for next frame VSYNC interrupt while stopping operation. */ #define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000) #define MAX_FIMC_CLOCKS 2 -#define FIMC_MODULE_NAME "s5p-fimc" +#define FIMC_DRIVER_NAME "exynos4-fimc" #define FIMC_MAX_DEVS 4 #define FIMC_MAX_OUT_BUFS 4 #define SCALER_MAX_HRATIO 64 @@ -620,6 +620,8 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx, /* fimc-core.c */ int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, struct v4l2_fmtdesc *f); +void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap, + unsigned int caps); int fimc_ctrls_create(struct fimc_ctx *ctx); void fimc_ctrls_delete(struct fimc_ctx *ctx); void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active); diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 8449c0705e60..275a9f8d9fdb 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -249,22 +249,20 @@ static struct vb2_ops fimc_qops = { * V4L2 ioctl handlers */ static int fimc_m2m_querycap(struct file *file, void *fh, - struct v4l2_capability *cap) + struct v4l2_capability *cap) { - struct fimc_ctx *ctx = fh_to_ctx(fh); - struct fimc_dev *fimc = ctx->fimc_dev; + struct fimc_dev *fimc = video_drvdata(file); + unsigned int caps; - strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1); - strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1); - cap->bus_info[0] = 0; /* * This is only a mem-to-mem video device. The capture and output * device capability flags are left only for backward compatibility * and are scheduled for removal. */ - cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE | + caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE; + __fimc_vidioc_querycap(&fimc->pdev->dev, cap, caps); return 0; } -- cgit v1.2.3 From cbd53542ca35842127c6f581fefbb0a7dd2b4a21 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 23 Apr 2013 12:40:24 -0300 Subject: [media] exynos4-is: Fix TRY format propagation at MIPI-CSIS subdev Ensure TRY format is propagated from the sink to source pad. The format at both pads is always same so the TRY format buffer for pad 0 is used to hold format for both pads. While at it remove redundant fmt->pad checking. Reported-by: Jacek Anaszewski Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/mipi-csis.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 8636bcddde1b..a2eda9d5ac87 100644 --- a/drivers/media/platform/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/exynos4-is/mipi-csis.c @@ -549,10 +549,10 @@ static struct csis_pix_format const *s5pcsis_try_format( static struct v4l2_mbus_framefmt *__s5pcsis_get_format( struct csis_state *state, struct v4l2_subdev_fh *fh, - u32 pad, enum v4l2_subdev_format_whence which) + enum v4l2_subdev_format_whence which) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL; + return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL; return &state->format; } @@ -564,10 +564,7 @@ static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct csis_pix_format const *csis_fmt; struct v4l2_mbus_framefmt *mf; - if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK) - return -EINVAL; - - mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which); + mf = __s5pcsis_get_format(state, fh, fmt->which); if (fmt->pad == CSIS_PAD_SOURCE) { if (mf) { @@ -594,10 +591,7 @@ static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct csis_state *state = sd_to_csis_state(sd); struct v4l2_mbus_framefmt *mf; - if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK) - return -EINVAL; - - mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which); + mf = __s5pcsis_get_format(state, fh, fmt->which); if (!mf) return -EINVAL; -- cgit v1.2.3 From f0c24fd81f704730c529dc69aa57f21c1ade5c4e Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 24 Apr 2013 13:07:49 -0300 Subject: [media] exynos4-is: Copy timestamps from M2M OUTPUT to CAPTURE buffer queue Add copying of buffer timestamps and set the timestamp_type to V4L2_BUF_FLAG_TIMESTAMP_COPY to avoid warnings about UNDEFINED timestamp type like: WARNING: at drivers/media/v4l2-core/videobuf2-core.c:2042 vb2_queue_init+0xe0/0x18c() Modules linked in: [] (unwind_backtrace+0x0/0x13c) from [] (warn_slowpath_common+0x54/0x64) [] (warn_slowpath_common+0x54/0x64) from [] (warn_slowpath_null+0x1c/0x24) [] (warn_slowpath_null+0x1c/0x24) from [] (vb2_queue_init+0xe0/0x18c) [] (vb2_queue_init+0xe0/0x18c) from [] (v4l2_m2m_ctx_init+0xa0/0xc4) [] (v4l2_m2m_ctx_init+0xa0/0xc4) from [] (fimc_m2m_open+0x130/0x1f8) [] (fimc_m2m_open+0x130/0x1f8) from [] (v4l2_open+0xac/0xe8) [] (v4l2_open+0xac/0xe8) from [] (chrdev_open+0x9c/0x158) [] (chrdev_open+0x9c/0x158) from [] (do_dentry_open+0x1f8/0x280) [] (do_dentry_open+0x1f8/0x280) from [] (finish_open+0x34/0x50) [] (finish_open+0x34/0x50) from [] (do_last+0x5bc/0xc00) [] (do_last+0x5bc/0xc00) from [] (path_openat+0xb0/0x484) [] (path_openat+0xb0/0x484) from [] (do_filp_open+0x30/0x84) [] (do_filp_open+0x30/0x84) from [] (do_sys_open+0xe8/0x170) [] (do_sys_open+0xe8/0x170) from [] (ret_fast_syscall+0x0/0x30) Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-m2m.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 275a9f8d9fdb..bde1f47f7ed3 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -99,7 +99,7 @@ static int stop_streaming(struct vb2_queue *q) static void fimc_device_run(void *priv) { - struct vb2_buffer *vb = NULL; + struct vb2_buffer *src_vb, *dst_vb; struct fimc_ctx *ctx = priv; struct fimc_frame *sf, *df; struct fimc_dev *fimc; @@ -122,16 +122,18 @@ static void fimc_device_run(void *priv) fimc_prepare_dma_offset(ctx, df); } - vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); - ret = fimc_prepare_addr(ctx, vb, sf, &sf->paddr); + src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + ret = fimc_prepare_addr(ctx, src_vb, sf, &sf->paddr); if (ret) goto dma_unlock; - vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - ret = fimc_prepare_addr(ctx, vb, df, &df->paddr); + dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + ret = fimc_prepare_addr(ctx, dst_vb, df, &df->paddr); if (ret) goto dma_unlock; + dst_vb->v4l2_buf.timestamp = src_vb->v4l2_buf.timestamp; + /* Reconfigure hardware if the context has changed. */ if (fimc->m2m.ctx != ctx) { ctx->state |= FIMC_PARAMS; @@ -620,6 +622,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->ops = &fimc_qops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(src_vq); if (ret) @@ -631,6 +634,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->ops = &fimc_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; return vb2_queue_init(dst_vq); } -- cgit v1.2.3 From dc7be2950b25c95cd240b8fe44edb59f8d7e3ae6 Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Wed, 24 Apr 2013 09:34:03 -0300 Subject: [media] s5p-g2d: Add copy time stamp handling Since the introduction of the timestamp_type field, it is necessary that the driver chooses which type it will use. This patch adds support for the timestamp_type. Signed-off-by: Kamil Debski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-g2d/g2d.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 14d663dacdbd..553d87e5ceab 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -158,6 +158,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->ops = &g2d_qops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(src_vq); if (ret) @@ -169,6 +170,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->ops = &g2d_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; return vb2_queue_init(dst_vq); } @@ -635,6 +637,9 @@ static irqreturn_t g2d_isr(int irq, void *prv) BUG_ON(src == NULL); BUG_ON(dst == NULL); + dst->v4l2_buf.timecode = src->v4l2_buf.timecode; + dst->v4l2_buf.timestamp = src->v4l2_buf.timestamp; + v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE); v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx); -- cgit v1.2.3 From aca326aeab43219ba8120a0a2976baa359b9a38d Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Wed, 24 Apr 2013 10:08:02 -0300 Subject: [media] s5p-jpeg: Add copy time stamp handling Since the introduction of the timestamp_type field, it is necessary that the driver chooses which type it will use. This patch adds support for the timestamp_type. Signed-off-by: Kamil Debski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-jpeg/jpeg-core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 3b023752bcb4..15d23968d1de 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c @@ -1229,6 +1229,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &s5p_jpeg_qops; src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(src_vq); if (ret) @@ -1240,6 +1241,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &s5p_jpeg_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; return vb2_queue_init(dst_vq); } @@ -1287,6 +1289,9 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id) payload_size = jpeg_compressed_size(jpeg->regs); } + dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode; + dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp; + v4l2_m2m_buf_done(src_buf, state); if (curr_ctx->mode == S5P_JPEG_ENCODE) vb2_set_plane_payload(dst_buf, 0, payload_size); -- cgit v1.2.3 From 56006017316cea85cedd22a5f2f7aa31e77a40df Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Wed, 24 Apr 2013 10:31:05 -0300 Subject: [media] s5p-mfc: Optimize copy time stamp handling For the sake of simplicity and readability memcpy was replaced with assignment. Signed-off-by: Kamil Debski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index a5853fa59531..01f9ae0dadb0 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -243,12 +243,10 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx) src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); list_for_each_entry(dst_buf, &ctx->dst_queue, list) { if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dec_y_addr) { - memcpy(&dst_buf->b->v4l2_buf.timecode, - &src_buf->b->v4l2_buf.timecode, - sizeof(struct v4l2_timecode)); - memcpy(&dst_buf->b->v4l2_buf.timestamp, - &src_buf->b->v4l2_buf.timestamp, - sizeof(struct timeval)); + dst_buf->b->v4l2_buf.timecode = + src_buf->b->v4l2_buf.timecode; + dst_buf->b->v4l2_buf.timestamp = + src_buf->b->v4l2_buf.timestamp; switch (frame_type) { case S5P_FIMV_DECODE_FRAME_I_FRAME: dst_buf->b->v4l2_buf.flags |= -- cgit v1.2.3 From ccd571cb67ddb54febada71e8788c6ca9d0e432f Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Wed, 24 Apr 2013 10:38:24 -0300 Subject: [media] coda: Add copy time stamp handling Since the introduction of the timestamp_type field, it is necessary that the driver chooses which type it will use. This patch adds support for the timestamp_type. Signed-off-by: Kamil Debski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 20827ba168fc..5612329f9ef7 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -1422,6 +1422,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &coda_qops; src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(src_vq); if (ret) @@ -1433,6 +1434,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &coda_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; return vb2_queue_init(dst_vq); } @@ -1628,6 +1630,9 @@ static irqreturn_t coda_irq_handler(int irq, void *data) dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME; } + dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp; + dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode; + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); -- cgit v1.2.3 From 9c303ec6dbb76390aadbcc2afed10458860d42ae Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Wed, 24 Apr 2013 10:50:55 -0300 Subject: [media] exynos-gsc: Add copy time stamp handling Since the introduction of the timestamp_type field, it is necessary that the driver chooses which type it will use. This patch adds support for the timestamp_type. Signed-off-by: Kamil Debski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-m2m.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index 386c0a7a3a52..40a73f7d20da 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -80,6 +80,9 @@ void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state) dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); if (src_vb && dst_vb) { + src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp; + src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode; + v4l2_m2m_buf_done(src_vb, vb_state); v4l2_m2m_buf_done(dst_vb, vb_state); @@ -584,6 +587,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->ops = &gsc_m2m_qops; src_vq->mem_ops = &vb2_dma_contig_memops; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(src_vq); if (ret) @@ -596,6 +600,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->ops = &gsc_m2m_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; return vb2_queue_init(dst_vq); } -- cgit v1.2.3 From 7f1e8f197e2fdc97ef51e6aa31ba3d207e6ef076 Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Wed, 24 Apr 2013 10:58:47 -0300 Subject: [media] m2m-deinterlace: Add copy time stamp handling Since the introduction of the timestamp_type field, it is necessary that the driver chooses which type it will use. This patch adds support for the timestamp_type. Signed-off-by: Kamil Debski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/m2m-deinterlace.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 6c4db9b98989..758564649589 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -207,6 +207,9 @@ static void dma_callback(void *data) src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); + src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp; + src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode; + v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); @@ -866,6 +869,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &deinterlace_qops; src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; q_data[V4L2_M2M_SRC].fmt = &formats[0]; q_data[V4L2_M2M_SRC].width = 640; q_data[V4L2_M2M_SRC].height = 480; @@ -882,6 +886,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &deinterlace_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; q_data[V4L2_M2M_DST].fmt = &formats[0]; q_data[V4L2_M2M_DST].width = 640; q_data[V4L2_M2M_DST].height = 480; -- cgit v1.2.3 From a8c9c345702b3f52a88498dea6b623dd3c3e27dc Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Thu, 25 Apr 2013 07:21:24 -0300 Subject: [media] mx2-emmaprp: Add copy time stamp handling Since the introduction of the timestamp_type field, it is necessary that the driver chooses which type it will use. This patch adds support for the timestamp_type. Signed-off-by: Kamil Debski Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mx2_emmaprp.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index 4b9e0a28616a..f7440e585b6b 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -377,6 +377,9 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data) src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); + src_vb->v4l2_buf.timestamp = dst_vb->v4l2_buf.timestamp; + src_vb->v4l2_buf.timecode = dst_vb->v4l2_buf.timecode; + spin_lock_irqsave(&pcdev->irqlock, flags); v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); @@ -763,6 +766,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &emmaprp_qops; src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(src_vq); if (ret) @@ -774,6 +778,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &emmaprp_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; return vb2_queue_init(dst_vq); } -- cgit v1.2.3 From d95d7c641299c1c77809d13565952d864da2d14d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 17 Apr 2013 03:04:10 -0300 Subject: [media] mem2mem_testdev: set timestamp_type and add debug param While testing v4l2-ctl I noticed that this m2m driver didn't set timestamp_type and that it spammed the kernel log with debug messages. Set timestamp_type correctly and add debug module option to enable debug messages. Signed-off-by: Hans Verkuil Signed-off-by: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mem2mem_testdev.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index 7487d7208dea..4cc7f65d7d76 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -38,6 +38,10 @@ MODULE_AUTHOR("Pawel Osciak, "); MODULE_LICENSE("GPL"); MODULE_VERSION("0.1.1"); +static unsigned debug; +module_param(debug, uint, 0644); +MODULE_PARM_DESC(debug, "activates debug info"); + #define MIN_W 32 #define MIN_H 32 #define MAX_W 640 @@ -67,7 +71,7 @@ MODULE_VERSION("0.1.1"); #define MEM2MEM_VFLIP (1 << 1) #define dprintk(dev, fmt, arg...) \ - v4l2_dbg(1, 1, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) + v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) static void m2mtest_dev_release(struct device *dev) @@ -234,6 +238,10 @@ static int device_process(struct m2mtest_ctx *ctx, bytes_left = bytesperline - tile_w * MEM2MEM_NUM_TILES; w = 0; + memcpy(&out_vb->v4l2_buf.timestamp, + &in_vb->v4l2_buf.timestamp, + sizeof(struct timeval)); + switch (ctx->mode) { case MEM2MEM_HFLIP | MEM2MEM_VFLIP: p_out += bytesperline * height - bytes_left; @@ -844,6 +852,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &m2mtest_qops; src_vq->mem_ops = &vb2_vmalloc_memops; + src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(src_vq); if (ret) @@ -855,6 +864,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &m2mtest_qops; dst_vq->mem_ops = &vb2_vmalloc_memops; + dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY; return vb2_queue_init(dst_vq); } -- cgit v1.2.3 From cb132cd5d75f6cd3295c2c041177eeb89f778db8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 17 Apr 2013 08:22:15 -0300 Subject: [media] videobuf-dma-contig: remove support for cached mem videobuf_queue_dma_contig_init_cached() is not used anywhere. Drop support for it, cleaning up the code a little bit. Signed-off-by: Mauro Carvalho Chehab Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf-dma-contig.c | 130 +++----------------------- include/media/videobuf-dma-contig.h | 10 -- 2 files changed, 14 insertions(+), 126 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c index 3a43ba0959bf..67f572c3fba2 100644 --- a/drivers/media/v4l2-core/videobuf-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf-dma-contig.c @@ -27,7 +27,6 @@ struct videobuf_dma_contig_memory { u32 magic; void *vaddr; dma_addr_t dma_handle; - bool cached; unsigned long size; }; @@ -43,26 +42,8 @@ static int __videobuf_dc_alloc(struct device *dev, unsigned long size, gfp_t flags) { mem->size = size; - if (mem->cached) { - mem->vaddr = alloc_pages_exact(mem->size, flags | GFP_DMA); - if (mem->vaddr) { - int err; - - mem->dma_handle = dma_map_single(dev, mem->vaddr, - mem->size, - DMA_FROM_DEVICE); - err = dma_mapping_error(dev, mem->dma_handle); - if (err) { - dev_err(dev, "dma_map_single failed\n"); - - free_pages_exact(mem->vaddr, mem->size); - mem->vaddr = NULL; - return err; - } - } - } else - mem->vaddr = dma_alloc_coherent(dev, mem->size, - &mem->dma_handle, flags); + mem->vaddr = dma_alloc_coherent(dev, mem->size, + &mem->dma_handle, flags); if (!mem->vaddr) { dev_err(dev, "memory alloc size %ld failed\n", mem->size); @@ -77,14 +58,7 @@ static int __videobuf_dc_alloc(struct device *dev, static void __videobuf_dc_free(struct device *dev, struct videobuf_dma_contig_memory *mem) { - if (mem->cached) { - if (!mem->vaddr) - return; - dma_unmap_single(dev, mem->dma_handle, mem->size, - DMA_FROM_DEVICE); - free_pages_exact(mem->vaddr, mem->size); - } else - dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle); + dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle); mem->vaddr = NULL; } @@ -234,7 +208,7 @@ out_up: return ret; } -static struct videobuf_buffer *__videobuf_alloc_vb(size_t size, bool cached) +static struct videobuf_buffer *__videobuf_alloc(size_t size) { struct videobuf_dma_contig_memory *mem; struct videobuf_buffer *vb; @@ -244,22 +218,11 @@ static struct videobuf_buffer *__videobuf_alloc_vb(size_t size, bool cached) vb->priv = ((char *)vb) + size; mem = vb->priv; mem->magic = MAGIC_DC_MEM; - mem->cached = cached; } return vb; } -static struct videobuf_buffer *__videobuf_alloc_uncached(size_t size) -{ - return __videobuf_alloc_vb(size, false); -} - -static struct videobuf_buffer *__videobuf_alloc_cached(size_t size) -{ - return __videobuf_alloc_vb(size, true); -} - static void *__videobuf_to_vaddr(struct videobuf_buffer *buf) { struct videobuf_dma_contig_memory *mem = buf->priv; @@ -310,19 +273,6 @@ static int __videobuf_iolock(struct videobuf_queue *q, return 0; } -static int __videobuf_sync(struct videobuf_queue *q, - struct videobuf_buffer *buf) -{ - struct videobuf_dma_contig_memory *mem = buf->priv; - BUG_ON(!mem); - MAGIC_CHECK(mem->magic, MAGIC_DC_MEM); - - dma_sync_single_for_cpu(q->dev, mem->dma_handle, mem->size, - DMA_FROM_DEVICE); - - return 0; -} - static int __videobuf_mmap_mapper(struct videobuf_queue *q, struct videobuf_buffer *buf, struct vm_area_struct *vma) @@ -331,8 +281,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, struct videobuf_mapping *map; int retval; unsigned long size; - unsigned long pos, start = vma->vm_start; - struct page *page; dev_dbg(q->dev, "%s\n", __func__); @@ -359,43 +307,16 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, size = vma->vm_end - vma->vm_start; size = (size < mem->size) ? size : mem->size; - if (!mem->cached) { - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - retval = remap_pfn_range(vma, vma->vm_start, - mem->dma_handle >> PAGE_SHIFT, + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + retval = remap_pfn_range(vma, vma->vm_start, + mem->dma_handle >> PAGE_SHIFT, size, vma->vm_page_prot); - if (retval) { - dev_err(q->dev, "mmap: remap failed with error %d. ", - retval); - dma_free_coherent(q->dev, mem->size, - mem->vaddr, mem->dma_handle); - goto error; - } - } else { - pos = (unsigned long)mem->vaddr; - - while (size > 0) { - page = virt_to_page((void *)pos); - if (NULL == page) { - dev_err(q->dev, "mmap: virt_to_page failed\n"); - __videobuf_dc_free(q->dev, mem); - goto error; - } - retval = vm_insert_page(vma, start, page); - if (retval) { - dev_err(q->dev, "mmap: insert failed with error %d\n", - retval); - __videobuf_dc_free(q->dev, mem); - goto error; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } + if (retval) { + dev_err(q->dev, "mmap: remap failed with error %d. ", + retval); + dma_free_coherent(q->dev, mem->size, + mem->vaddr, mem->dma_handle); + goto error; } vma->vm_ops = &videobuf_vm_ops; @@ -417,17 +338,8 @@ error: static struct videobuf_qtype_ops qops = { .magic = MAGIC_QTYPE_OPS, - .alloc_vb = __videobuf_alloc_uncached, - .iolock = __videobuf_iolock, - .mmap_mapper = __videobuf_mmap_mapper, - .vaddr = __videobuf_to_vaddr, -}; - -static struct videobuf_qtype_ops qops_cached = { - .magic = MAGIC_QTYPE_OPS, - .alloc_vb = __videobuf_alloc_cached, + .alloc_vb = __videobuf_alloc, .iolock = __videobuf_iolock, - .sync = __videobuf_sync, .mmap_mapper = __videobuf_mmap_mapper, .vaddr = __videobuf_to_vaddr, }; @@ -447,20 +359,6 @@ void videobuf_queue_dma_contig_init(struct videobuf_queue *q, } EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init); -void videobuf_queue_dma_contig_init_cached(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, struct mutex *ext_lock) -{ - videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, - priv, &qops_cached, ext_lock); -} -EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init_cached); - dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf) { struct videobuf_dma_contig_memory *mem = buf->priv; diff --git a/include/media/videobuf-dma-contig.h b/include/media/videobuf-dma-contig.h index f473aeb86d3f..f0ed82543d9f 100644 --- a/include/media/videobuf-dma-contig.h +++ b/include/media/videobuf-dma-contig.h @@ -26,16 +26,6 @@ void videobuf_queue_dma_contig_init(struct videobuf_queue *q, void *priv, struct mutex *ext_lock); -void videobuf_queue_dma_contig_init_cached(struct videobuf_queue *q, - const struct videobuf_queue_ops *ops, - struct device *dev, - spinlock_t *irqlock, - enum v4l2_buf_type type, - enum v4l2_field field, - unsigned int msize, - void *priv, - struct mutex *ext_lock); - dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf); void videobuf_dma_contig_free(struct videobuf_queue *q, struct videobuf_buffer *buf); -- cgit v1.2.3 From b3404a8ef567de43b74018bbdbd989b53426d422 Mon Sep 17 00:00:00 2001 From: Frank Schaefer Date: Mon, 8 Apr 2013 13:06:59 -0300 Subject: [media] em28xx: save isoc endpoint number for DVB only if endpoint has alt settings with xMaxPacketSize != 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Patchwork-Delegate: mchehab@redhat.com In addition to commit 72cc9ba3 "em28xx: ignore isoc DVB USB endpoints with wMaxPacketSize = 0 bytes for all alt settings" we should not save the endpoint number of the isoc DVB endpoint before it has been validated. While the current code works fine, dev->dvb_ep_isoc != 0 could be interpreted as indicator that the device provides DVB support. Signed-off-by: Frank Schäfer Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index d2ed67825993..83bfbe4c980f 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3220,9 +3220,9 @@ static int em28xx_usb_probe(struct usb_interface *interface, e->bEndpointAddress; } else { if (usb_endpoint_xfer_isoc(e)) { - dev->dvb_ep_isoc = e->bEndpointAddress; if (size > dev->dvb_max_pkt_size_isoc) { has_dvb = true; /* see NOTE (~) */ + dev->dvb_ep_isoc = e->bEndpointAddress; dev->dvb_max_pkt_size_isoc = size; dev->dvb_alt_isoc = i; } -- cgit v1.2.3 From 7f8414594e4755234fd0ca415630cfe2dfab42ce Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 19 Apr 2013 07:18:01 -0300 Subject: [media] media: videobuf2: fix the length check for mmap Memory maps typically require that the buffer size to be page aligned. Currently, two memops drivers do such alignment internally, but videobuf-vmalloc doesn't. Also, the buffer overflow check doesn't take it into account. So, instead of doing it at each memops driver, enforce it at VB2 core. Reported-by: Prabhakar lad Acked-by: Laurent Pinchart Acked-by: Marek Szyprowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 21 +++++++++++++++++---- drivers/media/v4l2-core/videobuf2-dma-contig.c | 3 --- drivers/media/v4l2-core/videobuf2-dma-sg.c | 3 ++- 3 files changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 58c17444d22f..7d833eefaf4e 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -54,10 +54,15 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) void *mem_priv; int plane; - /* Allocate memory for all planes in this buffer */ + /* + * Allocate memory for all planes in this buffer + * NOTE: mmapped areas should be page aligned + */ for (plane = 0; plane < vb->num_planes; ++plane) { + unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]); + mem_priv = call_memop(q, alloc, q->alloc_ctx[plane], - q->plane_sizes[plane], q->gfp_flags); + size, q->gfp_flags); if (IS_ERR_OR_NULL(mem_priv)) goto free; @@ -1852,6 +1857,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) struct vb2_buffer *vb; unsigned int buffer, plane; int ret; + unsigned long length; if (q->memory != V4L2_MEMORY_MMAP) { dprintk(1, "Queue is not currently set up for mmap\n"); @@ -1886,8 +1892,15 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma) vb = q->bufs[buffer]; - if (vb->v4l2_planes[plane].length < (vma->vm_end - vma->vm_start)) { - dprintk(1, "Invalid length\n"); + /* + * MMAP requires page_aligned buffers. + * The buffer length was page_aligned at __vb2_buf_mem_alloc(), + * so, we need to do the same here. + */ + length = PAGE_ALIGN(vb->v4l2_planes[plane].length); + if (length < (vma->vm_end - vma->vm_start)) { + dprintk(1, + "MMAP invalid, as it would overflow buffer length\n"); return -EINVAL; } diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index ae35d255a430..fd56f2563201 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -162,9 +162,6 @@ static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags) if (!buf) return ERR_PTR(-ENOMEM); - /* align image size to PAGE_SIZE */ - size = PAGE_ALIGN(size); - buf->vaddr = dma_alloc_coherent(dev, size, &buf->dma_addr, GFP_KERNEL | gfp_flags); if (!buf->vaddr) { diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index 59522b2ebae1..16ae3dcc7e29 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c @@ -55,7 +55,8 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_fla buf->write = 0; buf->offset = 0; buf->sg_desc.size = size; - buf->sg_desc.num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + /* size is already page aligned */ + buf->sg_desc.num_pages = size >> PAGE_SHIFT; buf->sg_desc.sglist = vzalloc(buf->sg_desc.num_pages * sizeof(*buf->sg_desc.sglist)); -- cgit v1.2.3 From ecb52ab8213173e81717ac6fb3ba956f048aeda9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 24 Apr 2013 07:36:45 -0300 Subject: [media] anysee: Initialize ret = 0 in anysee_frontend_attach() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/media/usb/dvb-usb-v2/anysee.c: In function ‘anysee_frontend_attach’: drivers/media/usb/dvb-usb-v2/anysee.c:641: warning: ‘ret’ may be used uninitialized in this function And gcc is right (see the ANYSEE_HW_507T case), so initialize ret to zero to fix this. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/anysee.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index 2e762742a4c7..d6daad10287c 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -635,7 +635,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) { struct anysee_state *state = adap_to_priv(adap); struct dvb_usb_device *d = adap_to_d(adap); - int ret; + int ret = 0; u8 tmp; struct i2c_msg msg[2] = { { -- cgit v1.2.3 From 542b329f8e0d92ca93d033d13a9db16b89830acd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 24 Apr 2013 07:36:46 -0300 Subject: [media] anysee: Grammar s/report the/report to/ [mchehab@redhat.com: Fix a merge conflict] Signed-off-by: Geert Uytterhoeven Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/anysee.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index d6daad10287c..90cfa35ef6e6 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -882,7 +882,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap) /* we have no frontend :-( */ ret = -ENODEV; dev_err(&d->udev->dev, - "%s: Unsupported Anysee version. Please report the .\n", + "%s: Unsupported Anysee version. Please report to .\n", KBUILD_MODNAME); } error: -- cgit v1.2.3 From f7a12fdfd6b6a6f37827d213e67930b945d3081d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 18 Apr 2013 15:20:40 -0300 Subject: [media] r820t: precendence bug in r820t_xtal_check() The test as written is always false. It looks like the intent was to test that the bit was not set. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/r820t.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 905a10615e52..ba033fd6b717 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -1378,7 +1378,7 @@ static int r820t_xtal_check(struct r820t_priv *priv) rc = r820t_read(priv, 0x00, data, sizeof(data)); if (rc < 0) return rc; - if ((!data[2]) & 0x40) + if (!(data[2] & 0x40)) continue; val = data[2] & 0x3f; -- cgit v1.2.3 From ef0c87001c50ade70183b5cccbf573ef28320965 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 18 Apr 2013 15:21:17 -0300 Subject: [media] r820t: memory leak in release() I've moved the kfree(fe->tuner_priv) one line earlier, otherwise it is a no-op. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/r820t.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index ba033fd6b717..36ddbf1e08b3 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -2252,9 +2252,8 @@ static int r820t_release(struct dvb_frontend *fe) mutex_unlock(&r820t_list_mutex); - fe->tuner_priv = NULL; - kfree(fe->tuner_priv); + fe->tuner_priv = NULL; return 0; } -- cgit v1.2.3 From 619ab8f611e269e12c956361a38a4206cef9155d Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Sat, 20 Apr 2013 06:02:16 -0300 Subject: [media] r820t: quiet gcc warning on n_ring drivers/media/tuners/r820t.c: In function 'r820t_imr': drivers/media/tuners/r820t.c:1871:8: warning: 'n_ring' may be used uninitialized in this function [-Wmaybe-uninitialized] Mauro: This is a FALSE POSITIVE: the loop will always return a value for n_ring, as the last test will fill it with 15, if the loop fails. Signed-off-by: Fengguang Wu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/r820t.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 36ddbf1e08b3..e6e7a06d2b40 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -1854,15 +1854,12 @@ static int r820t_imr(struct r820t_priv *priv, unsigned imr_mem, bool im_flag) else ring_ref = priv->cfg->xtal; + n_ring = 15; for (n = 0; n < 16; n++) { if ((16 + n) * 8 * ring_ref >= 3100000) { n_ring = n; break; } - - /* n_ring not found */ - if (n == 15) - n_ring = n; } reg18 = r820t_read_cache_reg(priv, 0x18); -- cgit v1.2.3 From 6f7ee06f4ec40d2bfc91ec67ee6e40e5fd2f2e59 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 25 Apr 2013 10:36:56 -0300 Subject: [media] dib8000: warning fix: declare internal functions as static drivers/media/dvb-frontends/dib8000.c:2412:5: warning: no previous prototype for 'dib8000_wait_lock' [-Wmissing-prototypes] drivers/media/dvb-frontends/dib8000.c:2688:5: warning: no previous prototype for 'dib8000_get_symbol_duration' [-Wmissing-prototypes] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib8000.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 1d719cce8995..d065a72e0bb7 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -2409,7 +2409,8 @@ static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq state->isdbt_cfg_loaded = 0; } -u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal, u32 wait0_ms, u32 wait1_ms, u32 wait2_ms) +static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal, + u32 wait0_ms, u32 wait1_ms, u32 wait2_ms) { u32 value; u16 reg = 11; /* P_search_end0 start addr */ @@ -2685,7 +2686,8 @@ static void dib8000_set_frequency_offset(struct dib8000_state *state) } static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 }; -u32 dib8000_get_symbol_duration(struct dib8000_state *state) + +static u32 dib8000_get_symbol_duration(struct dib8000_state *state) { u16 i; -- cgit v1.2.3 From c82056d0b4ac7b805ac4e7d3870c42bb19e3b3d5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 25 Apr 2013 10:51:15 -0300 Subject: [media] dib8000: store dtv_property_cache in a temp var dtv_property_cache is used on several places on very long lines. On all places it is used, a long list of struct reference is done. Instead of doing it, at the routines where it is used more than once, replace it by one temporary var. That may help the compiler to use a better code. It also makes easier to review the code, as the lines becomes closer to 80 columns, making them a way clearer to read. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib8000.c | 255 ++++++++++++++++++---------------- 1 file changed, 133 insertions(+), 122 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index d065a72e0bb7..77dac46bfcbf 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -1941,8 +1941,9 @@ static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 }; static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation) { u8 cr, constellation, time_intlv; + struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; - switch (state->fe[0]->dtv_property_cache.layer[layer_index].modulation) { + switch (c->layer[layer_index].modulation) { case DQPSK: constellation = 0; break; @@ -1958,7 +1959,7 @@ static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 ma break; } - switch (state->fe[0]->dtv_property_cache.layer[layer_index].fec) { + switch (c->layer[layer_index].fec) { case FEC_1_2: cr = 1; break; @@ -1977,22 +1978,22 @@ static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 ma break; } - if ((state->fe[0]->dtv_property_cache.layer[layer_index].interleaving > 0) && ((state->fe[0]->dtv_property_cache.layer[layer_index].interleaving <= 3) || (state->fe[0]->dtv_property_cache.layer[layer_index].interleaving == 4 && state->fe[0]->dtv_property_cache.isdbt_sb_mode == 1))) - time_intlv = state->fe[0]->dtv_property_cache.layer[layer_index].interleaving; + if ((c->layer[layer_index].interleaving > 0) && ((c->layer[layer_index].interleaving <= 3) || (c->layer[layer_index].interleaving == 4 && c->isdbt_sb_mode == 1))) + time_intlv = c->layer[layer_index].interleaving; else time_intlv = 0; - dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((state->fe[0]->dtv_property_cache.layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv); - if (state->fe[0]->dtv_property_cache.layer[layer_index].segment_count > 0) { + dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv); + if (c->layer[layer_index].segment_count > 0) { switch (max_constellation) { case DQPSK: case QPSK: - if (state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_16 || state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_64) - max_constellation = state->fe[0]->dtv_property_cache.layer[layer_index].modulation; + if (c->layer[layer_index].modulation == QAM_16 || c->layer[layer_index].modulation == QAM_64) + max_constellation = c->layer[layer_index].modulation; break; case QAM_16: - if (state->fe[0]->dtv_property_cache.layer[layer_index].modulation == QAM_64) - max_constellation = state->fe[0]->dtv_property_cache.layer[layer_index].modulation; + if (c->layer[layer_index].modulation == QAM_64) + max_constellation = c->layer[layer_index].modulation; break; } } @@ -2135,30 +2136,31 @@ static void dib8000_small_fine_tune(struct dib8000_state *state) { u16 i; const s16 *ncoeff; + struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; dib8000_write_word(state, 352, state->seg_diff_mask); dib8000_write_word(state, 353, state->seg_mask); /* P_small_coef_ext_enable=ISDB-Tsb, P_small_narrow_band=ISDB-Tsb, P_small_last_seg=13, P_small_offset_num_car=5 */ - dib8000_write_word(state, 351, (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 9) | (state->fe[0]->dtv_property_cache.isdbt_sb_mode << 8) | (13 << 4) | 5); + dib8000_write_word(state, 351, (c->isdbt_sb_mode << 9) | (c->isdbt_sb_mode << 8) | (13 << 4) | 5); - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { + if (c->isdbt_sb_mode) { /* ---- SMALL ---- */ - switch (state->fe[0]->dtv_property_cache.transmission_mode) { + switch (c->transmission_mode) { case TRANSMISSION_MODE_2K: - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */ - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */ + if (c->isdbt_partial_reception == 0) { /* 1-seg */ + if (c->layer[0].modulation == DQPSK) /* DQPSK */ ncoeff = coeff_2k_sb_1seg_dqpsk; else /* QPSK or QAM */ ncoeff = coeff_2k_sb_1seg; } else { /* 3-segments */ - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */ - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */ + if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */ + if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ ncoeff = coeff_2k_sb_3seg_0dqpsk_1dqpsk; else /* QPSK or QAM on external segments */ ncoeff = coeff_2k_sb_3seg_0dqpsk; } else { /* QPSK or QAM on central segment */ - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */ + if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ ncoeff = coeff_2k_sb_3seg_1dqpsk; else /* QPSK or QAM on external segments */ ncoeff = coeff_2k_sb_3seg; @@ -2166,19 +2168,19 @@ static void dib8000_small_fine_tune(struct dib8000_state *state) } break; case TRANSMISSION_MODE_4K: - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */ - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */ + if (c->isdbt_partial_reception == 0) { /* 1-seg */ + if (c->layer[0].modulation == DQPSK) /* DQPSK */ ncoeff = coeff_4k_sb_1seg_dqpsk; else /* QPSK or QAM */ ncoeff = coeff_4k_sb_1seg; } else { /* 3-segments */ - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */ - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */ + if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */ + if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ ncoeff = coeff_4k_sb_3seg_0dqpsk_1dqpsk; else /* QPSK or QAM on external segments */ ncoeff = coeff_4k_sb_3seg_0dqpsk; } else { /* QPSK or QAM on central segment */ - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */ + if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ ncoeff = coeff_4k_sb_3seg_1dqpsk; else /* QPSK or QAM on external segments */ ncoeff = coeff_4k_sb_3seg; @@ -2188,19 +2190,19 @@ static void dib8000_small_fine_tune(struct dib8000_state *state) case TRANSMISSION_MODE_AUTO: case TRANSMISSION_MODE_8K: default: - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* 1-seg */ - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) /* DQPSK */ + if (c->isdbt_partial_reception == 0) { /* 1-seg */ + if (c->layer[0].modulation == DQPSK) /* DQPSK */ ncoeff = coeff_8k_sb_1seg_dqpsk; else /* QPSK or QAM */ ncoeff = coeff_8k_sb_1seg; } else { /* 3-segments */ - if (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) { /* DQPSK on central segment */ - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */ + if (c->layer[0].modulation == DQPSK) { /* DQPSK on central segment */ + if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ ncoeff = coeff_8k_sb_3seg_0dqpsk_1dqpsk; else /* QPSK or QAM on external segments */ ncoeff = coeff_8k_sb_3seg_0dqpsk; } else { /* QPSK or QAM on central segment */ - if (state->fe[0]->dtv_property_cache.layer[1].modulation == DQPSK) /* DQPSK on external segments */ + if (c->layer[1].modulation == DQPSK) /* DQPSK on external segments */ ncoeff = coeff_8k_sb_3seg_1dqpsk; else /* QPSK or QAM on external segments */ ncoeff = coeff_8k_sb_3seg; @@ -2218,10 +2220,11 @@ static const u16 coff_thres_1seg[3] = {300, 150, 80}; static const u16 coff_thres_3seg[3] = {350, 300, 250}; static void dib8000_set_sb_channel(struct dib8000_state *state) { + struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; const u16 *coff; u16 i; - if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K || state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_4K) { + if (c->transmission_mode == TRANSMISSION_MODE_2K || c->transmission_mode == TRANSMISSION_MODE_4K) { dib8000_write_word(state, 219, dib8000_read_word(state, 219) | 0x1); /* adp_pass =1 */ dib8000_write_word(state, 190, dib8000_read_word(state, 190) | (0x1 << 14)); /* pha3_force_pha_shift = 1 */ } else { @@ -2229,7 +2232,7 @@ static void dib8000_set_sb_channel(struct dib8000_state *state) dib8000_write_word(state, 190, dib8000_read_word(state, 190) & 0xbfff); /* pha3_force_pha_shift = 0 */ } - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 1) /* 3-segments */ + if (c->isdbt_partial_reception == 1) /* 3-segments */ state->seg_mask = 0x00E0; else /* 1-segment */ state->seg_mask = 0x0040; @@ -2238,13 +2241,13 @@ static void dib8000_set_sb_channel(struct dib8000_state *state) /* ---- COFF ---- Carloff, the most robust --- */ /* P_coff_cpil_alpha=4, P_coff_inh=0, P_coff_cpil_winlen=64, P_coff_narrow_band=1, P_coff_square_val=1, P_coff_one_seg=~partial_rcpt, P_coff_use_tmcc=1, P_coff_use_ac=1 */ - dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 2) | 0x3); + dib8000_write_word(state, 187, (4 << 12) | (0 << 11) | (63 << 5) | (0x3 << 3) | ((~c->isdbt_partial_reception & 1) << 2) | 0x3); dib8000_write_word(state, 340, (16 << 6) | (8 << 0)); /* P_ctrl_pre_freq_win_len=16, P_ctrl_pre_freq_thres_lockin=8 */ dib8000_write_word(state, 341, (6 << 3) | (1 << 2) | (1 << 1) | (1 << 0));/* P_ctrl_pre_freq_thres_lockout=6, P_small_use_tmcc/ac/cp=1 */ /* Sound Broadcasting mode 1 seg */ - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { + if (c->isdbt_partial_reception == 0) { /* P_coff_winlen=63, P_coff_thres_lock=15, P_coff_one_seg_width = (P_mode == 3) , P_coff_one_seg_sym = (P_mode-1) */ if (state->mode == 3) dib8000_write_word(state, 180, 0x1fcf | ((state->mode - 1) << 14)); @@ -2264,7 +2267,7 @@ static void dib8000_set_sb_channel(struct dib8000_state *state) dib8000_write_word(state, 228, 1); /* P_2d_mode_byp=1 */ dib8000_write_word(state, 205, dib8000_read_word(state, 205) & 0xfff0); /* P_cspu_win_cut = 0 */ - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0 && state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_2K) + if (c->isdbt_partial_reception == 0 && c->transmission_mode == TRANSMISSION_MODE_2K) dib8000_write_word(state, 265, 15); /* P_equal_noise_sel = 15 */ /* Write COFF thres */ @@ -2280,7 +2283,7 @@ static void dib8000_set_sb_channel(struct dib8000_state *state) dib8000_write_word(state, 266, ~state->seg_mask | state->seg_diff_mask); /* P_equal_noise_seg_inh */ - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) + if (c->isdbt_partial_reception == 0) dib8000_write_word(state, 178, 64); /* P_fft_powrange = 64 */ else dib8000_write_word(state, 178, 32); /* P_fft_powrange = 32 */ @@ -2292,6 +2295,7 @@ static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq u16 tmcc_pow = 0, ana_gain = 0, tmp = 0, i = 0, nbseg_diff = 0 ; u16 max_constellation = DQPSK; int init_prbs; + struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; /* P_mode */ dib8000_write_word(state, 10, (seq << 4)); @@ -2301,20 +2305,20 @@ static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq /* set guard */ tmp = dib8000_read_word(state, 1); - dib8000_write_word(state, 1, (tmp&0xfffc) | (state->fe[0]->dtv_property_cache.guard_interval & 0x3)); + dib8000_write_word(state, 1, (tmp&0xfffc) | (c->guard_interval & 0x3)); - dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | ((state->fe[0]->dtv_property_cache.isdbt_partial_reception & 1) << 5) | ((state->fe[0]->dtv_property_cache.isdbt_sb_mode & 1) << 4)); + dib8000_write_word(state, 274, (dib8000_read_word(state, 274) & 0xffcf) | ((c->isdbt_partial_reception & 1) << 5) | ((c->isdbt_sb_mode & 1) << 4)); /* signal optimization parameter */ - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) { - state->seg_diff_mask = (state->fe[0]->dtv_property_cache.layer[0].modulation == DQPSK) << permu_seg[0]; + if (c->isdbt_partial_reception) { + state->seg_diff_mask = (c->layer[0].modulation == DQPSK) << permu_seg[0]; for (i = 1; i < 3; i++) - nbseg_diff += (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count; + nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count; for (i = 0; i < nbseg_diff; i++) state->seg_diff_mask |= 1 << permu_seg[i+1]; } else { for (i = 0; i < 3; i++) - nbseg_diff += (state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * state->fe[0]->dtv_property_cache.layer[i].segment_count; + nbseg_diff += (c->layer[i].modulation == DQPSK) * c->layer[i].segment_count; for (i = 0; i < nbseg_diff; i++) state->seg_diff_mask |= 1 << permu_seg[i]; } @@ -2327,8 +2331,8 @@ static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq for (i = 0; i < 3; i++) max_constellation = dib8000_set_layer(state, i, max_constellation); if (autosearching == 0) { - state->layer_b_nb_seg = state->fe[0]->dtv_property_cache.layer[1].segment_count; - state->layer_c_nb_seg = state->fe[0]->dtv_property_cache.layer[2].segment_count; + state->layer_b_nb_seg = c->layer[1].segment_count; + state->layer_c_nb_seg = c->layer[2].segment_count; } /* WRITE: Mode & Diff mask */ @@ -2343,16 +2347,16 @@ static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq dib8000_update_ana_gain(state, ana_gain); /* ---- ANA_FE ---- */ - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception) /* 3-segments */ + if (c->isdbt_partial_reception) /* 3-segments */ dib8000_load_ana_fe_coefs(state, ana_fe_coeff_3seg); else dib8000_load_ana_fe_coefs(state, ana_fe_coeff_1seg); /* 1-segment */ /* TSB or ISDBT ? apply it now */ - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { + if (c->isdbt_sb_mode) { dib8000_set_sb_channel(state); - if (state->fe[0]->dtv_property_cache.isdbt_sb_subchannel != -1) - init_prbs = dib8000_get_init_prbs(state, state->fe[0]->dtv_property_cache.isdbt_sb_subchannel); + if (c->isdbt_sb_subchannel != -1) + init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel); else init_prbs = 0; } else { @@ -2392,7 +2396,7 @@ static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq /* ---- TMCC ---- */ for (i = 0; i < 3; i++) - tmcc_pow += (((state->fe[0]->dtv_property_cache.layer[i].modulation == DQPSK) * 4 + 1) * state->fe[0]->dtv_property_cache.layer[i].segment_count) ; + tmcc_pow += (((c->layer[i].modulation == DQPSK) * 4 + 1) * c->layer[i].segment_count) ; /* Quantif of "P_tmcc_dec_thres_?k" is (0, 5+mode, 9); */ /* Threshold is set at 1/4 of max power. */ @@ -2434,6 +2438,7 @@ static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal, static int dib8000_autosearch_start(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; u8 slist = 0; u32 value, internal = state->cfg.pll->internal; @@ -2477,16 +2482,16 @@ static int dib8000_autosearch_start(struct dvb_frontend *fe) dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */ dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */ } else if (state->autosearch_state == AS_SEARCHING_GUARD) { - state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; - state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; - state->fe[0]->dtv_property_cache.inversion = 0; - state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64; - state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3; - state->fe[0]->dtv_property_cache.layer[0].interleaving = 0; - state->fe[0]->dtv_property_cache.layer[0].segment_count = 13; + c->transmission_mode = TRANSMISSION_MODE_8K; + c->guard_interval = GUARD_INTERVAL_1_8; + c->inversion = 0; + c->layer[0].modulation = QAM_64; + c->layer[0].fec = FEC_2_3; + c->layer[0].interleaving = 0; + c->layer[0].segment_count = 13; slist = 16; - state->fe[0]->dtv_property_cache.transmission_mode = state->found_nfft; + c->transmission_mode = state->found_nfft; dib8000_set_isdbt_common_channel(state, slist, 1); @@ -2515,32 +2520,32 @@ static int dib8000_autosearch_start(struct dvb_frontend *fe) dib8000_read_word(state, 1284); /* reset the INT. n_irq_pending */ dib8000_write_word(state, 0, (u16)value); } else { - state->fe[0]->dtv_property_cache.inversion = 0; - state->fe[0]->dtv_property_cache.layer[0].modulation = QAM_64; - state->fe[0]->dtv_property_cache.layer[0].fec = FEC_2_3; - state->fe[0]->dtv_property_cache.layer[0].interleaving = 0; - state->fe[0]->dtv_property_cache.layer[0].segment_count = 13; - if (!state->fe[0]->dtv_property_cache.isdbt_sb_mode) - state->fe[0]->dtv_property_cache.layer[0].segment_count = 13; + c->inversion = 0; + c->layer[0].modulation = QAM_64; + c->layer[0].fec = FEC_2_3; + c->layer[0].interleaving = 0; + c->layer[0].segment_count = 13; + if (!c->isdbt_sb_mode) + c->layer[0].segment_count = 13; /* choose the right list, in sb, always do everything */ - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { + if (c->isdbt_sb_mode) { slist = 7; dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); } else { - if (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) { - if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { - state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; - state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; + if (c->guard_interval == GUARD_INTERVAL_AUTO) { + if (c->transmission_mode == TRANSMISSION_MODE_AUTO) { + c->transmission_mode = TRANSMISSION_MODE_8K; + c->guard_interval = GUARD_INTERVAL_1_8; slist = 7; dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 to have autosearch start ok with mode2 */ } else { - state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8; + c->guard_interval = GUARD_INTERVAL_1_8; slist = 3; } } else { - if (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) { - state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K; + if (c->transmission_mode == TRANSMISSION_MODE_AUTO) { + c->transmission_mode = TRANSMISSION_MODE_8K; slist = 2; dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x9fff) | (1 << 13)); /* P_mode = 1 */ } else @@ -2653,6 +2658,7 @@ static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz) static void dib8000_set_frequency_offset(struct dib8000_state *state) { + struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; int i; u32 current_rf; int total_dds_offset_khz; @@ -2660,26 +2666,26 @@ static void dib8000_set_frequency_offset(struct dib8000_state *state) if (state->fe[0]->ops.tuner_ops.get_frequency) state->fe[0]->ops.tuner_ops.get_frequency(state->fe[0], ¤t_rf); else - current_rf = state->fe[0]->dtv_property_cache.frequency; + current_rf = c->frequency; current_rf /= 1000; - total_dds_offset_khz = (int)current_rf - (int)state->fe[0]->dtv_property_cache.frequency / 1000; + total_dds_offset_khz = (int)current_rf - (int)c->frequency / 1000; - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { - state->subchannel = state->fe[0]->dtv_property_cache.isdbt_sb_subchannel; + if (c->isdbt_sb_mode) { + state->subchannel = c->isdbt_sb_subchannel; i = dib8000_read_word(state, 26) & 1; /* P_dds_invspec */ - dib8000_write_word(state, 26, state->fe[0]->dtv_property_cache.inversion ^ i); + dib8000_write_word(state, 26, c->inversion ^ i); if (state->cfg.pll->ifreq == 0) { /* low if tuner */ - if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) + if ((c->inversion ^ i) == 0) dib8000_write_word(state, 26, dib8000_read_word(state, 26) | 1); } else { - if ((state->fe[0]->dtv_property_cache.inversion ^ i) == 0) + if ((c->inversion ^ i) == 0) total_dds_offset_khz *= -1; } } - dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d", state->fe[0]->dtv_property_cache.frequency - current_rf, state->fe[0]->dtv_property_cache.frequency, current_rf, total_dds_offset_khz); + dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d", c->frequency - current_rf, c->frequency, current_rf, total_dds_offset_khz); /* apply dds offset now */ dib8000_set_dds(state, total_dds_offset_khz); @@ -2689,9 +2695,10 @@ static u16 LUT_isdbt_symbol_duration[4] = { 26, 101, 63 }; static u32 dib8000_get_symbol_duration(struct dib8000_state *state) { + struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; u16 i; - switch (state->fe[0]->dtv_property_cache.transmission_mode) { + switch (c->transmission_mode) { case TRANSMISSION_MODE_2K: i = 0; break; @@ -2705,17 +2712,18 @@ static u32 dib8000_get_symbol_duration(struct dib8000_state *state) break; } - return (LUT_isdbt_symbol_duration[i] / (state->fe[0]->dtv_property_cache.bandwidth_hz / 1000)) + 1; + return (LUT_isdbt_symbol_duration[i] / (c->bandwidth_hz / 1000)) + 1; } static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum param_loop_step loop_step) { + struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; u16 reg_32 = 0, reg_37 = 0; switch (loop_step) { case LOOP_TUNE_1: - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { + if (c->isdbt_sb_mode) { + if (c->isdbt_partial_reception == 0) { reg_32 = ((11 - state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (11-P_mode), P_corm_alpha=6, P_corm_thres=0x40 */ reg_37 = (3 << 5) | (0 << 4) | (10 - state->mode); /* P_ctrl_pha_off_max=3 P_ctrl_sfreq_inh =0 P_ctrl_sfreq_step = (10-P_mode) */ } else { /* Sound Broadcasting mode 3 seg */ @@ -2728,8 +2736,8 @@ static void dib8000_set_isdbt_loop_params(struct dib8000_state *state, enum para } break; case LOOP_TUNE_2: - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode) { - if (state->fe[0]->dtv_property_cache.isdbt_partial_reception == 0) { /* Sound Broadcasting mode 1 seg */ + if (c->isdbt_sb_mode) { + if (c->isdbt_partial_reception == 0) { /* Sound Broadcasting mode 1 seg */ reg_32 = ((13-state->mode) << 12) | (6 << 8) | 0x40; /* P_timf_alpha = (13-P_mode) , P_corm_alpha=6, P_corm_thres=0x40*/ reg_37 = (12-state->mode) | ((5 + state->mode) << 5); } else { /* Sound Broadcasting mode 3 seg */ @@ -2755,10 +2763,11 @@ static void dib8000_demod_restart(struct dib8000_state *state) static void dib8000_set_sync_wait(struct dib8000_state *state) { + struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; u16 sync_wait = 64; /* P_dvsy_sync_wait - reuse mode */ - switch (state->fe[0]->dtv_property_cache.transmission_mode) { + switch (c->transmission_mode) { case TRANSMISSION_MODE_8K: sync_wait = 256; break; @@ -2772,9 +2781,9 @@ static void dib8000_set_sync_wait(struct dib8000_state *state) } if (state->cfg.diversity_delay == 0) - sync_wait = (sync_wait * (1 << (state->fe[0]->dtv_property_cache.guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */ + sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + 48; /* add 50% SFN margin + compensate for one DVSY-fifo */ else - sync_wait = (sync_wait * (1 << (state->fe[0]->dtv_property_cache.guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */ + sync_wait = (sync_wait * (1 << (c->guard_interval)) * 3) / 2 + state->cfg.diversity_delay; /* add 50% SFN margin + compensate for DVSY-fifo */ dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4)); } @@ -2847,6 +2856,7 @@ static int dib8090p_init_sdram(struct dib8000_state *state) static int dib8000_tune(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; enum frontend_tune_state *tune_state = &state->tune_state; u16 locks, deeper_interleaver = 0, i; @@ -2871,30 +2881,30 @@ static int dib8000_tune(struct dvb_frontend *fe) if (state->revision == 0x8090) dib8090p_init_sdram(state); state->status = FE_STATUS_TUNE_PENDING; - if ((state->fe[0]->dtv_property_cache.delivery_system != SYS_ISDBT) || - (state->fe[0]->dtv_property_cache.inversion == INVERSION_AUTO) || - (state->fe[0]->dtv_property_cache.transmission_mode == TRANSMISSION_MODE_AUTO) || - (state->fe[0]->dtv_property_cache.guard_interval == GUARD_INTERVAL_AUTO) || - (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) != 0) && - (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0xff) && - (state->fe[0]->dtv_property_cache.layer[0].segment_count != 0) && - ((state->fe[0]->dtv_property_cache.layer[0].modulation == QAM_AUTO) || - (state->fe[0]->dtv_property_cache.layer[0].fec == FEC_AUTO))) || - (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 1)) != 0) && - (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0xff) && - (state->fe[0]->dtv_property_cache.layer[1].segment_count != 0) && - ((state->fe[0]->dtv_property_cache.layer[1].modulation == QAM_AUTO) || - (state->fe[0]->dtv_property_cache.layer[1].fec == FEC_AUTO))) || - (((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 2)) != 0) && - (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0xff) && - (state->fe[0]->dtv_property_cache.layer[2].segment_count != 0) && - ((state->fe[0]->dtv_property_cache.layer[2].modulation == QAM_AUTO) || - (state->fe[0]->dtv_property_cache.layer[2].fec == FEC_AUTO))) || - (((state->fe[0]->dtv_property_cache.layer[0].segment_count == 0) || - ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (1 << 0)) == 0)) && - ((state->fe[0]->dtv_property_cache.layer[1].segment_count == 0) || - ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (2 << 0)) == 0)) && - ((state->fe[0]->dtv_property_cache.layer[2].segment_count == 0) || ((state->fe[0]->dtv_property_cache.isdbt_layer_enabled & (3 << 0)) == 0)))) + if ((c->delivery_system != SYS_ISDBT) || + (c->inversion == INVERSION_AUTO) || + (c->transmission_mode == TRANSMISSION_MODE_AUTO) || + (c->guard_interval == GUARD_INTERVAL_AUTO) || + (((c->isdbt_layer_enabled & (1 << 0)) != 0) && + (c->layer[0].segment_count != 0xff) && + (c->layer[0].segment_count != 0) && + ((c->layer[0].modulation == QAM_AUTO) || + (c->layer[0].fec == FEC_AUTO))) || + (((c->isdbt_layer_enabled & (1 << 1)) != 0) && + (c->layer[1].segment_count != 0xff) && + (c->layer[1].segment_count != 0) && + ((c->layer[1].modulation == QAM_AUTO) || + (c->layer[1].fec == FEC_AUTO))) || + (((c->isdbt_layer_enabled & (1 << 2)) != 0) && + (c->layer[2].segment_count != 0xff) && + (c->layer[2].segment_count != 0) && + ((c->layer[2].modulation == QAM_AUTO) || + (c->layer[2].fec == FEC_AUTO))) || + (((c->layer[0].segment_count == 0) || + ((c->isdbt_layer_enabled & (1 << 0)) == 0)) && + ((c->layer[1].segment_count == 0) || + ((c->isdbt_layer_enabled & (2 << 0)) == 0)) && + ((c->layer[2].segment_count == 0) || ((c->isdbt_layer_enabled & (3 << 0)) == 0)))) state->channel_parameters_set = 0; /* auto search */ else state->channel_parameters_set = 1; /* channel parameters are known */ @@ -2905,7 +2915,7 @@ static int dib8000_tune(struct dvb_frontend *fe) dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60); dib8000_set_frequency_offset(state); - dib8000_set_bandwidth(fe, state->fe[0]->dtv_property_cache.bandwidth_hz / 1000); + dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000); if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */ #ifdef DIB8000_AGC_FREEZE @@ -3092,7 +3102,7 @@ static int dib8000_tune(struct dvb_frontend *fe) dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/ - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode && state->fe[0]->dtv_property_cache.isdbt_sb_subchannel == -1 && !state->differential_constellation) { + if (c->isdbt_sb_mode && c->isdbt_sb_subchannel == -1 && !state->differential_constellation) { state->subchannel = 0; *tune_state = CT_DEMOD_STEP_11; } else { @@ -3105,10 +3115,10 @@ static int dib8000_tune(struct dvb_frontend *fe) if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */ /* defines timeout for mpeg lock depending on interleaver lenght of longest layer */ for (i = 0; i < 3; i++) { - if (state->fe[0]->dtv_property_cache.layer[i].interleaving >= deeper_interleaver) { - dprintk("layer%i: time interleaver = %d ", i, state->fe[0]->dtv_property_cache.layer[i].interleaving); - if (state->fe[0]->dtv_property_cache.layer[i].segment_count > 0) { /* valid layer */ - deeper_interleaver = state->fe[0]->dtv_property_cache.layer[0].interleaving; + if (c->layer[i].interleaving >= deeper_interleaver) { + dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving); + if (c->layer[i].segment_count > 0) { /* valid layer */ + deeper_interleaver = c->layer[0].interleaving; state->longest_intlv_layer = i; } } @@ -3136,14 +3146,14 @@ static int dib8000_tune(struct dvb_frontend *fe) locks = dib8000_read_lock(fe); if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */ dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1); - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode && state->fe[0]->dtv_property_cache.isdbt_sb_subchannel == -1 && !state->differential_constellation) + if (c->isdbt_sb_mode && c->isdbt_sb_subchannel == -1 && !state->differential_constellation) /* signal to the upper layer, that there was a channel found and the parameters can be read */ state->status = FE_STATUS_DEMOD_SUCCESS; else state->status = FE_STATUS_DATA_LOCKED; *tune_state = CT_DEMOD_STOP; } else if (now > *timeout) { - if (state->fe[0]->dtv_property_cache.isdbt_sb_mode && state->fe[0]->dtv_property_cache.isdbt_sb_subchannel == -1 && !state->differential_constellation) { /* continue to try init prbs autosearch */ + if (c->isdbt_sb_mode && c->isdbt_sb_subchannel == -1 && !state->differential_constellation) { /* continue to try init prbs autosearch */ state->subchannel += 3; *tune_state = CT_DEMOD_STEP_11; } else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */ @@ -3389,18 +3399,19 @@ static int dib8000_get_frontend(struct dvb_frontend *fe) static int dib8000_set_frontend(struct dvb_frontend *fe) { struct dib8000_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache; int l, i, active, time, ret, time_slave = FE_CALLBACK_TIME_NEVER; u8 exit_condition, index_frontend; u32 delay, callback_time; - if (state->fe[0]->dtv_property_cache.frequency == 0) { + if (c->frequency == 0) { dprintk("dib8000: must at least specify frequency "); return 0; } - if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) { + if (c->bandwidth_hz == 0) { dprintk("dib8000: no bandwidth specified, set to default "); - state->fe[0]->dtv_property_cache.bandwidth_hz = 6000000; + c->bandwidth_hz = 6000000; } for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { -- cgit v1.2.3 From 746f7ae0e9ca500f8be888675d88befed5740413 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 25 Apr 2013 11:15:54 -0300 Subject: [media] dib8000: Fix sub-channel range isdbt_sb_subchannel is unsigned with 8 bits. So, it will never be -1. Instead, any value bigger than 13 is invalid. As is, the current code generates the following warnings: drivers/media/dvb-frontends/dib8000.c: In function 'dib8000_set_isdbt_common_channel': drivers/media/dvb-frontends/dib8000.c:2358:3: warning: comparison is always true due to limited range of data type [-Wtype-limits] drivers/media/dvb-frontends/dib8000.c: In function 'dib8000_tune': drivers/media/dvb-frontends/dib8000.c:3107:8: warning: comparison is always false due to limited range of data type [-Wtype-limits] drivers/media/dvb-frontends/dib8000.c:3153:9: warning: comparison is always false due to limited range of data type [-Wtype-limits] drivers/media/dvb-frontends/dib8000.c:3160:5: warning: comparison is always false It should also be noticed that ARIB STD-B31, item "3.15.6.8 Number of segments" at TMCC table defines the value 15 for unused segment, and 14 as reserved. So, better to change the check to consider any value bigger than 13 to mean that sub-channels should be disabled, fixing the warning and doing the right thing even if an invalid value is filled by userspace. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib8000.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 77dac46bfcbf..57863d3fd1cf 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -2355,7 +2355,7 @@ static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq /* TSB or ISDBT ? apply it now */ if (c->isdbt_sb_mode) { dib8000_set_sb_channel(state); - if (c->isdbt_sb_subchannel != -1) + if (c->isdbt_sb_subchannel < 14) init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel); else init_prbs = 0; @@ -3102,7 +3102,9 @@ static int dib8000_tune(struct dvb_frontend *fe) dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2); /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/ - if (c->isdbt_sb_mode && c->isdbt_sb_subchannel == -1 && !state->differential_constellation) { + if (c->isdbt_sb_mode + && c->isdbt_sb_subchannel < 14 + && !state->differential_constellation) { state->subchannel = 0; *tune_state = CT_DEMOD_STEP_11; } else { @@ -3146,14 +3148,18 @@ static int dib8000_tune(struct dvb_frontend *fe) locks = dib8000_read_lock(fe); if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */ dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1); - if (c->isdbt_sb_mode && c->isdbt_sb_subchannel == -1 && !state->differential_constellation) + if (c->isdbt_sb_mode + && c->isdbt_sb_subchannel < 14 + && !state->differential_constellation) /* signal to the upper layer, that there was a channel found and the parameters can be read */ state->status = FE_STATUS_DEMOD_SUCCESS; else state->status = FE_STATUS_DATA_LOCKED; *tune_state = CT_DEMOD_STOP; } else if (now > *timeout) { - if (c->isdbt_sb_mode && c->isdbt_sb_subchannel == -1 && !state->differential_constellation) { /* continue to try init prbs autosearch */ + if (c->isdbt_sb_mode + && c->isdbt_sb_subchannel < 14 + && !state->differential_constellation) { /* continue to try init prbs autosearch */ state->subchannel += 3; *tune_state = CT_DEMOD_STEP_11; } else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */ -- cgit v1.2.3 From 13122f98c6479ddbfc308eb4253f84aaf4a2b45e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 25 Apr 2013 15:22:20 -0300 Subject: [media] dib8000: fix a warning drivers/media/dvb-frontends/dib8000.c: In function 'dib8000_wait_lock': drivers/media/dvb-frontends/dib8000.c:3972:1: warning: 'value' may be used uninitialized in this function [-Wmaybe-uninitialized] drivers/media/dvb-frontends/dib8000.c:2419:6: note: 'value' was declared here Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib8000.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 57863d3fd1cf..a54182dd0e91 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -2416,19 +2416,19 @@ static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq static u32 dib8000_wait_lock(struct dib8000_state *state, u32 internal, u32 wait0_ms, u32 wait1_ms, u32 wait2_ms) { - u32 value; - u16 reg = 11; /* P_search_end0 start addr */ + u32 value = 0; /* P_search_end0 wait time */ + u16 reg = 11; /* P_search_end0 start addr */ for (reg = 11; reg < 16; reg += 2) { if (reg == 11) { if (state->revision == 0x8090) - value = internal * wait1_ms; /* P_search_end0 wait time */ + value = internal * wait1_ms; else - value = internal * wait0_ms; /* P_search_end0 wait time */ + value = internal * wait0_ms; } else if (reg == 13) - value = internal * wait1_ms; /* P_search_end0 wait time */ + value = internal * wait1_ms; else if (reg == 15) - value = internal * wait2_ms; /* P_search_end0 wait time */ + value = internal * wait2_ms; dib8000_write_word(state, reg, (u16)((value >> 16) & 0xffff)); dib8000_write_word(state, (reg + 1), (u16)(value & 0xffff)); } -- cgit v1.2.3 From 751dc8c7fa706c6bafa0eeee88f22f59987157e0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 25 Apr 2013 15:30:40 -0300 Subject: [media] dib0090: Fix a warning at dib0090_set_EFUSE The check if the values for c, h and n are within the range is always true, as, if one of this values is out of range, the previous "if" clauses will default to a value within the range. That fixes the following warning: drivers/media/dvb-frontends/dib0090.c: In function 'dib0090_set_EFUSE': drivers/media/dvb-frontends/dib0090.c:1545:5: warning: comparison is always true due to limited range of data type [-Wtype-limits] and makes the code easier to read. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib0090.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index f9916b8434b7..3ee22ff76315 100644 --- a/drivers/media/dvb-frontends/dib0090.c +++ b/drivers/media/dvb-frontends/dib0090.c @@ -1540,13 +1540,9 @@ static void dib0090_set_EFUSE(struct dib0090_state *state) if ((n >= POLY_MAX) || (n <= POLY_MIN)) n = 3; - if ((c >= CAP_VALUE_MIN) && (c <= CAP_VALUE_MAX) - && (h >= HR_MIN) && (h <= HR_MAX) - && (n >= POLY_MIN) && (n <= POLY_MAX)) { - dib0090_write_reg(state, 0x13, (h << 10)); - e2 = (n << 11) | ((h >> 2)<<6) | c; - dib0090_write_reg(state, 0x2, e2); /* Load the BB_2 */ - } + dib0090_write_reg(state, 0x13, (h << 10)); + e2 = (n << 11) | ((h >> 2)<<6) | c; + dib0090_write_reg(state, 0x2, e2); /* Load the BB_2 */ } } -- cgit v1.2.3 From 7063c1456fc0a6366f467f10e7a35178ecc881ad Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 25 Apr 2013 15:40:21 -0300 Subject: [media] r820t: Remove a warning for an unused value Currently, the driver complains about the pre_detect var: drivers/media/tuners/r820t.c: In function 'r820t_sysfreq_sel': drivers/media/tuners/r820t.c:722:31: warning: variable 'pre_dect' set but not used [-Wunused-but-set-variable] While rtl8232 code comments it, perhaps some other driver may use. So, the better is to keep the code there, allowing to enable it via r820t config data. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/r820t.c | 7 +++++++ drivers/media/tuners/r820t.h | 1 + 2 files changed, 8 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index e6e7a06d2b40..4835021aa3b6 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -797,6 +797,13 @@ static int r820t_sysfreq_sel(struct r820t_priv *priv, u32 freq, cable2_in = 0x00; } + + if (priv->cfg->use_predetect) { + rc = r820t_write_reg_mask(priv, 0x06, pre_dect, 0x40); + if (rc < 0) + return rc; + } + rc = r820t_write_reg_mask(priv, 0x1d, lna_top, 0xc7); if (rc < 0) return rc; diff --git a/drivers/media/tuners/r820t.h b/drivers/media/tuners/r820t.h index 4c0823b21693..48af3548027d 100644 --- a/drivers/media/tuners/r820t.h +++ b/drivers/media/tuners/r820t.h @@ -39,6 +39,7 @@ struct r820t_config { enum r820t_chip rafael_chip; unsigned max_i2c_msg_len; bool use_diplexer; + bool use_predetect; }; #if IS_ENABLED(CONFIG_MEDIA_TUNER_R820T) -- cgit v1.2.3 From 66f93178042b6f151552fdb74cbaa2724e59c97c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 25 Apr 2013 15:46:36 -0300 Subject: [media] cx25821-video: remove maxw from cx25821_vidioc_try_fmt_vid_cap After cx25821-video cleanup, this var is not used anymore: drivers/media/pci/cx25821/cx25821-video.c: In function 'cx25821_vidioc_try_fmt_vid_cap': drivers/media/pci/cx25821/cx25821-video.c:591:15: warning: variable 'maxw' set but not used [-Wunused-but-set-variable] as the code now checks the max width as the default case for the range check. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index b194138961df..3ba856a2a9f3 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -588,13 +588,12 @@ static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct cx25821_dev *dev = chan->dev; const struct cx25821_fmt *fmt; enum v4l2_field field = f->fmt.pix.field; - unsigned int maxw, maxh; + unsigned int maxh; unsigned w; fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat); if (NULL == fmt) return -EINVAL; - maxw = 720; maxh = (dev->tvnorm & V4L2_STD_625_50) ? 576 : 480; w = f->fmt.pix.width; -- cgit v1.2.3 From a3f17af2d97a2a51af37e7b1dab5de5562c9b66d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 25 Apr 2013 15:49:33 -0300 Subject: [media] cx25821-video: declare cx25821_vidioc_s_std as static Fixes the following warning: drivers/media/pci/cx25821/cx25821-video.c: At top level: drivers/media/pci/cx25821/cx25821-video.c:766:5: warning: no previous prototype for 'cx25821_vidioc_s_std' [-Wmissing-prototypes] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-video.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 3ba856a2a9f3..d270819fd875 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -762,7 +762,8 @@ static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvno return 0; } -int cx25821_vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) +static int cx25821_vidioc_s_std(struct file *file, void *priv, + v4l2_std_id tvnorms) { struct cx25821_channel *chan = video_drvdata(file); struct cx25821_dev *dev = chan->dev; -- cgit v1.2.3 From f327cabf7fc2a356e6eddfa51b1dc54c3bc625d9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 25 Apr 2013 15:58:44 -0300 Subject: [media] cx25821-alsa: get rid of a __must_check warning The hole reason for __must_check is to not ignore an error. However, a "ret" value is used at cx25821 just to avoid the Kernel compilation to compain about it. That, however, produces another warning (with W=1): drivers/media/pci/cx25821/cx25821-alsa.c: In function 'cx25821_audio_fini': drivers/media/pci/cx25821/cx25821-alsa.c:727:6: warning: variable 'ret' set but not used [-Wunused-but-set-variable] With the current implementation of driver_for_each_device() and cx25821_alsa_exit_callback(), there's actually just one very unlikely condition where it will currently produce an error: if driver_find() returns NULL. Ok, there's not much that can be done, as it is on a driver's function that returns void, but it can at least print some message if the error happens. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx25821/cx25821-alsa.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 81361c26c54e..6e91e84d6bf9 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -727,6 +727,8 @@ static void cx25821_audio_fini(void) int ret; ret = driver_for_each_device(drv, NULL, NULL, cx25821_alsa_exit_callback); + if (ret) + pr_err("%s failed to find a cx25821 driver.\n", __func__); } static int cx25821_alsa_init_callback(struct device *dev, void *data) -- cgit v1.2.3 From 4494f0fdd825958d596d05a4bd577df94b149038 Mon Sep 17 00:00:00 2001 From: Gianluca Gennari Date: Thu, 25 Apr 2013 10:46:38 -0300 Subject: [media] s5c73m3: fix indentation of the help section in Kconfig The 'help' section of the Kconfig entry for this driver is missing an extra alignment. That seems to violate what's stated at: Documentation/kbuild/kconfig-language.txt Even if it works, the better is to add 2 extra spaces there, as this is the common practice and helps human reading of the file. Also, the way it is, it breaks backport trees. Signed-off-by: Gianluca Gennari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 9e7ce8bff4e9..f981d50a2a8c 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -559,8 +559,8 @@ config VIDEO_S5C73M3 tristate "Samsung S5C73M3 sensor support" depends on I2C && SPI && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API ---help--- - This is a V4L2 sensor-level driver for Samsung S5C73M3 - 8 Mpixel camera. + This is a V4L2 sensor-level driver for Samsung S5C73M3 + 8 Mpixel camera. comment "Flash devices" -- cgit v1.2.3 From a3b60209e7dd4db05249a9fb27940bb6705cd186 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 28 Apr 2013 10:33:57 -0300 Subject: [media] em28xx: fix oops at em28xx_dvb_bus_ctrl() em28xx is oopsing with some DVB devices: [10856.061884] general protection fault: 0000 [#1] SMP [10856.067041] Modules linked in: rc_hauppauge em28xx_rc xc5000 drxk em28xx_dvb dvb_core em28xx videobuf2_vmalloc videobuf2_memops videobuf2_core rc_pixelview_new tuner_xc2028 tuner cx8800 cx88xx tveeprom btcx_risc videobuf_dma_sg videobuf_core rc_core v4l2_common videodev ebtable_nat ebtables nf_conntrack_ipv4 nf_defrag_ipv4 xt_CHECKSUM be2iscsi iscsi_boot_sysfs iptable_mangle bnx2i cnic uio cxgb4i cxgb4 tun bridge cxgb3i cxgb3 stp ip6t_REJECT mdio libcxgbi nf_conntrack_ipv6 llc nf_defrag_ipv6 ib_iser rdma_cm ib_addr xt_conntrack iw_cm ib_cm ib_sa nf_conntrack ib_mad ib_core bnep bluetooth iscsi_tcp libiscsi_tcp ip6table_filter libiscsi ip6_tables scsi_transport_iscsi xfs libcrc32c snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm tg3 snd_page_alloc snd_timer [10856.139176] snd ptp iTCO_wdt soundcore pps_core iTCO_vendor_support lpc_ich mfd_core coretemp nfsd hp_wmi crc32c_intel microcode serio_raw rfkill sparse_keymap nfs_acl lockd sunrpc kvm_intel kvm uinput binfmt_misc firewire_ohci nouveau mxm_wmi i2c_algo_bit drm_kms_helper firewire_core crc_itu_t ttm drm i2c_core wmi [last unloaded: dib0070] [10856.168969] CPU 1 [10856.170799] Pid: 13606, comm: dvbv5-zap Not tainted 3.9.0-rc5+ #26 Hewlett-Packard HP Z400 Workstation/0AE4h [10856.181187] RIP: 0010:[] [] em28xx_write_regs_req+0x37/0x1c0 [em28xx] [10856.191028] RSP: 0018:ffff880118401a58 EFLAGS: 00010282 [10856.196533] RAX: 00020000012d0000 RBX: ffff88010804aec8 RCX: ffff880118401b14 [10856.203852] RDX: 0000000000000048 RSI: 0000000000000000 RDI: ffff88010804aec8 [10856.211174] RBP: ffff880118401ac8 R08: 0000000000000001 R09: 0000000000000000 [10856.218496] R10: 0000000000000000 R11: 0000000000000006 R12: 0000000000000048 [10856.226026] R13: ffff880118401b14 R14: ffff88011752b258 R15: ffff88011752b258 [10856.233352] FS: 00007f26636d2740(0000) GS:ffff88011fc20000(0000) knlGS:0000000000000000 [10856.241626] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [10856.247565] CR2: 00007f2663716e20 CR3: 00000000c7eb1000 CR4: 00000000000007e0 [10856.254889] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [10856.262215] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [10856.269542] Process dvbv5-zap (pid: 13606, threadinfo ffff880118400000, task ffff8800cd625d40) [10856.278340] Stack: [10856.280564] ffff88011ffe8de8 0000000000000002 0000000000000000 ffff88011ffe9b00 [10856.288191] ffff880118401b14 00ff88011ffe9b08 ffff880100000048 ffffffff8112a52a [10856.295893] 0000000000000001 ffff88010804aec8 0000000000000048 ffff880118401b14 [10856.303521] Call Trace: [10856.306182] [] ? __alloc_pages_nodemask+0x15a/0x960 [10856.312912] [] em28xx_write_regs+0x32/0xa0 [em28xx] [10856.319638] [] em28xx_write_reg+0x21/0x30 [em28xx] [10856.326279] [] em28xx_gpio_set+0x9c/0x100 [em28xx] [10856.332919] [] em28xx_set_mode+0x7c/0x80 [em28xx] [10856.339472] [] em28xx_dvb_bus_ctrl+0x32/0x40 [em28xx_dvb] This is caused by commit c7a45e5b4f8c2f96cd242ae1b1c06e7fb19a08d0, that added support for two I2C buses. A partial fix was applied at 3de09fbbfaa521e68675bd30cfece252c4856600, but it doesn't cover all cases, as the DVB core fills fe->dvb->priv with adapter->priv. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-dvb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 1f1f56ff6294..b22f8fed8127 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -270,7 +270,8 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed) /* ------------------------------------------------------------------ */ static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) { - struct em28xx *dev = fe->dvb->priv; + struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv; + struct em28xx *dev = i2c_bus->dev; if (acquire) return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); -- cgit v1.2.3 From 02615ed5e1b2283db2495af3cf8f4ee172c77d80 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 28 Apr 2013 07:15:41 -0300 Subject: [media] cx88: make core less verbose Along the time, several debug messages were added at cx88-cards. While those are still useful to track some troubles with tuners, they're too verbose: [ 5768.281801] cx88[0]: Calling XC2028/3028 callback [ 5768.287388] cx88[0]: Calling XC2028/3028 callback [ 5768.292575] cx88[0]: Calling XC2028/3028 callback [ 5768.299408] cx88[0]: Calling XC2028/3028 callback [ 5768.306244] cx88[0]: Calling XC2028/3028 callback ... and, most of the time, useless. So, disable them, except if core_debug modprobe parameter is used. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-cards.c | 29 ++++++++++++++++------------- drivers/media/pci/cx88/cx88-core.c | 12 +++++++----- drivers/media/pci/cx88/cx88.h | 2 ++ 3 files changed, 25 insertions(+), 18 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index 07b700a9ed7f..a87a0e19593e 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c @@ -59,6 +59,11 @@ MODULE_PARM_DESC(disable_ir, "Disable IR support"); #define err_printk(core, fmt, arg...) \ printk(KERN_ERR "%s: " fmt, core->name , ## arg) +#define dprintk(level,fmt, arg...) do { \ + if (cx88_core_debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, core->name , ## arg); \ + } while(0) + /* ------------------------------------------------------------------ */ /* board config info */ @@ -3134,7 +3139,7 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core, case XC2028_TUNER_RESET: switch (INPUT(core->input).type) { case CX88_RADIO: - info_printk(core, "setting GPIO to radio!\n"); + dprintk(1, "setting GPIO to radio!\n"); cx_write(MO_GP0_IO, 0x4ff); mdelay(250); cx_write(MO_GP2_IO, 0xff); @@ -3142,7 +3147,7 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core, break; case CX88_VMUX_DVB: /* Digital TV*/ default: /* Analog TV */ - info_printk(core, "setting GPIO to TV!\n"); + dprintk(1, "setting GPIO to TV!\n"); break; } cx_write(MO_GP1_IO, 0x101010); @@ -3200,8 +3205,7 @@ static int cx88_xc5000_tuner_callback(struct cx88_core *core, not having any tuning at all. */ return 0; } else { - err_printk(core, "xc5000: unknown tuner " - "callback command.\n"); + dprintk(1, "xc5000: unknown tuner callback command.\n"); return -EINVAL; } break; @@ -3212,8 +3216,7 @@ static int cx88_xc5000_tuner_callback(struct cx88_core *core, cx_set(MO_GP0_IO, 0x00000010); return 0; } else { - printk(KERN_ERR - "xc5000: unknown tuner callback command.\n"); + dprintk(1, "xc5000: unknown tuner callback command.\n"); return -EINVAL; } break; @@ -3243,13 +3246,13 @@ int cx88_tuner_callback(void *priv, int component, int command, int arg) switch (core->board.tuner_type) { case TUNER_XC2028: - info_printk(core, "Calling XC2028/3028 callback\n"); + dprintk(1, "Calling XC2028/3028 callback\n"); return cx88_xc2028_tuner_callback(core, command, arg); case TUNER_XC4000: - info_printk(core, "Calling XC4000 callback\n"); + dprintk(1, "Calling XC4000 callback\n"); return cx88_xc4000_tuner_callback(core, command, arg); case TUNER_XC5000: - info_printk(core, "Calling XC5000 callback\n"); + dprintk(1, "Calling XC5000 callback\n"); return cx88_xc5000_tuner_callback(core, command, arg); } err_printk(core, "Error: Calling callback for tuner %d\n", @@ -3590,8 +3593,8 @@ static void cx88_card_setup(struct cx88_core *core) memset(&xc2028_cfg, 0, sizeof(xc2028_cfg)); xc2028_cfg.tuner = TUNER_XC2028; xc2028_cfg.priv = &ctl; - info_printk(core, "Asking xc2028/3028 to load firmware %s\n", - ctl.fname); + dprintk(1, "Asking xc2028/3028 to load firmware %s\n", + ctl.fname); call_all(core, tuner, s_config, &xc2028_cfg); } call_all(core, core, s_power, 0); @@ -3760,8 +3763,8 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) if (radio[core->nr] != UNSET) core->board.radio_type = radio[core->nr]; - info_printk(core, "TV tuner type %d, Radio tuner type %d\n", - core->board.tuner_type, core->board.radio_type); + dprintk(1, "TV tuner type %d, Radio tuner type %d\n", + core->board.tuner_type, core->board.radio_type); /* init hardware */ cx88_reset(core); diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index 39f095c37ffd..c8f3dcc579d4 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -48,9 +48,9 @@ MODULE_LICENSE("GPL"); /* ------------------------------------------------------------------ */ -static unsigned int core_debug; -module_param(core_debug,int,0644); -MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); +unsigned int cx88_core_debug; +module_param_named(core_debug, cx88_core_debug, int, 0644); +MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); static unsigned int nicam; module_param(nicam,int,0644); @@ -60,8 +60,10 @@ static unsigned int nocomb; module_param(nocomb,int,0644); MODULE_PARM_DESC(nocomb,"disable comb filter"); -#define dprintk(level,fmt, arg...) if (core_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, core->name , ## arg) +#define dprintk(level,fmt, arg...) do { \ + if (cx88_core_debug >= level) \ + printk(KERN_DEBUG "%s: " fmt, core->name , ## arg); \ + } while(0) static unsigned int cx88_devcount; static LIST_HEAD(cx88_devlist); diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index 4e29c9deb684..51ce2c0e8bc1 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -618,6 +618,8 @@ struct cx8802_dev { /* ----------------------------------------------------------- */ /* cx88-core.c */ +extern unsigned int cx88_core_debug; + extern void cx88_print_irqbits(const char *name, const char *tag, const char *strings[], int len, u32 bits, u32 mask); -- cgit v1.2.3