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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 32bd7de..d1e6ba6 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index d1e6ba6..a221633 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index a221633..346c92a 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 346c92a..2f7c5ab 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 2f7c5ab..c1f6c59 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index c1f6c59..e13b777 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index e13b777..ea73dd4 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index ea73dd4..8ddf300 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 8ddf300..e7f6f57 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index e7f6f57..c214305 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index c214305..2ee2957 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 2ee2957..6d26123 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index aaedd11..26d2499 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index 885089e..0a3cb04 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 6d26123..9451e1e 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 9451e1e..197823c 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 197823c..f745617 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index f745617..86fd907 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 5f0b2c5..6a9e3e1 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 6a9e3e1..7dc27b5 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 26d2499..b2dcb3d 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 0a3cb04..8fd3c7f 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 54a03b20..9332d05 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 86fd907..48b937d 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 7dc27b5..a3c08ae7a 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index a3c08ae7a..4160a2a 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 48b937d..93fc620 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 8532c1d..4ffcafb 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 4ffcafb..ebe1ec6 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index ebe1ec6..b8e9946 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index b8e9946..b8a9bee 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index b8a9bee..1b90e75 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 4160a2a..90266a1 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 9332d05..f371dbe 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 1b90e75..3f0012c 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 90266a1..139dfe5 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 3f0012c..438cfbc 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index f371dbe..331d550 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 438cfbc..8d48177 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 139dfe5..77f600d 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 8d48177..6152423 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 77f600d..2d6d31a 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index f19cd73..44bfb88 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 44bfb88..daeee81 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index daeee81..2720b82 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 2720b82..0fbfae2 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 0fbfae2..9948fcb 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 v0.10.2 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 diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index d81dbb2..8896993 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 9948fcb..68a8818 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 68a8818..b6cdc44 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index b6cdc44..746adad 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 746adad..1c135aa 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 7c4e360..14e2610 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index a81ec2e..7200dfe 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 1c135aa..1859e9d 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 1859e9d..d04b52e 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 bf22e77..1a7dea2 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 331d550..4dcef9d 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-main.c b/drivers/media/usb/tlg2300/pd-main.c index 7b1f6eb..247d6ac 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 25eeb16..90dc1d1 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 90dc1d1..c4feffb 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index c4feffb..4c76e089 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index 5dd73b7..3a89128 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 4c76e089..719c3da 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index 3a89128..b26082a 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 719c3da..45b3d7a 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index b26082a..67ad065 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 247d6ac..e07e4c6 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 45b3d7a..854ffa0 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 854ffa0..80307d3 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index 80307d3..0f958f7 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index 67ad065..052cb0c 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 2172337..312809a 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 312809a..8ab2894 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index 052cb0c..55fe66e 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 8ab2894..da7cbd4 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index da7cbd4..122f299 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index 55fe66e..cb5cb0f 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 122f299..849c4bb 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 849c4bb..4c045b3 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index cb5cb0f..3010496 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 4c045b3..834428d 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 v0.10.2 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 diff --git a/drivers/media/usb/tlg2300/pd-common.h b/drivers/media/usb/tlg2300/pd-common.h index 3010496..9e23ad32 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 834428d..dab0ca3 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 v0.10.2 From a545e2ea149b9268c97228c6cd0288a4e1db310c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 7 Feb 2013 09:26:14 -0300 Subject: [media] tlg2300: update MAINTAINERS file Remove two maintainers: telegent.com no longer exists, so those email addresses are invalid as well. Added myself as co-maintainer and change the status to 'Odd Fixes'. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index e95b1e9..ff2fcc9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6864,9 +6864,8 @@ F: drivers/clocksource TLG2300 VIDEO4LINUX-2 DRIVER M: Huang Shijie -M: Kang Yong -M: Zhang Xiaobing -S: Supported +M: Hans Verkuil +S: Odd Fixes F: drivers/media/usb/tlg2300 SC1200 WDT DRIVER -- cgit v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index ccd18e4..cc7f58f 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index cc7f58f..b36d675 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 79a1124..6139ce2 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 4ee125b..b5996f9 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index b36d675..6e61dbd 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 6e61dbd..f6f2b00 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index f6f2b00..546a9f5 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 9ec0adb..528e03e 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 546a9f5..fb8ec0a 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index fb8ec0a..dbf18821 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index dbf18821..cffa8b6 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index cffa8b6..73404b7 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 v0.10.2 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 diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c index f7707e6..28b5121 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index c4c5917..682ed89 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 73404b7..8e0a44d 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 */ @@ -623,198 +634,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; @@ -1643,6 +1356,121 @@ static int bttv_s_ctrl(struct file *file, void *f, /* ----------------------------------------------------------------------- */ +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) { unsigned int outbits, data; @@ -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 528e03e..c3882ef 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 dcd6374..1d00ca9 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 8e0a44d..d34d271 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 c3882ef..288cfd8 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index d34d271..41de79b 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 288cfd8..12cc4eb 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 41de79b..46ead7d 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 12cc4eb..86d67bb 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index 682ed89..fa0faaa 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 v0.10.2 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 diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index e3b33b7..4c91b35 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 46ead7d..0fdaef2 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 0fdaef2..b5100da 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index b5100da..265263a 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 86d67bb..eb13be7 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 265263a..8610b6a 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 06376d9..ffeedcd 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index ffeedcd..1b29158 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 1b29158..2cd3112 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 2cd3112..a31f7dae 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index 7222079..4706ed3 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 a31f7dae..2b7b094 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 2b7b094..9593fd3 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 9593fd3..f3104f0 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index f3104f0..5389825 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index b4c99c7..b40360b 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 8d52956..d6acb1e 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 5389825..7be2e73 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 3e11462..53408ce 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 7be2e73..26d2a4f 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 53408ce..4c83ff5 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 28688db..a4091dd 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 26d2a4f..ae27c82 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index a4091dd..15dd334 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 ae27c82..8d49640 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 8d49640..b0cd699 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 4c83ff5..c17889d 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index b0cd699..b6cde46 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 15dd334..ac15a55 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index ac15a55..be8f7481 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 b6cde46..c199eae 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 c17889d..efc0d1c 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index be8f7481..cbdc141 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index cbdc141..2c05c8f 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 2c05c8f..567d7ab 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 c199eae..bdaa5e0 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 efc0d1c..6130e4f 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 567d7ab..49c842a 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 6130e4f..0f92fd1 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index 46e3892..1340ff2 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index d6acb1e..7094451 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index bdaa5e0..41c5c99 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 7094451..62d104b 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index b40360b..81a1d97 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 4706ed3..3f26f64 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 62d104b..b7b1acd7 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 05358d4..4ba3ce0 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 7473c33..d7308ab 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index 3f26f64..2e51fb9 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 0f92fd1..a8e50d2d 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 v0.10.2 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 diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 4cbab08..b2a5ee4 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 v0.10.2 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 diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index b2a5ee4..e9dbe23 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 v0.10.2 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 diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index e9dbe23..eaf152c 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 9f67366..49ebe85 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 v0.10.2 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 diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index eaf152c..f1cf906 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 49ebe85..901f0df 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 v0.10.2 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 diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index f1cf906..49a4dfd 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 v0.10.2 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 diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 49a4dfd..c073666 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 901f0df..2156320 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 v0.10.2 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 diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index c073666..a00edf3 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 v0.10.2 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 diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index a00edf3..bb52457 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 v0.10.2 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 diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index bb52457..2f1a09d 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 2156320..03550cf 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 v0.10.2 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 diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 2f1a09d..a8fdbaf 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 03550cf..9bbfa3d 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 v0.10.2 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 diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index a8fdbaf..45d73e2 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 v0.10.2 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 diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 45d73e2..c43c8d3 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 v0.10.2 From 53bf0f446bc387eabdd535dca080789cc74607f4 Mon Sep 17 00:00:00 2001 From: Kamil Debski Date: Fri, 25 Jan 2013 06:29:56 -0300 Subject: [media] v4l: Define video buffer flag for the COPY timestamp type Define video buffer flag for the COPY timestamp. In this case the timestamp value is copied from the OUTPUT to the corresponding CAPTURE buffer. 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 diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index e6c5855..2c4c068 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -1145,6 +1145,12 @@ in which case caches have not been used. same clock outside V4L2, use clock_gettime(2) . + + V4L2_BUF_FLAG_TIMESTAMP_COPY + 0x4000 + The CAPTURE buffer timestamp has been taken from the + corresponding OUTPUT buffer. This flag applies only to mem2mem devices. + diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 234d1d8..b5f5cdd 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -705,6 +705,7 @@ struct v4l2_buffer { #define V4L2_BUF_FLAG_TIMESTAMP_MASK 0xe000 #define V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN 0x0000 #define V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC 0x2000 +#define V4L2_BUF_FLAG_TIMESTAMP_COPY 0x4000 /** * struct v4l2_exportbuffer - export of video buffer as DMABUF file descriptor -- cgit v0.10.2 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 diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 5f209d5..8ffe42a 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 5e6b0ca..9f9f2c1 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 5892d2b..1943e41 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 dd249c9..5477c2c 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 a55793c..e91f350 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 f553cc2..87b6842 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 bfc4206..47fbf7b 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 e84703c..92c6bf1 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 82dbf99..c314ff9 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 ffba7d9..048c26a 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 f5cbb92..2c3bd69 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 bb08a46..973e72b 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 8a33a71..c46d2e8 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 5ec15cb..77bbf78 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 6694f9e..5307a63 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 6c233a5..cd962be 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 db1235d..be04481 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 9cfd4ee..a2d4274 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 v0.10.2 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 diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index e91f350..70438a0 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index aaaf276..14d663d 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 v0.10.2 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 diff --git a/drivers/media/usb/gspca/sonixj.c b/drivers/media/usb/gspca/sonixj.c index 671d0c6..8246e1d 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 v0.10.2 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 diff --git a/drivers/media/usb/gspca/gl860/gl860.c b/drivers/media/usb/gspca/gl860/gl860.c index ced3b71..96d9c28 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 v0.10.2 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 diff --git a/drivers/media/usb/gspca/m5602/m5602_bridge.h b/drivers/media/usb/gspca/m5602/m5602_bridge.h index 51af3ee..19eb1a6 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 ed22638..907a968 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 6268aa2..b5f6692 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 8c672b5..07448d3 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 9a14835..3bbe3ad5 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 2b6a13b..6fece1c 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 2114a8b..e2fe2f9 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 f7aa5bf..f9f5870 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 b877169..1890862 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 81a2bcb..a6ab761 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 c8e1572..42ffaf0 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 8e0035e..9953e97 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 1de743a..69ee6e2 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 7995224..d61b918 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 edff4f1..48341b4 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 v0.10.2 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 diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c index 104ae25..3fe207e 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 v0.10.2 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 diff --git a/drivers/media/usb/gspca/autogain_functions.h b/drivers/media/usb/gspca/autogain_functions.h deleted file mode 100644 index d625eaf..0000000 --- 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 v0.10.2 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 diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 3564bdb..5784ff4 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 5559932..ac62cd3 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 v0.10.2 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 diff --git a/drivers/media/usb/gspca/benq.c b/drivers/media/usb/gspca/benq.c index 352f321..05f406dea 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 c9052f2..38714df 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 1dcdd9f..064b530 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 38f68e1..948a635 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 96d9c28..cb1e64c 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 5784ff4..5800d65 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 ac62cd3..c3af321 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 1ba29fe..8da3dde 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 61e25db..39c96bb 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 907a968..d926e62 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 b5f6692..cfa4663 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 3bbe3ad5..4ac7889 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 e2fe2f9..59bc62b 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 1890862..4bf5c43 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 42ffaf0..7d12599 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 69ee6e2..7cbc3a0 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 8f4714d..68bb2f3 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 9ad19a7..a3958ee 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 bb09d78..2e28c81 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 3b75097..83519be 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 add6f72..682ef33 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 a12dfbf..1a5bdc8 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 8462a7c..fbc5e22 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 03fa3fd..39b6b2e 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 8246e1d..3b5ccb1 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 14d6352..688592b 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 25cb68d..9f8bf51 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 3b7f777..d92fd17 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 bc7d67c..232b330 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 1286b41..75f2beb 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 d1db3d8..403d71c 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 1d99f10..a7ae0ec 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 410cdcb..acb19fb 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 7e8748b..b10d082 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 6760527..9c08276 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 657160b..55ee7a6 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 06fa54c5e..2220b70 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 cdfc3d0..8206b77 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 8a57990..515a9e1 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 e95fa89..bf3e5c3 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 9ccfcb1..af8767a 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 e500795..c00ac57 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 9e3a909..2165da0 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 a8dc421..cbfc2f9 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 v0.10.2 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 diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c index 84b7b9f..fe0a4f8 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 v0.10.2 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 diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index b1f844c..09cfbc3 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 v0.10.2 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 diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 498c57e..2dcb29b 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 1d00ca9..7eab0b9 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 v0.10.2 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 diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 2dcb29b..42c3afe 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 v0.10.2 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 diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 42c3afe..55c972a 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 v0.10.2 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 diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 55c972a..9cb8325 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 v0.10.2 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 diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 9cb8325..88f728d 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 v0.10.2 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 diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 88f728d..a16bc6c 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 v0.10.2 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 diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index a16bc6c..9693eb9 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 v0.10.2 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 diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 9693eb9..eaae9d1 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 v0.10.2 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 diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index eaae9d1..59d40e6 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 v0.10.2 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 diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 59d40e6..cd06f3c 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 @@ -430,6 +425,11 @@ static const struct s2255_fmt formats[] = { .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, .depth = 8 -- cgit v0.10.2 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 diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index cd06f3c..2bd8613 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index d98387a..3d128a5 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c index 04207a7..01c7121 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-i2c.c b/drivers/media/pci/bt8xx/bttv-i2c.c index c63c643..b7c52dc 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 01c7121..f368213 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 eb13be7..e7910e0 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 41c5c99..ac62008 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index f11cc42..d3cb8d5 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 v0.10.2 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 diff --git a/drivers/media/platform/timblogiw.c b/drivers/media/platform/timblogiw.c index c3a2a44..2d91eeb 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c index f36eeef..56d470a 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 9578a67..24cfd4b 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 v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h index f5e46e8..b3c6190 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 v0.10.2 From 4d35435d3ffb853b491f5bb21a62529cd925d660 Mon Sep 17 00:00:00 2001 From: Ismael Luceno Date: Thu, 21 Feb 2013 18:53:58 -0300 Subject: [media] solo6x10: Maintainer change Signed-off-by: Ismael Luceno Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index ff2fcc9..c530544 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7600,8 +7600,8 @@ S: Odd Fixes F: drivers/staging/sm7xxfb/ STAGING - SOFTLOGIC 6x10 MPEG CODEC -M: Ben Collins -S: Odd Fixes +M: Ismael Luceno +S: Supported F: drivers/staging/media/solo6x10/ STAGING - SPEAKUP CONSOLE SPEECH DRIVER -- cgit v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index f30c58c..96804be 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 v0.10.2 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 diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index 5c61935..73195fe 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index 3cac8bd..42801f8 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 5716662..74c911f 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index b86d0f2..2fa7c6e 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 533637d..3a6f3ad 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index d3cb8d5..66f6519 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 29f3eec..6d098a9 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index a20d691..85ba246 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 c1a4273..8f426d9 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index 85ba246..2e76274 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 v0.10.2 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 diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c index df16380..ef75abe 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 83c7ed7..cae4f46 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 2547bf8..9689a6e 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 1507c9d..8ae8442d 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 8ead492..31b955b 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 1842e64..9565dcc 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 v0.10.2 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 diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c index 05b94aa..9ff1230 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 v0.10.2 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 diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c index 0945173..878d2c4 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb/cinergyT2-fe.c b/drivers/media/usb/dvb-usb/cinergyT2-fe.c index 1efc028..c890fe4 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 v0.10.2 From c937ca034a033a228e9f66bfda02d5037b08180e Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Wed, 27 Feb 2013 10:37:39 -0300 Subject: [media] MAINTAINERS: Add maintainer entry for si4713 FM transmitter driver Add maintainer entry for the files composing si4713 FM transmitter driver. Signed-off-by: Eduardo Valentin Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index c530544..a4ae440 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7112,6 +7112,22 @@ F: drivers/media/radio/si470x/radio-si470x-common.c F: drivers/media/radio/si470x/radio-si470x.h F: drivers/media/radio/si470x/radio-si470x-usb.c +SI4713 FM RADIO TRANSMITTER I2C DRIVER +M: Eduardo Valentin +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +W: http://linuxtv.org +S: Odd Fixes +F: drivers/media/radio/si4713-i2c.? + +SI4713 FM RADIO TRANSMITTER PLATFORM DRIVER +M: Eduardo Valentin +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +W: http://linuxtv.org +S: Odd Fixes +F: drivers/media/radio/radio-si4713.h + SH_VEU V4L2 MEM2MEM DRIVER M: Guennadi Liakhovetski L: linux-media@vger.kernel.org -- cgit v0.10.2 From a2262508cba04587dbb0793ddf23be57f86dc583 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Thu, 28 Feb 2013 03:08:02 -0300 Subject: [media] drivers/staging/media/as102: using ccflags-y instead of EXTRA_FLAGS in Makefile need using ccflags-y instead of EXTRA_CFLAGS can reference scripts/checkpatch.pl (1755..1766) when make EXTRA_CFLAGS=-W, the compiling issue will be occured. Signed-off-by: Chen Gang Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/as102/Makefile b/drivers/staging/media/as102/Makefile index d8dfb75..8916d8a 100644 --- a/drivers/staging/media/as102/Makefile +++ b/drivers/staging/media/as102/Makefile @@ -3,4 +3,4 @@ dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \ obj-$(CONFIG_DVB_AS102) += dvb-as102.o -EXTRA_CFLAGS += -Idrivers/media/dvb-core +ccflags-y += -Idrivers/media/dvb-core -- cgit v0.10.2 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 diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index 2e51fb9..235ba65 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 b7b1acd7..13249e5 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 a8e50d2d..dff3f1d 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 v0.10.2 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 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 754bfbc..5708fc3 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 v0.10.2 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 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 13877808..ad4f1df 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 v0.10.2 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 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 beb6dba..33de88b 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 v0.10.2 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 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 f61dba8..c7ad329 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 v0.10.2 From c368360beb8269774e9bac99510db12a4276c1d6 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Sat, 2 Mar 2013 21:53:42 -0300 Subject: [media] MAINTAINERS: fix drivers/media/i2c/cx2341x.c This file was moved to drivers/media/common/ by commit 6259582 ([media] cx2341x: move from media/i2c to media/common). Signed-off-by: Cesar Eduardo Barros Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index a4ae440..8492eb7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2290,7 +2290,7 @@ L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git W: http://linuxtv.org S: Maintained -F: drivers/media/i2c/cx2341x* +F: drivers/media/common/cx2341x* F: include/media/cx2341x* CX88 VIDEO4LINUX DRIVER -- cgit v0.10.2 From e42bf501776c2ae2dc6eb8cce95573bcbc3edd2c Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Sat, 2 Mar 2013 21:53:47 -0300 Subject: [media] MAINTAINERS: fix Documentation/video4linux/saa7134/ That directory never existed. The intention was probably to match CARDLIST.saa7134 and README.saa7134. Signed-off-by: Cesar Eduardo Barros Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index 8492eb7..2e81d5f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6771,7 +6771,7 @@ L: linux-media@vger.kernel.org W: http://linuxtv.org T: git git://linuxtv.org/media_tree.git S: Odd fixes -F: Documentation/video4linux/saa7134/ +F: Documentation/video4linux/*.saa7134 F: drivers/media/pci/saa7134/ SAA7146 VIDEO4LINUX-2 DRIVER -- cgit v0.10.2 From 445ba89f1cbdb3058e83e6727bb249d1cb48b582 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Sat, 2 Mar 2013 21:53:48 -0300 Subject: [media] MAINTAINERS: remove include/media/sh_veu.h Apparently a copy-paste mistake; the similar sh_vou.h exists, and both were added to MAINTAINERS by commit b618b69 ([media] MAINTAINERS: add entries for sh_veu and sh_vou V4L2 drivers). Signed-off-by: Cesar Eduardo Barros Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index 2e81d5f..bfeb235 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7133,7 +7133,6 @@ M: Guennadi Liakhovetski L: linux-media@vger.kernel.org S: Maintained F: drivers/media/platform/sh_veu.c -F: include/media/sh_veu.h SH_VOU V4L2 OUTPUT DRIVER M: Guennadi Liakhovetski -- cgit v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index 92afeb2..79b31ae 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 v0.10.2 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 diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 05d7b63..42c62aa 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 976d029..8c05565 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 4dcef9d..d81f7ee 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 7200dfe..98b95be 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 6152423..9086e57 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 1bef990..466b19d 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 2d6d31a..5de7b6c 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index d81f7ee..16ab4d7 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 5de7b6c..43eb1c6 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 16ab4d7..6e62b72 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 9086e57..d4a48cb 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 43eb1c6..f6ac1df 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 93fc620..d585c19 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index d4a48cb..de9b208 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 v0.10.2 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 diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 6e50a75..d0d193d 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 v0.10.2 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 diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index d0d193d..eaa0a74 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,70 +1608,86 @@ 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-audio-upstream.c b/drivers/media/pci/cx25821/cx25821-audio-upstream.c index 87491ca..ea97320 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 v0.10.2 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 diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index 023b2a1..fb0f046 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 f6caafc..3446af2 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 v0.10.2 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 diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index d01fcb7..99b80b6 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 v0.10.2 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 diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index da99cf7..27ddb3d 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 v0.10.2 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 diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 27ddb3d..66f599f 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 v0.10.2 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 diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index 3f12865..c591814 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 c754a80..ca5ee6a 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 6e62b72..46fff5c 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 98b95be..42a6a26 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 f6ac1df..4c667fd 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 v0.10.2 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 diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 1b37fe2..842bdcd 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 v0.10.2 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 diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 842bdcd..ec655b8 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 v0.10.2 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 diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index ec655b8..12167a6 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 v0.10.2 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 diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index d319717..71641b2 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 v0.10.2 From fc3a62e9f5ff5585ad9b9c27c2b800338aa3f751 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Mar 2013 15:15:59 -0300 Subject: [media] em28xx: update cardlist There's one missing USB ID at the card list. Add it. Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index c591814..e818644 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -76,7 +76,7 @@ 76 -> KWorld PlusTV 340U or UB435-Q (ATSC) (em2870) [1b80:a340] 77 -> EM2874 Leadership ISDBT (em2874) 78 -> PCTV nanoStick T2 290e (em28174) - 79 -> Terratec Cinergy H5 (em2884) [0ccd:10a2,0ccd:10ad] + 79 -> Terratec Cinergy H5 (em2884) [0ccd:10a2,0ccd:10ad,0ccd:10b6] 80 -> PCTV DVB-S2 Stick (460e) (em28174) 81 -> Hauppauge WinTV HVR 930C (em2884) [2040:1605] 82 -> Terratec Cinergy HTC Stick (em2884) [0ccd:00b2] -- cgit v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 96804be..b3fd0ff 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 v0.10.2 From e76d4ce49f574b6d94324239f8b7d655774d062c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= 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 diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 759a40a..a92b8c5 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 v0.10.2 From 40fc5325e1b6764754116cc36dd34adfb964ef65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= 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 diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index a92b8c5..f304792 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 24cfd4b..d5957b0 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 v0.10.2 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 diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 537f6b4..7995eeb 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 v0.10.2 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 diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 7995eeb..d7a08bc4 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 v0.10.2 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 diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index d7a08bc4..7406de9 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 v0.10.2 From 4bd3bb7129ac9a0ee3ba4b587c228f5f43b841cd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 14:51:23 -0300 Subject: [media] davinci_vpfe: fix copy-paste errors in several comments This removes some incorrect dv_preset references left over from copy-and-paste errors. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c index 99ccbebe..19dc5b0 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c @@ -1016,12 +1016,12 @@ vpfe_query_dv_timings(struct file *file, void *fh, } /* - * vpfe_s_dv_timings() - set dv_preset on external subdev + * vpfe_s_dv_timings() - set dv_timings on external subdev * @file: file pointer * @priv: void pointer * @timings: pointer to v4l2_dv_timings structure * - * set dv_timings pointed by preset on external subdev through + * set dv_timings pointed by timings on external subdev through * v4l2_device_call_until_err, this configures amplifier also * * Return 0 on success, error code otherwise @@ -1042,12 +1042,12 @@ vpfe_s_dv_timings(struct file *file, void *fh, } /* - * vpfe_g_dv_timings() - get dv_preset which is set on external subdev + * vpfe_g_dv_timings() - get dv_timings which is set on external subdev * @file: file pointer * @priv: void pointer * @timings: pointer to v4l2_dv_timings structure * - * get dv_preset which is set on external subdev through + * get dv_timings which is set on external subdev through * v4l2_subdev_call * * Return 0 on success, error code otherwise @@ -1423,7 +1423,7 @@ static int vpfe_dqbuf(struct file *file, void *priv, } /* - * vpfe_streamon() - get dv_preset which is set on external subdev + * vpfe_streamon() - start streaming * @file: file pointer * @priv: void pointer * @buf_type: enum v4l2_buf_type @@ -1472,7 +1472,7 @@ static int vpfe_streamon(struct file *file, void *priv, } /* - * vpfe_streamoff() - get dv_preset which is set on external subdev + * vpfe_streamoff() - stop streaming * @file: file pointer * @priv: void pointer * @buf_type: enum v4l2_buf_type -- cgit v0.10.2 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 diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 71735e7..a021800 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 db1dd92..ee0e994 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 4ca0f9a..2a49f00 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 9f9f2c1..8290fdd 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 bdbebd5..9546d26 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 9b85396..05dbe0b 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 v0.10.2 From 20a005a62a2497552ccd2dc3782814093facc6c8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 15:10:45 -0300 Subject: [media] davinci: replace V4L2_OUT_CAP_CUSTOM_TIMINGS by V4L2_OUT_CAP_DV_TIMINGS The use of V4L2_OUT_CAP_CUSTOM_TIMINGS is deprecated, use DV_TIMINGS instead. Note that V4L2_OUT_CAP_CUSTOM_TIMINGS is just a #define for V4L2_OUT_CAP_DV_TIMINGS. At some point in the future these CUSTOM_TIMINGS defines might be removed. Signed-off-by: Hans Verkuil Acked-by: Lad, Prabhakar Acked-by: Sekhar Nori Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index de7adff..fc4871a 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -514,7 +514,7 @@ static const struct vpif_output dm6467_ch0_outputs[] = { .index = 1, .name = "Component", .type = V4L2_OUTPUT_TYPE_ANALOG, - .capabilities = V4L2_OUT_CAP_CUSTOM_TIMINGS, + .capabilities = V4L2_OUT_CAP_DV_TIMINGS, }, .subdev_name = "adv7343", .output_route = ADV7343_COMPONENT_ID, -- cgit v0.10.2 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 diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 28d019d..70facc0 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 v0.10.2 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 diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 8290fdd..30976dc 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 v0.10.2 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 diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 70facc0..3d1af67 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 v0.10.2 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 diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c index 318e805..971d639 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 90370e4..2b0aca5 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 3e178eb..852e96c 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 v0.10.2 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 diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c index 4277e4a..2364dba 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 d6d2ef0..2e1946e 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 5050f92..abc3ae3 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 aa69a46..3993aec 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 adf2fe4..c669a9f 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 v0.10.2 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 diff --git a/arch/blackfin/mach-bf609/boards/ezkit.c b/arch/blackfin/mach-bf609/boards/ezkit.c index 61c1f47..97d7016 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 8ffe42a..476cfc8 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 v0.10.2 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 diff --git a/drivers/media/platform/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c index 12ad17c..396a51c 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 9546d26..f15f211 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 v0.10.2 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 diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 680c781..8ee2e92 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 9565dcc..3b2fc87 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 c592ae0..a6d29a2 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index a6d29a2..62f05e8 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 v0.10.2 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 diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 8ee2e92..b22b61d 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 3b2fc87..804eb32 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 62f05e8..f2510f5 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index f2510f5..4a0a763 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 804eb32..bc15dce 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 4a0a763..0078fef 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 aa77e54..57f3560 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 de2c102..2050e4c 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index 0078fef..fc451e2 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index bc15dce..1dab4b6 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 v0.10.2 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 diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h index d8cdf75..9f1861a 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 v0.10.2 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 diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index 2050e4c..a31bf74 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 1dab4b6..7b5d81a 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 fc451e2..f1440a5 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 7b5d81a..d489701c 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 f1440a5..91db853 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index d489701c..5034153 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 5034153..7302f95 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 v0.10.2 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 diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index b22b61d..04bb04c 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 7302f95..ba73293 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 91db853..8af94c4 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index ba73293..67d0319 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index 57f3560..f4fd670 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index f4fd670..4900aa9 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index 4900aa9..864f53e 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index 8af94c4..7925c04 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 864f53e..dbb807e 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 v0.10.2 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 diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 04bb04c..bb6e558 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 9f1861a..c63b544 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 15d3493..c96da47 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 a31bf74..751c0d6 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 67d0319..6b53367 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -825,6 +825,57 @@ static int smscore_init_ir(struct smscore_device_t *coredev) } /** + * 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 * * @param coredev pointer to a coredev object returned by @@ -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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 6b53367..9379ea7 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1279,6 +1279,42 @@ static char *smscore_get_fw_filename(struct smscore_device_t *coredev, } /** + * 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 9379ea7..8c576a6 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 dbb807e..6335574 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 c96da47..8834c43 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 751c0d6..acd3d1e 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index 6335574..1d6b8df 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index 1d6b8df..04544f5 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index 04544f5..a5f5272 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index a5f5272..70ea3e9 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb.c b/drivers/media/common/siano/smsdvb.c index 70ea3e9..aeadd8a 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 v0.10.2 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 diff --git a/drivers/media/common/siano/Kconfig b/drivers/media/common/siano/Kconfig index 68f0f60..f3f5ec4 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 81b1e98..4c0567f 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 7925c04..53b81cb 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 0000000..4d5dd47 --- /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 0000000..c14f10d --- /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 aeadd8a..0000000 --- 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 0000000..09982bc --- /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 acd3d1e..def5e41 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index 4d5dd47..59c7323 100644 --- a/drivers/media/common/siano/smsdvb-debugfs.c +++ b/drivers/media/common/siano/smsdvb-debugfs.c @@ -166,6 +166,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, "IsDemodLocked = %d\t", p->IsDemodLocked); @@ -251,6 +256,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, "IsDemodLocked = %d\t", p->IsDemodLocked); -- cgit v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index c14f10d..4242005 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 09982bc..3422069 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index 4242005..90f6e89 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index 90f6e89..632a250 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index 632a250..d83896b 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index d83896b..4393c68 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 3422069..63cdd75 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index 4393c68..c53cb4e 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c index 59c7323..0219be3 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 8c576a6..9b2f2b4 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 9b2f2b4..44040a6 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 44040a6..d57df91 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index d57df91..c04d826 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 v0.10.2 From beb91d461ba19c47ce42a8ff5b3e5be39be10473 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Mar 2013 12:42:45 -0300 Subject: [media] siano: add a MAINTAINERS entry for it Nobody is maintaining this driver. The project started by a developer that used to work at Hauppauge. A Siano developer assumed its maintainership after that, but he left the company. Another Siano developer sent several patches updating it, but, after upstream feedback, it seems he gave up merging the driver, as he never answered back to the received feedbacks. As I have a few siano devices here that work with ISDB-T, I can help to keep it into a good shape. So, better to take its maintainership. I don't have any siano SDIO setup here, trough. So, I'll just apply without any test any patch that looks sane and touches only drivers/media/mmc/siano. So, let's tag it as "Odd fixes". Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index bfeb235..7f6dec5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7128,6 +7128,17 @@ W: http://linuxtv.org S: Odd Fixes F: drivers/media/radio/radio-si4713.h +SIANO DVB DRIVER +M: Mauro Carvalho Chehab +L: linux-media@vger.kernel.org +W: http://linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Odd fixes +F: drivers/media/common/siano/ +F: drivers/media/dvb/siano/ +F: drivers/media/usb/siano/ +F: drivers/media/mmc/siano + SH_VEU V4L2 MEM2MEM DRIVER M: Guennadi Liakhovetski L: linux-media@vger.kernel.org -- cgit v0.10.2 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 diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index def5e41..01a0f39 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index c04d826..92eea54 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 c53cb4e..a2882f5 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 92eea54..b5e40aa 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 v0.10.2 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 diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index bb6e558..6680134 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 b5e40aa..b7aa63f 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 53b81cb..a9672e0 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index b7aa63f..5006d1c 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 a9672e0..bb74246 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 v0.10.2 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 diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 6680134..9bd7aa1 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 5006d1c..e5fa4056 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 bb74246..4b0cd7d 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 0219be3..5a28506 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 a2882f5..cec85fe 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 63cdd75..e1ff07c 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 e2657c2..32a7b28 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 8834c43..912c281 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 01a0f39..3a290f1 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index 4b0cd7d..b65232a 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 5a28506..f63121c 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 cec85fe..29d1c41 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 e1ff07c..513f853 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index b65232a..b0253d2 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 v0.10.2 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 diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 9bd7aa1..8276999 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 e5fa4056..19e7a5f 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 b0253d2..d3e781f 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 f63121c..a881da5 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 29d1c41..d965a7a 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 513f853..92c413b 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 32a7b28..bfe831c 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 3a290f1..03761c6 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 19e7a5f..e7fc4de 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 d3e781f..d0799e3 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 a881da5..4c5691e 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index e7fc4de..ebb9ece 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 4c5691e..0bb4430 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index c2fc7da0d..0e40832 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 0e40832..8c4de7c 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 d18a896..b8424f1 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 23e16c1..761613f 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 8c4de7c..6e25053 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 6e25053..fc93bd3 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 v0.10.2 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 diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index eaa0a74..57601c0 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 v0.10.2 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 diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index be04481..70827fe 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 10beaee..ae35d25 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 25c3b36..952776f 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 a47fd4f..313d977 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 a2d4274..d88a098 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 v0.10.2 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 diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c index 952776f..59522b2 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 v0.10.2 From 70b8ff3c3d454aa5fd8b478fd829b6bd3a4345db Mon Sep 17 00:00:00 2001 From: Ismael Luceno Date: Sat, 9 Mar 2013 03:25:07 -0300 Subject: [media] solo6x10: Update TODO (maintainer change) Signed-off-by: Ismael Luceno Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/TODO b/drivers/staging/media/solo6x10/TODO index 539f739..d09dd03 100644 --- a/drivers/staging/media/solo6x10/TODO +++ b/drivers/staging/media/solo6x10/TODO @@ -20,5 +20,5 @@ TODO (general): - implement loopback of external sound jack with incoming audio? - implement pause/resume -Plase send patches to Mauro Carvalho Chehab and Cc Ben Collins - +Please send patches to the linux media list and +Cc Ismael Luceno . -- cgit v0.10.2 From 01c8132303ea5ea237cdc85ae7f144f62747910b Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghiu Date: Sun, 10 Mar 2013 08:14:53 -0300 Subject: [media] Drivers: staging: media: davinci_vpfe: Use resource_size function Use resource_size function on resource object instead of explicit computation. Signed-off-by: Alexandru Gheorghiu Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c index c8cae51..b2f4ef8 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c +++ b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c @@ -1065,7 +1065,6 @@ vpfe_ipipeif_cleanup(struct vpfe_ipipeif_device *ipipeif, iounmap(ipipeif->ipipeif_base_addr); res = platform_get_resource(pdev, IORESOURCE_MEM, 3); if (res) - release_mem_region(res->start, - res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); } -- cgit v0.10.2 From 18ace0e27395423b40352ff24c7792f4c0313e24 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 5 Mar 2013 07:52:14 -0300 Subject: [media] davinci_vpfe: Use module_platform_driver macro module_platform_driver() eliminates the boilerplate and simplifies the code. Signed-off-by: Sachin Kamat Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c index 7b35171..c7ae7d7 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c @@ -719,22 +719,4 @@ static struct platform_driver vpfe_driver = { .remove = vpfe_remove, }; -/** - * vpfe_init : This function registers device driver - */ -static __init int vpfe_init(void) -{ - /* Register driver to the kernel */ - return platform_driver_register(&vpfe_driver); -} - -/** - * vpfe_cleanup : This function un-registers device driver - */ -static void vpfe_cleanup(void) -{ - platform_driver_unregister(&vpfe_driver); -} - -module_init(vpfe_init); -module_exit(vpfe_cleanup); +module_platform_driver(vpfe_driver); -- cgit v0.10.2 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 diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 7b771ba..ec07ceb 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 e747524..3ca60c7 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 0000000..980ec51 --- /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 b5996f9..c259b36 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 v0.10.2 From e64171b97b88a1adf297d429826fdbb9e232ab53 Mon Sep 17 00:00:00 2001 From: Manjunath Hadli Date: Thu, 7 Feb 2013 13:48:51 -0300 Subject: [media] media: add support for decoder as one of media entity types A lot of SOCs including Texas Instruments Davinci family mainly use video decoders as input devices. This patch adds a flag 'MEDIA_ENT_T_V4L2_SUBDEV_DECODER' media entity type for decoder's. Along side updates the documentation for this media entity type. Signed-off-by: Manjunath Hadli Signed-off-by: Lad, Prabhakar Reviewed-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml index 576b68b..116c301 100644 --- a/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml +++ b/Documentation/DocBook/media/v4l/media-ioc-enum-entities.xml @@ -272,6 +272,16 @@ MEDIA_ENT_T_V4L2_SUBDEV_LENS Lens controller + + MEDIA_ENT_T_V4L2_SUBDEV_DECODER + Video decoder, the basic function of the video decoder is to + accept analogue video from a wide variety of sources such as + broadcast, DVD players, cameras and video cassette recorders, in + either NTSC, PAL or HD format and still occasionally SECAM, separate + it into its component parts, luminance and chrominance, and output + it in some digital video standard, with appropriate embedded timing + signals. + diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index 0ef8833..ed49574 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -56,6 +56,8 @@ struct media_device_info { #define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENT_T_V4L2_SUBDEV + 1) #define MEDIA_ENT_T_V4L2_SUBDEV_FLASH (MEDIA_ENT_T_V4L2_SUBDEV + 2) #define MEDIA_ENT_T_V4L2_SUBDEV_LENS (MEDIA_ENT_T_V4L2_SUBDEV + 3) +/* A converter of analogue video to its digital representation. */ +#define MEDIA_ENT_T_V4L2_SUBDEV_DECODER (MEDIA_ENT_T_V4L2_SUBDEV + 4) #define MEDIA_ENT_FL_DEFAULT (1 << 0) -- cgit v0.10.2 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 diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index aa94ebc..ab8f3fe 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 */ @@ -200,6 +211,21 @@ static struct tvp514x_reg tvp514x_reg_list_default[] = { }; /** + * 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 - * * Currently supports two standards only, need to add support for rest of the @@ -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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 6f809a7..0e2ec6f 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 v0.10.2 From cbaa5c54cb73897ed6c2544a60ed52aa3215b0f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Th=C3=A9baudeau?= 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 diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index bbc4ff9..0b0ebaa 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 v0.10.2 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 diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index 0b0ebaa..2902ba6 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 v0.10.2 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 diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index a5e65d6..53eaf899 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 v0.10.2 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 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 973e72b..d7294ef 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 v0.10.2 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 diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c index 42c559e..09cb4fc 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 v0.10.2 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 diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index 395e2e0..42abbce 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 v0.10.2 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 diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index cb54c69..362d88e 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 v0.10.2 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 diff --git a/drivers/media/platform/soc_camera/mx1_camera.c b/drivers/media/platform/soc_camera/mx1_camera.c index 25b2a28..4389f43 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 v0.10.2 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 diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index 362d88e..0b32cc3 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 v0.10.2 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 diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 66c8da1..d853162 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 v0.10.2 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 diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig index 6dff2b7..23d352f 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 v0.10.2 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 diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index d6be1b6..5cd09a6 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 v0.10.2 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 diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 96c4a17..477268a 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 v0.10.2 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 diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index dec203b..178b946 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 v0.10.2 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 diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 178b946..b8f9f85 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 v0.10.2 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 diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index e8fdf71..ffabd66 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 5e569b1..f136a6d 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 0000000..6ee4f97 --- /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 0000000..3583e56 --- /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 0000000..e4a0136 --- /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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index c9cad989..dece775 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 82bd8c1..53fd304 100644 --- a/drivers/media/dvb-frontends/af9033.h +++ b/drivers/media/dvb-frontends/af9033.h @@ -36,6 +36,13 @@ struct af9033_config { u32 clock; /* + * ADC multiplier + */ +#define AF9033_ADC_MULTIPLIER_1X 0 +#define AF9033_ADC_MULTIPLIER_2X 1 + u8 adc_multiplier; + + /* * tuner */ #define AF9033_TUNER_TUA9001 0x27 /* Infineon TUA 9001 */ @@ -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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 692224d..2d4abfa 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 66f6519..f43e83c 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 6d098a9..1b2f69f 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index f43e83c..2c5b01d 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 1b2f69f..4465f85 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 2c5b01d..1a4aeef 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 2fa7c6e..d556042 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 1a4aeef..ad66ac4 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index 4465f85..f126eea 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index ad66ac4..3f00f0b 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 3f00f0b..44a1196 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 f126eea..7e49e1a 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 44a1196..f4f3a21 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index dece775..f510228 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index f4f3a21..5c025f6 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,63 +349,14 @@ 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! * * byte 0: MCS 51 core @@ -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 7e49e1a..2f7d269 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 v0.10.2 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 diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 6ee4f97..f1938a1 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 v0.10.2 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 diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index f1938a1..6eb3afa 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 v0.10.2 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 diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 6eb3afa..82cc053 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 v0.10.2 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 diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 82cc053..de20da1 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 v0.10.2 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 diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index de20da1..66d4b72 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 3583e56..12dd36b 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 5c025f6..ce8cccb 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 v0.10.2 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 diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 66d4b72..6ae9d5a 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 e4a0136..315ff6c 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 v0.10.2 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 diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 6ae9d5a..1cb9709 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 315ff6c..1491bf8 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 v0.10.2 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 diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 1cb9709..66e003f 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index f510228..23690aa 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 e9bd782..0808319 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 v0.10.2 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 diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c index 66e003f..ec4964c 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 1491bf8..7d0e292 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index ce8cccb..75d99ae 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 75d99ae..1ccc9ce 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 1ccc9ce..3efb79a 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 3efb79a..735646d 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index 2f7d269..0f42b6c 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 23690aa..1386d29 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 0808319..0dc13eb 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 1386d29..d6fc566 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 0dc13eb..5e35ef6 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index d6fc566..920c875 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 5e35ef6..01844d5 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 920c875..9359dbd 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 01844d5..3b4ff8b 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 9359dbd..c3c3a6d 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 3b4ff8b..4a78b66 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index c3c3a6d..847a9b6 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 4a78b66..fc2ad58 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 847a9b6..0320747 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 ec4964c..2c60bf7 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 7d0e292..00dcf3c 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 0320747..8e3a99d 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 2c60bf7..4d7a247 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 8e3a99d..2dba516 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 2dba516..a777b4b 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 735646d..5d6b371 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 5d6b371..bc26b52 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 v0.10.2 From d7104bffcfb7a1a7f1dbb1274443e339588c2cb3 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sat, 9 Mar 2013 22:58:13 -0300 Subject: [media] MAINTAINERS: add drivers/media/tuners/it913x* Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index 7f6dec5..b74fe21 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4418,6 +4418,16 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/ S: Maintained F: drivers/media/dvb-frontends/it913x-fe* +IT913X MEDIA DRIVER +M: Antti Palosaari +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +W: http://palosaari.fi/linux/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/anttip/media_tree.git +S: Maintained +F: drivers/media/tuners/it913x* + IVTV VIDEO4LINUX DRIVER M: Andy Walls L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers) -- cgit v0.10.2 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 diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index d965a7a..297f1b2 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index fc93bd3..55a4c22 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smsir.h b/drivers/media/common/siano/smsir.h index 69b59b9..fc8b792 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 v0.10.2 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 diff --git a/drivers/media/usb/gspca/m5602/m5602_ov7660.c b/drivers/media/usb/gspca/m5602/m5602_ov7660.c index 4ac7889..64b3b03 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index de9b208..9e2fa41 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 46fff5c..cb7cdd3 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 v0.10.2 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 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 74c911f..aa0c35e 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 v0.10.2 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 diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index da6b779..6a15405 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/a8293.h b/drivers/media/dvb-frontends/a8293.h index ed29e55..b6ef642 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 dc837d9..09273b2 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 53fd304..c286e8f 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 0242733..8e0ac98 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 565dcf3..f2111e0 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 f154e1f..0b1a6c2 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 01eb7b9..782711ba 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 7d90ab9..2ec84fa 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 51ae866..102e70d 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 6acc21c..82b3d93 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 d75ffad..129d142 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 81fcf22..b585413 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 b61b03a..cf5e779 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 216c8c3..5f1d6b5 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 94fecfb..e666718 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 478ad66..f9c21fb 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 1fcb987..0cbf961 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 b847971..3755840 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 4ad00d7..05cd130 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 07fa459..df0ad42 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 67e89d6..1a735a7 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 9e2c0f4..a5f0368 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 02172ec..d9ab556 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 d1417678..c2da596 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 33c3c5e..dadb78b 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 c059b16..b327a4f 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 fcdf1c6..dbcbcc2 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 63e2dec..63861b3 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 5a8023e..14ce31e 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 1a7dea2..6627a39 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 f4349a1..3313847 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 785a466..fefba0e 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 91f2ebd..63b1e0a 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 45ec0f8..e4f5687 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 b57438c..70917dd 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 f220d82..8d5e2a6 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 141b5b8..1509fed 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 7be479c..a768189 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 f2b53db..a0bd931 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 93cc4a5..ea80b34 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 91c7ee8..e2a6dc6 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 fe71bba..8fa07e6 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 fb2ef5a..5e7bf4e 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 bff1c38..f9542f6 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 1389c74..dd84f7b 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 c7e64af..5bcb9a7 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 d84b8f8..5f1e821 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 5eee7ea..750b9bc 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 v0.10.2 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 diff --git a/drivers/media/tuners/e4000.h b/drivers/media/tuners/e4000.h index 71b1935..3783a0b 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 0ee581f..43ec893 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 54508fc..1d08057 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 594efd6..d65d5b3 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 222601e..9c43c1c 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 c063c36..26e1dc6 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 34f3892..9aae50a 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 fc8a1ff..ae8db88 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 9bd5da4..7e0d503 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 b4180d1..366410e 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 cf5b815..26358da 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 b1a5474..7245cae 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 v0.10.2 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 diff --git a/drivers/media/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h index 70e4fd6..4998c96 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h index 432706a..3f3f8bf 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 ff33396..90f583e 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 af0d432..c2dded9 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index 42801f8..658c6d4 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 0867920..c91da3c 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 v0.10.2 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 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 c91da3c..9b24a0e 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 aa0c35e..33ff97e 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 7346f85..ca8f3c2 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/cypress_firmware.c b/drivers/media/usb/dvb-usb-v2/cypress_firmware.c index 211df54..cfb1733 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 v0.10.2 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 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 9b24a0e..19f6737 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/it913x.c b/drivers/media/usb/dvb-usb-v2/it913x.c index 8338479..e48cdeb 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 v0.10.2 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 diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 8ae8442d..1e0d6fa 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 v0.10.2 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 diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 1e0d6fa..e025c39 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 v0.10.2 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 diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index e025c39..7b66013 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 v0.10.2 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 diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 7b66013..3df4339 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 v0.10.2 From 1c3fc152b8ebadd59814767e3189c961b73f20c8 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Tue, 19 Mar 2013 23:26:09 -0300 Subject: [media] drivers/staging/media/go7007: using strlcpy instead of strncpy for NUL terminated string, need always set 0 in the end. Signed-off-by: Chen Gang Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/snd-go7007.c b/drivers/staging/media/go7007/snd-go7007.c index 5af29ff..6f6271e 100644 --- a/drivers/staging/media/go7007/snd-go7007.c +++ b/drivers/staging/media/go7007/snd-go7007.c @@ -267,9 +267,9 @@ int go7007_snd_init(struct go7007 *go) kfree(gosnd); return ret; } - strncpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver)); - strncpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->driver)); - strncpy(gosnd->card->longname, gosnd->card->shortname, + strlcpy(gosnd->card->driver, "go7007", sizeof(gosnd->card->driver)); + strlcpy(gosnd->card->shortname, go->name, sizeof(gosnd->card->driver)); + strlcpy(gosnd->card->longname, gosnd->card->shortname, sizeof(gosnd->card->longname)); gosnd->pcm->private_data = go; -- cgit v0.10.2 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 diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c index 28638a8..3bc4db8 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 a1ab6a0..9956e67 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 1943e41..d869c8e 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 5477c2c..3bb187c 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 55a4c22..ec24d71 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 v0.10.2 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 diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 5800d65..924e032 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-tv/hdmiphy_drv.c b/drivers/media/platform/s5p-tv/hdmiphy_drv.c index 80717ce..ef0d812 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c index 8de1b3d..c78f54c 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 82142a2..24fb381 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 24fb381..9961e13 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c index c78f54c..4e86626 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-tv/hdmiphy_drv.c b/drivers/media/platform/s5p-tv/hdmiphy_drv.c index ef0d812..e19a0af 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index bc26b52..b1f7059 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index d5957b0..6e237b6 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 v0.10.2 From 9719afae5e589b409e137c36f89073d134f0de33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= 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 diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 08ae067..2586e46 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 69edffb..3948138 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 9945e5e..ff4d93d 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 33fafa4..9f3c9b5 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 a47ee36..9a90094 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 17c94be..5c42750 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 5b4d1dd..4e53a31 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 fd807a8..865fe84 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 e19072f..7cba7d3 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 7e69a3b..0a06205 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 fb91434..29ab9c2 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 5d87287..70a180b 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 f304792..1cf382a 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 f03445f..06a75de 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 v0.10.2 From b279265cfd677b618f2aee8089073a3e4632d85b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 11 Mar 2013 09:57:22 -0300 Subject: [media] davinci: vpfe: fix return value check in vpfe_enable_clock() In case of error, the function clk_get() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Signed-off-by: Wei Yongjun Acked-by: Lad, Prabhakar Reviewed-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c index c7ae7d7..b88e1dd 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c @@ -243,7 +243,7 @@ static int vpfe_enable_clock(struct vpfe_device *vpfe_dev) vpfe_dev->clks[i] = clk_get(vpfe_dev->pdev, vpfe_cfg->clocks[i]); - if (vpfe_dev->clks[i] == NULL) { + if (IS_ERR(vpfe_dev->clks[i])) { v4l2_err(vpfe_dev->pdev->driver, "Failed to get clock %s\n", vpfe_cfg->clocks[i]); @@ -264,7 +264,7 @@ static int vpfe_enable_clock(struct vpfe_device *vpfe_dev) return 0; out: for (i = 0; i < vpfe_cfg->num_clocks; i++) - if (vpfe_dev->clks[i]) { + if (!IS_ERR(vpfe_dev->clks[i])) { clk_disable_unprepare(vpfe_dev->clks[i]); clk_put(vpfe_dev->clks[i]); } -- cgit v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 8610b6a..a584d82 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index a584d82..a082ab4 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index a082ab4..e01a8d8 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index fa0faaa..b7dc921 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 e01a8d8..81ee70d 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 e7910e0..9c1cc2c 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 81ee70d..f1cb0db 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index f1cb0db..0df4a16 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 0df4a16..55eab61 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 v0.10.2 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 diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 55eab61..2fb2168 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 v0.10.2 From 69aa6f4ec669b9121057cc9e32cb10b5f744f6d6 Mon Sep 17 00:00:00 2001 From: Silviu-Mihai Popescu Date: Mon, 18 Mar 2013 15:06:20 -0300 Subject: [media] drivers: staging: davinci_vpfe: use resource_size() This uses the resource_size() function instead of explicit computation. Signed-off-by: Silviu-Mihai Popescu Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c index 9285353..05673ed 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c +++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c @@ -1859,5 +1859,5 @@ void vpfe_ipipe_cleanup(struct vpfe_ipipe_device *ipipe, iounmap(ipipe->isp5_base_addr); res = platform_get_resource(pdev, IORESOURCE_MEM, 4); if (res) - release_mem_region(res->start, res->end - res->start + 1); + release_mem_region(res->start, resource_size(res)); } diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c index ebeea72..c4a5660 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_isif.c +++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c @@ -1953,7 +1953,7 @@ static void isif_remove(struct vpfe_isif_device *isif, res = platform_get_resource(pdev, IORESOURCE_MEM, i); if (res) release_mem_region(res->start, - res->end - res->start + 1); + resource_size(res)); i++; } } @@ -2003,7 +2003,7 @@ int vpfe_isif_init(struct vpfe_isif_device *isif, struct platform_device *pdev) status = -ENOENT; goto fail_nobase_res; } - res_len = res->end - res->start + 1; + res_len = resource_size(res); res = request_mem_region(res->start, res_len, res->name); if (!res) { status = -EBUSY; diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c index 9cb0262..126f84c 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c +++ b/drivers/staging/media/davinci_vpfe/dm365_resizer.c @@ -1995,5 +1995,5 @@ vpfe_resizer_cleanup(struct vpfe_resizer_device *vpfe_rsz, res = platform_get_resource(pdev, IORESOURCE_MEM, 5); if (res) release_mem_region(res->start, - res->end - res->start + 1); + resource_size(res)); } -- cgit v0.10.2 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 diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index f4149eb..f4339ed 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 766305f6..77053ba 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 4c91b35..4b12c51 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 1e74465..d15cfd9 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 bee77ea..27c27b4 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 2fb2168..3156daf 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 f164b7f..a2c51e0 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 cd8d2c2..5cd22e7 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 2f9dd59..aa9b44a 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 5d5052d..84a1b75 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 5991bc8..5ba15b8 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 59c322d..5687d3f 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 d4de021..1219d60 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 c265e35..969340c 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 a6ff8a6..82aa11f 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 bc78354..4f10875 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 feff53c..eca02c2 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 7a8b0d0..e6258b6 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 7c553d1..34c6bc1 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 7c503fb..6c619d1 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 91369da..27dc49b 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 9bb0903..34f700d 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 b453229..5a8a6ad 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 730e906..65adaa7 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 63b112b..e140a72 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 643d80a..59be293 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 fe0a4f8..0c1e27b 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 296941a..4c9ae76 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 c61f590..7f85c6f 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 3d0ff44..2b8d31d 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 9c5a267..f9cdd8b 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 637a555..6142b5b 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 3df4339..2a2d21e 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 1978516..8938428 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 4b5190d..fcd7c19 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 b87effe..1712c05 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 02151e0..9a02fee 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 1898938..5708633 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 bd61b3b..e305c14 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 b18c2dc..8673955 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 0a8ee8f..0183956 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 8b9e826..b1d6b03 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 ac62008..96f6531 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 dff3f1d..6f701e9 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 d585c19..af79089 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 34c3b6e..75657c6 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 0f958f7..8b1daf1 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 dab0ca3..8ef7c8c 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 1a68579..49df753 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 cd1fe78..b668445 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 b5a8aac..279f65e 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 aa6e7c7..8ec8abe 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 cb9fe33..1288f1c 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 4118ad1..f06436d 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 b137a5e..1a82a50 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 3c6c1e3..738c5ad 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 v0.10.2 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 diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index f4339ed..234b7c6 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 77053ba..54a9dd3 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 0caac50..b4e1ccb 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 1e84466..5608b93 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 3d7ddd9..01441e3 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 4b12c51..b72a59d 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 7cfbc9d..e71f139 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 3156daf..7aea24b 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 a2c51e0..c22242b 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 5cd22e7..173ccd2 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 84a1b75..812ec5f 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 5ba15b8..2bbda43 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 1219d60..75281c1 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 969340c..f0e70ff 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 82aa11f..486ca8d 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 4f10875..ede6f13 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 8f0d077..af52def 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 e6258b6..852f11e 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 6c619d1..1e23547 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 27dc49b..9dd044b 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 34f700d..e7fbd03 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 5a8a6ad..bfc8cec 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 65adaa7..6c4076a 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 e140a72..142c2ee 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 59be293..545c04c 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 0c1e27b..6ff3508 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 7f85c6f..18320c2 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 2b8d31d..a7e93d7 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 f9cdd8b..2ce75d1 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 6142b5b..adfcc61 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 8938428..38d563d 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 fcd7c19..e245597 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 1712c05..bb7b143 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 9a02fee..97c2c18 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 5708633..5c57e5b 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 8673955..82c6c94 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 0183956..5dec323 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 b1d6b03..11316f2 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 96f6531..53020a7 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 6f701e9..2f9faee 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 af79089..3ef696d 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 75657c6..0f729c9 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 8b1daf1..ea6070b 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 8ef7c8c..9595309 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 49df753..b4618d7 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 b668445..874cfec 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 279f65e..f775768 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 1288f1c..4e477f3 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 f06436d..0da8682 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 1a82a50..79784fc 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 738c5ad..8a36a1d 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 v0.10.2 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 diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index 4143d61..fe907f2 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 77f9c921..66c957a 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 7aea24b..4b9a256 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 613e5ae..67b61cf 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 173ccd2..254c50f 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 aa9b44a..4343396 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 812ec5f..6dea11a 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 2bbda43..ed08c89 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 75281c1..93c7d57 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 f0e70ff..239f63c 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 486ca8d..150bb76 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 ede6f13..ead5be5 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 2928e72..07b84609 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 68387d4..ed73edd 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 852f11e..080f179 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 34c6bc1..75c3977 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 4df79c6..66a7081 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 1e23547..a6c69a4 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 71eefef..62169dd 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 e7fbd03..538de52 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 bfc8cec..da224eb 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 4b703fe..7005695 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 2e8f518..1168a84 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 476cfc8..96f6a49 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 2a49f00..33b9660 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 30976dc..bcf0ada3 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 3d1af67..20db8a0 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 d869c8e..00b7f9c 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 3bb187c..f1dff9e 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 5f7db3f..3a6a0dc 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 92a33f0..76a8623 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 9961e13..ef0efdf 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 d853162..8e3b95a 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 8ec9805..3592968 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 2d91eeb..a2f7bdd 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 b051c4a..a794cd6 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 eb5d6f9..c6af974 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 11316f2..e9dd01c 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 49c842a..f548db8 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 53020a7..4cff2f4 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 3ef696d..96d84c2 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 6a15405..2983bf0 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 0f729c9..a7774e3 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 2bd8613..ab97e7d 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 5307a63..f6a6cdc 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 9595309..8df668d 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 b4618d7..a78de1d 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 874cfec..041f19e 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 8ec8abe..d80d8af 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 19dc5b0..3670a7b 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 e33b7f5..073b3b3 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 4e477f3..29fe94d 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 4977e86..310b126 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 ca774cc..87f3c04 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 a7ca488..57585c7 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 0da8682..ee7b7c6 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 v0.10.2 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 diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index d80d8af..29c751d 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 v0.10.2 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 diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 080f179..861e462 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c index 5243ba6..526902b 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 c2886b6..58344b6 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 6fed5b7..56a1fa4 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 f47555b..31a63c9 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 ba67465..fd47465 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 c8581e2..1d2f7c8 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 234b7c6..12fb9b2 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 0991576..39f50fd 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 f80c1d7e..2526b66 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 73b7688..3f415fd 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 05ed5b8..617ad3f 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 6b6788c..5d9d033 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 b745f68..8a47ac1 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 5608b93..cf3a0aa 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 bcdc861..dd90898 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 2902ba6..8bd4e0d 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 d80d044..26a15b8 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 188e29b..a7256b7 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 53eaf899..a295e59 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 0f520f6..e316842 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 9d53309..9aa56de 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 dbe4f56..991202d 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 fbeb5b2..713d62e 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 0599304..20ca62d 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 2f236da..012bd62 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 5c92679..1f9ec3b 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 7d20746..bad90b1 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 3ca60c7..c433955 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 5967e1a0..485159a 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 7406de9..027809c 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 d15cfd9..f0a0921 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 75d6acc..343e021 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 9ac1b8c3..f366fad 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 4b9a256..e33a2d2 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 c22242b..38b1d64 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 254c50f..7dbd5a9 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 ea9a614..acdb6d5 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 315be0c..a608096 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 d51eed0..fa672fe 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 93c7d57..1465591 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 239f63c..11ba5eb 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 ead5be5..e3f6181 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 861e462..50379b2 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 a6c69a4..1363e97 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 9dd044b..71e8bea 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 538de52..0b74fb2 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 96f6a49..0e55b08 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 bcf0ada3..1802f11 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 00b7f9c..5f98df1 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 f1dff9e..1b3fb5c 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 76a8623..64ab91e 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 8e3b95a..7d02350 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 3592968..bf55abf 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 e9dd01c..79f1d510 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 4cff2f4..cd22147 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 2f9faee..5ad9fd6 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 96d84c2..d09b5c0 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 924e032..5995ec4 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 c3af321..ef8efeb 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 682ef33..6008c8d 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 4ec544f..ead9a1f 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 299751a..e11267f 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 8060fc6..91bae93 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 a7774e3..a8a65fa 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 f6a6cdc..c4c723b 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 041f19e..d34c2af 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 29c751d..936ca25 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 ee7b7c6..a4175cd 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 79784fc..8158a08 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 v0.10.2 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 diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 936ca25..168b51e 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 v0.10.2 From 842059aa4796d7c59bc3801d48896ba06b1a1287 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Sun, 24 Mar 2013 02:25:56 -0300 Subject: [media] documentation: DocBook/media : Fix typo in dvbproperty.xml Correct spelling typos. Signed-off-by: Masanari Iida Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml index 4a5eaee..31dc4df 100644 --- a/Documentation/DocBook/media/dvb/dvbproperty.xml +++ b/Documentation/DocBook/media/dvb/dvbproperty.xml @@ -1,6 +1,6 @@
<constant>FE_GET_PROPERTY/FE_SET_PROPERTY</constant> -This section describes the DVB version 5 extention of the DVB-API, also +This section describes the DVB version 5 extension of the DVB-API, also called "S2API", as this API were added to provide support for DVB-S2. It was designed to be able to replace the old frontend API. Yet, the DISEQC and the capability ioctls weren't implemented yet via the new way. @@ -952,7 +952,7 @@ enum fe_interleaving { Measures the amount of bits received before the inner code block, during the same period as DTV_STAT_PRE_ERROR_BIT_COUNT measurement was taken. It should be noticed that this measurement can be smaller than the total amount of bits on the transport stream, - as the frontend may need to manually restart the measurement, loosing some data between each measurement interval. + as the frontend may need to manually restart the measurement, losing some data between each measurement interval. This measurement is monotonically increased, as the frontend gets more bit count measurements. The frontend may reset it when a channel/transponder is tuned. Possible scales for this metric are: @@ -981,7 +981,7 @@ enum fe_interleaving { Measures the amount of bits received after the inner coding, during the same period as DTV_STAT_POST_ERROR_BIT_COUNT measurement was taken. It should be noticed that this measurement can be smaller than the total amount of bits on the transport stream, - as the frontend may need to manually restart the measurement, loosing some data between each measurement interval. + as the frontend may need to manually restart the measurement, losing some data between each measurement interval. This measurement is monotonically increased, as the frontend gets more bit count measurements. The frontend may reset it when a channel/transponder is tuned. Possible scales for this metric are: -- cgit v0.10.2 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 diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 6b28b58..b36d1ec 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 f00d42b..7343a27 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 v0.10.2 From 2180f92def1921397f422f278b3cc65751b749cc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 3 Mar 2013 20:12:31 -0300 Subject: [media] v4l2-core: add code to check for specific ops This patch adds a v4l2_subdev_has_op() macro and a v4l2_device_has_op macro to quickly check if a specific subdev or any subdev supports a particular subdev operation. This makes it easy for drivers to disable certain ioctls if none of the subdevs supports the necessary functionality. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index d61febfb..c9b1593 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h @@ -190,4 +190,17 @@ v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev); ##args); \ }) +#define v4l2_device_has_op(v4l2_dev, o, f) \ +({ \ + struct v4l2_subdev *__sd; \ + bool __result = false; \ + list_for_each_entry(__sd, &(v4l2_dev)->subdevs, list) { \ + if (v4l2_subdev_has_op(__sd, o, f)) { \ + __result = true; \ + break; \ + } \ + } \ + __result; \ +}) + #endif diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 8158a08..c42703a 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -687,4 +687,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, ((!(sd) || !(sd)->v4l2_dev || !(sd)->v4l2_dev->notify) ? -ENODEV : \ (sd)->v4l2_dev->notify((sd), (notification), (arg))) +#define v4l2_subdev_has_op(sd, o, f) \ + ((sd)->ops->o && (sd)->ops->o->f) + #endif -- cgit v0.10.2 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 diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 168b51e..72c22fd 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 v0.10.2 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 diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 9e8f854..b4952e2 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -2300,6 +2300,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 Enabled the deblocking post processing filter for MPEG4 decoder. diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index b36d1ec..f662df3 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 7eab0b9..844dc02 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 v0.10.2 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 diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index 5d9d033..c3e7e12 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 bab2127..8b2ecc6 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 v0.10.2 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 diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index c3e7e12..cdff1f6 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 v0.10.2 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 diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index cdff1f6..52c717d 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 8b2ecc6..4079186 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 v0.10.2 From ffb9749346b4e3bb567d0d5daa88edae9f8ec8ae Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 06:18:03 -0300 Subject: [media] go7007: fix i2c_xfer return codes The i2c_xfer functions didn't return the proper error codes and (especially important) on success they returned 0 instead of the number of transferred messages. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-i2c.c b/drivers/staging/media/go7007/go7007-i2c.c index 39456a3..1d0a400 100644 --- a/drivers/staging/media/go7007/go7007-i2c.c +++ b/drivers/staging/media/go7007/go7007-i2c.c @@ -52,11 +52,11 @@ static DEFINE_MUTEX(adlink_mpg24_i2c_lock); static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read, u16 command, int flags, u8 *data) { - int i, ret = -1; + int i, ret = -EIO; u16 val; if (go->status == STATUS_SHUTDOWN) - return -1; + return -ENODEV; #ifdef GO7007_I2C_DEBUG if (read) @@ -146,7 +146,7 @@ static int go7007_smbus_xfer(struct i2c_adapter *adapter, u16 addr, struct go7007 *go = i2c_get_adapdata(adapter); if (size != I2C_SMBUS_BYTE_DATA) - return -1; + return -EIO; return go7007_i2c_xfer(go, addr, read_write == I2C_SMBUS_READ, command, flags & I2C_CLIENT_SCCB ? 0x10 : 0x00, &data->byte); } @@ -170,26 +170,26 @@ static int go7007_i2c_master_xfer(struct i2c_adapter *adapter, (msgs[i].flags & I2C_M_RD) || !(msgs[i + 1].flags & I2C_M_RD) || msgs[i + 1].len != 1) - return -1; + return -EIO; if (go7007_i2c_xfer(go, msgs[i].addr, 1, (msgs[i].buf[0] << 8) | msgs[i].buf[1], 0x01, &msgs[i + 1].buf[0]) < 0) - return -1; + return -EIO; ++i; } else if (msgs[i].len == 3) { if (msgs[i].flags & I2C_M_RD) - return -1; + return -EIO; if (msgs[i].len != 3) - return -1; + return -EIO; if (go7007_i2c_xfer(go, msgs[i].addr, 0, (msgs[i].buf[0] << 8) | msgs[i].buf[1], 0x01, &msgs[i].buf[2]) < 0) - return -1; + return -EIO; } else - return -1; + return -EIO; } - return 0; + return num; } static u32 go7007_functionality(struct i2c_adapter *adapter) diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 9dbf5ec..914b247 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -876,10 +876,10 @@ static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter, struct go7007_usb *usb = go->hpi_context; u8 buf[16]; int buf_len, i; - int ret = -1; + int ret = -EIO; if (go->status == STATUS_SHUTDOWN) - return -1; + return -ENODEV; mutex_lock(&usb->i2c_lock); @@ -936,7 +936,7 @@ static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter, memcpy(msgs[i].buf, buf + 1, msgs[i].len); } } - ret = 0; + ret = num; i2c_done: mutex_unlock(&usb->i2c_lock); -- cgit v0.10.2 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 diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index c83f6e4..5b83a3f 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 2da4440..98bc15a 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 914b247..3333a8f 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 29fe94d..4ad383a 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 6d09c06..97763db 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 926aff9..24eaafe 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 v0.10.2 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 diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index ec07ceb..785e213 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 cfefd30..4c57075 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 0000000..bc73e8f --- /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 v0.10.2 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 diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 785e213..7907885 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 4c57075..adf9504 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 0000000..b0cc927 --- /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 v0.10.2 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 diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 7907885..5df353f 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 adf9504..b1775b3 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 0000000..3af4085 --- /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 0000000..cd15640 --- /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 v0.10.2 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 diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 5df353f..eb1831c 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 b1775b3..af8fb29 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 0000000..f0d0ef5 --- /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 v0.10.2 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 diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index eb1831c..07d9c11 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 af8fb29..399050a 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 0000000..4bb5ba6 --- /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 v0.10.2 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 diff --git a/drivers/media/i2c/tw2804.c b/drivers/media/i2c/tw2804.c index 4bb5ba6..441b766 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 v0.10.2 From dcafb6dea60fd6d4eaf20f8d5ce1503b0c03155d Mon Sep 17 00:00:00 2001 From: Volokh Konstantin Date: Sat, 9 Mar 2013 08:48:25 -0300 Subject: [media] go7007: i2c initialization changes for tw2804 Do i2c initialization via struct item as tw2804 has a 0x00 i2c address, so we need to use the I2C_CLIENT_TEN flag for validity. Signed-off-by: Volokh Konstantin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index 6695091..2e5be70 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -196,18 +196,22 @@ int go7007_reset_encoder(struct go7007 *go) /* * Attempt to instantiate an I2C client by ID, probably loading a module. */ -static int init_i2c_module(struct i2c_adapter *adapter, const char *type, - int addr) +static int init_i2c_module(struct i2c_adapter *adapter, const struct go_i2c *const i2c) { struct go7007 *go = i2c_get_adapdata(adapter); struct v4l2_device *v4l2_dev = &go->v4l2_dev; + struct i2c_board_info info; - if (v4l2_i2c_new_subdev(v4l2_dev, adapter, type, addr, NULL)) + memset(&info, 0, sizeof(info)); + strlcpy(info.type, i2c->type, sizeof(info.type)); + info.addr = i2c->addr; + info.flags = i2c->flags; + + if (v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, NULL)) return 0; - dev_info(&adapter->dev, - "go7007: probing for module i2c:%s failed\n", type); - return -1; + printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", i2c->type); + return -EINVAL; } /* @@ -243,9 +247,7 @@ int go7007_register_encoder(struct go7007 *go) } if (go->i2c_adapter_online) { for (i = 0; i < go->board_info->num_i2c_devs; ++i) - init_i2c_module(&go->i2c_adapter, - go->board_info->i2c_devs[i].type, - go->board_info->i2c_devs[i].addr); + init_i2c_module(&go->i2c_adapter, &go->board_info->i2c_devs[i]); if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) i2c_clients_command(&go->i2c_adapter, DECODER_SET_CHANNEL, &go->channel_number); diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index b58c394..b9ebdfb 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -88,10 +88,11 @@ struct go7007_board_info { int audio_bclk_div; int audio_main_div; int num_i2c_devs; - struct { + struct go_i2c { const char *type; int id; int addr; + u32 flags; } i2c_devs[4]; int num_inputs; struct { diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 3333a8f..b44f9b1 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -398,6 +398,7 @@ static struct go7007_usb_board board_adlink_mpg24 = { .type = "wis_tw2804", .id = I2C_DRIVERID_WIS_TW2804, .addr = 0x00, /* yes, really */ + .flags = I2C_CLIENT_TEN, }, }, .num_inputs = 1, -- cgit v0.10.2 From 3acd16ab5c1c4e2a679c5c3e082db648f0e85100 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 09:25:47 -0300 Subject: [media] go7007: switch to standard tuner/i2c subdevs Instead of using the wis-* drivers we now use the standard 'proper' subdev drivers. The board configuration tables now also list the possible audio inputs, this will be used later to implement audio inputs. Special mention deserves a little change in set_capture_size() where the height passed to s_mbus_fmt is doubled: that is because the saa7115 driver expects to see the frame height, not the field height as the wis_saa7115 driver did. Another change is that the tuner input is moved from last to the first input, which is consistent with the common practice in other video drivers. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/Kconfig b/drivers/staging/media/go7007/Kconfig index 7dfb281..da320319 100644 --- a/drivers/staging/media/go7007/Kconfig +++ b/drivers/staging/media/go7007/Kconfig @@ -8,6 +8,12 @@ config VIDEO_GO7007 select VIDEO_TVEEPROM select SND_PCM select CRC32 + select VIDEO_SONY_BTF_MPX if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_TW2804 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_TW9903 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_UDA1342 if MEDIA_SUBDRV_AUTOSELECT default N ---help--- This is a video4linux driver for the WIS GO7007 MPEG @@ -36,74 +42,3 @@ config VIDEO_GO7007_USB_S2250_BOARD To compile this driver as a module, choose M here: the module will be called s2250 - -config VIDEO_GO7007_OV7640 - tristate "OV7640 subdev support" - depends on VIDEO_GO7007 - default N - ---help--- - This is a video4linux driver for the OV7640 sub-device. - - To compile this driver as a module, choose M here: the - module will be called wis-ov7640 - -config VIDEO_GO7007_SAA7113 - tristate "SAA7113 subdev support" - depends on VIDEO_GO7007 - default N - ---help--- - This is a video4linux driver for the SAA7113 sub-device. - - To compile this driver as a module, choose M here: the - module will be called wis-saa7113 - -config VIDEO_GO7007_SAA7115 - tristate "SAA7115 subdev support" - depends on VIDEO_GO7007 - default N - ---help--- - This is a video4linux driver for the SAA7115 sub-device. - - To compile this driver as a module, choose M here: the - module will be called wis-saa7115 - -config VIDEO_GO7007_TW9903 - tristate "TW9903 subdev support" - depends on VIDEO_GO7007 - default N - ---help--- - This is a video4linux driver for the TW9903 sub-device. - - To compile this driver as a module, choose M here: the - module will be called wis-tw9903 - -config VIDEO_GO7007_UDA1342 - tristate "UDA1342 subdev support" - depends on VIDEO_GO7007 - default N - ---help--- - This is a video4linux driver for the UDA1342 sub-device. - - To compile this driver as a module, choose M here: the - module will be called wis-uda1342 - -config VIDEO_GO7007_SONY_TUNER - tristate "Sony tuner subdev support" - depends on VIDEO_GO7007 - default N - ---help--- - This is a video4linux driver for the Sony Tuner sub-device. - - To compile this driver as a module, choose M here: the - module will be called wis-sony-tuner - -config VIDEO_GO7007_TW2804 - tristate "TW2804 subdev support" - depends on VIDEO_GO7007 - default N - ---help--- - This is a video4linux driver for the TW2804 sub-device. - - To compile this driver as a module, choose M here: the - module will be called wis-tw2804 - diff --git a/drivers/staging/media/go7007/Makefile b/drivers/staging/media/go7007/Makefile index 3fdbef5..5bed78b 100644 --- a/drivers/staging/media/go7007/Makefile +++ b/drivers/staging/media/go7007/Makefile @@ -1,18 +1,6 @@ -#obj-m += go7007.o go7007-usb.o snd-go7007.o wis-saa7115.o wis-tw9903.o \ - wis-uda1342.o wis-sony-tuner.o wis-saa7113.o wis-ov7640.o \ - wis-tw2804.o - - obj-$(CONFIG_VIDEO_GO7007) += go7007.o obj-$(CONFIG_VIDEO_GO7007_USB) += go7007-usb.o obj-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD) += s2250.o s2250-loader.o -obj-$(CONFIG_VIDEO_GO7007_SAA7113) += wis-saa7113.o -obj-$(CONFIG_VIDEO_GO7007_OV7640) += wis-ov7640.o -obj-$(CONFIG_VIDEO_GO7007_SAA7115) += wis-saa7115.o -obj-$(CONFIG_VIDEO_GO7007_TW9903) += wis-tw9903.o -obj-$(CONFIG_VIDEO_GO7007_UDA1342) += wis-uda1342.o -obj-$(CONFIG_VIDEO_GO7007_SONY_TUNER) += wis-sony-tuner.o -obj-$(CONFIG_VIDEO_GO7007_TW2804) += wis-tw2804.o go7007-y := go7007-v4l2.o go7007-driver.o go7007-i2c.o go7007-fw.o \ snd-go7007.o diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index 2e5be70..09d0ef4 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -35,7 +35,6 @@ #include #include "go7007-priv.h" -#include "wis-i2c.h" /* * Wait for an interrupt to be delivered from the GO7007SB and return @@ -200,6 +199,7 @@ static int init_i2c_module(struct i2c_adapter *adapter, const struct go_i2c *con { struct go7007 *go = i2c_get_adapdata(adapter); struct v4l2_device *v4l2_dev = &go->v4l2_dev; + struct v4l2_subdev *sd; struct i2c_board_info info; memset(&info, 0, sizeof(info)); @@ -207,8 +207,14 @@ static int init_i2c_module(struct i2c_adapter *adapter, const struct go_i2c *con info.addr = i2c->addr; info.flags = i2c->flags; - if (v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, NULL)) + sd = v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, NULL); + if (sd) { + if (i2c->is_video) + go->sd_video = sd; + if (i2c->is_audio) + go->sd_audio = sd; return 0; + } printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", i2c->type); return -EINVAL; @@ -222,7 +228,7 @@ static int init_i2c_module(struct i2c_adapter *adapter, const struct go_i2c *con * * Must NOT be called with the hw_lock held. */ -int go7007_register_encoder(struct go7007 *go) +int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs) { int i, ret; @@ -246,11 +252,22 @@ int go7007_register_encoder(struct go7007 *go) go->i2c_adapter_online = 1; } if (go->i2c_adapter_online) { - for (i = 0; i < go->board_info->num_i2c_devs; ++i) + for (i = 0; i < num_i2c_devs; ++i) init_i2c_module(&go->i2c_adapter, &go->board_info->i2c_devs[i]); + + if (go->tuner_type >= 0) { + struct tuner_setup setup = { + .addr = ADDR_UNSET, + .type = go->tuner_type, + .mode_mask = T_ANALOG_TV, + }; + + v4l2_device_call_all(&go->v4l2_dev, 0, tuner, + s_type_addr, &setup); + } if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) - i2c_clients_command(&go->i2c_adapter, - DECODER_SET_CHANNEL, &go->channel_number); + v4l2_subdev_call(go->sd_video, video, s_routing, + 0, 0, go->channel_number + 1); } if (go->board_info->flags & GO7007_BOARD_HAS_AUDIO) { go->audio_enabled = 1; diff --git a/drivers/staging/media/go7007/go7007-i2c.c b/drivers/staging/media/go7007/go7007-i2c.c index 1d0a400..74f25e0 100644 --- a/drivers/staging/media/go7007/go7007-i2c.c +++ b/drivers/staging/media/go7007/go7007-i2c.c @@ -28,7 +28,6 @@ #include #include "go7007-priv.h" -#include "wis-i2c.h" /********************* Driver for on-board I2C adapter *********************/ diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index b9ebdfb..898eb5b 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -90,16 +90,23 @@ struct go7007_board_info { int num_i2c_devs; struct go_i2c { const char *type; - int id; + int is_video:1; + int is_audio:1; int addr; u32 flags; - } i2c_devs[4]; + } i2c_devs[5]; int num_inputs; struct { int video_input; - int audio_input; + int audio_index; char *name; } inputs[4]; + int video_config; + int num_aud_inputs; + struct { + int audio_input; + char *name; + } aud_inputs[3]; }; struct go7007_hpi_ops { @@ -178,9 +185,12 @@ struct go7007 { int streaming; int in_use; int audio_enabled; + struct v4l2_subdev *sd_video; + struct v4l2_subdev *sd_audio; /* Video input */ int input; + int aud_input; enum { GO7007_STD_NTSC, GO7007_STD_PAL, GO7007_STD_OTHER } standard; int sensor_framerate; int width; @@ -268,7 +278,7 @@ int go7007_read_addr(struct go7007 *go, u16 addr, u16 *data); int go7007_read_interrupt(struct go7007 *go, u16 *value, u16 *data); int go7007_boot_encoder(struct go7007 *go, int init_i2c); int go7007_reset_encoder(struct go7007 *go); -int go7007_register_encoder(struct go7007 *go); +int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs); int go7007_start_encoder(struct go7007 *go); void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length); struct go7007 *go7007_alloc(struct go7007_board_info *board, diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index b44f9b1..5e3e5a0 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -26,11 +26,11 @@ #include #include #include -#include +#include #include +#include #include "go7007-priv.h" -#include "wis-i2c.h" static unsigned int assume_endura; module_param(assume_endura, int, 0644); @@ -93,9 +93,9 @@ static struct go7007_usb_board board_matrix_ii = { .num_i2c_devs = 1, .i2c_devs = { { - .type = "wis_saa7115", - .id = I2C_DRIVERID_WIS_SAA7115, + .type = "saa7115", .addr = 0x20, + .is_video = 1, }, }, .num_inputs = 2, @@ -109,6 +109,7 @@ static struct go7007_usb_board board_matrix_ii = { .name = "S-Video", }, }, + .video_config = SAA7115_IDQ_IS_DEFAULT, }, }; @@ -130,9 +131,9 @@ static struct go7007_usb_board board_matrix_reload = { .num_i2c_devs = 1, .i2c_devs = { { - .type = "wis_saa7113", - .id = I2C_DRIVERID_WIS_SAA7113, + .type = "saa7115", .addr = 0x25, + .is_video = 1, }, }, .num_inputs = 2, @@ -146,6 +147,7 @@ static struct go7007_usb_board board_matrix_reload = { .name = "S-Video", }, }, + .video_config = SAA7115_IDQ_IS_DEFAULT, }, }; @@ -168,30 +170,31 @@ static struct go7007_usb_board board_star_trek = { .num_i2c_devs = 1, .i2c_devs = { { - .type = "wis_saa7115", - .id = I2C_DRIVERID_WIS_SAA7115, + .type = "saa7115", .addr = 0x20, + .is_video = 1, }, }, .num_inputs = 2, .inputs = { + /* { + * .video_input = 3, + * .audio_index = AUDIO_TUNER, + * .name = "Tuner", + * }, + */ { .video_input = 1, - /* .audio_input = AUDIO_EXTERN, */ + /* .audio_index = AUDIO_EXTERN, */ .name = "Composite", }, { .video_input = 8, - /* .audio_input = AUDIO_EXTERN, */ + /* .audio_index = AUDIO_EXTERN, */ .name = "S-Video", }, - /* { - * .video_input = 3, - * .audio_input = AUDIO_TUNER, - * .name = "Tuner", - * }, - */ }, + .video_config = SAA7115_IDQ_IS_DEFAULT, }, }; @@ -211,41 +214,60 @@ static struct go7007_usb_board board_px_tv402u = { .audio_bclk_div = 8, .audio_main_div = 2, .hpi_buffer_cap = 7, - .num_i2c_devs = 3, + .num_i2c_devs = 5, .i2c_devs = { { - .type = "wis_saa7115", - .id = I2C_DRIVERID_WIS_SAA7115, + .type = "saa7115", .addr = 0x20, + .is_video = 1, }, { - .type = "wis_uda1342", - .id = I2C_DRIVERID_WIS_UDA1342, + .type = "uda1342", .addr = 0x1a, + .is_audio = 1, }, { - .type = "wis_sony_tuner", - .id = I2C_DRIVERID_WIS_SONY_TUNER, + .type = "tuner", .addr = 0x60, }, + { + .type = "tuner", + .addr = 0x43, + }, + { + .type = "sony-btf-mpx", + .addr = 0x44, + }, }, .num_inputs = 3, .inputs = { { + .video_input = 3, + .audio_index = 0, + .name = "Tuner", + }, + { .video_input = 1, - .audio_input = TVAUDIO_INPUT_EXTERN, + .audio_index = 1, .name = "Composite", }, { .video_input = 8, - .audio_input = TVAUDIO_INPUT_EXTERN, + .audio_index = 1, .name = "S-Video", }, + }, + .video_config = SAA7115_IDQ_IS_DEFAULT, + .num_aud_inputs = 2, + .aud_inputs = { { - .video_input = 3, - .audio_input = TVAUDIO_INPUT_TUNER, + .audio_input = UDA1342_IN2, .name = "Tuner", }, + { + .audio_input = UDA1342_IN1, + .name = "Line In", + }, }, }, }; @@ -272,8 +294,7 @@ static struct go7007_usb_board board_xmen = { .num_i2c_devs = 1, .i2c_devs = { { - .type = "wis_ov7640", - .id = I2C_DRIVERID_WIS_OV7640, + .type = "ov7640", .addr = 0x21, }, }, @@ -305,8 +326,8 @@ static struct go7007_usb_board board_matrix_revolution = { .num_i2c_devs = 1, .i2c_devs = { { - .type = "wis_tw9903", - .id = I2C_DRIVERID_WIS_TW9903, + .type = "tw9903", + .is_video = 1, .addr = 0x44, }, }, @@ -395,10 +416,10 @@ static struct go7007_usb_board board_adlink_mpg24 = { .num_i2c_devs = 1, .i2c_devs = { { - .type = "wis_tw2804", - .id = I2C_DRIVERID_WIS_TW2804, + .type = "tw2804", .addr = 0x00, /* yes, really */ .flags = I2C_CLIENT_TEN, + .is_video = 1, }, }, .num_inputs = 1, @@ -428,8 +449,9 @@ static struct go7007_usb_board board_sensoray_2250 = { .i2c_devs = { { .type = "s2250", - .id = I2C_DRIVERID_S2250, .addr = 0x43, + .is_video = 1, + .is_audio = 1, }, }, .num_inputs = 2, @@ -443,6 +465,21 @@ static struct go7007_usb_board board_sensoray_2250 = { .name = "S-Video", }, }, + .num_aud_inputs = 3, + .aud_inputs = { + { + .audio_input = 0, + .name = "Line In", + }, + { + .audio_input = 1, + .name = "Mic", + }, + { + .audio_input = 2, + .name = "Mic Boost", + }, + }, }, }; @@ -972,6 +1009,7 @@ static int go7007_usb_probe(struct usb_interface *intf, struct go7007_usb *usb; struct go7007_usb_board *board; struct usb_device *usbdev = interface_to_usbdev(intf); + unsigned num_i2c_devs; char *name; int video_pipe, i, v_urb_len; @@ -1126,6 +1164,8 @@ static int go7007_usb_probe(struct usb_interface *intf, } } + num_i2c_devs = go->board_info->num_i2c_devs; + /* Probe the tuner model on the TV402U */ if (go->board_id == GO7007_BOARDID_PX_TV402U_ANY) { u8 data[3]; @@ -1145,12 +1185,14 @@ static int go7007_usb_probe(struct usb_interface *intf, case 2: go->board_id = GO7007_BOARDID_PX_TV402U_JP; go->tuner_type = TUNER_SONY_BTF_PK467Z; + num_i2c_devs -= 2; strncpy(go->name, "Plextor PX-TV402U-JP", sizeof(go->name)); break; case 3: go->board_id = GO7007_BOARDID_PX_TV402U_NA; go->tuner_type = TUNER_SONY_BTF_PB463Z; + num_i2c_devs -= 2; strncpy(go->name, "Plextor PX-TV402U-NA", sizeof(go->name)); break; @@ -1180,7 +1222,7 @@ static int go7007_usb_probe(struct usb_interface *intf, /* Do any final GO7007 initialization, then register the * V4L2 and ALSA interfaces */ - if (go7007_register_encoder(go) < 0) + if (go7007_register_encoder(go, num_i2c_devs) < 0) goto initfail; /* Allocate the URBs and buffers for receiving the video stream */ diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 4ad383a..fcd3e2d 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -37,7 +37,6 @@ #include "go7007.h" #include "go7007-priv.h" -#include "wis-i2c.h" /* Temporary defines until accepted in v4l-dvb */ #ifndef V4L2_MPEG_STREAM_TYPE_MPEG_ELEM @@ -264,6 +263,7 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) mbus_fmt.height = height; go->encoder_v_halve = 1; } + mbus_fmt.height *= 2; call_all(&go->v4l2_dev, video, s_mbus_fmt, &mbus_fmt); } else { if (width <= sensor_width / 4) { @@ -1184,9 +1184,9 @@ static int vidioc_enum_input(struct file *file, void *priv, strncpy(inp->name, go->board_info->inputs[inp->index].name, sizeof(inp->name)); - /* If this board has a tuner, it will be the last input */ + /* If this board has a tuner, it will be the first input */ if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && - inp->index == go->board_info->num_inputs - 1) + inp->index == 0) inp->type = V4L2_INPUT_TYPE_TUNER; else inp->type = V4L2_INPUT_TYPE_CAMERA; @@ -1223,7 +1223,17 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int input) go->input = input; - return call_all(&go->v4l2_dev, video, s_routing, input, 0, 0); + v4l2_subdev_call(go->sd_video, video, s_routing, + go->board_info->inputs[input].video_input, 0, + go->board_info->video_config); + if (go->board_info->num_aud_inputs) { + int aud_input = go->board_info->inputs[input].audio_index; + + v4l2_subdev_call(go->sd_audio, audio, s_routing, + go->board_info->aud_inputs[aud_input].audio_input, 0, 0); + go->aud_input = aud_input; + } + return 0; } static int vidioc_g_tuner(struct file *file, void *priv, diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c index cf7c34a..e037a39 100644 --- a/drivers/staging/media/go7007/saa7134-go7007.c +++ b/drivers/staging/media/go7007/saa7134-go7007.c @@ -468,7 +468,7 @@ static int saa7134_go7007_init(struct saa7134_dev *dev) /* Do any final GO7007 initialization, then register the * V4L2 and ALSA interfaces */ - if (go7007_register_encoder(go) < 0) + if (go7007_register_encoder(go, go->board_info->num_i2c_devs) < 0) goto initfail; dev->empress_dev = go->video_dev; video_set_drvdata(dev->empress_dev, go); -- cgit v0.10.2 From 94c0c676592da0e3a8da06fee7ba88c6e9c360f3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 09:27:54 -0300 Subject: [media] go7007: remove all wis* drivers These are now no longer used and so they can be removed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/wis-i2c.h b/drivers/staging/media/go7007/wis-i2c.h deleted file mode 100644 index 97763db..0000000 --- a/drivers/staging/media/go7007/wis-i2c.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - */ - -/* Temporary I2C IDs -- these need to be replaced with real registered IDs */ -#define I2C_DRIVERID_WIS_SAA7115 0xf0f0 -#define I2C_DRIVERID_WIS_UDA1342 0xf0f1 -#define I2C_DRIVERID_WIS_SONY_TUNER 0xf0f2 -#define I2C_DRIVERID_WIS_TW9903 0xf0f3 -#define I2C_DRIVERID_WIS_SAA7113 0xf0f4 -#define I2C_DRIVERID_WIS_OV7640 0xf0f5 -#define I2C_DRIVERID_WIS_TW2804 0xf0f6 -#define I2C_DRIVERID_S2250 0xf0f7 - -/* Definitions for new video decoder commands */ - -struct video_decoder_resolution { - unsigned int width; - unsigned int height; -}; - -#define DECODER_SET_RESOLUTION _IOW('d', 200, struct video_decoder_resolution) -#define DECODER_SET_CHANNEL _IOW('d', 201, int) diff --git a/drivers/staging/media/go7007/wis-ov7640.c b/drivers/staging/media/go7007/wis-ov7640.c deleted file mode 100644 index 9f01657f..0000000 --- a/drivers/staging/media/go7007/wis-ov7640.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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 "wis-i2c.h" - -struct wis_ov7640 { - int brightness; - int contrast; - int saturation; - int hue; -}; - -static 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, 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 int wis_ov7640_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = client->adapter; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - client->flags = I2C_CLIENT_SCCB; - - dev_dbg(&client->dev, - "wis-ov7640: initializing OV7640 at address %d on %s\n", - client->addr, adapter->name); - - if (write_regs(client, initial_registers) < 0) { - dev_err(&client->dev, "wis-ov7640: error initializing OV7640\n"); - return -ENODEV; - } - - return 0; -} - -static int wis_ov7640_remove(struct i2c_client *client) -{ - return 0; -} - -static const struct i2c_device_id wis_ov7640_id[] = { - { "wis_ov7640", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wis_ov7640_id); - -static struct i2c_driver wis_ov7640_driver = { - .driver = { - .name = "WIS OV7640 I2C driver", - }, - .probe = wis_ov7640_probe, - .remove = wis_ov7640_remove, - .id_table = wis_ov7640_id, -}; - -module_i2c_driver(wis_ov7640_driver); - -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/go7007/wis-saa7113.c b/drivers/staging/media/go7007/wis-saa7113.c deleted file mode 100644 index 891cde7..0000000 --- a/drivers/staging/media/go7007/wis-saa7113.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * 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 "wis-i2c.h" - -struct wis_saa7113 { - int norm; - int brightness; - int contrast; - int saturation; - int hue; -}; - -static u8 initial_registers[] = { - 0x01, 0x08, - 0x02, 0xc0, - 0x03, 0x33, - 0x04, 0x00, - 0x05, 0x00, - 0x06, 0xe9, - 0x07, 0x0d, - 0x08, 0xd8, - 0x09, 0x40, - 0x0a, 0x80, - 0x0b, 0x47, - 0x0c, 0x40, - 0x0d, 0x00, - 0x0e, 0x01, - 0x0f, 0x2a, - 0x10, 0x40, - 0x11, 0x0c, - 0x12, 0xfe, - 0x13, 0x00, - 0x14, 0x00, - 0x15, 0x04, - 0x16, 0x00, - 0x17, 0x00, - 0x18, 0x00, - 0x19, 0x00, - 0x1a, 0x00, - 0x1b, 0x00, - 0x1c, 0x00, - 0x1d, 0x00, - 0x1e, 0x00, - 0x1f, 0xc8, - 0x40, 0x00, - 0x41, 0xff, - 0x42, 0xff, - 0x43, 0xff, - 0x44, 0xff, - 0x45, 0xff, - 0x46, 0xff, - 0x47, 0xff, - 0x48, 0xff, - 0x49, 0xff, - 0x4a, 0xff, - 0x4b, 0xff, - 0x4c, 0xff, - 0x4d, 0xff, - 0x4e, 0xff, - 0x4f, 0xff, - 0x50, 0xff, - 0x51, 0xff, - 0x52, 0xff, - 0x53, 0xff, - 0x54, 0xff, - 0x55, 0xff, - 0x56, 0xff, - 0x57, 0xff, - 0x58, 0x00, - 0x59, 0x54, - 0x5a, 0x07, - 0x5b, 0x83, - 0x5c, 0x00, - 0x5d, 0x00, - 0x5e, 0x00, - 0x5f, 0x00, - 0x60, 0x00, - 0x61, 0x00, - 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */ -}; - -static int write_reg(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int write_regs(struct i2c_client *client, u8 *regs) -{ - int i; - - for (i = 0; regs[i] != 0x00; i += 2) - if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) - return -1; - return 0; -} - -static int wis_saa7113_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct wis_saa7113 *dec = i2c_get_clientdata(client); - - switch (cmd) { - case VIDIOC_S_INPUT: - { - int *input = arg; - - i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input); - i2c_smbus_write_byte_data(client, 0x09, - *input < 6 ? 0x40 : 0x80); - break; - } - case VIDIOC_S_STD: - { - v4l2_std_id *input = arg; - dec->norm = *input; - if (dec->norm & V4L2_STD_NTSC) { - write_reg(client, 0x0e, 0x01); - write_reg(client, 0x10, 0x40); - } else if (dec->norm & V4L2_STD_PAL) { - write_reg(client, 0x0e, 0x01); - write_reg(client, 0x10, 0x48); - } else if (dec->norm & V4L2_STD_SECAM) { - write_reg(client, 0x0e, 0x50); - write_reg(client, 0x10, 0x48); - } - break; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 255; - ctrl->step = 1; - ctrl->default_value = 128; - ctrl->flags = 0; - break; - case V4L2_CID_CONTRAST: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 71; - ctrl->flags = 0; - break; - case V4L2_CID_SATURATION: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 64; - ctrl->flags = 0; - break; - case V4L2_CID_HUE: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); - ctrl->minimum = -128; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 0; - ctrl->flags = 0; - break; - } - break; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - if (ctrl->value > 255) - dec->brightness = 255; - else if (ctrl->value < 0) - dec->brightness = 0; - else - dec->brightness = ctrl->value; - write_reg(client, 0x0a, dec->brightness); - break; - case V4L2_CID_CONTRAST: - if (ctrl->value > 127) - dec->contrast = 127; - else if (ctrl->value < 0) - dec->contrast = 0; - else - dec->contrast = ctrl->value; - write_reg(client, 0x0b, dec->contrast); - break; - case V4L2_CID_SATURATION: - if (ctrl->value > 127) - dec->saturation = 127; - else if (ctrl->value < 0) - dec->saturation = 0; - else - dec->saturation = ctrl->value; - write_reg(client, 0x0c, dec->saturation); - break; - case V4L2_CID_HUE: - if (ctrl->value > 127) - dec->hue = 127; - else if (ctrl->value < -128) - dec->hue = -128; - else - dec->hue = ctrl->value; - write_reg(client, 0x0d, dec->hue); - break; - } - break; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = dec->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = dec->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = dec->saturation; - break; - case V4L2_CID_HUE: - ctrl->value = dec->hue; - break; - } - break; - } - default: - break; - } - return 0; -} - -static int wis_saa7113_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = client->adapter; - struct wis_saa7113 *dec; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - dec = kmalloc(sizeof(struct wis_saa7113), GFP_KERNEL); - if (dec == NULL) - return -ENOMEM; - - dec->norm = V4L2_STD_NTSC; - dec->brightness = 128; - dec->contrast = 71; - dec->saturation = 64; - dec->hue = 0; - i2c_set_clientdata(client, dec); - - dev_dbg(&client->dev, - "wis-saa7113: initializing SAA7113 at address %d on %s\n", - client->addr, adapter->name); - - if (write_regs(client, initial_registers) < 0) { - dev_err(&client->dev, - "wis-saa7113: error initializing SAA7113\n"); - kfree(dec); - return -ENODEV; - } - - return 0; -} - -static int wis_saa7113_remove(struct i2c_client *client) -{ - struct wis_saa7113 *dec = i2c_get_clientdata(client); - - kfree(dec); - return 0; -} - -static const struct i2c_device_id wis_saa7113_id[] = { - { "wis_saa7113", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wis_saa7113_id); - -static struct i2c_driver wis_saa7113_driver = { - .driver = { - .name = "WIS SAA7113 I2C driver", - }, - .probe = wis_saa7113_probe, - .remove = wis_saa7113_remove, - .command = wis_saa7113_command, - .id_table = wis_saa7113_id, -}; - -module_i2c_driver(wis_saa7113_driver); - -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/go7007/wis-saa7115.c b/drivers/staging/media/go7007/wis-saa7115.c deleted file mode 100644 index fa86acd..0000000 --- a/drivers/staging/media/go7007/wis-saa7115.c +++ /dev/null @@ -1,457 +0,0 @@ -/* - * 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 "wis-i2c.h" - -struct wis_saa7115 { - int norm; - int brightness; - int contrast; - int saturation; - int hue; -}; - -static u8 initial_registers[] = { - 0x01, 0x08, - 0x02, 0xc0, - 0x03, 0x20, - 0x04, 0x80, - 0x05, 0x80, - 0x06, 0xeb, - 0x07, 0xe0, - 0x08, 0xf0, /* always toggle FID */ - 0x09, 0x40, - 0x0a, 0x80, - 0x0b, 0x40, - 0x0c, 0x40, - 0x0d, 0x00, - 0x0e, 0x03, - 0x0f, 0x2a, - 0x10, 0x0e, - 0x11, 0x00, - 0x12, 0x8d, - 0x13, 0x00, - 0x14, 0x00, - 0x15, 0x11, - 0x16, 0x01, - 0x17, 0xda, - 0x18, 0x40, - 0x19, 0x80, - 0x1a, 0x00, - 0x1b, 0x42, - 0x1c, 0xa9, - 0x30, 0x66, - 0x31, 0x90, - 0x32, 0x01, - 0x34, 0x00, - 0x35, 0x00, - 0x36, 0x20, - 0x38, 0x03, - 0x39, 0x20, - 0x3a, 0x88, - 0x40, 0x00, - 0x41, 0xff, - 0x42, 0xff, - 0x43, 0xff, - 0x44, 0xff, - 0x45, 0xff, - 0x46, 0xff, - 0x47, 0xff, - 0x48, 0xff, - 0x49, 0xff, - 0x4a, 0xff, - 0x4b, 0xff, - 0x4c, 0xff, - 0x4d, 0xff, - 0x4e, 0xff, - 0x4f, 0xff, - 0x50, 0xff, - 0x51, 0xff, - 0x52, 0xff, - 0x53, 0xff, - 0x54, 0xf4 /*0xff*/, - 0x55, 0xff, - 0x56, 0xff, - 0x57, 0xff, - 0x58, 0x40, - 0x59, 0x47, - 0x5a, 0x06 /*0x03*/, - 0x5b, 0x83, - 0x5d, 0x06, - 0x5e, 0x00, - 0x80, 0x30, /* window defined scaler operation, task A and B enabled */ - 0x81, 0x03, /* use scaler datapath generated V */ - 0x83, 0x00, - 0x84, 0x00, - 0x85, 0x00, - 0x86, 0x45, - 0x87, 0x31, - 0x88, 0xc0, - 0x90, 0x02, /* task A process top field */ - 0x91, 0x08, - 0x92, 0x09, - 0x93, 0x80, - 0x94, 0x06, - 0x95, 0x00, - 0x96, 0xc0, - 0x97, 0x02, - 0x98, 0x12, - 0x99, 0x00, - 0x9a, 0xf2, - 0x9b, 0x00, - 0x9c, 0xd0, - 0x9d, 0x02, - 0x9e, 0xf2, - 0x9f, 0x00, - 0xa0, 0x01, - 0xa1, 0x01, - 0xa2, 0x01, - 0xa4, 0x80, - 0xa5, 0x40, - 0xa6, 0x40, - 0xa8, 0x00, - 0xa9, 0x04, - 0xaa, 0x00, - 0xac, 0x00, - 0xad, 0x02, - 0xae, 0x00, - 0xb0, 0x00, - 0xb1, 0x04, - 0xb2, 0x00, - 0xb3, 0x04, - 0xb4, 0x00, - 0xb8, 0x00, - 0xbc, 0x00, - 0xc0, 0x03, /* task B process bottom field */ - 0xc1, 0x08, - 0xc2, 0x09, - 0xc3, 0x80, - 0xc4, 0x06, - 0xc5, 0x00, - 0xc6, 0xc0, - 0xc7, 0x02, - 0xc8, 0x12, - 0xc9, 0x00, - 0xca, 0xf2, - 0xcb, 0x00, - 0xcc, 0xd0, - 0xcd, 0x02, - 0xce, 0xf2, - 0xcf, 0x00, - 0xd0, 0x01, - 0xd1, 0x01, - 0xd2, 0x01, - 0xd4, 0x80, - 0xd5, 0x40, - 0xd6, 0x40, - 0xd8, 0x00, - 0xd9, 0x04, - 0xda, 0x00, - 0xdc, 0x00, - 0xdd, 0x02, - 0xde, 0x00, - 0xe0, 0x00, - 0xe1, 0x04, - 0xe2, 0x00, - 0xe3, 0x04, - 0xe4, 0x00, - 0xe8, 0x00, - 0x88, 0xf0, /* End of original static list */ - 0x00, 0x00, /* Terminator (reg 0x00 is read-only) */ -}; - -static int write_reg(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int write_regs(struct i2c_client *client, u8 *regs) -{ - int i; - - for (i = 0; regs[i] != 0x00; i += 2) - if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) - return -1; - return 0; -} - -static int wis_saa7115_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct wis_saa7115 *dec = i2c_get_clientdata(client); - - switch (cmd) { - case VIDIOC_S_INPUT: - { - int *input = arg; - - i2c_smbus_write_byte_data(client, 0x02, 0xC0 | *input); - i2c_smbus_write_byte_data(client, 0x09, - *input < 6 ? 0x40 : 0xC0); - break; - } - case DECODER_SET_RESOLUTION: - { - struct video_decoder_resolution *res = arg; - /* Course-grained scaler */ - int h_integer_scaler = res->width < 704 ? 704 / res->width : 1; - /* Fine-grained scaler to take care of remainder */ - int h_scaling_increment = (704 / h_integer_scaler) * - 1024 / res->width; - /* Fine-grained scaler only */ - int v_scaling_increment = (dec->norm & V4L2_STD_NTSC ? - 240 : 288) * 1024 / res->height; - u8 regs[] = { - 0x88, 0xc0, - 0x9c, res->width & 0xff, - 0x9d, res->width >> 8, - 0x9e, res->height & 0xff, - 0x9f, res->height >> 8, - 0xa0, h_integer_scaler, - 0xa1, 1, - 0xa2, 1, - 0xa8, h_scaling_increment & 0xff, - 0xa9, h_scaling_increment >> 8, - 0xac, (h_scaling_increment / 2) & 0xff, - 0xad, (h_scaling_increment / 2) >> 8, - 0xb0, v_scaling_increment & 0xff, - 0xb1, v_scaling_increment >> 8, - 0xb2, v_scaling_increment & 0xff, - 0xb3, v_scaling_increment >> 8, - 0xcc, res->width & 0xff, - 0xcd, res->width >> 8, - 0xce, res->height & 0xff, - 0xcf, res->height >> 8, - 0xd0, h_integer_scaler, - 0xd1, 1, - 0xd2, 1, - 0xd8, h_scaling_increment & 0xff, - 0xd9, h_scaling_increment >> 8, - 0xdc, (h_scaling_increment / 2) & 0xff, - 0xdd, (h_scaling_increment / 2) >> 8, - 0xe0, v_scaling_increment & 0xff, - 0xe1, v_scaling_increment >> 8, - 0xe2, v_scaling_increment & 0xff, - 0xe3, v_scaling_increment >> 8, - 0x88, 0xf0, - 0, 0, - }; - write_regs(client, regs); - break; - } - case VIDIOC_S_STD: - { - v4l2_std_id *input = arg; - u8 regs[] = { - 0x88, 0xc0, - 0x98, *input & V4L2_STD_NTSC ? 0x12 : 0x16, - 0x9a, *input & V4L2_STD_NTSC ? 0xf2 : 0x20, - 0x9b, *input & V4L2_STD_NTSC ? 0x00 : 0x01, - 0xc8, *input & V4L2_STD_NTSC ? 0x12 : 0x16, - 0xca, *input & V4L2_STD_NTSC ? 0xf2 : 0x20, - 0xcb, *input & V4L2_STD_NTSC ? 0x00 : 0x01, - 0x88, 0xf0, - 0x30, *input & V4L2_STD_NTSC ? 0x66 : 0x00, - 0x31, *input & V4L2_STD_NTSC ? 0x90 : 0xe0, - 0, 0, - }; - write_regs(client, regs); - dec->norm = *input; - break; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 255; - ctrl->step = 1; - ctrl->default_value = 128; - ctrl->flags = 0; - break; - case V4L2_CID_CONTRAST: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 64; - ctrl->flags = 0; - break; - case V4L2_CID_SATURATION: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 64; - ctrl->flags = 0; - break; - case V4L2_CID_HUE: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); - ctrl->minimum = -128; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 0; - ctrl->flags = 0; - break; - } - break; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - if (ctrl->value > 255) - dec->brightness = 255; - else if (ctrl->value < 0) - dec->brightness = 0; - else - dec->brightness = ctrl->value; - write_reg(client, 0x0a, dec->brightness); - break; - case V4L2_CID_CONTRAST: - if (ctrl->value > 127) - dec->contrast = 127; - else if (ctrl->value < 0) - dec->contrast = 0; - else - dec->contrast = ctrl->value; - write_reg(client, 0x0b, dec->contrast); - break; - case V4L2_CID_SATURATION: - if (ctrl->value > 127) - dec->saturation = 127; - else if (ctrl->value < 0) - dec->saturation = 0; - else - dec->saturation = ctrl->value; - write_reg(client, 0x0c, dec->saturation); - break; - case V4L2_CID_HUE: - if (ctrl->value > 127) - dec->hue = 127; - else if (ctrl->value < -128) - dec->hue = -128; - else - dec->hue = ctrl->value; - write_reg(client, 0x0d, dec->hue); - break; - } - break; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = dec->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = dec->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = dec->saturation; - break; - case V4L2_CID_HUE: - ctrl->value = dec->hue; - break; - } - break; - } - default: - break; - } - return 0; -} - -static int wis_saa7115_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = client->adapter; - struct wis_saa7115 *dec; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - dec = kmalloc(sizeof(struct wis_saa7115), GFP_KERNEL); - if (dec == NULL) - return -ENOMEM; - - dec->norm = V4L2_STD_NTSC; - dec->brightness = 128; - dec->contrast = 64; - dec->saturation = 64; - dec->hue = 0; - i2c_set_clientdata(client, dec); - - dev_dbg(&client->dev, - "wis-saa7115: initializing SAA7115 at address %d on %s\n", - client->addr, adapter->name); - - if (write_regs(client, initial_registers) < 0) { - dev_err(&client->dev, - "wis-saa7115: error initializing SAA7115\n"); - kfree(dec); - return -ENODEV; - } - - return 0; -} - -static int wis_saa7115_remove(struct i2c_client *client) -{ - struct wis_saa7115 *dec = i2c_get_clientdata(client); - - kfree(dec); - return 0; -} - -static const struct i2c_device_id wis_saa7115_id[] = { - { "wis_saa7115", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wis_saa7115_id); - -static struct i2c_driver wis_saa7115_driver = { - .driver = { - .name = "WIS SAA7115 I2C driver", - }, - .probe = wis_saa7115_probe, - .remove = wis_saa7115_remove, - .command = wis_saa7115_command, - .id_table = wis_saa7115_id, -}; - -module_i2c_driver(wis_saa7115_driver); - -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/go7007/wis-sony-tuner.c b/drivers/staging/media/go7007/wis-sony-tuner.c deleted file mode 100644 index 5d7ff8c..0000000 --- a/drivers/staging/media/go7007/wis-sony-tuner.c +++ /dev/null @@ -1,707 +0,0 @@ -/* - * 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 "wis-i2c.h" - -/* #define MPX_DEBUG */ - -/* AS(IF/MPX) pin: LOW HIGH/OPEN - * IF/MPX address: 0x42/0x40 0x43/0x44 - */ -#define IF_I2C_ADDR 0x43 -#define MPX_I2C_ADDR 0x44 - -static v4l2_std_id force_band; -static char force_band_str[] = "-"; -module_param_string(force_band, force_band_str, sizeof(force_band_str), 0644); -static int force_mpx_mode = -1; -module_param(force_mpx_mode, int, 0644); - -/* Store tuner info in the same format as tuner.c, so maybe we can put the - * Sony tuner support in there. */ -struct sony_tunertype { - char *name; - unsigned char Vendor; /* unused here */ - unsigned char Type; /* unused here */ - - unsigned short thresh1; /* band switch VHF_LO <=> VHF_HI */ - unsigned short thresh2; /* band switch VHF_HI <=> UHF */ - unsigned char VHF_L; - unsigned char VHF_H; - unsigned char UHF; - unsigned char config; - unsigned short IFPCoff; -}; - -/* This array is indexed by (tuner_type - 200) */ -static struct sony_tunertype sony_tuners[] = { - { "Sony PAL+SECAM (BTF-PG472Z)", 0, 0, - 16*144.25, 16*427.25, 0x01, 0x02, 0x04, 0xc6, 623}, - { "Sony NTSC_JP (BTF-PK467Z)", 0, 0, - 16*220.25, 16*467.25, 0x01, 0x02, 0x04, 0xc6, 940}, - { "Sony NTSC (BTF-PB463Z)", 0, 0, - 16*130.25, 16*364.25, 0x01, 0x02, 0x04, 0xc6, 732}, -}; - -struct wis_sony_tuner { - int type; - v4l2_std_id std; - unsigned int freq; - int mpxmode; - u32 audmode; -}; - -/* Basically the same as default_set_tv_freq() in tuner.c */ -static int set_freq(struct i2c_client *client, int freq) -{ - struct wis_sony_tuner *t = i2c_get_clientdata(client); - char *band_name; - int n; - int band_select; - struct sony_tunertype *tun; - u8 buffer[4]; - - tun = &sony_tuners[t->type - 200]; - if (freq < tun->thresh1) { - band_name = "VHF_L"; - band_select = tun->VHF_L; - } else if (freq < tun->thresh2) { - band_name = "VHF_H"; - band_select = tun->VHF_H; - } else { - band_name = "UHF"; - band_select = tun->UHF; - } - dev_dbg(&client->dev, "tuning to frequency %d.%04d (%s)\n", - freq / 16, (freq % 16) * 625, band_name); - n = freq + tun->IFPCoff; - - buffer[0] = n >> 8; - buffer[1] = n & 0xff; - buffer[2] = tun->config; - buffer[3] = band_select; - i2c_master_send(client, buffer, 4); - - return 0; -} - -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 = MPX_I2C_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 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 i2c_client *client) -{ - struct wis_sony_tuner *t = i2c_get_clientdata(client); - u16 source = 0; - u8 buffer[3]; - struct i2c_msg msg; - - /* reset MPX */ - buffer[0] = 0x00; - buffer[1] = 0x80; - buffer[2] = 0x00; - msg.addr = MPX_I2C_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 (mpx_audio_modes[t->mpxmode].audio_mode != AUD_MONO) { - switch (t->audmode) { - case V4L2_TUNER_MODE_MONO: - switch (mpx_audio_modes[t->mpxmode].audio_mode) { - case AUD_A2: - source = mpx_audio_modes[t->mpxmode].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[t->mpxmode].source; - break; - case V4L2_TUNER_MODE_LANG1: - source = 0x0300; - break; - case V4L2_TUNER_MODE_LANG2: - source = 0x0400; - break; - } - source |= mpx_audio_modes[t->mpxmode].source & 0x00ff; - } else - source = mpx_audio_modes[t->mpxmode].source; - - mpx_write(client, 0x10, 0x0030, mpx_audio_modes[t->mpxmode].modus); - mpx_write(client, 0x12, 0x0008, source); - mpx_write(client, 0x12, 0x0013, mpx_audio_modes[t->mpxmode].acb); - mpx_write(client, 0x12, 0x000e, - mpx_audio_modes[t->mpxmode].fm_prescale); - mpx_write(client, 0x12, 0x0010, - mpx_audio_modes[t->mpxmode].nicam_prescale); - mpx_write(client, 0x12, 0x000d, - mpx_audio_modes[t->mpxmode].scart_prescale); - mpx_write(client, 0x10, 0x0020, mpx_audio_modes[t->mpxmode].system); - mpx_write(client, 0x12, 0x0000, mpx_audio_modes[t->mpxmode].volume); - if (mpx_audio_modes[t->mpxmode].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]; - - dev_dbg(&client->dev, - "MPX registers: %04x %04x %04x %04x %04x %04x %04x %04x\n", - mpx_audio_modes[t->mpxmode].modus, - source, - mpx_audio_modes[t->mpxmode].acb, - mpx_audio_modes[t->mpxmode].fm_prescale, - mpx_audio_modes[t->mpxmode].nicam_prescale, - mpx_audio_modes[t->mpxmode].scart_prescale, - mpx_audio_modes[t->mpxmode].system, - mpx_audio_modes[t->mpxmode].volume); - buf1[0] = 0x11; - buf1[1] = 0x00; - buf1[2] = 0x7e; - msgs[0].addr = MPX_I2C_ADDR; - msgs[0].flags = 0; - msgs[0].len = 3; - msgs[0].buf = buf1; - msgs[1].addr = MPX_I2C_ADDR; - msgs[1].flags = I2C_M_RD; - msgs[1].len = 2; - msgs[1].buf = buf2; - i2c_transfer(client->adapter, msgs, 2); - dev_dbg(&client->dev, "MPX system: %02x%02x\n", - buf2[0], buf2[1]); - buf1[0] = 0x11; - buf1[1] = 0x02; - buf1[2] = 0x00; - i2c_transfer(client->adapter, msgs, 2); - dev_dbg(&client->dev, "MPX status: %02x%02x\n", - buf2[0], buf2[1]); - } -#endif - return 0; -} - -/* - * IF configuration values for the BTF-PG472Z: - * - * B/G: 0x94 0x70 0x49 - * I: 0x14 0x70 0x4a - * D/K: 0x14 0x70 0x4b - * L: 0x04 0x70 0x4b - * L': 0x44 0x70 0x53 - * M: 0x50 0x30 0x4c - */ - -static int set_if(struct i2c_client *client) -{ - struct wis_sony_tuner *t = i2c_get_clientdata(client); - u8 buffer[4]; - struct i2c_msg msg; - int default_mpx_mode = 0; - - /* configure IF */ - buffer[0] = 0; - if (t->std & V4L2_STD_PAL_BG) { - buffer[1] = 0x94; - buffer[2] = 0x70; - buffer[3] = 0x49; - default_mpx_mode = 1; - } else if (t->std & V4L2_STD_PAL_I) { - buffer[1] = 0x14; - buffer[2] = 0x70; - buffer[3] = 0x4a; - default_mpx_mode = 4; - } else if (t->std & V4L2_STD_PAL_DK) { - buffer[1] = 0x14; - buffer[2] = 0x70; - buffer[3] = 0x4b; - default_mpx_mode = 6; - } else if (t->std & V4L2_STD_SECAM_L) { - buffer[1] = 0x04; - buffer[2] = 0x70; - buffer[3] = 0x4b; - default_mpx_mode = 11; - } - msg.addr = IF_I2C_ADDR; - msg.flags = 0; - msg.len = 4; - msg.buf = buffer; - i2c_transfer(client->adapter, &msg, 1); - - /* Select MPX mode if not forced by the user */ - if (force_mpx_mode >= 0 && force_mpx_mode < MPX_NUM_MODES) - t->mpxmode = force_mpx_mode; - else - t->mpxmode = default_mpx_mode; - dev_dbg(&client->dev, "setting MPX to mode %d\n", t->mpxmode); - mpx_setup(client); - - return 0; -} - -static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct wis_sony_tuner *t = i2c_get_clientdata(client); - - switch (cmd) { -#if 0 -#ifdef TUNER_SET_TYPE_ADDR - case TUNER_SET_TYPE_ADDR: - { - struct tuner_setup *tun_setup = arg; - int *type = &tun_setup->type; -#else - case TUNER_SET_TYPE: - { - int *type = arg; -#endif - - if (t->type >= 0) { - if (t->type != *type) - dev_err(&client->dev, - "type already set to %d, ignoring request for %d\n", - t->type, *type); - break; - } - t->type = *type; - switch (t->type) { - case TUNER_SONY_BTF_PG472Z: - switch (force_band_str[0]) { - case 'b': - case 'B': - case 'g': - case 'G': - dev_info(&client->dev, - "forcing tuner to PAL-B/G bands\n"); - force_band = V4L2_STD_PAL_BG; - break; - case 'i': - case 'I': - dev_info(&client->dev, - "forcing tuner to PAL-I band\n"); - force_band = V4L2_STD_PAL_I; - break; - case 'd': - case 'D': - case 'k': - case 'K': - dev_info(&client->dev, - "forcing tuner to PAL-D/K bands\n"); - force_band = V4L2_STD_PAL_I; - break; - case 'l': - case 'L': - dev_info(&client->dev, - "forcing tuner to SECAM-L band\n"); - force_band = V4L2_STD_SECAM_L; - break; - default: - force_band = 0; - break; - } - if (force_band) - t->std = force_band; - else - t->std = V4L2_STD_PAL_BG; - set_if(client); - break; - case TUNER_SONY_BTF_PK467Z: - t->std = V4L2_STD_NTSC_M_JP; - break; - case TUNER_SONY_BTF_PB463Z: - t->std = V4L2_STD_NTSC_M; - break; - default: - dev_err(&client->dev, - "tuner type %d is not supported by this module\n", - *type); - break; - } - if (type >= 0) - dev_info(&clinet->dev, - "type set to %d (%s)\n", - t->type, sony_tuners[t->type - 200].name); - break; - } -#endif - case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - f->frequency = t->freq; - break; - } - case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - t->freq = f->frequency; - set_freq(client, t->freq); - break; - } - case VIDIOC_ENUMSTD: - { - struct v4l2_standard *std = arg; - - switch (t->type) { - case TUNER_SONY_BTF_PG472Z: - switch (std->index) { - case 0: - v4l2_video_std_construct(std, - V4L2_STD_PAL_BG, "PAL-B/G"); - break; - case 1: - v4l2_video_std_construct(std, - V4L2_STD_PAL_I, "PAL-I"); - break; - case 2: - v4l2_video_std_construct(std, - V4L2_STD_PAL_DK, "PAL-D/K"); - break; - case 3: - v4l2_video_std_construct(std, - V4L2_STD_SECAM_L, "SECAM-L"); - break; - default: - std->id = 0; /* hack to indicate EINVAL */ - break; - } - break; - case TUNER_SONY_BTF_PK467Z: - if (std->index != 0) { - std->id = 0; /* hack to indicate EINVAL */ - break; - } - v4l2_video_std_construct(std, - V4L2_STD_NTSC_M_JP, "NTSC-J"); - break; - case TUNER_SONY_BTF_PB463Z: - if (std->index != 0) { - std->id = 0; /* hack to indicate EINVAL */ - break; - } - v4l2_video_std_construct(std, V4L2_STD_NTSC_M, "NTSC"); - break; - } - break; - } - case VIDIOC_G_STD: - { - v4l2_std_id *std = arg; - - *std = t->std; - break; - } - case VIDIOC_S_STD: - { - v4l2_std_id *std = arg; - v4l2_std_id old = t->std; - - switch (t->type) { - case TUNER_SONY_BTF_PG472Z: - if (force_band && (*std & force_band) != *std && - *std != V4L2_STD_PAL && - *std != V4L2_STD_SECAM) { - dev_dbg(&client->dev, - "ignoring requested TV standard in favor of force_band value\n"); - t->std = force_band; - } else if (*std & V4L2_STD_PAL_BG) { /* default */ - t->std = V4L2_STD_PAL_BG; - } else if (*std & V4L2_STD_PAL_I) { - t->std = V4L2_STD_PAL_I; - } else if (*std & V4L2_STD_PAL_DK) { - t->std = V4L2_STD_PAL_DK; - } else if (*std & V4L2_STD_SECAM_L) { - t->std = V4L2_STD_SECAM_L; - } else { - dev_err(&client->dev, - "TV standard not supported\n"); - *std = 0; /* hack to indicate EINVAL */ - break; - } - if (old != t->std) - set_if(client); - break; - case TUNER_SONY_BTF_PK467Z: - if (!(*std & V4L2_STD_NTSC_M_JP)) { - dev_err(&client->dev, - "TV standard not supported\n"); - *std = 0; /* hack to indicate EINVAL */ - } - break; - case TUNER_SONY_BTF_PB463Z: - if (!(*std & V4L2_STD_NTSC_M)) { - dev_err(&client->dev, - "TV standard not supported\n"); - *std = 0; /* hack to indicate EINVAL */ - } - break; - } - break; - } - case VIDIOC_QUERYSTD: - { - v4l2_std_id *std = arg; - - switch (t->type) { - case TUNER_SONY_BTF_PG472Z: - if (force_band) - *std = force_band; - else - *std = V4L2_STD_PAL_BG | V4L2_STD_PAL_I | - V4L2_STD_PAL_DK | V4L2_STD_SECAM_L; - break; - case TUNER_SONY_BTF_PK467Z: - *std = V4L2_STD_NTSC_M_JP; - break; - case TUNER_SONY_BTF_PB463Z: - *std = V4L2_STD_NTSC_M; - break; - } - break; - } - case VIDIOC_G_TUNER: - { - struct v4l2_tuner *tun = arg; - - memset(tun, 0, sizeof(*tun)); - strcpy(tun->name, "Television"); - tun->type = V4L2_TUNER_ANALOG_TV; - tun->rangelow = 0UL; /* does anything use these? */ - tun->rangehigh = 0xffffffffUL; - switch (t->type) { - case TUNER_SONY_BTF_PG472Z: - tun->capability = V4L2_TUNER_CAP_NORM | - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | - V4L2_TUNER_CAP_LANG2; - tun->rxsubchans = V4L2_TUNER_SUB_MONO | - V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_LANG1 | - V4L2_TUNER_SUB_LANG2; - break; - case TUNER_SONY_BTF_PK467Z: - case TUNER_SONY_BTF_PB463Z: - tun->capability = V4L2_TUNER_CAP_STEREO; - tun->rxsubchans = V4L2_TUNER_SUB_MONO | - V4L2_TUNER_SUB_STEREO; - break; - } - tun->audmode = t->audmode; - return 0; - } - case VIDIOC_S_TUNER: - { - struct v4l2_tuner *tun = arg; - - switch (t->type) { - case TUNER_SONY_BTF_PG472Z: - if (tun->audmode != t->audmode) { - t->audmode = tun->audmode; - mpx_setup(client); - } - break; - case TUNER_SONY_BTF_PK467Z: - case TUNER_SONY_BTF_PB463Z: - break; - } - return 0; - } - default: - break; - } - return 0; -} - -static int wis_sony_tuner_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = client->adapter; - struct wis_sony_tuner *t; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) - return -ENODEV; - - t = kmalloc(sizeof(struct wis_sony_tuner), GFP_KERNEL); - if (t == NULL) - return -ENOMEM; - - t->type = -1; - t->freq = 0; - t->mpxmode = 0; - t->audmode = V4L2_TUNER_MODE_STEREO; - i2c_set_clientdata(client, t); - - dev_dbg(&client->dev, "initializing tuner at address %d on %s\n", - client->addr, adapter->name); - - return 0; -} - -static int wis_sony_tuner_remove(struct i2c_client *client) -{ - struct wis_sony_tuner *t = i2c_get_clientdata(client); - - kfree(t); - return 0; -} - -static const struct i2c_device_id wis_sony_tuner_id[] = { - { "wis_sony_tuner", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wis_sony_tuner_id); - -static struct i2c_driver wis_sony_tuner_driver = { - .driver = { - .name = "WIS Sony TV Tuner I2C driver", - }, - .probe = wis_sony_tuner_probe, - .remove = wis_sony_tuner_remove, - .command = tuner_command, - .id_table = wis_sony_tuner_id, -}; - -module_i2c_driver(wis_sony_tuner_driver); - -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/go7007/wis-tw2804.c b/drivers/staging/media/go7007/wis-tw2804.c deleted file mode 100644 index 290fd8c..0000000 --- a/drivers/staging/media/go7007/wis-tw2804.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * 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 "wis-i2c.h" - -struct wis_tw2804 { - int channel; - int norm; - int brightness; - int contrast; - int saturation; - int hue; -}; - -static 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 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, int channel) -{ - return i2c_smbus_write_byte_data(client, reg | (channel << 6), value); -} - -static int write_regs(struct i2c_client *client, u8 *regs, int channel) -{ - int i; - - for (i = 0; regs[i] != 0xff; i += 2) - if (i2c_smbus_write_byte_data(client, - regs[i] | (channel << 6), regs[i + 1]) < 0) - return -1; - return 0; -} - -static int wis_tw2804_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct wis_tw2804 *dec = i2c_get_clientdata(client); - - if (cmd == DECODER_SET_CHANNEL) { - int *input = arg; - - if (*input < 0 || *input > 3) { - dev_err(&client->dev, - "channel %d is not between 0 and 3!\n", *input); - return 0; - } - dec->channel = *input; - 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 0; - } - if (write_regs(client, channel_registers, dec->channel) < 0) { - dev_err(&client->dev, - "error initializing TW2804 channel %d\n", - dec->channel); - return 0; - } - return 0; - } - - if (dec->channel < 0) { - dev_dbg(&client->dev, - "ignoring command %08x until channel number is set\n", - cmd); - return 0; - } - - switch (cmd) { - case VIDIOC_S_STD: - { - v4l2_std_id *input = arg; - u8 regs[] = { - 0x01, *input & V4L2_STD_NTSC ? 0xc4 : 0x84, - 0x09, *input & V4L2_STD_NTSC ? 0x07 : 0x04, - 0x0a, *input & V4L2_STD_NTSC ? 0xf0 : 0x20, - 0x0b, *input & V4L2_STD_NTSC ? 0x07 : 0x04, - 0x0c, *input & V4L2_STD_NTSC ? 0xf0 : 0x20, - 0x0d, *input & V4L2_STD_NTSC ? 0x40 : 0x4a, - 0x16, *input & V4L2_STD_NTSC ? 0x00 : 0x40, - 0x17, *input & V4L2_STD_NTSC ? 0x00 : 0x40, - 0x20, *input & V4L2_STD_NTSC ? 0x07 : 0x0f, - 0x21, *input & V4L2_STD_NTSC ? 0x07 : 0x0f, - 0xff, 0xff, - }; - write_regs(client, regs, dec->channel); - dec->norm = *input; - break; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 255; - ctrl->step = 1; - ctrl->default_value = 128; - ctrl->flags = 0; - break; - case V4L2_CID_CONTRAST: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 255; - ctrl->step = 1; - ctrl->default_value = 128; - ctrl->flags = 0; - break; - case V4L2_CID_SATURATION: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 255; - ctrl->step = 1; - ctrl->default_value = 128; - ctrl->flags = 0; - break; - case V4L2_CID_HUE: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 255; - ctrl->step = 1; - ctrl->default_value = 128; - ctrl->flags = 0; - break; - } - break; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - if (ctrl->value > 255) - dec->brightness = 255; - else if (ctrl->value < 0) - dec->brightness = 0; - else - dec->brightness = ctrl->value; - write_reg(client, 0x12, dec->brightness, dec->channel); - break; - case V4L2_CID_CONTRAST: - if (ctrl->value > 255) - dec->contrast = 255; - else if (ctrl->value < 0) - dec->contrast = 0; - else - dec->contrast = ctrl->value; - write_reg(client, 0x11, dec->contrast, dec->channel); - break; - case V4L2_CID_SATURATION: - if (ctrl->value > 255) - dec->saturation = 255; - else if (ctrl->value < 0) - dec->saturation = 0; - else - dec->saturation = ctrl->value; - write_reg(client, 0x10, dec->saturation, dec->channel); - break; - case V4L2_CID_HUE: - if (ctrl->value > 255) - dec->hue = 255; - else if (ctrl->value < 0) - dec->hue = 0; - else - dec->hue = ctrl->value; - write_reg(client, 0x0f, dec->hue, dec->channel); - break; - } - break; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = dec->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = dec->contrast; - break; - case V4L2_CID_SATURATION: - ctrl->value = dec->saturation; - break; - case V4L2_CID_HUE: - ctrl->value = dec->hue; - break; - } - break; - } - default: - break; - } - return 0; -} - -static int wis_tw2804_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = client->adapter; - struct wis_tw2804 *dec; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - dec = kmalloc(sizeof(struct wis_tw2804), GFP_KERNEL); - if (dec == NULL) - return -ENOMEM; - - dec->channel = -1; - dec->norm = V4L2_STD_NTSC; - dec->brightness = 128; - dec->contrast = 128; - dec->saturation = 128; - dec->hue = 128; - i2c_set_clientdata(client, dec); - - dev_dbg(&client->dev, "creating TW2804 at address %d on %s\n", - client->addr, adapter->name); - - return 0; -} - -static int wis_tw2804_remove(struct i2c_client *client) -{ - struct wis_tw2804 *dec = i2c_get_clientdata(client); - - kfree(dec); - return 0; -} - -static const struct i2c_device_id wis_tw2804_id[] = { - { "wis_tw2804", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wis_tw2804_id); - -static struct i2c_driver wis_tw2804_driver = { - .driver = { - .name = "WIS TW2804 I2C driver", - }, - .probe = wis_tw2804_probe, - .remove = wis_tw2804_remove, - .command = wis_tw2804_command, - .id_table = wis_tw2804_id, -}; - -module_i2c_driver(wis_tw2804_driver); - -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/go7007/wis-tw9903.c b/drivers/staging/media/go7007/wis-tw9903.c deleted file mode 100644 index 684ca37..0000000 --- a/drivers/staging/media/go7007/wis-tw9903.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * 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 "wis-i2c.h" - -struct wis_tw9903 { - int norm; - int brightness; - int contrast; - int hue; -}; - -static 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 i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int write_regs(struct i2c_client *client, u8 *regs) -{ - int i; - - for (i = 0; regs[i] != 0x00; i += 2) - if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) - return -1; - return 0; -} - -static int wis_tw9903_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - struct wis_tw9903 *dec = i2c_get_clientdata(client); - - switch (cmd) { - case VIDIOC_S_INPUT: - { - int *input = arg; - - i2c_smbus_write_byte_data(client, 0x02, 0x40 | (*input << 1)); - break; - } -#if 0 - /* The scaler on this thing seems to be horribly broken */ - case DECODER_SET_RESOLUTION: - { - struct video_decoder_resolution *res = arg; - /*int hscale = 256 * 720 / res->width;*/ - int hscale = 256 * 720 / (res->width - (res->width > 704 ? 0 : 8)); - int vscale = 256 * (dec->norm & V4L2_STD_NTSC ? 240 : 288) - / res->height; - u8 regs[] = { - 0x0d, vscale & 0xff, - 0x0f, hscale & 0xff, - 0x0e, ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8), - 0x06, 0xc0, /* reset device */ - 0, 0, - }; - dev_dbg(&client->dev, "vscale is %04x, hscale is %04x\n", - vscale, hscale); - /*write_regs(client, regs);*/ - break; - } -#endif - case VIDIOC_S_STD: - { - v4l2_std_id *input = arg; - u8 regs[] = { - 0x05, *input & V4L2_STD_NTSC ? 0x80 : 0x00, - 0x07, *input & V4L2_STD_NTSC ? 0x02 : 0x12, - 0x08, *input & V4L2_STD_NTSC ? 0x14 : 0x18, - 0x09, *input & V4L2_STD_NTSC ? 0xf0 : 0x20, - 0, 0, - }; - write_regs(client, regs); - dec->norm = *input; - break; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)); - ctrl->minimum = -128; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 0x00; - ctrl->flags = 0; - break; - case V4L2_CID_CONTRAST: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 255; - ctrl->step = 1; - ctrl->default_value = 0x60; - ctrl->flags = 0; - break; -#if 0 - /* I don't understand how the Chroma Gain registers work... */ - case V4L2_CID_SATURATION: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)); - ctrl->minimum = 0; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 64; - ctrl->flags = 0; - break; -#endif - case V4L2_CID_HUE: - ctrl->type = V4L2_CTRL_TYPE_INTEGER; - strncpy(ctrl->name, "Hue", sizeof(ctrl->name)); - ctrl->minimum = -128; - ctrl->maximum = 127; - ctrl->step = 1; - ctrl->default_value = 0; - ctrl->flags = 0; - break; - } - break; - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - if (ctrl->value > 127) - dec->brightness = 127; - else if (ctrl->value < -128) - dec->brightness = -128; - else - dec->brightness = ctrl->value; - write_reg(client, 0x10, dec->brightness); - break; - case V4L2_CID_CONTRAST: - if (ctrl->value > 255) - dec->contrast = 255; - else if (ctrl->value < 0) - dec->contrast = 0; - else - dec->contrast = ctrl->value; - write_reg(client, 0x11, dec->contrast); - break; -#if 0 - case V4L2_CID_SATURATION: - if (ctrl->value > 127) - dec->saturation = 127; - else if (ctrl->value < 0) - dec->saturation = 0; - else - dec->saturation = ctrl->value; - /*write_reg(client, 0x0c, dec->saturation);*/ - break; -#endif - case V4L2_CID_HUE: - if (ctrl->value > 127) - dec->hue = 127; - else if (ctrl->value < -128) - dec->hue = -128; - else - dec->hue = ctrl->value; - write_reg(client, 0x15, dec->hue); - break; - } - break; - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrl->value = dec->brightness; - break; - case V4L2_CID_CONTRAST: - ctrl->value = dec->contrast; - break; -#if 0 - case V4L2_CID_SATURATION: - ctrl->value = dec->saturation; - break; -#endif - case V4L2_CID_HUE: - ctrl->value = dec->hue; - break; - } - break; - } - default: - break; - } - return 0; -} - -static int wis_tw9903_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = client->adapter; - struct wis_tw9903 *dec; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -ENODEV; - - dec = kmalloc(sizeof(struct wis_tw9903), GFP_KERNEL); - if (dec == NULL) - return -ENOMEM; - - dec->norm = V4L2_STD_NTSC; - dec->brightness = 0; - dec->contrast = 0x60; - dec->hue = 0; - i2c_set_clientdata(client, dec); - - dev_dbg(&client->dev, "initializing TW9903 at address %d on %s\n", - client->addr, adapter->name); - - if (write_regs(client, initial_registers) < 0) { - dev_err(&client->dev, "error initializing TW9903\n"); - kfree(dec); - return -ENODEV; - } - - return 0; -} - -static int wis_tw9903_remove(struct i2c_client *client) -{ - struct wis_tw9903 *dec = i2c_get_clientdata(client); - - kfree(dec); - return 0; -} - -static const struct i2c_device_id wis_tw9903_id[] = { - { "wis_tw9903", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wis_tw9903_id); - -static struct i2c_driver wis_tw9903_driver = { - .driver = { - .name = "WIS TW9903 I2C driver", - }, - .probe = wis_tw9903_probe, - .remove = wis_tw9903_remove, - .command = wis_tw9903_command, - .id_table = wis_tw9903_id, -}; - -module_i2c_driver(wis_tw9903_driver); - -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/go7007/wis-uda1342.c b/drivers/staging/media/go7007/wis-uda1342.c deleted file mode 100644 index 582ea12..0000000 --- a/drivers/staging/media/go7007/wis-uda1342.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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 "wis-i2c.h" - -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 wis_uda1342_command(struct i2c_client *client, - unsigned int cmd, void *arg) -{ - switch (cmd) { - case VIDIOC_S_AUDIO: - { - int *inp = arg; - - switch (*inp) { - case TVAUDIO_INPUT_TUNER: - write_reg(client, 0x00, 0x1441); /* select input 2 */ - break; - case TVAUDIO_INPUT_EXTERN: - write_reg(client, 0x00, 0x1241); /* select input 1 */ - break; - default: - dev_err(&client->dev, "input %d not supported\n", - *inp); - break; - } - break; - } - default: - break; - } - return 0; -} - -static int wis_uda1342_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct i2c_adapter *adapter = client->adapter; - - 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); - - write_reg(client, 0x00, 0x8000); /* reset registers */ - write_reg(client, 0x00, 0x1241); /* select input 1 */ - - return 0; -} - -static int wis_uda1342_remove(struct i2c_client *client) -{ - return 0; -} - -static const struct i2c_device_id wis_uda1342_id[] = { - { "wis_uda1342", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, wis_uda1342_id); - -static struct i2c_driver wis_uda1342_driver = { - .driver = { - .name = "WIS UDA1342 I2C driver", - }, - .probe = wis_uda1342_probe, - .remove = wis_uda1342_remove, - .command = wis_uda1342_command, - .id_table = wis_uda1342_id, -}; - -module_i2c_driver(wis_uda1342_driver); - -MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 5e4105467bfff64242e1b7aca17ae9e4438be32c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 13:19:08 -0300 Subject: [media] go7007: add audio input ioctls Since we now know what audio inputs there are, we can also get/set and enumerate them. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index fcd3e2d..a730781 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -608,9 +608,10 @@ static int vidioc_querycap(struct file *file, void *priv, cap->version = KERNEL_VERSION(0, 9, 8); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING; /* | V4L2_CAP_AUDIO; */ + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + if (go->board_info->num_aud_inputs) + cap->device_caps |= V4L2_CAP_AUDIO; if (go->board_info->flags & GO7007_BOARD_HAS_TUNER) cap->capabilities |= V4L2_CAP_TUNER; @@ -1191,7 +1192,10 @@ static int vidioc_enum_input(struct file *file, void *priv, else inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->audioset = 0; + if (go->board_info->num_aud_inputs) + inp->audioset = (1 << go->board_info->num_aud_inputs) - 1; + else + inp->audioset = 0; inp->tuner = 0; if (go->board_info->sensor_flags & GO7007_SENSOR_TV) inp->std = V4L2_STD_NTSC | V4L2_STD_PAL | @@ -1212,6 +1216,39 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *input) return 0; } +static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a) +{ + struct go7007 *go = video_drvdata(file); + + if (a->index >= go->board_info->num_aud_inputs) + return -EINVAL; + strlcpy(a->name, go->board_info->aud_inputs[a->index].name, sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) +{ + struct go7007 *go = video_drvdata(file); + + a->index = go->aud_input; + strlcpy(a->name, go->board_info->aud_inputs[go->aud_input].name, sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; + return 0; +} + +static int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *a) +{ + struct go7007 *go = video_drvdata(file); + + if (a->index >= go->board_info->num_aud_inputs) + return -EINVAL; + go->aud_input = a->index; + v4l2_subdev_call(go->sd_audio, audio, s_routing, + go->board_info->aud_inputs[go->aud_input].audio_input, 0, 0); + return 0; +} + static int vidioc_s_input(struct file *file, void *priv, unsigned int input) { struct go7007 *go = ((struct go7007_file *) priv)->go; @@ -1772,6 +1809,9 @@ 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_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, @@ -1816,6 +1856,11 @@ int go7007_v4l2_init(struct go7007 *go) go->video_dev = NULL; return rv; } + if (go->board_info->num_aud_inputs == 0) { + v4l2_disable_ioctl(go->video_dev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(go->video_dev, VIDIOC_S_AUDIO); + v4l2_disable_ioctl(go->video_dev, VIDIOC_ENUMAUDIO); + } rv = v4l2_device_register(go->dev, &go->v4l2_dev); if (rv < 0) { video_device_release(go->video_dev); -- cgit v0.10.2 From c046981f1aa0e1e1345e6ec43f6bea611e575351 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 09:35:07 -0300 Subject: [media] s2250-loader: use usbv2_cypress_load_firmware The v2 of this function doesn't do DMA to objects on the stack like its predecessor does. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/Makefile b/drivers/staging/media/go7007/Makefile index 5bed78b..f9c8e0f 100644 --- a/drivers/staging/media/go7007/Makefile +++ b/drivers/staging/media/go7007/Makefile @@ -11,8 +11,8 @@ s2250-y := s2250-board.o #obj-$(CONFIG_VIDEO_SAA7134) += saa7134-go7007.o #ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/video/saa7134 -DSAA7134_MPEG_GO7007=3 -# S2250 needs cypress ezusb loader from dvb-usb -ccflags-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD:m=y) += -Idrivers/media/usb/dvb-usb +# S2250 needs cypress ezusb loader from dvb-usb-v2 +ccflags-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD:m=y) += -Idrivers/media/usb/dvb-usb-v2 ccflags-y += -Idrivers/media/dvb-frontends ccflags-y += -Idrivers/media/dvb-core diff --git a/drivers/staging/media/go7007/s2250-loader.c b/drivers/staging/media/go7007/s2250-loader.c index 72e5175..6453ec0 100644 --- a/drivers/staging/media/go7007/s2250-loader.c +++ b/drivers/staging/media/go7007/s2250-loader.c @@ -19,7 +19,8 @@ #include #include #include -#include +#include +#include #define S2250_LOADER_FIRMWARE "s2250_loader.fw" #define S2250_FIRMWARE "s2250.fw" @@ -104,7 +105,7 @@ static int s2250loader_probe(struct usb_interface *interface, S2250_LOADER_FIRMWARE); goto failed2; } - ret = usb_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); + ret = usbv2_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); release_firmware(fw); if (0 != ret) { dev_err(&interface->dev, "loader download failed\n"); @@ -117,7 +118,7 @@ static int s2250loader_probe(struct usb_interface *interface, S2250_FIRMWARE); goto failed2; } - ret = usb_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); + ret = usbv2_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); release_firmware(fw); if (0 != ret) { dev_err(&interface->dev, "firmware_s2250 download failed\n"); -- cgit v0.10.2 From 4d217b83fe315776d54b11d752fb09c5fb0de2da Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 09:38:03 -0300 Subject: [media] go7007: go7007: add device_caps and bus_info support to querycap And don't set the version field, the core does that for you. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index 898eb5b..1c4b049 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -171,6 +171,7 @@ enum go7007_parser_state { struct go7007 { struct device *dev; + u8 bus_info[32]; struct go7007_board_info *board_info; unsigned int board_id; int tuner_type; diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 5e3e5a0..0b1af50 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -1087,6 +1087,7 @@ static int go7007_usb_probe(struct usb_interface *intf, goto allocfail; usb->board = board; usb->usbdev = usbdev; + usb_make_path(usbdev, go->bus_info, sizeof(go->bus_info)); go->board_id = id->driver_info; strncpy(go->name, name, sizeof(go->name)); if (board->flags & GO7007_USB_EZUSB) diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index a730781..e9196bb 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -602,19 +602,15 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->driver, "go7007", sizeof(cap->driver)); strlcpy(cap->card, go->name, sizeof(cap->card)); -#if 0 - strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info)); -#endif - - cap->version = KERNEL_VERSION(0, 9, 8); + strlcpy(cap->bus_info, go->bus_info, sizeof(cap->bus_info)); cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; if (go->board_info->num_aud_inputs) cap->device_caps |= V4L2_CAP_AUDIO; if (go->board_info->flags & GO7007_BOARD_HAS_TUNER) - cap->capabilities |= V4L2_CAP_TUNER; - + cap->device_caps |= V4L2_CAP_TUNER; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c index e037a39..d65e17a 100644 --- a/drivers/staging/media/go7007/saa7134-go7007.c +++ b/drivers/staging/media/go7007/saa7134-go7007.c @@ -456,6 +456,7 @@ static int saa7134_go7007_init(struct saa7134_dev *dev) if (go == NULL) goto allocfail; go->board_id = GO7007_BOARDID_PCI_VOYAGER; + snprintf(go->bus_info, sizeof(go->bus_info), "PCI:%s", pci_name(dev->pci)); strncpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name)); go->hpi_ops = &saa7134_go7007_hpi_ops; go->hpi_context = saa; -- cgit v0.10.2 From fabfd71153c7e98aca77c8069a633f3a25bcdaf7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 17 Feb 2013 09:06:27 -0300 Subject: [media] go7007: remove current_norm It's deprecated and replaced by g_std. Since this driver already implements g_std the use of current_norm can just be removed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index e9196bb..6cb6f43 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -1834,7 +1834,6 @@ static struct video_device go7007_template = { .release = go7007_vfl_release, .ioctl_ops = &video_ioctl_ops, .tvnorms = V4L2_STD_ALL, - .current_norm = V4L2_STD_NTSC, }; int go7007_v4l2_init(struct go7007 *go) -- cgit v0.10.2 From 9b6ebf3309d1b2e62727133b446397a783813331 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 09:59:16 -0300 Subject: [media] go7007: fix DMA related errors - Don't pass data allocated on the stack to usb_control_msg. - Use dma_mapping_error after calling dma_map_page(). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index 1c4b049..daae6dd 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -188,6 +188,7 @@ struct go7007 { int audio_enabled; struct v4l2_subdev *sd_video; struct v4l2_subdev *sd_audio; + u8 usb_buf[16]; /* Video input */ int input; diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 0b1af50..f496720 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -652,7 +652,7 @@ static int go7007_usb_ezusb_write_interrupt(struct go7007 *go, { struct go7007_usb *usb = go->hpi_context; int i, r; - u16 status_reg; + u16 status_reg = 0; int timeout = 500; #ifdef GO7007_USB_DEBUG @@ -664,15 +664,17 @@ static int go7007_usb_ezusb_write_interrupt(struct go7007 *go, r = usb_control_msg(usb->usbdev, usb_rcvctrlpipe(usb->usbdev, 0), 0x14, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - 0, HPI_STATUS_ADDR, &status_reg, + 0, HPI_STATUS_ADDR, go->usb_buf, sizeof(status_reg), timeout); if (r < 0) - goto write_int_error; - __le16_to_cpus(&status_reg); + break; + status_reg = le16_to_cpu(*((u16 *)go->usb_buf)); if (!(status_reg & 0x0010)) break; msleep(10); } + if (r < 0) + goto write_int_error; if (i == 100) { printk(KERN_ERR "go7007-usb: device is hung, status reg = 0x%04x\n", @@ -700,7 +702,6 @@ static int go7007_usb_onboard_write_interrupt(struct go7007 *go, int addr, int data) { struct go7007_usb *usb = go->hpi_context; - u8 *tbuf; int r; int timeout = 500; @@ -709,17 +710,14 @@ static int go7007_usb_onboard_write_interrupt(struct go7007 *go, "go7007-usb: WriteInterrupt: %04x %04x\n", addr, data); #endif - tbuf = kzalloc(8, GFP_KERNEL); - if (tbuf == NULL) - return -ENOMEM; - tbuf[0] = data & 0xff; - tbuf[1] = data >> 8; - tbuf[2] = addr & 0xff; - tbuf[3] = addr >> 8; + go->usb_buf[0] = data & 0xff; + go->usb_buf[1] = data >> 8; + go->usb_buf[2] = addr & 0xff; + go->usb_buf[3] = addr >> 8; + go->usb_buf[4] = go->usb_buf[5] = go->usb_buf[6] = go->usb_buf[7] = 0; r = usb_control_msg(usb->usbdev, usb_sndctrlpipe(usb->usbdev, 2), 0x00, USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0x55aa, - 0xf0f0, tbuf, 8, timeout); - kfree(tbuf); + 0xf0f0, go->usb_buf, 8, timeout); if (r < 0) { printk(KERN_ERR "go7007-usb: error in WriteInterrupt: %d\n", r); return r; @@ -913,7 +911,7 @@ static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter, { struct go7007 *go = i2c_get_adapdata(adapter); struct go7007_usb *usb = go->hpi_context; - u8 buf[16]; + u8 *buf = go->usb_buf; int buf_len, i; int ret = -EIO; @@ -1169,14 +1167,12 @@ static int go7007_usb_probe(struct usb_interface *intf, /* Probe the tuner model on the TV402U */ if (go->board_id == GO7007_BOARDID_PX_TV402U_ANY) { - u8 data[3]; - /* Board strapping indicates tuner model */ - if (go7007_usb_vendor_request(go, 0x41, 0, 0, data, 3, 1) < 0) { + if (go7007_usb_vendor_request(go, 0x41, 0, 0, go->usb_buf, 3, 1) < 0) { printk(KERN_ERR "go7007-usb: GPIO read failed!\n"); goto initfail; } - switch (data[0] >> 6) { + switch (go->usb_buf[0] >> 6) { case 1: go->board_id = GO7007_BOARDID_PX_TV402U_EU; go->tuner_type = TUNER_SONY_BTF_PG472Z; @@ -1309,8 +1305,8 @@ static void go7007_usb_disconnect(struct usb_interface *intf) kfree(go->hpi_context); - go7007_remove(go); go->status = STATUS_SHUTDOWN; + go7007_remove(go); } static struct usb_driver go7007_usb_driver = { diff --git a/drivers/staging/media/go7007/s2250-board.c b/drivers/staging/media/go7007/s2250-board.c index 37400bf..2266e1b 100644 --- a/drivers/staging/media/go7007/s2250-board.c +++ b/drivers/staging/media/go7007/s2250-board.c @@ -584,7 +584,7 @@ static int s2250_probe(struct i2c_client *client, if (audio == NULL) return -ENOMEM; - state = kmalloc(sizeof(struct s2250), GFP_KERNEL); + state = kzalloc(sizeof(struct s2250), GFP_KERNEL); if (state == NULL) { i2c_unregister_device(audio); return -ENOMEM; diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c index d65e17a..afe21f3 100644 --- a/drivers/staging/media/go7007/saa7134-go7007.c +++ b/drivers/staging/media/go7007/saa7134-go7007.c @@ -261,12 +261,12 @@ static int saa7134_go7007_stream_start(struct go7007 *go) saa->top_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->top), 0, PAGE_SIZE, DMA_FROM_DEVICE); - if (!saa->top_dma) + if (dma_mapping_error(&dev->pci->dev, saa->top_dma)) return -ENOMEM; saa->bottom_dma = dma_map_page(&dev->pci->dev, virt_to_page(saa->bottom), 0, PAGE_SIZE, DMA_FROM_DEVICE); - if (!saa->bottom_dma) { + if (dma_mapping_error(&dev->pci->dev, saa->bottom_dma)) { dma_unmap_page(&dev->pci->dev, saa->top_dma, PAGE_SIZE, DMA_FROM_DEVICE); return -ENOMEM; -- cgit v0.10.2 From 95ef39403f890360a3e48fe550d8e8e5d088ad74 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 10:37:52 -0300 Subject: [media] go7007: remember boot firmware Don't load it everytime you stop encoding. Instead remember it. Another reason for not loading it every time is that this could be called from within the release() file operation, which turns out to be deadly. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index 09d0ef4..db9a4b3 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -95,34 +95,34 @@ static int go7007_load_encoder(struct go7007 *go) int fw_len, rv = 0; u16 intr_val, intr_data; - if (request_firmware(&fw_entry, fw_name, go->dev)) { - v4l2_err(go, "unable to load firmware from file " - "\"%s\"\n", fw_name); - return -1; - } - if (fw_entry->size < 16 || memcmp(fw_entry->data, "WISGO7007FW", 11)) { - v4l2_err(go, "file \"%s\" does not appear to be " - "go7007 firmware\n", fw_name); - release_firmware(fw_entry); - return -1; - } - fw_len = fw_entry->size - 16; - bounce = kmemdup(fw_entry->data + 16, fw_len, GFP_KERNEL); - if (bounce == NULL) { - v4l2_err(go, "unable to allocate %d bytes for " - "firmware transfer\n", fw_len); + if (go->boot_fw == NULL) { + if (request_firmware(&fw_entry, fw_name, go->dev)) { + v4l2_err(go, "unable to load firmware from file \"%s\"\n", fw_name); + return -1; + } + if (fw_entry->size < 16 || memcmp(fw_entry->data, "WISGO7007FW", 11)) { + v4l2_err(go, "file \"%s\" does not appear to be go7007 firmware\n", fw_name); + release_firmware(fw_entry); + return -1; + } + fw_len = fw_entry->size - 16; + bounce = kmemdup(fw_entry->data + 16, fw_len, GFP_KERNEL); + if (bounce == NULL) { + v4l2_err(go, "unable to allocate %d bytes for firmware transfer\n", fw_len); + release_firmware(fw_entry); + return -1; + } release_firmware(fw_entry); - return -1; + go->boot_fw_len = fw_len; + go->boot_fw = bounce; } - release_firmware(fw_entry); if (go7007_interface_reset(go) < 0 || - go7007_send_firmware(go, bounce, fw_len) < 0 || - go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || + go7007_send_firmware(go, go->boot_fw, go->boot_fw_len) < 0 || + go7007_read_interrupt(go, &intr_val, &intr_data) < 0 || (intr_val & ~0x1) != 0x5a5a) { v4l2_err(go, "error transferring firmware\n"); rv = -1; } - kfree(bounce); return rv; } @@ -675,6 +675,7 @@ void go7007_remove(struct go7007 *go) if (go->audio_enabled) go7007_snd_remove(go); + kfree(go->boot_fw); go7007_v4l2_remove(go); } EXPORT_SYMBOL(go7007_remove); diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index daae6dd..d390120 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -178,6 +178,8 @@ struct go7007 { int channel_number; /* for multi-channel boards like Adlink PCI-MPG24 */ char name[64]; struct video_device *video_dev; + void *boot_fw; + unsigned boot_fw_len; struct v4l2_device v4l2_dev; int ref_count; enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status; -- cgit v0.10.2 From d5d3a7cc127d096c22ad63c4ff72970e1beb22ef Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 04:48:30 -0300 Subject: [media] go7007: fix unregister/disconnect handling - use the v4l2_device's release() callback - remove the unnecessary ref_count - don't free usb data structures on disconnect, only do that in the final release callback. This is the correct way in order to safely handle disconnect and removal of modules. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index db9a4b3..dca85d8 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -221,6 +221,31 @@ static int init_i2c_module(struct i2c_adapter *adapter, const struct go_i2c *con } /* + * Detach and unregister the encoder. The go7007 struct won't be freed + * until v4l2 finishes releasing its resources and all associated fds are + * closed by applications. + */ +static void go7007_remove(struct v4l2_device *v4l2_dev) +{ + struct go7007 *go = container_of(v4l2_dev, struct go7007, v4l2_dev); + + v4l2_device_unregister(v4l2_dev); + if (go->hpi_ops->release) + go->hpi_ops->release(go); + if (go->i2c_adapter_online) { + if (i2c_del_adapter(&go->i2c_adapter) == 0) + go->i2c_adapter_online = 0; + else + v4l2_err(&go->v4l2_dev, + "error removing I2C adapter!\n"); + } + + kfree(go->boot_fw); + go7007_v4l2_remove(go); + kfree(go); +} + +/* * Finalize the GO7007 hardware setup, register the on-board I2C adapter * (if used on this board), load the I2C client driver for the sensor * (SAA7115 or whatever) and other devices, and register the ALSA and V4L2 @@ -234,17 +259,17 @@ int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs) dev_info(go->dev, "go7007: registering new %s\n", go->name); + go->v4l2_dev.release = go7007_remove; + ret = v4l2_device_register(go->dev, &go->v4l2_dev); + if (ret < 0) + return ret; + mutex_lock(&go->hw_lock); ret = go7007_init_encoder(go); mutex_unlock(&go->hw_lock); if (ret < 0) return -1; - /* v4l2 init must happen before i2c subdevs */ - ret = go7007_v4l2_init(go); - if (ret < 0) - return ret; - if (!go->i2c_adapter_online && go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) { if (go7007_i2c_init(go) < 0) @@ -269,6 +294,11 @@ int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs) v4l2_subdev_call(go->sd_video, video, s_routing, 0, 0, go->channel_number + 1); } + + ret = go7007_v4l2_init(go); + if (ret < 0) + return ret; + if (go->board_info->flags & GO7007_BOARD_HAS_AUDIO) { go->audio_enabled = 1; go7007_snd_init(go); @@ -608,7 +638,6 @@ struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev) init_waitqueue_head(&go->frame_waitq); spin_lock_init(&go->spinlock); go->video_dev = NULL; - go->ref_count = 0; go->status = STATUS_INIT; memset(&go->i2c_adapter, 0, sizeof(go->i2c_adapter)); go->i2c_adapter_online = 0; @@ -658,26 +687,4 @@ struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev) } EXPORT_SYMBOL(go7007_alloc); -/* - * Detach and unregister the encoder. The go7007 struct won't be freed - * until v4l2 finishes releasing its resources and all associated fds are - * closed by applications. - */ -void go7007_remove(struct go7007 *go) -{ - if (go->i2c_adapter_online) { - if (i2c_del_adapter(&go->i2c_adapter) == 0) - go->i2c_adapter_online = 0; - else - v4l2_err(&go->v4l2_dev, - "error removing I2C adapter!\n"); - } - - if (go->audio_enabled) - go7007_snd_remove(go); - kfree(go->boot_fw); - go7007_v4l2_remove(go); -} -EXPORT_SYMBOL(go7007_remove); - MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index d390120..54cfc0a 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -117,6 +117,7 @@ struct go7007_hpi_ops { int (*stream_stop)(struct go7007 *go); int (*send_firmware)(struct go7007 *go, u8 *data, int len); int (*send_command)(struct go7007 *go, unsigned int cmd, void *arg); + void (*release)(struct go7007 *go); }; /* The video buffer size must be a multiple of PAGE_SIZE */ @@ -181,7 +182,6 @@ struct go7007 { void *boot_fw; unsigned boot_fw_len; struct v4l2_device v4l2_dev; - int ref_count; enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status; spinlock_t spinlock; struct mutex hw_lock; @@ -287,8 +287,6 @@ int go7007_start_encoder(struct go7007 *go); void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length); struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev); -void go7007_remove(struct go7007 *go); - /* go7007-fw.c */ int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen); diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index f496720..2d349f4 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -617,6 +617,8 @@ static int go7007_usb_interface_reset(struct go7007 *go) struct go7007_usb *usb = go->hpi_context; u16 intr_val, intr_data; + if (go->status == STATUS_SHUTDOWN) + return -1; /* Reset encoder */ if (go7007_write_interrupt(go, 0x0001, 0x0001) < 0) return -1; @@ -886,6 +888,35 @@ static int go7007_usb_send_firmware(struct go7007 *go, u8 *data, int len) &transferred, timeout); } +static void go7007_usb_release(struct go7007 *go) +{ + struct go7007_usb *usb = go->hpi_context; + struct urb *vurb, *aurb; + int i; + + usb_kill_urb(usb->intr_urb); + + /* Free USB-related structs */ + for (i = 0; i < 8; ++i) { + vurb = usb->video_urbs[i]; + if (vurb) { + usb_kill_urb(vurb); + kfree(vurb->transfer_buffer); + usb_free_urb(vurb); + } + aurb = usb->audio_urbs[i]; + if (aurb) { + usb_kill_urb(aurb); + kfree(aurb->transfer_buffer); + usb_free_urb(aurb); + } + } + kfree(usb->intr_urb->transfer_buffer); + usb_free_urb(usb->intr_urb); + + kfree(go->hpi_context); +} + static struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = { .interface_reset = go7007_usb_interface_reset, .write_interrupt = go7007_usb_ezusb_write_interrupt, @@ -893,6 +924,7 @@ static struct go7007_hpi_ops go7007_usb_ezusb_hpi_ops = { .stream_start = go7007_usb_stream_start, .stream_stop = go7007_usb_stream_stop, .send_firmware = go7007_usb_send_firmware, + .release = go7007_usb_release, }; static struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = { @@ -902,6 +934,7 @@ static struct go7007_hpi_ops go7007_usb_onboard_hpi_ops = { .stream_start = go7007_usb_stream_start, .stream_stop = go7007_usb_stream_stop, .send_firmware = go7007_usb_send_firmware, + .release = go7007_usb_release, }; /********************* Driver for EZ-USB I2C adapter *********************/ @@ -1279,34 +1312,15 @@ allocfail: static void go7007_usb_disconnect(struct usb_interface *intf) { struct go7007 *go = to_go7007(usb_get_intfdata(intf)); - struct go7007_usb *usb = go->hpi_context; - struct urb *vurb, *aurb; - int i; - - usb_kill_urb(usb->intr_urb); - - /* Free USB-related structs */ - for (i = 0; i < 8; ++i) { - vurb = usb->video_urbs[i]; - if (vurb) { - usb_kill_urb(vurb); - kfree(vurb->transfer_buffer); - usb_free_urb(vurb); - } - aurb = usb->audio_urbs[i]; - if (aurb) { - usb_kill_urb(aurb); - kfree(aurb->transfer_buffer); - usb_free_urb(aurb); - } - } - kfree(usb->intr_urb->transfer_buffer); - usb_free_urb(usb->intr_urb); - kfree(go->hpi_context); + if (go->audio_enabled) + go7007_snd_remove(go); go->status = STATUS_SHUTDOWN; - go7007_remove(go); + v4l2_device_disconnect(&go->v4l2_dev); + video_unregister_device(go->video_dev); + + v4l2_device_put(&go->v4l2_dev); } static struct usb_driver go7007_usb_driver = { diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 6cb6f43..216c94a 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -100,7 +100,6 @@ static int go7007_open(struct file *file) gofh = kzalloc(sizeof(struct go7007_file), GFP_KERNEL); if (gofh == NULL) return -ENOMEM; - ++go->ref_count; gofh->go = go; mutex_init(&gofh->lock); gofh->buf_count = 0; @@ -120,8 +119,6 @@ static int go7007_release(struct file *file) gofh->buf_count = 0; } kfree(gofh); - if (--go->ref_count == 0) - kfree(go); file->private_data = NULL; return 0; } @@ -1772,11 +1769,7 @@ static unsigned int go7007_poll(struct file *file, poll_table *wait) static void go7007_vfl_release(struct video_device *vfd) { - struct go7007 *go = video_get_drvdata(vfd); - video_device_release(vfd); - if (--go->ref_count == 0) - kfree(go); } static struct v4l2_file_operations go7007_fops = { @@ -1844,7 +1837,8 @@ int go7007_v4l2_init(struct go7007 *go) if (go->video_dev == NULL) return -ENOMEM; *go->video_dev = go7007_template; - go->video_dev->parent = go->dev; + video_set_drvdata(go->video_dev, go); + go->video_dev->v4l2_dev = &go->v4l2_dev; rv = video_register_device(go->video_dev, VFL_TYPE_GRABBER, -1); if (rv < 0) { video_device_release(go->video_dev); @@ -1856,14 +1850,6 @@ int go7007_v4l2_init(struct go7007 *go) v4l2_disable_ioctl(go->video_dev, VIDIOC_S_AUDIO); v4l2_disable_ioctl(go->video_dev, VIDIOC_ENUMAUDIO); } - rv = v4l2_device_register(go->dev, &go->v4l2_dev); - if (rv < 0) { - video_device_release(go->video_dev); - go->video_dev = NULL; - return rv; - } - video_set_drvdata(go->video_dev, go); - ++go->ref_count; dev_info(go->dev, "registered device %s [v4l2]\n", video_device_node_name(go->video_dev)); @@ -1883,8 +1869,4 @@ void go7007_v4l2_remove(struct go7007 *go) spin_unlock_irqrestore(&go->spinlock, flags); } mutex_unlock(&go->hw_lock); - if (go->video_dev) - video_unregister_device(go->video_dev); - if (go->status != STATUS_SHUTDOWN) - v4l2_device_unregister(&go->v4l2_dev); } diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c index afe21f3..4c73945 100644 --- a/drivers/staging/media/go7007/saa7134-go7007.c +++ b/drivers/staging/media/go7007/saa7134-go7007.c @@ -499,12 +499,17 @@ static int saa7134_go7007_fini(struct saa7134_dev *dev) return 0; go = video_get_drvdata(dev->empress_dev); + if (go->audio_enabled) + go7007_snd_remove(go); + saa = go->hpi_context; go->status = STATUS_SHUTDOWN; free_page((unsigned long)saa->top); free_page((unsigned long)saa->bottom); kfree(saa); - go7007_remove(go); + video_unregister_device(&go->vdev); + + v4l2_device_put(&go->v4l2_dev); dev->empress_dev = NULL; return 0; diff --git a/drivers/staging/media/go7007/snd-go7007.c b/drivers/staging/media/go7007/snd-go7007.c index 6f6271e..4be0fa4 100644 --- a/drivers/staging/media/go7007/snd-go7007.c +++ b/drivers/staging/media/go7007/snd-go7007.c @@ -221,8 +221,6 @@ static int go7007_snd_free(struct snd_device *device) kfree(go->snd_context); go->snd_context = NULL; - if (--go->ref_count == 0) - kfree(go); return 0; } @@ -285,8 +283,8 @@ int go7007_snd_init(struct go7007 *go) gosnd->substream = NULL; go->snd_context = gosnd; + v4l2_device_get(&go->v4l2_dev); ++dev; - ++go->ref_count; return 0; } @@ -298,6 +296,7 @@ int go7007_snd_remove(struct go7007 *go) snd_card_disconnect(gosnd->card); snd_card_free_when_closed(gosnd->card); + v4l2_device_put(&go->v4l2_dev); return 0; } EXPORT_SYMBOL(go7007_snd_remove); -- cgit v0.10.2 From 9b8451d5af25ca79f63066e1312526ffee606a76 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 05:19:59 -0300 Subject: [media] go7007: convert to the control framework and remove obsolete JPEGCOMP support Just add a read-only V4L2_CID_JPEG_ACTIVE_MARKER control to replace the JPEGCOMP support. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index dca85d8..d689989 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -268,12 +268,17 @@ int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs) ret = go7007_init_encoder(go); mutex_unlock(&go->hw_lock); if (ret < 0) - return -1; + return ret; + + ret = go7007_v4l2_ctrl_init(go); + if (ret < 0) + return ret; if (!go->i2c_adapter_online && go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) { - if (go7007_i2c_init(go) < 0) - return -1; + ret = go7007_i2c_init(go); + if (ret < 0) + return ret; go->i2c_adapter_online = 1; } if (go->i2c_adapter_online) { diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index 54cfc0a..d127a8d 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -22,6 +22,7 @@ */ #include +#include struct go7007; @@ -182,6 +183,7 @@ struct go7007 { void *boot_fw; unsigned boot_fw_len; struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler hdl; enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status; spinlock_t spinlock; struct mutex hw_lock; @@ -296,6 +298,7 @@ int go7007_i2c_remove(struct go7007 *go); /* go7007-v4l2.c */ int go7007_v4l2_init(struct go7007 *go); +int go7007_v4l2_ctrl_init(struct go7007 *go); void go7007_v4l2_remove(struct go7007 *go); /* snd-go7007.c */ diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 216c94a..b794743 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -42,9 +42,6 @@ #ifndef V4L2_MPEG_STREAM_TYPE_MPEG_ELEM #define V4L2_MPEG_STREAM_TYPE_MPEG_ELEM 6 /* MPEG elementary stream */ #endif -#ifndef V4L2_MPEG_VIDEO_ENCODING_MPEG_4 -#define V4L2_MPEG_VIDEO_ENCODING_MPEG_4 3 -#endif #define call_all(dev, o, f, args...) \ v4l2_device_call_until_err(dev, 0, o, f, ##args) @@ -387,67 +384,18 @@ static int clip_to_modet_map(struct go7007 *go, int region, } #endif -static int mpeg_query_ctrl(struct v4l2_queryctrl *ctrl) +static int go7007_s_ctrl(struct v4l2_ctrl *ctrl) { - static const u32 mpeg_ctrls[] = { - V4L2_CID_MPEG_CLASS, - V4L2_CID_MPEG_STREAM_TYPE, - V4L2_CID_MPEG_VIDEO_ENCODING, - V4L2_CID_MPEG_VIDEO_ASPECT, - V4L2_CID_MPEG_VIDEO_GOP_SIZE, - V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, - V4L2_CID_MPEG_VIDEO_BITRATE, - 0 - }; - static const u32 *ctrl_classes[] = { - mpeg_ctrls, - NULL - }; - - ctrl->id = v4l2_ctrl_next(ctrl_classes, ctrl->id); - - switch (ctrl->id) { - case V4L2_CID_MPEG_CLASS: - return v4l2_ctrl_query_fill(ctrl, 0, 0, 0, 0); - case V4L2_CID_MPEG_STREAM_TYPE: - return v4l2_ctrl_query_fill(ctrl, - V4L2_MPEG_STREAM_TYPE_MPEG2_DVD, - V4L2_MPEG_STREAM_TYPE_MPEG_ELEM, 1, - V4L2_MPEG_STREAM_TYPE_MPEG_ELEM); - case V4L2_CID_MPEG_VIDEO_ENCODING: - return v4l2_ctrl_query_fill(ctrl, - V4L2_MPEG_VIDEO_ENCODING_MPEG_1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4, 1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2); - case V4L2_CID_MPEG_VIDEO_ASPECT: - return v4l2_ctrl_query_fill(ctrl, - V4L2_MPEG_VIDEO_ASPECT_1x1, - V4L2_MPEG_VIDEO_ASPECT_16x9, 1, - V4L2_MPEG_VIDEO_ASPECT_1x1); - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - return v4l2_ctrl_query_fill(ctrl, 0, 34, 1, 15); - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - return v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0); - case V4L2_CID_MPEG_VIDEO_BITRATE: - return v4l2_ctrl_query_fill(ctrl, - 64000, - 10000000, 1, - 1500000); - default: - return -EINVAL; - } - return 0; -} + struct go7007 *go = + container_of(ctrl->handler, struct go7007, hdl); -static int mpeg_s_ctrl(struct v4l2_control *ctrl, struct go7007 *go) -{ /* pretty sure we can't change any of these while streaming */ if (go->streaming) return -EBUSY; switch (ctrl->id) { case V4L2_CID_MPEG_STREAM_TYPE: - switch (ctrl->value) { + switch (ctrl->val) { case V4L2_MPEG_STREAM_TYPE_MPEG2_DVD: go->format = GO7007_FORMAT_MPEG2; go->bitrate = 9800000; @@ -459,15 +407,12 @@ static int mpeg_s_ctrl(struct v4l2_control *ctrl, struct go7007 *go) go->gop_header_enable = 1; go->dvd_mode = 1; break; - case V4L2_MPEG_STREAM_TYPE_MPEG_ELEM: - /* todo: */ - break; default: return -EINVAL; } break; case V4L2_CID_MPEG_VIDEO_ENCODING: - switch (ctrl->value) { + switch (ctrl->val) { case V4L2_MPEG_VIDEO_ENCODING_MPEG_1: go->format = GO7007_FORMAT_MPEG1; go->pali = 0; @@ -479,7 +424,7 @@ static int mpeg_s_ctrl(struct v4l2_control *ctrl, struct go7007 *go) else*/ go->pali = 0x48; break; - case V4L2_MPEG_VIDEO_ENCODING_MPEG_4: + case V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC: go->format = GO7007_FORMAT_MPEG4; /*if (mpeg->pali >> 24 == 4) go->pali = mpeg->pali & 0xff; @@ -499,9 +444,10 @@ static int mpeg_s_ctrl(struct v4l2_control *ctrl, struct go7007 *go) go->dvd_mode = 0; break; case V4L2_CID_MPEG_VIDEO_ASPECT: + /* TODO: is this really the right thing to do for mjpeg? */ if (go->format == GO7007_FORMAT_MJPEG) return -EINVAL; - switch (ctrl->value) { + switch (ctrl->val) { case V4L2_MPEG_VIDEO_ASPECT_1x1: go->aspect_ratio = GO7007_RATIO_1_1; break; @@ -511,80 +457,18 @@ static int mpeg_s_ctrl(struct v4l2_control *ctrl, struct go7007 *go) case V4L2_MPEG_VIDEO_ASPECT_16x9: go->aspect_ratio = GO7007_RATIO_16_9; break; - case V4L2_MPEG_VIDEO_ASPECT_221x100: - default: - return -EINVAL; - } - break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - if (ctrl->value < 0 || ctrl->value > 34) - return -EINVAL; - go->gop_size = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - if (ctrl->value != 0 && ctrl->value != 1) - return -EINVAL; - go->closed_gop = ctrl->value; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - /* Upper bound is kind of arbitrary here */ - if (ctrl->value < 64000 || ctrl->value > 10000000) - return -EINVAL; - go->bitrate = ctrl->value; - break; - default: - return -EINVAL; - } - return 0; -} - -static int mpeg_g_ctrl(struct v4l2_control *ctrl, struct go7007 *go) -{ - switch (ctrl->id) { - case V4L2_CID_MPEG_STREAM_TYPE: - if (go->dvd_mode) - ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_DVD; - else - ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG_ELEM; - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - switch (go->format) { - case GO7007_FORMAT_MPEG1: - ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - break; - case GO7007_FORMAT_MPEG2: - ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2; - break; - case GO7007_FORMAT_MPEG4: - ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4; - break; - default: - return -EINVAL; - } - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - switch (go->aspect_ratio) { - case GO7007_RATIO_1_1: - ctrl->value = V4L2_MPEG_VIDEO_ASPECT_1x1; - break; - case GO7007_RATIO_4_3: - ctrl->value = V4L2_MPEG_VIDEO_ASPECT_4x3; - break; - case GO7007_RATIO_16_9: - ctrl->value = V4L2_MPEG_VIDEO_ASPECT_16x9; - break; default: return -EINVAL; } break; case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - ctrl->value = go->gop_size; + go->gop_size = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - ctrl->value = go->closed_gop; + go->closed_gop = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_BITRATE: - ctrl->value = go->bitrate; + go->bitrate = ctrl->val; break; default: return -EINVAL; @@ -968,41 +852,6 @@ static int vidioc_streamoff(struct file *file, void *priv, return 0; } -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *query) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - int id = query->id; - - if (0 == call_all(&go->v4l2_dev, core, queryctrl, query)) - return 0; - - query->id = id; - return mpeg_query_ctrl(query); -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (0 == call_all(&go->v4l2_dev, core, g_ctrl, ctrl)) - return 0; - - return mpeg_g_ctrl(ctrl, go); -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (0 == call_all(&go->v4l2_dev, core, s_ctrl, ctrl)) - return 0; - - return mpeg_s_ctrl(ctrl, go); -} - static int vidioc_g_parm(struct file *filp, void *priv, struct v4l2_streamparm *parm) { @@ -1423,28 +1272,6 @@ static int vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop * return 0; } -static int vidioc_g_jpegcomp(struct file *file, void *priv, - struct v4l2_jpegcompression *params) -{ - memset(params, 0, sizeof(*params)); - params->quality = 50; /* ?? */ - params->jpeg_markers = V4L2_JPEG_MARKER_DHT | - V4L2_JPEG_MARKER_DQT; - - return 0; -} - -static int vidioc_s_jpegcomp(struct file *file, void *priv, - const struct v4l2_jpegcompression *params) -{ - if (params->quality != 50 || - params->jpeg_markers != (V4L2_JPEG_MARKER_DHT | - V4L2_JPEG_MARKER_DQT)) - return -EINVAL; - - return 0; -} - /* FIXME: Those ioctls are private, and not needed, since several standard extended controls already provide streaming control. @@ -1782,6 +1609,10 @@ static struct v4l2_file_operations go7007_fops = { .poll = go7007_poll, }; +static struct v4l2_ctrl_ops go7007_ctrl_ops = { + .s_ctrl = go7007_s_ctrl, +}; + static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, @@ -1801,9 +1632,6 @@ static const struct v4l2_ioctl_ops video_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_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_g_tuner = vidioc_g_tuner, @@ -1817,8 +1645,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_cropcap = vidioc_cropcap, .vidioc_g_crop = vidioc_g_crop, .vidioc_s_crop = vidioc_s_crop, - .vidioc_g_jpegcomp = vidioc_g_jpegcomp, - .vidioc_s_jpegcomp = vidioc_s_jpegcomp, }; static struct video_device go7007_template = { @@ -1829,6 +1655,50 @@ static struct video_device go7007_template = { .tvnorms = V4L2_STD_ALL, }; +int go7007_v4l2_ctrl_init(struct go7007 *go) +{ + struct v4l2_ctrl_handler *hdl = &go->hdl; + struct v4l2_ctrl *ctrl; + + v4l2_ctrl_handler_init(hdl, 12); + v4l2_ctrl_new_std_menu(hdl, &go7007_ctrl_ops, + V4L2_CID_MPEG_STREAM_TYPE, + V4L2_MPEG_STREAM_TYPE_MPEG2_DVD, + 0x7, + V4L2_MPEG_STREAM_TYPE_MPEG2_DVD); + v4l2_ctrl_new_std_menu(hdl, &go7007_ctrl_ops, + V4L2_CID_MPEG_VIDEO_ENCODING, + V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, + 0, + V4L2_MPEG_VIDEO_ENCODING_MPEG_2); + v4l2_ctrl_new_std_menu(hdl, &go7007_ctrl_ops, + V4L2_CID_MPEG_VIDEO_ASPECT, + V4L2_MPEG_VIDEO_ASPECT_16x9, + 0, + V4L2_MPEG_VIDEO_ASPECT_1x1); + v4l2_ctrl_new_std(hdl, &go7007_ctrl_ops, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, 34, 1, 15); + v4l2_ctrl_new_std(hdl, &go7007_ctrl_ops, + V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 0); + v4l2_ctrl_new_std(hdl, &go7007_ctrl_ops, + V4L2_CID_MPEG_VIDEO_BITRATE, + 64000, 10000000, 1, 1500000); + ctrl = v4l2_ctrl_new_std(hdl, &go7007_ctrl_ops, + V4L2_CID_JPEG_ACTIVE_MARKER, 0, + V4L2_JPEG_ACTIVE_MARKER_DQT | V4L2_JPEG_ACTIVE_MARKER_DHT, 0, + V4L2_JPEG_ACTIVE_MARKER_DQT | V4L2_JPEG_ACTIVE_MARKER_DHT); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + if (hdl->error) { + int rv = hdl->error; + + v4l2_err(&go->v4l2_dev, "Could not register controls\n"); + return rv; + } + go->v4l2_dev.ctrl_handler = hdl; + return 0; +} + int go7007_v4l2_init(struct go7007 *go) { int rv; @@ -1869,4 +1739,5 @@ void go7007_v4l2_remove(struct go7007 *go) spin_unlock_irqrestore(&go->spinlock, flags); } mutex_unlock(&go->hw_lock); + v4l2_ctrl_handler_free(&go->hdl); } -- cgit v0.10.2 From d3b2ccd9e307eae80b4b4eeb0ede46cb02212df2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 3 Mar 2013 10:50:34 -0300 Subject: [media] s2250: convert to the control framework Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/s2250-board.c b/drivers/staging/media/go7007/s2250-board.c index 2266e1b..5899513 100644 --- a/drivers/staging/media/go7007/s2250-board.c +++ b/drivers/staging/media/go7007/s2250-board.c @@ -116,6 +116,7 @@ static u16 vid_regs_fp_pal[] = { struct s2250 { struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; v4l2_std_id std; int input; int brightness; @@ -370,110 +371,36 @@ static int s2250_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) return 0; } -static int s2250_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *query) +static int s2250_s_ctrl(struct v4l2_ctrl *ctrl) { - switch (query->id) { - case V4L2_CID_BRIGHTNESS: - return v4l2_ctrl_query_fill(query, 0, 100, 1, 50); - case V4L2_CID_CONTRAST: - return v4l2_ctrl_query_fill(query, 0, 100, 1, 50); - case V4L2_CID_SATURATION: - return v4l2_ctrl_query_fill(query, 0, 100, 1, 50); - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(query, -50, 50, 1, 0); - default: - return -EINVAL; - } - return 0; -} - -static int s2250_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct s2250 *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int value1; + struct s2250 *state = container_of(ctrl->handler, struct s2250, hdl); + struct i2c_client *client = v4l2_get_subdevdata(&state->sd); u16 oldvalue; switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - if (ctrl->value > 100) - state->brightness = 100; - else if (ctrl->value < 0) - state->brightness = 0; - else - state->brightness = ctrl->value; - value1 = (state->brightness - 50) * 255 / 100; read_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, &oldvalue); write_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, - value1 | (oldvalue & ~0xff)); + ctrl->val | (oldvalue & ~0xff)); read_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, &oldvalue); write_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, - value1 | (oldvalue & ~0xff)); + ctrl->val | (oldvalue & ~0xff)); write_reg_fp(client, 0x140, 0x60); break; case V4L2_CID_CONTRAST: - if (ctrl->value > 100) - state->contrast = 100; - else if (ctrl->value < 0) - state->contrast = 0; - else - state->contrast = ctrl->value; - value1 = state->contrast * 0x40 / 100; - if (value1 > 0x3f) - value1 = 0x3f; /* max */ read_reg_fp(client, VPX322_ADDR_CONTRAST0, &oldvalue); write_reg_fp(client, VPX322_ADDR_CONTRAST0, - value1 | (oldvalue & ~0x3f)); + ctrl->val | (oldvalue & ~0x3f)); read_reg_fp(client, VPX322_ADDR_CONTRAST1, &oldvalue); write_reg_fp(client, VPX322_ADDR_CONTRAST1, - value1 | (oldvalue & ~0x3f)); + ctrl->val | (oldvalue & ~0x3f)); write_reg_fp(client, 0x140, 0x60); break; case V4L2_CID_SATURATION: - if (ctrl->value > 100) - state->saturation = 100; - else if (ctrl->value < 0) - state->saturation = 0; - else - state->saturation = ctrl->value; - value1 = state->saturation * 4140 / 100; - if (value1 > 4094) - value1 = 4094; - write_reg_fp(client, VPX322_ADDR_SAT, value1); - break; - case V4L2_CID_HUE: - if (ctrl->value > 50) - state->hue = 50; - else if (ctrl->value < -50) - state->hue = -50; - else - state->hue = ctrl->value; - /* clamp the hue range */ - value1 = state->hue * 280 / 50; - write_reg_fp(client, VPX322_ADDR_HUE, value1); - break; - default: - return -EINVAL; - } - return 0; -} - -static int s2250_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) -{ - struct s2250 *state = to_state(sd); - - 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; + write_reg_fp(client, VPX322_ADDR_SAT, ctrl->val); break; case V4L2_CID_HUE: - ctrl->value = state->hue; + write_reg_fp(client, VPX322_ADDR_HUE, ctrl->val); break; default: return -EINVAL; @@ -531,24 +458,21 @@ static int s2250_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "Input: %s\n", state->input == 0 ? "Composite" : state->input == 1 ? "S-video" : "error"); - v4l2_info(sd, "Brightness: %d\n", state->brightness); - v4l2_info(sd, "Contrast: %d\n", state->contrast); - v4l2_info(sd, "Saturation: %d\n", state->saturation); - v4l2_info(sd, "Hue: %d\n", state->hue); v4l2_info(sd, "Audio input: %s\n", state->audio_input == 0 ? "Line In" : state->audio_input == 1 ? "Mic" : state->audio_input == 2 ? "Mic Boost" : "error"); - return 0; + return v4l2_ctrl_subdev_log_status(sd); } /* --------------------------------------------------------------------------*/ +static const struct v4l2_ctrl_ops s2250_ctrl_ops = { + .s_ctrl = s2250_s_ctrl, +}; + static const struct v4l2_subdev_core_ops s2250_core_ops = { .log_status = s2250_log_status, - .g_ctrl = s2250_g_ctrl, - .s_ctrl = s2250_s_ctrl, - .queryctrl = s2250_queryctrl, .s_std = s2250_s_std, }; @@ -596,6 +520,24 @@ static int s2250_probe(struct i2c_client *client, v4l2_info(sd, "initializing %s at address 0x%x on %s\n", "Sensoray 2250/2251", client->addr, client->adapter->name); + v4l2_ctrl_handler_init(&state->hdl, 4); + v4l2_ctrl_new_std(&state->hdl, &s2250_ctrl_ops, + V4L2_CID_BRIGHTNESS, -128, 127, 1, 0); + v4l2_ctrl_new_std(&state->hdl, &s2250_ctrl_ops, + V4L2_CID_CONTRAST, 0, 0x3f, 1, 0x32); + v4l2_ctrl_new_std(&state->hdl, &s2250_ctrl_ops, + V4L2_CID_SATURATION, 0, 4094, 1, 2070); + v4l2_ctrl_new_std(&state->hdl, &s2250_ctrl_ops, + V4L2_CID_HUE, -512, 511, 1, 0); + sd->ctrl_handler = &state->hdl; + if (state->hdl.error) { + int err = state->hdl.error; + + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return err; + } + state->std = V4L2_STD_NTSC; state->brightness = 50; state->contrast = 50; @@ -606,22 +548,16 @@ static int s2250_probe(struct i2c_client *client, /* initialize the audio */ if (write_regs(audio, aud_regs) < 0) { dev_err(&client->dev, "error initializing audio\n"); - i2c_unregister_device(audio); - kfree(state); - return 0; + goto fail; } if (write_regs(client, vid_regs) < 0) { dev_err(&client->dev, "error initializing decoder\n"); - i2c_unregister_device(audio); - kfree(state); - return 0; + goto fail; } if (write_regs_fp(client, vid_regs_fp) < 0) { dev_err(&client->dev, "error initializing decoder\n"); - i2c_unregister_device(audio); - kfree(state); - return 0; + goto fail; } /* set default channel */ /* composite */ @@ -657,14 +593,21 @@ static int s2250_probe(struct i2c_client *client, v4l2_info(sd, "initialized successfully\n"); return 0; + +fail: + i2c_unregister_device(audio); + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); + return -EIO; } static int s2250_remove(struct i2c_client *client) { - struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct s2250 *state = to_state(i2c_get_clientdata(client)); - v4l2_device_unregister_subdev(sd); - kfree(to_state(sd)); + v4l2_device_unregister_subdev(&state->sd); + v4l2_ctrl_handler_free(&state->hdl); + kfree(state); return 0; } -- cgit v0.10.2 From bae7432060960dd0ffdc4bd67986ac3d1f5733b0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 11:08:41 -0300 Subject: [media] go7007: add prio and control event support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index d127a8d..2321fd7 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -23,6 +23,7 @@ #include #include +#include struct go7007; @@ -143,6 +144,7 @@ struct go7007_buffer { }; struct go7007_file { + struct v4l2_fh fh; struct go7007 *go; struct mutex lock; int buf_count; diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index b794743..7efdfdf 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -27,13 +27,14 @@ #include #include #include +#include +#include +#include #include #include #include #include -#include -#include -#include +#include #include "go7007.h" #include "go7007-priv.h" @@ -101,6 +102,8 @@ static int go7007_open(struct file *file) mutex_init(&gofh->lock); gofh->buf_count = 0; file->private_data = gofh; + v4l2_fh_init(&gofh->fh, video_devdata(file)); + v4l2_fh_add(&gofh->fh); return 0; } @@ -115,6 +118,8 @@ static int go7007_release(struct file *file) kfree(gofh->bufs); gofh->buf_count = 0; } + v4l2_fh_del(&gofh->fh); + v4l2_fh_exit(&gofh->fh); kfree(gofh); file->private_data = NULL; return 0; @@ -1582,16 +1587,20 @@ static int go7007_mmap(struct file *file, struct vm_area_struct *vma) static unsigned int go7007_poll(struct file *file, poll_table *wait) { + unsigned long req_events = poll_requested_events(wait); struct go7007_file *gofh = file->private_data; struct go7007_buffer *gobuf; + unsigned int res = v4l2_ctrl_poll(file, wait); + if (!(req_events & (POLLIN | POLLRDNORM))) + return res; if (list_empty(&gofh->go->stream)) return POLLERR; gobuf = list_entry(gofh->go->stream.next, struct go7007_buffer, stream); poll_wait(file, &gofh->go->frame_waitq, wait); if (gobuf->state == BUF_STATE_DONE) - return POLLIN | POLLRDNORM; - return 0; + return res | POLLIN | POLLRDNORM; + return res; } static void go7007_vfl_release(struct video_device *vfd) @@ -1645,6 +1654,9 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_cropcap = vidioc_cropcap, .vidioc_g_crop = vidioc_g_crop, .vidioc_s_crop = vidioc_s_crop, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device go7007_template = { @@ -1707,6 +1719,7 @@ int go7007_v4l2_init(struct go7007 *go) if (go->video_dev == NULL) return -ENOMEM; *go->video_dev = go7007_template; + set_bit(V4L2_FL_USE_FH_PRIO, &go->video_dev->flags); video_set_drvdata(go->video_dev, go); go->video_dev->v4l2_dev = &go->v4l2_dev; rv = video_register_device(go->video_dev, VFL_TYPE_GRABBER, -1); -- cgit v0.10.2 From 59d7b91a1d89168d44f07c8f8fb0ad0dc65a140f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 11:25:09 -0300 Subject: [media] go7007: add log_status support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 7efdfdf..e7f832e 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -1188,6 +1188,14 @@ static int vidioc_s_frequency(struct file *file, void *priv, return call_all(&go->v4l2_dev, tuner, s_frequency, f); } +static int vidioc_log_status(struct file *file, void *priv) +{ + struct go7007 *go = ((struct go7007_file *) priv)->go; + + v4l2_ctrl_log_status(file, priv); + return call_all(&go->v4l2_dev, core, log_status); +} + static int vidioc_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cropcap) { @@ -1654,7 +1662,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_cropcap = vidioc_cropcap, .vidioc_g_crop = vidioc_g_crop, .vidioc_s_crop = vidioc_s_crop, - .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_log_status = vidioc_log_status, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -- cgit v0.10.2 From 50deb74905d1e123878f50ed31f829916b936ded Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 05:50:21 -0300 Subject: [media] go7007: tuner/std related fixes - The Adlink is initially detected as a sensor board, so the driver config is set up as if it was a sensor. Later the driver discovers that it really is a video capture card and that means that the driver configuration has to be updated for a PAL/NTSC capture card. - Setup the correct initial std based on the TV tuner type. - Remember the exact std the user selected, don't map it to STD_PAL or NTSC. - Use v4l2_disable_ioctl to disable ioctls based on the board config and drop a lot of checking code in each of those ioctls since that is no longer needed. - enum_input should use tvnorms to fill its std field. - configure the input, std and initial tuner frequency at driver initialization. - fix std handling in the s2250 driver. - the code handling scaling for devices without a scaler was broken. This is now fixed. - correctly set readbuffers and capability in g/s_parm. - remove the bogus test for capturemode in s_parm. - correctly implement enum_framesizes/intervals. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index d689989..eac91bc 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -650,19 +650,7 @@ struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev) init_waitqueue_head(&go->interrupt_waitq); go->in_use = 0; go->input = 0; - if (board->sensor_flags & GO7007_SENSOR_TV) { - go->standard = GO7007_STD_NTSC; - go->width = 720; - go->height = 480; - go->sensor_framerate = 30000; - } else { - go->standard = GO7007_STD_OTHER; - go->width = board->sensor_width; - go->height = board->sensor_height; - go->sensor_framerate = board->sensor_framerate; - } - go->encoder_v_offset = board->sensor_v_offset; - go->encoder_h_offset = board->sensor_h_offset; + go7007_update_board(go); go->encoder_h_halve = 0; go->encoder_v_halve = 0; go->encoder_subsample = 0; @@ -692,4 +680,25 @@ struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev) } EXPORT_SYMBOL(go7007_alloc); +void go7007_update_board(struct go7007 *go) +{ + struct go7007_board_info *board = go->board_info; + + if (board->sensor_flags & GO7007_SENSOR_TV) { + go->standard = GO7007_STD_NTSC; + go->std = V4L2_STD_NTSC_M; + go->width = 720; + go->height = 480; + go->sensor_framerate = 30000; + } else { + go->standard = GO7007_STD_OTHER; + go->width = board->sensor_width; + go->height = board->sensor_height; + go->sensor_framerate = board->sensor_framerate; + } + go->encoder_v_offset = board->sensor_v_offset; + go->encoder_h_offset = board->sensor_h_offset; +} +EXPORT_SYMBOL(go7007_update_board); + MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index 2321fd7..bf874dd 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -200,6 +200,7 @@ struct go7007 { int input; int aud_input; enum { GO7007_STD_NTSC, GO7007_STD_PAL, GO7007_STD_OTHER } standard; + v4l2_std_id std; int sensor_framerate; int width; int height; @@ -291,6 +292,8 @@ int go7007_start_encoder(struct go7007 *go); void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length); struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev); +void go7007_update_board(struct go7007 *go); + /* go7007-fw.c */ int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen); diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 2d349f4..14d1cda 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -1193,6 +1193,7 @@ static int go7007_usb_probe(struct usb_interface *intf, "Adlink PCI-MPG24, channel #%d", channel); } + go7007_update_board(go); } } @@ -1209,12 +1210,14 @@ static int go7007_usb_probe(struct usb_interface *intf, case 1: go->board_id = GO7007_BOARDID_PX_TV402U_EU; go->tuner_type = TUNER_SONY_BTF_PG472Z; + go->std = V4L2_STD_PAL; strncpy(go->name, "Plextor PX-TV402U-EU", sizeof(go->name)); break; case 2: go->board_id = GO7007_BOARDID_PX_TV402U_JP; go->tuner_type = TUNER_SONY_BTF_PK467Z; + go->std = V4L2_STD_NTSC_M_JP; num_i2c_devs -= 2; strncpy(go->name, "Plextor PX-TV402U-JP", sizeof(go->name)); diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index e7f832e..fc776e5 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -160,30 +160,35 @@ static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format) return 0; } -static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) +static void get_resolution(struct go7007 *go, int *width, int *height) { - int sensor_height = 0, sensor_width = 0; - int width, height, i; - - if (fmt != NULL && fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && - fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG && - fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG4) - return -EINVAL; - switch (go->standard) { case GO7007_STD_NTSC: - sensor_width = 720; - sensor_height = 480; + *width = 720; + *height = 480; break; case GO7007_STD_PAL: - sensor_width = 720; - sensor_height = 576; + *width = 720; + *height = 576; break; case GO7007_STD_OTHER: - sensor_width = go->board_info->sensor_width; - sensor_height = go->board_info->sensor_height; + default: + *width = go->board_info->sensor_width; + *height = go->board_info->sensor_height; break; } +} + +static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) +{ + int sensor_height = 0, sensor_width = 0; + int width, height, i; + + if (fmt != NULL && fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && + fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG) + return -EINVAL; + + get_resolution(go, &sensor_width, &sensor_height); if (fmt == NULL) { width = sensor_width; @@ -203,13 +208,12 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) else height = fmt->fmt.pix.height & ~0x0f; } else { - int requested_size = fmt->fmt.pix.width * fmt->fmt.pix.height; - int sensor_size = sensor_width * sensor_height; + width = fmt->fmt.pix.width; - if (64 * requested_size < 9 * sensor_size) { + if (width <= sensor_width / 4) { width = sensor_width / 4; height = sensor_height / 4; - } else if (64 * requested_size < 36 * sensor_size) { + } else if (width <= sensor_width / 2) { width = sensor_width / 2; height = sensor_height / 2; } else { @@ -231,7 +235,7 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) fmt->fmt.pix.field = V4L2_FIELD_NONE; fmt->fmt.pix.bytesperline = 0; fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* ?? */ + fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; } if (try) @@ -250,19 +254,11 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) struct v4l2_mbus_framefmt mbus_fmt; mbus_fmt.code = V4L2_MBUS_FMT_FIXED; - if (fmt != NULL) - mbus_fmt.width = fmt->fmt.pix.width; - else - mbus_fmt.width = width; - - if (height > sensor_height / 2) { - mbus_fmt.height = height / 2; - go->encoder_v_halve = 0; - } else { - mbus_fmt.height = height; - go->encoder_v_halve = 1; - } - mbus_fmt.height *= 2; + mbus_fmt.width = fmt ? fmt->fmt.pix.width : width; + mbus_fmt.height = height; + go->encoder_h_halve = 0; + go->encoder_v_halve = 0; + go->encoder_subsample = 0; call_all(&go->v4l2_dev, video, s_mbus_fmt, &mbus_fmt); } else { if (width <= sensor_width / 4) { @@ -869,7 +865,8 @@ static int vidioc_g_parm(struct file *filp, void *priv, if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.readbuffers = 2; + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; parm->parm.capture.timeperframe = timeperframe; return 0; @@ -883,8 +880,6 @@ static int vidioc_s_parm(struct file *filp, void *priv, if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - if (parm->parm.capture.capturemode != 0) - return -EINVAL; n = go->sensor_framerate * parm->parm.capture.timeperframe.numerator; @@ -894,7 +889,7 @@ static int vidioc_s_parm(struct file *filp, void *priv, else go->fps_scale = 1; - return 0; + return vidioc_g_parm(filp, priv, parm); } /* VIDIOC_ENUMSTD on go7007 were used for enumerating the supported fps and @@ -911,19 +906,19 @@ static int vidioc_enum_framesizes(struct file *filp, void *priv, struct v4l2_frmsizeenum *fsize) { struct go7007 *go = ((struct go7007_file *) priv)->go; + int width, height; - /* Return -EINVAL, if it is a TV board */ - if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) || - (go->board_info->sensor_flags & GO7007_SENSOR_TV)) + if (fsize->index > 2) return -EINVAL; - if (fsize->index > 0) + if (fsize->pixel_format != V4L2_PIX_FMT_MJPEG && + fsize->pixel_format != V4L2_PIX_FMT_MPEG) return -EINVAL; + get_resolution(go, &width, &height); fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = go->board_info->sensor_width; - fsize->discrete.height = go->board_info->sensor_height; - + fsize->discrete.width = (width >> fsize->index) & ~0xf; + fsize->discrete.height = (height >> fsize->index) & ~0xf; return 0; } @@ -931,19 +926,28 @@ static int vidioc_enum_frameintervals(struct file *filp, void *priv, struct v4l2_frmivalenum *fival) { struct go7007 *go = ((struct go7007_file *) priv)->go; + int width, height; + int i; - /* Return -EINVAL, if it is a TV board */ - if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) || - (go->board_info->sensor_flags & GO7007_SENSOR_TV)) + if (fival->index > 4) return -EINVAL; - if (fival->index > 0) + if (fival->pixel_format != V4L2_PIX_FMT_MJPEG && + fival->pixel_format != V4L2_PIX_FMT_MPEG) return -EINVAL; + if (!(go->board_info->sensor_flags & GO7007_SENSOR_SCALING)) { + get_resolution(go, &width, &height); + for (i = 0; i <= 2; i++) + if (fival->width == ((width >> i) & ~0xf) && + fival->height == ((height >> i) & ~0xf)) + break; + if (i > 2) + return -EINVAL; + } fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; - fival->discrete.numerator = 1001; - fival->discrete.denominator = go->board_info->sensor_framerate; - + fival->discrete.numerator = 1001 * (fival->index + 1); + fival->discrete.denominator = go->sensor_framerate; return 0; } @@ -951,74 +955,42 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std) { struct go7007 *go = ((struct go7007_file *) priv)->go; - switch (go->standard) { - case GO7007_STD_NTSC: - *std = V4L2_STD_NTSC; - break; - case GO7007_STD_PAL: - *std = V4L2_STD_PAL; - break; - default: - return -EINVAL; + *std = go->std; + return 0; +} + +static int go7007_s_std(struct go7007 *go) +{ + if (go->std & V4L2_STD_525_60) { + go->standard = GO7007_STD_NTSC; + go->sensor_framerate = 30000; + } else { + go->standard = GO7007_STD_PAL; + go->sensor_framerate = 25025; } + call_all(&go->v4l2_dev, core, s_std, go->std); + set_capture_size(go, NULL, 0); return 0; } static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); if (go->streaming) return -EBUSY; - if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) && std != 0) - return -EINVAL; - - 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) - return -EINVAL; - } + go->std = std; - if (std & V4L2_STD_NTSC) { - go->standard = GO7007_STD_NTSC; - go->sensor_framerate = 30000; - } else if (std & V4L2_STD_PAL) { - go->standard = GO7007_STD_PAL; - go->sensor_framerate = 25025; - } 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); - set_capture_size(go, NULL, 0); - - return 0; + return go7007_s_std(go); } static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std) { struct go7007 *go = ((struct go7007_file *) priv)->go; - if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && - go->input == go->board_info->num_inputs - 1) { - if (!go->i2c_adapter_online) - return -EIO; - return call_all(&go->v4l2_dev, video, querystd, std); - } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) - *std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; - else - *std = 0; - - return 0; + return call_all(&go->v4l2_dev, video, querystd, std); } static int vidioc_enum_input(struct file *file, void *priv, @@ -1045,8 +1017,7 @@ static int vidioc_enum_input(struct file *file, void *priv, inp->audioset = 0; inp->tuner = 0; if (go->board_info->sensor_flags & GO7007_SENSOR_TV) - inp->std = V4L2_STD_NTSC | V4L2_STD_PAL | - V4L2_STD_SECAM; + inp->std = video_devdata(file)->tvnorms; else inp->std = 0; @@ -1096,16 +1067,9 @@ static int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio * return 0; } -static int vidioc_s_input(struct file *file, void *priv, unsigned int input) +static void go7007_s_input(struct go7007 *go) { - struct go7007 *go = ((struct go7007_file *) priv)->go; - - if (input >= go->board_info->num_inputs) - return -EINVAL; - if (go->streaming) - return -EBUSY; - - go->input = input; + unsigned int input = go->input; v4l2_subdev_call(go->sd_video, video, s_routing, go->board_info->inputs[input].video_input, 0, @@ -1117,6 +1081,20 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int input) go->board_info->aud_inputs[aud_input].audio_input, 0, 0); go->aud_input = aud_input; } +} + +static int vidioc_s_input(struct file *file, void *priv, unsigned int input) +{ + struct go7007 *go = video_drvdata(file); + + if (input >= go->board_info->num_inputs) + return -EINVAL; + if (go->streaming) + return -EBUSY; + + go->input = input; + go7007_s_input(go); + return 0; } @@ -1125,12 +1103,8 @@ static int vidioc_g_tuner(struct file *file, void *priv, { struct go7007 *go = ((struct go7007_file *) priv)->go; - if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) - return -EINVAL; if (t->index != 0) return -EINVAL; - if (!go->i2c_adapter_online) - return -EIO; strlcpy(t->name, "Tuner", sizeof(t->name)); return call_all(&go->v4l2_dev, tuner, g_tuner, t); @@ -1141,12 +1115,8 @@ static int vidioc_s_tuner(struct file *file, void *priv, { struct go7007 *go = ((struct go7007_file *) priv)->go; - if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) - return -EINVAL; if (t->index != 0) return -EINVAL; - if (!go->i2c_adapter_online) - return -EIO; switch (go->board_id) { case GO7007_BOARDID_PX_TV402U_NA: @@ -1165,12 +1135,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct go7007 *go = ((struct go7007_file *) priv)->go; - if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) + if (f->tuner) return -EINVAL; - if (!go->i2c_adapter_online) - return -EIO; - - f->type = V4L2_TUNER_ANALOG_TV; return call_all(&go->v4l2_dev, tuner, g_frequency, f); } @@ -1180,10 +1146,8 @@ static int vidioc_s_frequency(struct file *file, void *priv, { struct go7007 *go = ((struct go7007_file *) priv)->go; - if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) + if (f->tuner) return -EINVAL; - if (!go->i2c_adapter_online) - return -EIO; return call_all(&go->v4l2_dev, tuner, s_frequency, f); } @@ -1730,17 +1694,42 @@ int go7007_v4l2_init(struct go7007 *go) set_bit(V4L2_FL_USE_FH_PRIO, &go->video_dev->flags); video_set_drvdata(go->video_dev, go); go->video_dev->v4l2_dev = &go->v4l2_dev; - rv = video_register_device(go->video_dev, VFL_TYPE_GRABBER, -1); - if (rv < 0) { - video_device_release(go->video_dev); - go->video_dev = NULL; - return rv; + if (!v4l2_device_has_op(&go->v4l2_dev, video, querystd)) + v4l2_disable_ioctl(go->video_dev, VIDIOC_QUERYSTD); + if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) { + v4l2_disable_ioctl(go->video_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(go->video_dev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(go->video_dev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(go->video_dev, VIDIOC_G_TUNER); + } else { + struct v4l2_frequency f = { + .type = V4L2_TUNER_ANALOG_TV, + .frequency = 980, + }; + + call_all(&go->v4l2_dev, tuner, s_frequency, &f); + } + if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV)) { + v4l2_disable_ioctl(go->video_dev, VIDIOC_G_STD); + v4l2_disable_ioctl(go->video_dev, VIDIOC_S_STD); + go->video_dev->tvnorms = 0; } + if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) + v4l2_disable_ioctl(go->video_dev, VIDIOC_ENUM_FRAMESIZES); if (go->board_info->num_aud_inputs == 0) { v4l2_disable_ioctl(go->video_dev, VIDIOC_G_AUDIO); v4l2_disable_ioctl(go->video_dev, VIDIOC_S_AUDIO); v4l2_disable_ioctl(go->video_dev, VIDIOC_ENUMAUDIO); } + go7007_s_input(go); + if (go->board_info->sensor_flags & GO7007_SENSOR_TV) + go7007_s_std(go); + rv = video_register_device(go->video_dev, VFL_TYPE_GRABBER, -1); + if (rv < 0) { + video_device_release(go->video_dev); + go->video_dev = NULL; + return rv; + } dev_info(go->dev, "registered device %s [v4l2]\n", video_device_node_name(go->video_dev)); diff --git a/drivers/staging/media/go7007/s2250-board.c b/drivers/staging/media/go7007/s2250-board.c index 5899513..cb36427 100644 --- a/drivers/staging/media/go7007/s2250-board.c +++ b/drivers/staging/media/go7007/s2250-board.c @@ -354,18 +354,13 @@ static int s2250_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) u16 vidsource; vidsource = (state->input == 1) ? 0x040 : 0x020; - switch (norm) { - case V4L2_STD_NTSC: - write_regs_fp(client, vid_regs_fp); - write_reg_fp(client, 0x20, vidsource | 1); - break; - case V4L2_STD_PAL: + if (norm & V4L2_STD_625_50) { write_regs_fp(client, vid_regs_fp); write_regs_fp(client, vid_regs_fp_pal); write_reg_fp(client, 0x20, vidsource); - break; - default: - return -EINVAL; + } else { + write_regs_fp(client, vid_regs_fp); + write_reg_fp(client, 0x20, vidsource | 1); } state->std = norm; return 0; -- cgit v0.10.2 From 35d2d76dbeb6075dc629f3592bae304db81579ce Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 05:58:55 -0300 Subject: [media] go7007: standardize MPEG handling support The go7007 produces elementary streams, so we shouldn't use the STREAM_TYPE control, since that is for multiplexed streams. Instead use V4L2_PIX_FMT_MPEG1/2/4. Initially set up all the values for MPEG-2 dvd-mode, and select the dvd_mode field if those values match that setup precisely. Clean up lots of obsolete code relating to the custom ioctls for the MPEG support. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index eac91bc..732b452 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -433,12 +433,12 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) spin_lock(&go->spinlock); switch (go->format) { - case GO7007_FORMAT_MPEG4: + case V4L2_PIX_FMT_MPEG4: seq_start_code = 0xB0; frame_start_code = 0xB6; break; - case GO7007_FORMAT_MPEG1: - case GO7007_FORMAT_MPEG2: + case V4L2_PIX_FMT_MPEG1: + case V4L2_PIX_FMT_MPEG2: seq_start_code = 0xB3; frame_start_code = 0x00; break; @@ -518,9 +518,9 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) } /* If this is the start of a new MPEG frame, * get a new buffer */ - if ((go->format == GO7007_FORMAT_MPEG1 || - go->format == GO7007_FORMAT_MPEG2 || - go->format == GO7007_FORMAT_MPEG4) && + if ((go->format == V4L2_PIX_FMT_MPEG1 || + go->format == V4L2_PIX_FMT_MPEG2 || + go->format == V4L2_PIX_FMT_MPEG4) && (buf[i] == seq_start_code || buf[i] == 0xB8 || /* GOP code */ buf[i] == frame_start_code)) { @@ -577,7 +577,7 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) /* go->state remains STATE_FF */ break; case 0xD8: - if (go->format == GO7007_FORMAT_MJPEG) + if (go->format == V4L2_PIX_FMT_MJPEG) frame_boundary(go); /* fall through */ default: @@ -654,8 +654,8 @@ struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev) go->encoder_h_halve = 0; go->encoder_v_halve = 0; go->encoder_subsample = 0; + go->format = V4L2_PIX_FMT_MJPEG; go->streaming = 0; - go->format = GO7007_FORMAT_MJPEG; go->bitrate = 1500000; go->fps_scale = 1; go->pali = 0; diff --git a/drivers/staging/media/go7007/go7007-fw.c b/drivers/staging/media/go7007/go7007-fw.c index a5ede1c..524ba48 100644 --- a/drivers/staging/media/go7007/go7007-fw.c +++ b/drivers/staging/media/go7007/go7007-fw.c @@ -455,9 +455,9 @@ static int mpeg1_frame_header(struct go7007 *go, unsigned char *buf, CODE_ADD(c, frame == PFRAME ? 0x2 : 0x3, 13); CODE_ADD(c, 0xffff, 16); - CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4); + CODE_ADD(c, go->format == V4L2_PIX_FMT_MPEG2 ? 0x7 : 0x4, 4); if (frame != PFRAME) - CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 0x7 : 0x4, 4); + CODE_ADD(c, go->format == V4L2_PIX_FMT_MPEG2 ? 0x7 : 0x4, 4); else CODE_ADD(c, 0, 4); /* Is this supposed to be here?? */ CODE_ADD(c, 0, 3); /* What is this?? */ @@ -466,7 +466,7 @@ static int mpeg1_frame_header(struct go7007 *go, unsigned char *buf, if (j != 8) CODE_ADD(c, 0, j); - if (go->format == GO7007_FORMAT_MPEG2) { + if (go->format == V4L2_PIX_FMT_MPEG2) { CODE_ADD(c, 0x1, 24); CODE_ADD(c, 0xb5, 8); CODE_ADD(c, 0x844, 12); @@ -537,7 +537,7 @@ static int mpeg1_sequence_header(struct go7007 *go, unsigned char *buf, int ext) int i, aspect_ratio, picture_rate; CODE_GEN(c, buf + 6); - if (go->format == GO7007_FORMAT_MPEG1) { + if (go->format == V4L2_PIX_FMT_MPEG1) { switch (go->aspect_ratio) { case GO7007_RATIO_4_3: aspect_ratio = go->standard == GO7007_STD_NTSC ? 3 : 2; @@ -587,9 +587,9 @@ static int mpeg1_sequence_header(struct go7007 *go, unsigned char *buf, int ext) CODE_ADD(c, go->height, 12); CODE_ADD(c, aspect_ratio, 4); CODE_ADD(c, picture_rate, 4); - CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 20000 : 0x3ffff, 18); + CODE_ADD(c, go->format == V4L2_PIX_FMT_MPEG2 ? 20000 : 0x3ffff, 18); CODE_ADD(c, 1, 1); - CODE_ADD(c, go->format == GO7007_FORMAT_MPEG2 ? 112 : 20, 10); + CODE_ADD(c, go->format == V4L2_PIX_FMT_MPEG2 ? 112 : 20, 10); CODE_ADD(c, 0, 3); /* Byte-align with zeros */ @@ -597,7 +597,7 @@ static int mpeg1_sequence_header(struct go7007 *go, unsigned char *buf, int ext) if (i != 8) CODE_ADD(c, 0, i); - if (go->format == GO7007_FORMAT_MPEG2) { + if (go->format == V4L2_PIX_FMT_MPEG2) { CODE_ADD(c, 0x1, 24); CODE_ADD(c, 0xb5, 8); CODE_ADD(c, 0x148, 12); @@ -930,10 +930,10 @@ static int brctrl_to_package(struct go7007 *go, __le16 *code, int space, int *framelen) { int converge_speed = 0; - int lambda = (go->format == GO7007_FORMAT_MJPEG || go->dvd_mode) ? + int lambda = (go->format == V4L2_PIX_FMT_MJPEG || go->dvd_mode) ? 100 : 0; int peak_rate = 6 * go->bitrate / 5; - int vbv_buffer = go->format == GO7007_FORMAT_MJPEG ? + int vbv_buffer = go->format == V4L2_PIX_FMT_MJPEG ? go->bitrate : (go->dvd_mode ? 900000 : peak_rate); int fps = go->sensor_framerate / go->fps_scale; @@ -1096,10 +1096,10 @@ static int config_package(struct go7007 *go, __le16 *code, int space) 0xc003, 0x28b4, 0xc004, 0x3c5a, 0xdc05, 0x2a77, - 0xc6c3, go->format == GO7007_FORMAT_MPEG4 ? 0 : - (go->format == GO7007_FORMAT_H263 ? 0 : 1), - 0xc680, go->format == GO7007_FORMAT_MPEG4 ? 0xf1 : - (go->format == GO7007_FORMAT_H263 ? 0x61 : + 0xc6c3, go->format == V4L2_PIX_FMT_MPEG4 ? 0 : + (go->format == V4L2_PIX_FMT_H263 ? 0 : 1), + 0xc680, go->format == V4L2_PIX_FMT_MPEG4 ? 0xf1 : + (go->format == V4L2_PIX_FMT_H263 ? 0x61 : 0xd3), 0xc780, 0x0140, 0xe009, 0x0001, @@ -1123,15 +1123,15 @@ static int config_package(struct go7007 *go, __le16 *code, int space) (!go->interlace_coding) ? 0x0008 : 0x0009, 0xc404, go->interlace_coding ? 0x44 : - (go->format == GO7007_FORMAT_MPEG4 ? 0x11 : - (go->format == GO7007_FORMAT_MPEG1 ? 0x02 : - (go->format == GO7007_FORMAT_MPEG2 ? 0x04 : - (go->format == GO7007_FORMAT_H263 ? 0x08 : + (go->format == V4L2_PIX_FMT_MPEG4 ? 0x11 : + (go->format == V4L2_PIX_FMT_MPEG1 ? 0x02 : + (go->format == V4L2_PIX_FMT_MPEG2 ? 0x04 : + (go->format == V4L2_PIX_FMT_H263 ? 0x08 : 0x20)))), - 0xbf0a, (go->format == GO7007_FORMAT_MPEG4 ? 8 : - (go->format == GO7007_FORMAT_MPEG1 ? 1 : - (go->format == GO7007_FORMAT_MPEG2 ? 2 : - (go->format == GO7007_FORMAT_H263 ? 4 : 16)))) | + 0xbf0a, (go->format == V4L2_PIX_FMT_MPEG4 ? 8 : + (go->format == V4L2_PIX_FMT_MPEG1 ? 1 : + (go->format == V4L2_PIX_FMT_MPEG2 ? 2 : + (go->format == V4L2_PIX_FMT_H263 ? 4 : 16)))) | ((go->repeat_seqhead ? 1 : 0) << 6) | ((go->dvd_mode ? 1 : 0) << 9) | ((go->gop_header_enable ? 1 : 0) << 10), @@ -1348,19 +1348,19 @@ static int final_package(struct go7007 *go, __le16 *code, int space) 0x41, go->ipb ? 0xd4c : 0x36b, (rows << 8) | (go->width >> 4), - go->format == GO7007_FORMAT_MPEG4 ? 0x0404 : 0, + go->format == V4L2_PIX_FMT_MPEG4 ? 0x0404 : 0, (1 << 15) | ((go->interlace_coding ? 1 : 0) << 13) | ((go->closed_gop ? 1 : 0) << 12) | - ((go->format == GO7007_FORMAT_MPEG4 ? 1 : 0) << 11) | + ((go->format == V4L2_PIX_FMT_MPEG4 ? 1 : 0) << 11) | /* (1 << 9) | */ ((go->ipb ? 3 : 0) << 7) | ((go->modet_enable ? 1 : 0) << 2) | ((go->dvd_mode ? 1 : 0) << 1) | 1, - (go->format == GO7007_FORMAT_MPEG1 ? 0x89a0 : - (go->format == GO7007_FORMAT_MPEG2 ? 0x89a0 : - (go->format == GO7007_FORMAT_MJPEG ? 0x89a0 : - (go->format == GO7007_FORMAT_MPEG4 ? 0x8920 : - (go->format == GO7007_FORMAT_H263 ? 0x8920 : 0))))), + (go->format == V4L2_PIX_FMT_MPEG1 ? 0x89a0 : + (go->format == V4L2_PIX_FMT_MPEG2 ? 0x89a0 : + (go->format == V4L2_PIX_FMT_MJPEG ? 0x89a0 : + (go->format == V4L2_PIX_FMT_MPEG4 ? 0x8920 : + (go->format == V4L2_PIX_FMT_H263 ? 0x8920 : 0))))), go->ipb ? 0x1f15 : 0x1f0b, go->ipb ? 0x0015 : 0x000b, go->ipb ? 0xa800 : 0x5800, @@ -1503,13 +1503,13 @@ static int do_special(struct go7007 *go, u16 type, __le16 *code, int space, switch (type) { case SPECIAL_FRM_HEAD: switch (go->format) { - case GO7007_FORMAT_MJPEG: + case V4L2_PIX_FMT_MJPEG: return gen_mjpeghdr_to_package(go, code, space); - case GO7007_FORMAT_MPEG1: - case GO7007_FORMAT_MPEG2: + case V4L2_PIX_FMT_MPEG1: + case V4L2_PIX_FMT_MPEG2: return gen_mpeg1hdr_to_package(go, code, space, framelen); - case GO7007_FORMAT_MPEG4: + case V4L2_PIX_FMT_MPEG4: return gen_mpeg4hdr_to_package(go, code, space, framelen); } @@ -1519,11 +1519,11 @@ static int do_special(struct go7007 *go, u16 type, __le16 *code, int space, return config_package(go, code, space); case SPECIAL_SEQHEAD: switch (go->format) { - case GO7007_FORMAT_MPEG1: - case GO7007_FORMAT_MPEG2: + case V4L2_PIX_FMT_MPEG1: + case V4L2_PIX_FMT_MPEG2: return seqhead_to_package(go, code, space, mpeg1_sequence_header); - case GO7007_FORMAT_MPEG4: + case V4L2_PIX_FMT_MPEG4: return seqhead_to_package(go, code, space, mpeg4_sequence_header); default: @@ -1553,16 +1553,16 @@ int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen) int ret; switch (go->format) { - case GO7007_FORMAT_MJPEG: + case V4L2_PIX_FMT_MJPEG: mode_flag = FLAG_MODE_MJPEG; break; - case GO7007_FORMAT_MPEG1: + case V4L2_PIX_FMT_MPEG1: mode_flag = FLAG_MODE_MPEG1; break; - case GO7007_FORMAT_MPEG2: + case V4L2_PIX_FMT_MPEG2: mode_flag = FLAG_MODE_MPEG2; break; - case GO7007_FORMAT_MPEG4: + case V4L2_PIX_FMT_MPEG4: mode_flag = FLAG_MODE_MPEG4; break; default: diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index bf874dd..c2fafb2 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -151,12 +151,6 @@ struct go7007_file { struct go7007_buffer *bufs; }; -#define GO7007_FORMAT_MJPEG 0 -#define GO7007_FORMAT_MPEG4 1 -#define GO7007_FORMAT_MPEG1 2 -#define GO7007_FORMAT_MPEG2 3 -#define GO7007_FORMAT_H263 4 - #define GO7007_RATIO_1_1 0 #define GO7007_RATIO_4_3 1 #define GO7007_RATIO_16_9 2 @@ -186,6 +180,11 @@ struct go7007 { unsigned boot_fw_len; struct v4l2_device v4l2_dev; struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *mpeg_video_encoding; + struct v4l2_ctrl *mpeg_video_gop_size; + struct v4l2_ctrl *mpeg_video_gop_closure; + struct v4l2_ctrl *mpeg_video_bitrate; + struct v4l2_ctrl *mpeg_video_aspect_ratio; enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status; spinlock_t spinlock; struct mutex hw_lock; @@ -211,7 +210,7 @@ struct go7007 { unsigned int encoder_subsample:1; /* Encoder config */ - int format; + u32 format; int bitrate; int fps_scale; int pali; diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index fc776e5..70a5274 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -39,11 +39,6 @@ #include "go7007.h" #include "go7007-priv.h" -/* Temporary defines until accepted in v4l-dvb */ -#ifndef V4L2_MPEG_STREAM_TYPE_MPEG_ELEM -#define V4L2_MPEG_STREAM_TYPE_MPEG_ELEM 6 /* MPEG elementary stream */ -#endif - #define call_all(dev, o, f, args...) \ v4l2_device_call_until_err(dev, 0, o, f, ##args) @@ -85,6 +80,10 @@ static int go7007_streamoff(struct go7007 *go) go7007_reset_encoder(go); } mutex_unlock(&go->hw_lock); + v4l2_ctrl_grab(go->mpeg_video_gop_size, false); + v4l2_ctrl_grab(go->mpeg_video_gop_closure, false); + v4l2_ctrl_grab(go->mpeg_video_bitrate, false); + v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, false); return 0; } @@ -125,14 +124,27 @@ static int go7007_release(struct file *file) return 0; } +static bool valid_pixelformat(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_MJPEG: + case V4L2_PIX_FMT_MPEG1: + case V4L2_PIX_FMT_MPEG2: + case V4L2_PIX_FMT_MPEG4: + return true; + default: + return false; + } +} + static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format) { u8 *f = page_address(gobuf->pages[0]); switch (format) { - case GO7007_FORMAT_MJPEG: + case V4L2_PIX_FMT_MJPEG: return V4L2_BUF_FLAG_KEYFRAME; - case GO7007_FORMAT_MPEG4: + case V4L2_PIX_FMT_MPEG4: switch ((f[gobuf->frame_offset + 4] >> 6) & 0x3) { case 0: return V4L2_BUF_FLAG_KEYFRAME; @@ -143,8 +155,8 @@ static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format) default: return 0; } - case GO7007_FORMAT_MPEG1: - case GO7007_FORMAT_MPEG2: + case V4L2_PIX_FMT_MPEG1: + case V4L2_PIX_FMT_MPEG2: switch ((f[gobuf->frame_offset + 5] >> 3) & 0x7) { case 1: return V4L2_BUF_FLAG_KEYFRAME; @@ -179,13 +191,87 @@ static void get_resolution(struct go7007 *go, int *width, int *height) } } +static void set_formatting(struct go7007 *go) +{ + if (go->format == V4L2_PIX_FMT_MJPEG) { + go->pali = 0; + go->aspect_ratio = GO7007_RATIO_1_1; + go->gop_size = 0; + go->ipb = 0; + go->closed_gop = 0; + go->repeat_seqhead = 0; + go->seq_header_enable = 0; + go->gop_header_enable = 0; + go->dvd_mode = 0; + return; + } + + switch (go->format) { + case V4L2_PIX_FMT_MPEG1: + go->pali = 0; + break; + default: + case V4L2_PIX_FMT_MPEG2: + go->pali = 0x48; + break; + case V4L2_PIX_FMT_MPEG4: + /* For future reference: this is the list of MPEG4 + * profiles that are available, although they are + * untested: + * + * Profile pali + * -------------- ---- + * PROFILE_S_L0 0x08 + * PROFILE_S_L1 0x01 + * PROFILE_S_L2 0x02 + * PROFILE_S_L3 0x03 + * PROFILE_ARTS_L1 0x91 + * PROFILE_ARTS_L2 0x92 + * PROFILE_ARTS_L3 0x93 + * PROFILE_ARTS_L4 0x94 + * PROFILE_AS_L0 0xf0 + * PROFILE_AS_L1 0xf1 + * PROFILE_AS_L2 0xf2 + * PROFILE_AS_L3 0xf3 + * PROFILE_AS_L4 0xf4 + * PROFILE_AS_L5 0xf5 + */ + go->pali = 0xf5; + break; + } + go->gop_size = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_size); + go->closed_gop = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_closure); + go->bitrate = v4l2_ctrl_g_ctrl(go->mpeg_video_bitrate); + go->gop_header_enable = 1; + go->dvd_mode = 0; + if (go->format == V4L2_PIX_FMT_MPEG2) + go->dvd_mode = + go->bitrate == 9800000 && + go->gop_size == 15 && + go->closed_gop; + go->repeat_seqhead = go->dvd_mode; + go->ipb = 0; + + switch (v4l2_ctrl_g_ctrl(go->mpeg_video_aspect_ratio)) { + default: + case V4L2_MPEG_VIDEO_ASPECT_1x1: + go->aspect_ratio = GO7007_RATIO_1_1; + break; + case V4L2_MPEG_VIDEO_ASPECT_4x3: + go->aspect_ratio = GO7007_RATIO_4_3; + break; + case V4L2_MPEG_VIDEO_ASPECT_16x9: + go->aspect_ratio = GO7007_RATIO_16_9; + break; + } +} + static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) { int sensor_height = 0, sensor_width = 0; int width, height, i; - if (fmt != NULL && fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && - fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG) + if (fmt != NULL && !valid_pixelformat(fmt->fmt.pix.pixelformat)) return -EINVAL; get_resolution(go, &sensor_width, &sensor_height); @@ -241,6 +327,8 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) if (try) return 0; + if (fmt) + go->format = fmt->fmt.pix.pixelformat; go->width = width; go->height = height; go->encoder_h_offset = go->board_info->sensor_h_offset; @@ -275,55 +363,6 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) go->encoder_subsample = 0; } } - - if (fmt == NULL) - return 0; - - switch (fmt->fmt.pix.pixelformat) { - case V4L2_PIX_FMT_MPEG: - if (go->format == GO7007_FORMAT_MPEG1 || - go->format == GO7007_FORMAT_MPEG2 || - go->format == GO7007_FORMAT_MPEG4) - break; - go->format = GO7007_FORMAT_MPEG1; - go->pali = 0; - go->aspect_ratio = GO7007_RATIO_1_1; - go->gop_size = go->sensor_framerate / 1000; - go->ipb = 0; - go->closed_gop = 1; - go->repeat_seqhead = 1; - go->seq_header_enable = 1; - go->gop_header_enable = 1; - go->dvd_mode = 0; - break; - /* Backwards compatibility only! */ - case V4L2_PIX_FMT_MPEG4: - if (go->format == GO7007_FORMAT_MPEG4) - break; - go->format = GO7007_FORMAT_MPEG4; - go->pali = 0xf5; - go->aspect_ratio = GO7007_RATIO_1_1; - go->gop_size = go->sensor_framerate / 1000; - go->ipb = 0; - go->closed_gop = 1; - go->repeat_seqhead = 1; - go->seq_header_enable = 1; - go->gop_header_enable = 1; - go->dvd_mode = 0; - break; - case V4L2_PIX_FMT_MJPEG: - go->format = GO7007_FORMAT_MJPEG; - go->pali = 0; - go->aspect_ratio = GO7007_RATIO_1_1; - go->gop_size = 0; - go->ipb = 0; - go->closed_gop = 0; - go->repeat_seqhead = 0; - go->seq_header_enable = 0; - go->gop_header_enable = 0; - go->dvd_mode = 0; - break; - } return 0; } @@ -385,98 +424,6 @@ static int clip_to_modet_map(struct go7007 *go, int region, } #endif -static int go7007_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct go7007 *go = - container_of(ctrl->handler, struct go7007, hdl); - - /* pretty sure we can't change any of these while streaming */ - if (go->streaming) - return -EBUSY; - - switch (ctrl->id) { - case V4L2_CID_MPEG_STREAM_TYPE: - switch (ctrl->val) { - case V4L2_MPEG_STREAM_TYPE_MPEG2_DVD: - go->format = GO7007_FORMAT_MPEG2; - go->bitrate = 9800000; - go->gop_size = 15; - go->pali = 0x48; - go->closed_gop = 1; - go->repeat_seqhead = 0; - go->seq_header_enable = 1; - go->gop_header_enable = 1; - go->dvd_mode = 1; - break; - default: - return -EINVAL; - } - break; - case V4L2_CID_MPEG_VIDEO_ENCODING: - switch (ctrl->val) { - case V4L2_MPEG_VIDEO_ENCODING_MPEG_1: - go->format = GO7007_FORMAT_MPEG1; - go->pali = 0; - break; - case V4L2_MPEG_VIDEO_ENCODING_MPEG_2: - go->format = GO7007_FORMAT_MPEG2; - /*if (mpeg->pali >> 24 == 2) - go->pali = mpeg->pali & 0xff; - else*/ - go->pali = 0x48; - break; - case V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC: - go->format = GO7007_FORMAT_MPEG4; - /*if (mpeg->pali >> 24 == 4) - go->pali = mpeg->pali & 0xff; - else*/ - go->pali = 0xf5; - break; - default: - return -EINVAL; - } - go->gop_header_enable = - /*mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER - ? 0 :*/ 1; - /*if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER) - go->repeat_seqhead = 1; - else*/ - go->repeat_seqhead = 0; - go->dvd_mode = 0; - break; - case V4L2_CID_MPEG_VIDEO_ASPECT: - /* TODO: is this really the right thing to do for mjpeg? */ - if (go->format == GO7007_FORMAT_MJPEG) - return -EINVAL; - switch (ctrl->val) { - case V4L2_MPEG_VIDEO_ASPECT_1x1: - go->aspect_ratio = GO7007_RATIO_1_1; - break; - case V4L2_MPEG_VIDEO_ASPECT_4x3: - go->aspect_ratio = GO7007_RATIO_4_3; - break; - case V4L2_MPEG_VIDEO_ASPECT_16x9: - go->aspect_ratio = GO7007_RATIO_16_9; - break; - default: - return -EINVAL; - } - break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - go->gop_size = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - go->closed_gop = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - go->bitrate = ctrl->val; - break; - default: - return -EINVAL; - } - return 0; -} - static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -504,11 +451,19 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, switch (fmt->index) { case 0: fmt->pixelformat = V4L2_PIX_FMT_MJPEG; - desc = "Motion-JPEG"; + desc = "Motion JPEG"; break; case 1: - fmt->pixelformat = V4L2_PIX_FMT_MPEG; - desc = "MPEG1/MPEG2/MPEG4"; + fmt->pixelformat = V4L2_PIX_FMT_MPEG1; + desc = "MPEG-1 ES"; + break; + case 2: + fmt->pixelformat = V4L2_PIX_FMT_MPEG2; + desc = "MPEG-2 ES"; + break; + case 3: + fmt->pixelformat = V4L2_PIX_FMT_MPEG4; + desc = "MPEG-4 ES"; break; default: return -EINVAL; @@ -529,8 +484,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt->fmt.pix.width = go->width; fmt->fmt.pix.height = go->height; - fmt->fmt.pix.pixelformat = (go->format == GO7007_FORMAT_MJPEG) ? - V4L2_PIX_FMT_MJPEG : V4L2_PIX_FMT_MPEG; + fmt->fmt.pix.pixelformat = go->format; fmt->fmt.pix.field = V4L2_FIELD_NONE; fmt->fmt.pix.bytesperline = 0; fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE; @@ -578,6 +532,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, if (gofh->bufs[i].mapped > 0) goto unlock_and_return; + set_formatting(go); mutex_lock(&go->hw_lock); if (go->in_use > 0 && gofh->buf_count == 0) { mutex_unlock(&go->hw_lock); @@ -833,6 +788,10 @@ static int vidioc_streamon(struct file *file, void *priv, mutex_unlock(&go->hw_lock); mutex_unlock(&gofh->lock); call_all(&go->v4l2_dev, video, s_stream, 1); + v4l2_ctrl_grab(go->mpeg_video_gop_size, true); + v4l2_ctrl_grab(go->mpeg_video_gop_closure, true); + v4l2_ctrl_grab(go->mpeg_video_bitrate, true); + v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, true); return retval; } @@ -911,8 +870,7 @@ static int vidioc_enum_framesizes(struct file *filp, void *priv, if (fsize->index > 2) return -EINVAL; - if (fsize->pixel_format != V4L2_PIX_FMT_MJPEG && - fsize->pixel_format != V4L2_PIX_FMT_MPEG) + if (!valid_pixelformat(fsize->pixel_format)) return -EINVAL; get_resolution(go, &width, &height); @@ -932,8 +890,7 @@ static int vidioc_enum_frameintervals(struct file *filp, void *priv, if (fival->index > 4) return -EINVAL; - if (fival->pixel_format != V4L2_PIX_FMT_MJPEG && - fival->pixel_format != V4L2_PIX_FMT_MPEG) + if (!valid_pixelformat(fival->pixel_format)) return -EINVAL; if (!(go->board_info->sensor_flags & GO7007_SENSOR_SCALING)) { @@ -1257,180 +1214,6 @@ static int vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop * */ #if 0 - /* Temporary ioctls for controlling compression characteristics */ - case GO7007IOC_S_BITRATE: - { - int *bitrate = arg; - - if (go->streaming) - return -EINVAL; - /* Upper bound is kind of arbitrary here */ - if (*bitrate < 64000 || *bitrate > 10000000) - return -EINVAL; - go->bitrate = *bitrate; - return 0; - } - case GO7007IOC_G_BITRATE: - { - int *bitrate = arg; - - *bitrate = go->bitrate; - return 0; - } - case GO7007IOC_S_COMP_PARAMS: - { - struct go7007_comp_params *comp = arg; - - if (go->format == GO7007_FORMAT_MJPEG) - return -EINVAL; - if (comp->gop_size > 0) - go->gop_size = comp->gop_size; - else - go->gop_size = go->sensor_framerate / 1000; - if (go->gop_size != 15) - go->dvd_mode = 0; - /*go->ipb = comp->max_b_frames > 0;*/ /* completely untested */ - if (go->board_info->sensor_flags & GO7007_SENSOR_TV) { - switch (comp->aspect_ratio) { - case GO7007_ASPECT_RATIO_4_3_NTSC: - case GO7007_ASPECT_RATIO_4_3_PAL: - go->aspect_ratio = GO7007_RATIO_4_3; - break; - case GO7007_ASPECT_RATIO_16_9_NTSC: - case GO7007_ASPECT_RATIO_16_9_PAL: - go->aspect_ratio = GO7007_RATIO_16_9; - break; - default: - go->aspect_ratio = GO7007_RATIO_1_1; - break; - } - } - if (comp->flags & GO7007_COMP_OMIT_SEQ_HEADER) { - go->dvd_mode = 0; - go->seq_header_enable = 0; - } else { - go->seq_header_enable = 1; - } - /* fall-through */ - } - case GO7007IOC_G_COMP_PARAMS: - { - struct go7007_comp_params *comp = arg; - - if (go->format == GO7007_FORMAT_MJPEG) - return -EINVAL; - memset(comp, 0, sizeof(*comp)); - comp->gop_size = go->gop_size; - comp->max_b_frames = go->ipb ? 2 : 0; - switch (go->aspect_ratio) { - case GO7007_RATIO_4_3: - if (go->standard == GO7007_STD_NTSC) - comp->aspect_ratio = - GO7007_ASPECT_RATIO_4_3_NTSC; - else - comp->aspect_ratio = - GO7007_ASPECT_RATIO_4_3_PAL; - break; - case GO7007_RATIO_16_9: - if (go->standard == GO7007_STD_NTSC) - comp->aspect_ratio = - GO7007_ASPECT_RATIO_16_9_NTSC; - else - comp->aspect_ratio = - GO7007_ASPECT_RATIO_16_9_PAL; - break; - default: - comp->aspect_ratio = GO7007_ASPECT_RATIO_1_1; - break; - } - if (go->closed_gop) - comp->flags |= GO7007_COMP_CLOSED_GOP; - if (!go->seq_header_enable) - comp->flags |= GO7007_COMP_OMIT_SEQ_HEADER; - return 0; - } - case GO7007IOC_S_MPEG_PARAMS: - { - struct go7007_mpeg_params *mpeg = arg; - - if (go->format != GO7007_FORMAT_MPEG1 && - go->format != GO7007_FORMAT_MPEG2 && - go->format != GO7007_FORMAT_MPEG4) - return -EINVAL; - - if (mpeg->flags & GO7007_MPEG_FORCE_DVD_MODE) { - go->format = GO7007_FORMAT_MPEG2; - go->bitrate = 9800000; - go->gop_size = 15; - go->pali = 0x48; - go->closed_gop = 1; - go->repeat_seqhead = 0; - go->seq_header_enable = 1; - go->gop_header_enable = 1; - go->dvd_mode = 1; - } else { - switch (mpeg->mpeg_video_standard) { - case GO7007_MPEG_VIDEO_MPEG1: - go->format = GO7007_FORMAT_MPEG1; - go->pali = 0; - break; - case GO7007_MPEG_VIDEO_MPEG2: - go->format = GO7007_FORMAT_MPEG2; - if (mpeg->pali >> 24 == 2) - go->pali = mpeg->pali & 0xff; - else - go->pali = 0x48; - break; - case GO7007_MPEG_VIDEO_MPEG4: - go->format = GO7007_FORMAT_MPEG4; - if (mpeg->pali >> 24 == 4) - go->pali = mpeg->pali & 0xff; - else - go->pali = 0xf5; - break; - default: - return -EINVAL; - } - go->gop_header_enable = - mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER - ? 0 : 1; - if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER) - go->repeat_seqhead = 1; - else - go->repeat_seqhead = 0; - go->dvd_mode = 0; - } - /* fall-through */ - } - case GO7007IOC_G_MPEG_PARAMS: - { - struct go7007_mpeg_params *mpeg = arg; - - memset(mpeg, 0, sizeof(*mpeg)); - switch (go->format) { - case GO7007_FORMAT_MPEG1: - mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG1; - mpeg->pali = 0; - break; - case GO7007_FORMAT_MPEG2: - mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2; - mpeg->pali = GO7007_MPEG_PROFILE(2, go->pali); - break; - case GO7007_FORMAT_MPEG4: - mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4; - mpeg->pali = GO7007_MPEG_PROFILE(4, go->pali); - break; - default: - return -EINVAL; - } - if (!go->gop_header_enable) - mpeg->flags |= GO7007_MPEG_OMIT_GOP_HEADER; - if (go->repeat_seqhead) - mpeg->flags |= GO7007_MPEG_REPEAT_SEQHEADER; - if (go->dvd_mode) - mpeg->flags |= GO7007_MPEG_FORCE_DVD_MODE; - return 0; - } case GO7007IOC_S_MD_PARAMS: { struct go7007_md_params *mdp = arg; @@ -1449,25 +1232,6 @@ static int vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop * go->modet[mdp->region].enable = 0; /* fall-through */ } - case GO7007IOC_G_MD_PARAMS: - { - struct go7007_md_params *mdp = arg; - int region = mdp->region; - - if (mdp->region > 3) - return -EINVAL; - memset(mdp, 0, sizeof(struct go7007_md_params)); - mdp->region = region; - if (!go->modet[region].enable) - return 0; - mdp->pixel_threshold = - (go->modet[region].pixel_threshold << 1) + 1; - mdp->motion_threshold = - (go->modet[region].motion_threshold << 1) + 1; - mdp->trigger = - (go->modet[region].mb_threshold << 1) + 1; - return 0; - } case GO7007IOC_S_MD_REGION: { struct go7007_md_region *region = arg; @@ -1590,10 +1354,6 @@ static struct v4l2_file_operations go7007_fops = { .poll = go7007_poll, }; -static struct v4l2_ctrl_ops go7007_ctrl_ops = { - .s_ctrl = go7007_s_ctrl, -}; - static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, @@ -1645,29 +1405,18 @@ int go7007_v4l2_ctrl_init(struct go7007 *go) struct v4l2_ctrl *ctrl; v4l2_ctrl_handler_init(hdl, 12); - v4l2_ctrl_new_std_menu(hdl, &go7007_ctrl_ops, - V4L2_CID_MPEG_STREAM_TYPE, - V4L2_MPEG_STREAM_TYPE_MPEG2_DVD, - 0x7, - V4L2_MPEG_STREAM_TYPE_MPEG2_DVD); - v4l2_ctrl_new_std_menu(hdl, &go7007_ctrl_ops, - V4L2_CID_MPEG_VIDEO_ENCODING, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, - 0, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2); - v4l2_ctrl_new_std_menu(hdl, &go7007_ctrl_ops, - V4L2_CID_MPEG_VIDEO_ASPECT, - V4L2_MPEG_VIDEO_ASPECT_16x9, - 0, - V4L2_MPEG_VIDEO_ASPECT_1x1); - v4l2_ctrl_new_std(hdl, &go7007_ctrl_ops, + go->mpeg_video_gop_size = v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, 34, 1, 15); - v4l2_ctrl_new_std(hdl, &go7007_ctrl_ops, - V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 0); - v4l2_ctrl_new_std(hdl, &go7007_ctrl_ops, + go->mpeg_video_gop_closure = v4l2_ctrl_new_std(hdl, NULL, + V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 1); + go->mpeg_video_bitrate = v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_MPEG_VIDEO_BITRATE, - 64000, 10000000, 1, 1500000); - ctrl = v4l2_ctrl_new_std(hdl, &go7007_ctrl_ops, + 64000, 10000000, 1, 9800000); + go->mpeg_video_aspect_ratio = v4l2_ctrl_new_std_menu(hdl, NULL, + V4L2_CID_MPEG_VIDEO_ASPECT, + V4L2_MPEG_VIDEO_ASPECT_16x9, 0, + V4L2_MPEG_VIDEO_ASPECT_1x1); + ctrl = v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_JPEG_ACTIVE_MARKER, 0, V4L2_JPEG_ACTIVE_MARKER_DQT | V4L2_JPEG_ACTIVE_MARKER_DHT, 0, V4L2_JPEG_ACTIVE_MARKER_DQT | V4L2_JPEG_ACTIVE_MARKER_DHT); diff --git a/drivers/staging/media/go7007/go7007.h b/drivers/staging/media/go7007/go7007.h index 7399c91..54b9897 100644 --- a/drivers/staging/media/go7007/go7007.h +++ b/drivers/staging/media/go7007/go7007.h @@ -17,72 +17,6 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* DEPRECATED -- use V4L2_PIX_FMT_MPEG and then call GO7007IOC_S_MPEG_PARAMS - * to select between MPEG1, MPEG2, and MPEG4 */ -#define V4L2_PIX_FMT_MPEG4 v4l2_fourcc('M', 'P', 'G', '4') /* MPEG4 */ - -/* These will be replaced with a better interface - * soon, so don't get too attached to them */ -#define GO7007IOC_S_BITRATE _IOW('V', BASE_VIDIOC_PRIVATE + 0, int) -#define GO7007IOC_G_BITRATE _IOR('V', BASE_VIDIOC_PRIVATE + 1, int) - -enum go7007_aspect_ratio { - GO7007_ASPECT_RATIO_1_1 = 0, - GO7007_ASPECT_RATIO_4_3_NTSC = 1, - GO7007_ASPECT_RATIO_4_3_PAL = 2, - GO7007_ASPECT_RATIO_16_9_NTSC = 3, - GO7007_ASPECT_RATIO_16_9_PAL = 4, -}; - -/* Used to set generic compression parameters */ -struct go7007_comp_params { - __u32 gop_size; - __u32 max_b_frames; - enum go7007_aspect_ratio aspect_ratio; - __u32 flags; - __u32 reserved[8]; -}; - -#define GO7007_COMP_CLOSED_GOP 0x00000001 -#define GO7007_COMP_OMIT_SEQ_HEADER 0x00000002 - -enum go7007_mpeg_video_standard { - GO7007_MPEG_VIDEO_MPEG1 = 0, - GO7007_MPEG_VIDEO_MPEG2 = 1, - GO7007_MPEG_VIDEO_MPEG4 = 2, -}; - -/* Used to set parameters for V4L2_PIX_FMT_MPEG format */ -struct go7007_mpeg_params { - enum go7007_mpeg_video_standard mpeg_video_standard; - __u32 flags; - __u32 pali; - __u32 reserved[8]; -}; - -#define GO7007_MPEG_FORCE_DVD_MODE 0x00000001 -#define GO7007_MPEG_OMIT_GOP_HEADER 0x00000002 -#define GO7007_MPEG_REPEAT_SEQHEADER 0x00000004 - -#define GO7007_MPEG_PROFILE(format, pali) (((format)<<24)|(pali)) - -#define GO7007_MPEG2_PROFILE_MAIN_MAIN GO7007_MPEG_PROFILE(2, 0x48) - -#define GO7007_MPEG4_PROFILE_S_L0 GO7007_MPEG_PROFILE(4, 0x08) -#define GO7007_MPEG4_PROFILE_S_L1 GO7007_MPEG_PROFILE(4, 0x01) -#define GO7007_MPEG4_PROFILE_S_L2 GO7007_MPEG_PROFILE(4, 0x02) -#define GO7007_MPEG4_PROFILE_S_L3 GO7007_MPEG_PROFILE(4, 0x03) -#define GO7007_MPEG4_PROFILE_ARTS_L1 GO7007_MPEG_PROFILE(4, 0x91) -#define GO7007_MPEG4_PROFILE_ARTS_L2 GO7007_MPEG_PROFILE(4, 0x92) -#define GO7007_MPEG4_PROFILE_ARTS_L3 GO7007_MPEG_PROFILE(4, 0x93) -#define GO7007_MPEG4_PROFILE_ARTS_L4 GO7007_MPEG_PROFILE(4, 0x94) -#define GO7007_MPEG4_PROFILE_AS_L0 GO7007_MPEG_PROFILE(4, 0xf0) -#define GO7007_MPEG4_PROFILE_AS_L1 GO7007_MPEG_PROFILE(4, 0xf1) -#define GO7007_MPEG4_PROFILE_AS_L2 GO7007_MPEG_PROFILE(4, 0xf2) -#define GO7007_MPEG4_PROFILE_AS_L3 GO7007_MPEG_PROFILE(4, 0xf3) -#define GO7007_MPEG4_PROFILE_AS_L4 GO7007_MPEG_PROFILE(4, 0xf4) -#define GO7007_MPEG4_PROFILE_AS_L5 GO7007_MPEG_PROFILE(4, 0xf5) - struct go7007_md_params { __u16 region; __u16 trigger; @@ -98,14 +32,6 @@ struct go7007_md_region { __u32 reserved[8]; }; -#define GO7007IOC_S_MPEG_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 2, \ - struct go7007_mpeg_params) -#define GO7007IOC_G_MPEG_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 3, \ - struct go7007_mpeg_params) -#define GO7007IOC_S_COMP_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 4, \ - struct go7007_comp_params) -#define GO7007IOC_G_COMP_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 5, \ - struct go7007_comp_params) #define GO7007IOC_S_MD_PARAMS _IOWR('V', BASE_VIDIOC_PRIVATE + 6, \ struct go7007_md_params) #define GO7007IOC_G_MD_PARAMS _IOR('V', BASE_VIDIOC_PRIVATE + 7, \ -- cgit v0.10.2 From 9ff76e36dc632289658e7ff65e9e5fdfe6cca905 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 06:11:03 -0300 Subject: [media] go7007: simplify the PX-TV402U board ID handling There really is no need to split out the board IDs for each tuner. That's what the tuner_type is for, after all. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index c2fafb2..a6ef67b 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -36,15 +36,12 @@ struct go7007; #define GO7007_BOARDID_XMEN_II 5 #define GO7007_BOARDID_XMEN_III 6 #define GO7007_BOARDID_MATRIX_REV 7 -#define GO7007_BOARDID_PX_M402U 16 -#define GO7007_BOARDID_PX_TV402U_ANY 17 /* need to check tuner model */ -#define GO7007_BOARDID_PX_TV402U_NA 18 /* detected NTSC tuner */ -#define GO7007_BOARDID_PX_TV402U_EU 19 /* detected PAL tuner */ -#define GO7007_BOARDID_PX_TV402U_JP 20 /* detected NTSC-J tuner */ -#define GO7007_BOARDID_LIFEVIEW_LR192 21 /* TV Walker Ultra */ -#define GO7007_BOARDID_ENDURA 22 -#define GO7007_BOARDID_ADLINK_MPG24 23 -#define GO7007_BOARDID_SENSORAY_2250 24 /* Sensoray 2250/2251 */ +#define GO7007_BOARDID_PX_M402U 8 +#define GO7007_BOARDID_PX_TV402U 9 +#define GO7007_BOARDID_LIFEVIEW_LR192 10 /* TV Walker Ultra */ +#define GO7007_BOARDID_ENDURA 11 +#define GO7007_BOARDID_ADLINK_MPG24 12 +#define GO7007_BOARDID_SENSORAY_2250 13 /* Sensoray 2250/2251 */ /* Various characteristics of each board */ #define GO7007_BOARD_HAS_AUDIO (1<<0) diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 14d1cda..53c5b16 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -568,7 +568,7 @@ static const struct usb_device_id go7007_usb_id_table[] = { .idProduct = 0xa104, /* Product ID of TV402U */ .bcdDevice_lo = 0x1, .bcdDevice_hi = 0x1, - .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U_ANY, + .driver_info = (kernel_ulong_t)GO7007_BOARDID_PX_TV402U, }, { .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, @@ -1079,7 +1079,7 @@ static int go7007_usb_probe(struct usb_interface *intf, name = "Plextor PX-M402U"; board = &board_matrix_ii; break; - case GO7007_BOARDID_PX_TV402U_ANY: + case GO7007_BOARDID_PX_TV402U: name = "Plextor PX-TV402U (unknown tuner)"; board = &board_px_tv402u; break; @@ -1200,7 +1200,7 @@ static int go7007_usb_probe(struct usb_interface *intf, num_i2c_devs = go->board_info->num_i2c_devs; /* Probe the tuner model on the TV402U */ - if (go->board_id == GO7007_BOARDID_PX_TV402U_ANY) { + if (go->board_id == GO7007_BOARDID_PX_TV402U) { /* Board strapping indicates tuner model */ if (go7007_usb_vendor_request(go, 0x41, 0, 0, go->usb_buf, 3, 1) < 0) { printk(KERN_ERR "go7007-usb: GPIO read failed!\n"); @@ -1208,14 +1208,12 @@ static int go7007_usb_probe(struct usb_interface *intf, } switch (go->usb_buf[0] >> 6) { case 1: - go->board_id = GO7007_BOARDID_PX_TV402U_EU; go->tuner_type = TUNER_SONY_BTF_PG472Z; go->std = V4L2_STD_PAL; strncpy(go->name, "Plextor PX-TV402U-EU", sizeof(go->name)); break; case 2: - go->board_id = GO7007_BOARDID_PX_TV402U_JP; go->tuner_type = TUNER_SONY_BTF_PK467Z; go->std = V4L2_STD_NTSC_M_JP; num_i2c_devs -= 2; @@ -1223,7 +1221,6 @@ static int go7007_usb_probe(struct usb_interface *intf, sizeof(go->name)); break; case 3: - go->board_id = GO7007_BOARDID_PX_TV402U_NA; go->tuner_type = TUNER_SONY_BTF_PB463Z; num_i2c_devs -= 2; strncpy(go->name, "Plextor PX-TV402U-NA", diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 70a5274..4d9a998 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -1075,15 +1075,6 @@ static int vidioc_s_tuner(struct file *file, void *priv, if (t->index != 0) return -EINVAL; - switch (go->board_id) { - case GO7007_BOARDID_PX_TV402U_NA: - case GO7007_BOARDID_PX_TV402U_JP: - /* No selectable options currently */ - if (t->audmode != V4L2_TUNER_MODE_STEREO) - return -EINVAL; - break; - } - return call_all(&go->v4l2_dev, tuner, s_tuner, t); } -- cgit v0.10.2 From b95dd82cd1b1e81c2019effd5e012e6989622ba9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 06:12:10 -0300 Subject: [media] go7007: set up the saa7115 audio clock correctly The s_crystal_freq operation has to be called for the saa7115 to set up the audio clock correctly. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index a6ef67b..7f79cc1 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -60,6 +60,7 @@ struct go7007; #define GO7007_SENSOR_TV (1<<7) #define GO7007_SENSOR_VBI (1<<8) #define GO7007_SENSOR_SCALING (1<<9) +#define GO7007_SENSOR_SAA7115 (1<<10) /* Characteristics of audio sensor devices */ #define GO7007_AUDIO_I2S_MODE_1 (1) diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 53c5b16..5c7a19e6 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -88,6 +88,7 @@ static struct go7007_usb_board board_matrix_ii = { .sensor_flags = GO7007_SENSOR_656 | GO7007_SENSOR_VALID_ENABLE | GO7007_SENSOR_TV | + GO7007_SENSOR_SAA7115 | GO7007_SENSOR_VBI | GO7007_SENSOR_SCALING, .num_i2c_devs = 1, @@ -131,7 +132,7 @@ static struct go7007_usb_board board_matrix_reload = { .num_i2c_devs = 1, .i2c_devs = { { - .type = "saa7115", + .type = "saa7113", .addr = 0x25, .is_video = 1, }, @@ -160,6 +161,7 @@ static struct go7007_usb_board board_star_trek = { .sensor_flags = GO7007_SENSOR_656 | GO7007_SENSOR_VALID_ENABLE | GO7007_SENSOR_TV | + GO7007_SENSOR_SAA7115 | GO7007_SENSOR_VBI | GO7007_SENSOR_SCALING, .audio_flags = GO7007_AUDIO_I2S_MODE_1 | @@ -207,6 +209,7 @@ static struct go7007_usb_board board_px_tv402u = { .sensor_flags = GO7007_SENSOR_656 | GO7007_SENSOR_VALID_ENABLE | GO7007_SENSOR_TV | + GO7007_SENSOR_SAA7115 | GO7007_SENSOR_VBI | GO7007_SENSOR_SCALING, .audio_flags = GO7007_AUDIO_I2S_MODE_1 | diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 4d9a998..824b7e5 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "go7007.h" #include "go7007-priv.h" @@ -1461,6 +1462,12 @@ int go7007_v4l2_init(struct go7007 *go) v4l2_disable_ioctl(go->video_dev, VIDIOC_S_AUDIO); v4l2_disable_ioctl(go->video_dev, VIDIOC_ENUMAUDIO); } + /* Setup correct crystal frequency on this board */ + if (go->board_info->sensor_flags & GO7007_SENSOR_SAA7115) + v4l2_subdev_call(go->sd_video, video, s_crystal_freq, + SAA7115_FREQ_24_576_MHZ, + SAA7115_FREQ_FL_APLL | SAA7115_FREQ_FL_UCGC | + SAA7115_FREQ_FL_DOUBLE_ASCLK); go7007_s_input(go); if (go->board_info->sensor_flags & GO7007_SENSOR_TV) go7007_s_std(go); -- cgit v0.10.2 From 899eb84ce3b50dfa8de6a12e6f39f4e30fde9781 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 06:18:20 -0300 Subject: [media] go7007: drop struct go7007_file Remove struct go7007_file: all fields contained in that struct are moved to the go7007 struct since they are really global values. The lock has just been deleted (what's the point of a per-fh lock??). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index 7f79cc1..2c0afb1 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -141,14 +141,6 @@ struct go7007_buffer { int mapped; }; -struct go7007_file { - struct v4l2_fh fh; - struct go7007 *go; - struct mutex lock; - int buf_count; - struct go7007_buffer *bufs; -}; - #define GO7007_RATIO_1_1 0 #define GO7007_RATIO_4_3 1 #define GO7007_RATIO_16_9 2 @@ -242,6 +234,9 @@ struct go7007 { u32 next_seq; struct list_head stream; wait_queue_head_t frame_waitq; + int buf_count; + struct go7007_buffer *bufs; + struct v4l2_fh *bufs_owner; /* Audio streaming */ void (*audio_deliver)(struct go7007 *go, u8 *buf, int length); diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 824b7e5..b107020 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -88,41 +88,19 @@ static int go7007_streamoff(struct go7007 *go) return 0; } -static int go7007_open(struct file *file) -{ - struct go7007 *go = video_get_drvdata(video_devdata(file)); - struct go7007_file *gofh; - - if (go->status != STATUS_ONLINE) - return -EBUSY; - gofh = kzalloc(sizeof(struct go7007_file), GFP_KERNEL); - if (gofh == NULL) - return -ENOMEM; - gofh->go = go; - mutex_init(&gofh->lock); - gofh->buf_count = 0; - file->private_data = gofh; - v4l2_fh_init(&gofh->fh, video_devdata(file)); - v4l2_fh_add(&gofh->fh); - return 0; -} - static int go7007_release(struct file *file) { - struct go7007_file *gofh = file->private_data; - struct go7007 *go = gofh->go; + struct go7007 *go = video_drvdata(file); - if (gofh->buf_count > 0) { + if (file->private_data == go->bufs_owner && go->buf_count > 0) { go7007_streamoff(go); go->in_use = 0; - kfree(gofh->bufs); - gofh->buf_count = 0; + kfree(go->bufs); + go->bufs = NULL; + go->buf_count = 0; + go->bufs_owner = NULL; } - v4l2_fh_del(&gofh->fh); - v4l2_fh_exit(&gofh->fh); - kfree(gofh); - file->private_data = NULL; - return 0; + return v4l2_fh_release(file); } static bool valid_pixelformat(u32 pixelformat) @@ -428,7 +406,7 @@ static int clip_to_modet_map(struct go7007 *go, int region, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); strlcpy(cap->driver, "go7007", sizeof(cap->driver)); strlcpy(cap->card, go->name, sizeof(cap->card)); @@ -480,7 +458,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt->fmt.pix.width = go->width; @@ -497,7 +475,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); return set_capture_size(go, fmt, 1); } @@ -505,7 +483,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); if (go->streaming) return -EBUSY; @@ -516,8 +494,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *req) { - struct go7007_file *gofh = priv; - struct go7007 *go = gofh->go; + struct go7007 *go = video_drvdata(file); int retval = -EBUSY; unsigned int count, i; @@ -528,20 +505,19 @@ static int vidioc_reqbufs(struct file *file, void *priv, req->memory != V4L2_MEMORY_MMAP) return -EINVAL; - mutex_lock(&gofh->lock); - for (i = 0; i < gofh->buf_count; ++i) - if (gofh->bufs[i].mapped > 0) + for (i = 0; i < go->buf_count; ++i) + if (go->bufs[i].mapped > 0) goto unlock_and_return; set_formatting(go); mutex_lock(&go->hw_lock); - if (go->in_use > 0 && gofh->buf_count == 0) { + if (go->in_use > 0 && go->buf_count == 0) { mutex_unlock(&go->hw_lock); goto unlock_and_return; } - if (gofh->buf_count > 0) - kfree(gofh->bufs); + if (go->buf_count > 0) + kfree(go->bufs); retval = -ENOMEM; count = req->count; @@ -551,29 +527,30 @@ static int vidioc_reqbufs(struct file *file, void *priv, if (count > 32) count = 32; - gofh->bufs = kcalloc(count, sizeof(struct go7007_buffer), + go->bufs = kcalloc(count, sizeof(struct go7007_buffer), GFP_KERNEL); - if (!gofh->bufs) { + if (!go->bufs) { mutex_unlock(&go->hw_lock); goto unlock_and_return; } for (i = 0; i < count; ++i) { - gofh->bufs[i].go = go; - gofh->bufs[i].index = i; - gofh->bufs[i].state = BUF_STATE_IDLE; - gofh->bufs[i].mapped = 0; + go->bufs[i].go = go; + go->bufs[i].index = i; + go->bufs[i].state = BUF_STATE_IDLE; + go->bufs[i].mapped = 0; } go->in_use = 1; + go->bufs_owner = file->private_data; } else { go->in_use = 0; + go->bufs_owner = NULL; } - gofh->buf_count = count; + go->buf_count = count; mutex_unlock(&go->hw_lock); - mutex_unlock(&gofh->lock); memset(req, 0, sizeof(*req)); @@ -584,14 +561,13 @@ static int vidioc_reqbufs(struct file *file, void *priv, return 0; unlock_and_return: - mutex_unlock(&gofh->lock); return retval; } static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct go7007_file *gofh = priv; + struct go7007 *go = video_drvdata(file); int retval = -EINVAL; unsigned int index; @@ -600,15 +576,14 @@ static int vidioc_querybuf(struct file *file, void *priv, index = buf->index; - mutex_lock(&gofh->lock); - if (index >= gofh->buf_count) + if (index >= go->buf_count) goto unlock_and_return; memset(buf, 0, sizeof(*buf)); buf->index = index; buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - switch (gofh->bufs[index].state) { + switch (go->bufs[index].state) { case BUF_STATE_QUEUED: buf->flags = V4L2_BUF_FLAG_QUEUED; break; @@ -619,24 +594,21 @@ static int vidioc_querybuf(struct file *file, void *priv, buf->flags = 0; } - if (gofh->bufs[index].mapped) + if (go->bufs[index].mapped) buf->flags |= V4L2_BUF_FLAG_MAPPED; buf->memory = V4L2_MEMORY_MMAP; buf->m.offset = index * GO7007_BUF_SIZE; buf->length = GO7007_BUF_SIZE; - mutex_unlock(&gofh->lock); return 0; unlock_and_return: - mutex_unlock(&gofh->lock); return retval; } static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct go7007_file *gofh = priv; - struct go7007 *go = gofh->go; + struct go7007 *go = video_drvdata(file); struct go7007_buffer *gobuf; unsigned long flags; int retval = -EINVAL; @@ -646,11 +618,10 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) buf->memory != V4L2_MEMORY_MMAP) return retval; - mutex_lock(&gofh->lock); - if (buf->index >= gofh->buf_count) + if (buf->index >= go->buf_count) goto unlock_and_return; - gobuf = &gofh->bufs[buf->index]; + gobuf = &go->bufs[buf->index]; if (!gobuf->mapped) goto unlock_and_return; @@ -687,20 +658,17 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) spin_lock_irqsave(&go->spinlock, flags); list_add_tail(&gobuf->stream, &go->stream); spin_unlock_irqrestore(&go->spinlock, flags); - mutex_unlock(&gofh->lock); return 0; unlock_and_return: - mutex_unlock(&gofh->lock); return retval; } static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct go7007_file *gofh = priv; - struct go7007 *go = gofh->go; + struct go7007 *go = video_drvdata(file); struct go7007_buffer *gobuf; int retval = -EINVAL; unsigned long flags; @@ -712,7 +680,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) if (buf->memory != V4L2_MEMORY_MMAP) return retval; - mutex_lock(&gofh->lock); if (list_empty(&go->stream)) goto unlock_and_return; gobuf = list_entry(go->stream.next, @@ -756,25 +723,21 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) buf->length = GO7007_BUF_SIZE; buf->reserved = gobuf->modet_active; - mutex_unlock(&gofh->lock); return 0; unlock_and_return: - mutex_unlock(&gofh->lock); return retval; } static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct go7007_file *gofh = priv; - struct go7007 *go = gofh->go; + struct go7007 *go = video_drvdata(file); int retval = 0; if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - mutex_lock(&gofh->lock); mutex_lock(&go->hw_lock); if (!go->streaming) { @@ -787,7 +750,6 @@ static int vidioc_streamon(struct file *file, void *priv, retval = 0; } mutex_unlock(&go->hw_lock); - mutex_unlock(&gofh->lock); call_all(&go->v4l2_dev, video, s_stream, 1); v4l2_ctrl_grab(go->mpeg_video_gop_size, true); v4l2_ctrl_grab(go->mpeg_video_gop_closure, true); @@ -800,14 +762,11 @@ static int vidioc_streamon(struct file *file, void *priv, static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { - struct go7007_file *gofh = priv; - struct go7007 *go = gofh->go; + struct go7007 *go = video_drvdata(file); if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - mutex_lock(&gofh->lock); go7007_streamoff(go); - mutex_unlock(&gofh->lock); call_all(&go->v4l2_dev, video, s_stream, 0); return 0; @@ -816,7 +775,7 @@ static int vidioc_streamoff(struct file *file, void *priv, static int vidioc_g_parm(struct file *filp, void *priv, struct v4l2_streamparm *parm) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(filp); struct v4l2_fract timeperframe = { .numerator = 1001 * go->fps_scale, .denominator = go->sensor_framerate, @@ -835,7 +794,7 @@ static int vidioc_g_parm(struct file *filp, void *priv, static int vidioc_s_parm(struct file *filp, void *priv, struct v4l2_streamparm *parm) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(filp); unsigned int n, d; if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -865,7 +824,7 @@ static int vidioc_s_parm(struct file *filp, void *priv, static int vidioc_enum_framesizes(struct file *filp, void *priv, struct v4l2_frmsizeenum *fsize) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(filp); int width, height; if (fsize->index > 2) @@ -884,7 +843,7 @@ static int vidioc_enum_framesizes(struct file *filp, void *priv, static int vidioc_enum_frameintervals(struct file *filp, void *priv, struct v4l2_frmivalenum *fival) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(filp); int width, height; int i; @@ -911,7 +870,7 @@ static int vidioc_enum_frameintervals(struct file *filp, void *priv, static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); *std = go->std; return 0; @@ -946,7 +905,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); return call_all(&go->v4l2_dev, video, querystd, std); } @@ -954,7 +913,7 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std) static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); if (inp->index >= go->board_info->num_inputs) return -EINVAL; @@ -985,7 +944,7 @@ static int vidioc_enum_input(struct file *file, void *priv, static int vidioc_g_input(struct file *file, void *priv, unsigned int *input) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); *input = go->input; @@ -1059,7 +1018,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int input) static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); if (t->index != 0) return -EINVAL; @@ -1071,7 +1030,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); if (t->index != 0) return -EINVAL; @@ -1082,7 +1041,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); if (f->tuner) return -EINVAL; @@ -1093,7 +1052,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); if (f->tuner) return -EINVAL; @@ -1103,7 +1062,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_log_status(struct file *file, void *priv) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); v4l2_ctrl_log_status(file, priv); return call_all(&go->v4l2_dev, core, log_status); @@ -1112,7 +1071,7 @@ static int vidioc_log_status(struct file *file, void *priv) static int vidioc_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cropcap) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1156,7 +1115,7 @@ static int vidioc_cropcap(struct file *file, void *priv, static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) { - struct go7007 *go = ((struct go7007_file *) priv)->go; + struct go7007 *go = video_drvdata(file); if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1280,52 +1239,44 @@ static struct vm_operations_struct go7007_vm_ops = { static int go7007_mmap(struct file *file, struct vm_area_struct *vma) { - struct go7007_file *gofh = file->private_data; + struct go7007 *go = video_drvdata(file); unsigned int index; - if (gofh->go->status != STATUS_ONLINE) + if (go->status != STATUS_ONLINE) return -EIO; if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; /* only support VM_SHARED mapping */ if (vma->vm_end - vma->vm_start != GO7007_BUF_SIZE) return -EINVAL; /* must map exactly one full buffer */ - mutex_lock(&gofh->lock); index = vma->vm_pgoff / GO7007_BUF_PAGES; - if (index >= gofh->buf_count) { - mutex_unlock(&gofh->lock); + if (index >= go->buf_count) return -EINVAL; /* trying to map beyond requested buffers */ - } - if (index * GO7007_BUF_PAGES != vma->vm_pgoff) { - mutex_unlock(&gofh->lock); + if (index * GO7007_BUF_PAGES != vma->vm_pgoff) return -EINVAL; /* offset is not aligned on buffer boundary */ - } - if (gofh->bufs[index].mapped > 0) { - mutex_unlock(&gofh->lock); + if (go->bufs[index].mapped > 0) return -EBUSY; - } - gofh->bufs[index].mapped = 1; - gofh->bufs[index].user_addr = vma->vm_start; + go->bufs[index].mapped = 1; + go->bufs[index].user_addr = vma->vm_start; vma->vm_ops = &go7007_vm_ops; vma->vm_flags |= VM_DONTEXPAND; vma->vm_flags &= ~VM_IO; - vma->vm_private_data = &gofh->bufs[index]; - mutex_unlock(&gofh->lock); + vma->vm_private_data = &go->bufs[index]; return 0; } static unsigned int go7007_poll(struct file *file, poll_table *wait) { unsigned long req_events = poll_requested_events(wait); - struct go7007_file *gofh = file->private_data; + struct go7007 *go = video_drvdata(file); struct go7007_buffer *gobuf; unsigned int res = v4l2_ctrl_poll(file, wait); if (!(req_events & (POLLIN | POLLRDNORM))) return res; - if (list_empty(&gofh->go->stream)) + if (list_empty(&go->stream)) return POLLERR; - gobuf = list_entry(gofh->go->stream.next, struct go7007_buffer, stream); - poll_wait(file, &gofh->go->frame_waitq, wait); + gobuf = list_entry(go->stream.next, struct go7007_buffer, stream); + poll_wait(file, &go->frame_waitq, wait); if (gobuf->state == BUF_STATE_DONE) return res | POLLIN | POLLRDNORM; return res; @@ -1338,7 +1289,7 @@ static void go7007_vfl_release(struct video_device *vfd) static struct v4l2_file_operations go7007_fops = { .owner = THIS_MODULE, - .open = go7007_open, + .open = v4l2_fh_open, .release = go7007_release, .ioctl = video_ioctl2, .read = go7007_read, -- cgit v0.10.2 From ffcc1c082fdd8e3013f25f670d1fe66f86e04138 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 06:52:27 -0300 Subject: [media] go7007: convert to core locking and vb2 Convert this driver to videobuf2 and core locking. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/Kconfig b/drivers/staging/media/go7007/Kconfig index da320319..46cb7bf 100644 --- a/drivers/staging/media/go7007/Kconfig +++ b/drivers/staging/media/go7007/Kconfig @@ -2,7 +2,7 @@ config VIDEO_GO7007 tristate "WIS GO7007 MPEG encoder support" depends on VIDEO_DEV && PCI && I2C depends on SND - select VIDEOBUF_DMA_SG + select VIDEOBUF2_VMALLOC depends on RC_CORE select VIDEO_TUNER select VIDEO_TVEEPROM diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index 732b452..075de4d 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -363,48 +363,54 @@ start_error: /* * Store a byte in the current video buffer, if there is one. */ -static inline void store_byte(struct go7007_buffer *gobuf, u8 byte) +static inline void store_byte(struct go7007_buffer *vb, u8 byte) { - if (gobuf != NULL && gobuf->bytesused < GO7007_BUF_SIZE) { - unsigned int pgidx = gobuf->offset >> PAGE_SHIFT; - unsigned int pgoff = gobuf->offset & ~PAGE_MASK; + if (vb && vb->vb.v4l2_planes[0].bytesused < GO7007_BUF_SIZE) { + u8 *ptr = vb2_plane_vaddr(&vb->vb, 0); - *((u8 *)page_address(gobuf->pages[pgidx]) + pgoff) = byte; - ++gobuf->offset; - ++gobuf->bytesused; + ptr[vb->vb.v4l2_planes[0].bytesused++] = byte; } } /* * Deliver the last video buffer and get a new one to start writing to. */ -static void frame_boundary(struct go7007 *go) +static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buffer *vb) { - struct go7007_buffer *gobuf; + struct go7007_buffer *vb_tmp = NULL; + u32 *bytesused = &vb->vb.v4l2_planes[0].bytesused; int i; - if (go->active_buf) { - if (go->active_buf->modet_active) { - if (go->active_buf->bytesused + 216 < GO7007_BUF_SIZE) { + if (vb) { + if (vb->modet_active) { + if (*bytesused + 216 < GO7007_BUF_SIZE) { for (i = 0; i < 216; ++i) - store_byte(go->active_buf, - go->active_map[i]); - go->active_buf->bytesused -= 216; + store_byte(vb, go->active_map[i]); + *bytesused -= 216; } else - go->active_buf->modet_active = 0; + vb->modet_active = 0; } - go->active_buf->state = BUF_STATE_DONE; - wake_up_interruptible(&go->frame_waitq); - go->active_buf = NULL; + vb->vb.v4l2_buf.sequence = go->next_seq++; + v4l2_get_timestamp(&vb->vb.v4l2_buf.timestamp); + vb_tmp = vb; + spin_lock(&go->spinlock); + list_del(&vb->list); + if (list_empty(&go->vidq_active)) + vb = NULL; + else + vb = list_first_entry(&go->vidq_active, struct go7007_buffer, list); + go->active_buf = vb; + spin_unlock(&go->spinlock); + vb2_buffer_done(&vb_tmp->vb, VB2_BUF_STATE_DONE); + return vb; } - list_for_each_entry(gobuf, &go->stream, stream) - if (gobuf->state == BUF_STATE_QUEUED) { - gobuf->seq = go->next_seq; - do_gettimeofday(&gobuf->timestamp); - go->active_buf = gobuf; - break; - } - ++go->next_seq; + spin_lock(&go->spinlock); + if (!list_empty(&go->vidq_active)) + vb = go->active_buf = + list_first_entry(&go->vidq_active, struct go7007_buffer, list); + spin_unlock(&go->spinlock); + go->next_seq++; + return vb; } static void write_bitmap_word(struct go7007 *go) @@ -428,10 +434,9 @@ static void write_bitmap_word(struct go7007 *go) */ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) { + struct go7007_buffer *vb = go->active_buf; int i, seq_start_code = -1, frame_start_code = -1; - spin_lock(&go->spinlock); - switch (go->format) { case V4L2_PIX_FMT_MPEG4: seq_start_code = 0xB0; @@ -445,13 +450,12 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) } for (i = 0; i < length; ++i) { - if (go->active_buf != NULL && - go->active_buf->bytesused >= GO7007_BUF_SIZE - 3) { + if (vb && vb->vb.v4l2_planes[0].bytesused >= GO7007_BUF_SIZE - 3) { v4l2_info(&go->v4l2_dev, "dropping oversized frame\n"); - go->active_buf->offset -= go->active_buf->bytesused; - go->active_buf->bytesused = 0; - go->active_buf->modet_active = 0; - go->active_buf = NULL; + vb->vb.v4l2_planes[0].bytesused = 0; + vb->frame_offset = 0; + vb->modet_active = 0; + vb = go->active_buf = NULL; } switch (go->state) { @@ -464,7 +468,7 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) go->state = STATE_FF; break; default: - store_byte(go->active_buf, buf[i]); + store_byte(vb, buf[i]); break; } break; @@ -474,12 +478,12 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) go->state = STATE_00_00; break; case 0xFF: - store_byte(go->active_buf, 0x00); + store_byte(vb, 0x00); go->state = STATE_FF; break; default: - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, buf[i]); + store_byte(vb, 0x00); + store_byte(vb, buf[i]); go->state = STATE_DATA; break; } @@ -487,21 +491,21 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) case STATE_00_00: switch (buf[i]) { case 0x00: - store_byte(go->active_buf, 0x00); + store_byte(vb, 0x00); /* go->state remains STATE_00_00 */ break; case 0x01: go->state = STATE_00_00_01; break; case 0xFF: - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x00); + store_byte(vb, 0x00); + store_byte(vb, 0x00); go->state = STATE_FF; break; default: - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, buf[i]); + store_byte(vb, 0x00); + store_byte(vb, 0x00); + store_byte(vb, buf[i]); go->state = STATE_DATA; break; } @@ -509,10 +513,10 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) case STATE_00_00_01: if (buf[i] == 0xF8 && go->modet_enable == 0) { /* MODET start code, but MODET not enabled */ - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x01); - store_byte(go->active_buf, 0xF8); + store_byte(vb, 0x00); + store_byte(vb, 0x00); + store_byte(vb, 0x01); + store_byte(vb, 0xF8); go->state = STATE_DATA; break; } @@ -521,19 +525,14 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) if ((go->format == V4L2_PIX_FMT_MPEG1 || go->format == V4L2_PIX_FMT_MPEG2 || go->format == V4L2_PIX_FMT_MPEG4) && - (buf[i] == seq_start_code || - buf[i] == 0xB8 || /* GOP code */ - buf[i] == frame_start_code)) { - if (go->active_buf == NULL || go->seen_frame) - frame_boundary(go); - if (buf[i] == frame_start_code) { - if (go->active_buf != NULL) - go->active_buf->frame_offset = - go->active_buf->offset; - go->seen_frame = 1; - } else { - go->seen_frame = 0; - } + (buf[i] == seq_start_code || + buf[i] == 0xB8 || /* GOP code */ + buf[i] == frame_start_code)) { + if (vb == NULL || go->seen_frame) + vb = frame_boundary(go, vb); + go->seen_frame = buf[i] == frame_start_code; + if (vb && go->seen_frame) + vb->frame_offset = vb->vb.v4l2_planes[0].bytesused; } /* Handle any special chunk types, or just write the * start code to the (potentially new) buffer */ @@ -552,16 +551,16 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) go->state = STATE_MODET_MAP; break; case 0xFF: /* Potential JPEG start code */ - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x01); + store_byte(vb, 0x00); + store_byte(vb, 0x00); + store_byte(vb, 0x01); go->state = STATE_FF; break; default: - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x00); - store_byte(go->active_buf, 0x01); - store_byte(go->active_buf, buf[i]); + store_byte(vb, 0x00); + store_byte(vb, 0x00); + store_byte(vb, 0x01); + store_byte(vb, buf[i]); go->state = STATE_DATA; break; } @@ -569,20 +568,20 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) case STATE_FF: switch (buf[i]) { case 0x00: - store_byte(go->active_buf, 0xFF); + store_byte(vb, 0xFF); go->state = STATE_00; break; case 0xFF: - store_byte(go->active_buf, 0xFF); + store_byte(vb, 0xFF); /* go->state remains STATE_FF */ break; case 0xD8: if (go->format == V4L2_PIX_FMT_MJPEG) - frame_boundary(go); + vb = frame_boundary(go, vb); /* fall through */ default: - store_byte(go->active_buf, 0xFF); - store_byte(go->active_buf, buf[i]); + store_byte(vb, 0xFF); + store_byte(vb, buf[i]); go->state = STATE_DATA; break; } @@ -605,8 +604,8 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) write_bitmap_word(go); } else go->modet_word = buf[i] << 8; - } else if (go->parse_length == 207 && go->active_buf) { - go->active_buf->modet_active = buf[i]; + } else if (go->parse_length == 207 && vb) { + vb->modet_active = buf[i]; } if (++go->parse_length == 208) go->state = STATE_DATA; @@ -617,8 +616,6 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) break; } } - - spin_unlock(&go->spinlock); } EXPORT_SYMBOL(go7007_parse_video_stream); @@ -648,14 +645,12 @@ struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev) go->i2c_adapter_online = 0; go->interrupt_available = 0; init_waitqueue_head(&go->interrupt_waitq); - go->in_use = 0; go->input = 0; go7007_update_board(go); go->encoder_h_halve = 0; go->encoder_v_halve = 0; go->encoder_subsample = 0; go->format = V4L2_PIX_FMT_MJPEG; - go->streaming = 0; go->bitrate = 1500000; go->fps_scale = 1; go->pali = 0; @@ -674,7 +669,6 @@ struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev) go->modet_map[i] = 0; go->audio_deliver = NULL; go->audio_enabled = 0; - INIT_LIST_HEAD(&go->stream); return go; } diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index 2c0afb1..30148eb 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -24,6 +24,7 @@ #include #include #include +#include struct go7007; @@ -125,20 +126,10 @@ struct go7007_hpi_ops { #define GO7007_BUF_SIZE (GO7007_BUF_PAGES << PAGE_SHIFT) struct go7007_buffer { - struct go7007 *go; /* Reverse reference for VMA ops */ - int index; /* Reverse reference for DQBUF */ - enum { BUF_STATE_IDLE, BUF_STATE_QUEUED, BUF_STATE_DONE } state; - u32 seq; - struct timeval timestamp; - struct list_head stream; - struct page *pages[GO7007_BUF_PAGES + 1]; /* extra for straddling */ - unsigned long user_addr; - unsigned int page_count; - unsigned int offset; - unsigned int bytesused; + struct vb2_buffer vb; + struct list_head list; unsigned int frame_offset; u32 modet_active; - int mapped; }; #define GO7007_RATIO_1_1 0 @@ -178,8 +169,7 @@ struct go7007 { enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status; spinlock_t spinlock; struct mutex hw_lock; - int streaming; - int in_use; + struct mutex serialize_lock; int audio_enabled; struct v4l2_subdev *sd_video; struct v4l2_subdev *sd_audio; @@ -226,17 +216,16 @@ struct go7007 { unsigned char active_map[216]; /* Video streaming */ - struct go7007_buffer *active_buf; + struct mutex queue_lock; + struct vb2_queue vidq; enum go7007_parser_state state; int parse_length; u16 modet_word; int seen_frame; u32 next_seq; - struct list_head stream; + struct list_head vidq_active; wait_queue_head_t frame_waitq; - int buf_count; - struct go7007_buffer *bufs; - struct v4l2_fh *bufs_owner; + struct go7007_buffer *active_buf; /* Audio streaming */ void (*audio_deliver)(struct go7007 *go, u8 *buf, int length); diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 5c7a19e6..c95538c 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -780,7 +780,7 @@ static void go7007_usb_read_video_pipe_complete(struct urb *urb) struct go7007 *go = (struct go7007 *)urb->context; int r, status = urb->status; - if (!go->streaming) { + if (!vb2_is_streaming(&go->vidq)) { wake_up_interruptible(&go->frame_waitq); return; } @@ -804,7 +804,7 @@ static void go7007_usb_read_audio_pipe_complete(struct urb *urb) struct go7007 *go = (struct go7007 *)urb->context; int r, status = urb->status; - if (!go->streaming) + if (!vb2_is_streaming(&go->vidq)) return; if (status) { printk(KERN_ERR "go7007-usb: error in audio pipe: %d\n", @@ -1316,12 +1316,17 @@ static void go7007_usb_disconnect(struct usb_interface *intf) { struct go7007 *go = to_go7007(usb_get_intfdata(intf)); + mutex_lock(&go->queue_lock); + mutex_lock(&go->serialize_lock); + if (go->audio_enabled) go7007_snd_remove(go); go->status = STATUS_SHUTDOWN; v4l2_device_disconnect(&go->v4l2_dev); video_unregister_device(go->video_dev); + mutex_unlock(&go->serialize_lock); + mutex_unlock(&go->queue_lock); v4l2_device_put(&go->v4l2_dev); } diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index b107020..d210d33 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "go7007.h" @@ -43,66 +44,6 @@ #define call_all(dev, o, f, args...) \ v4l2_device_call_until_err(dev, 0, o, f, ##args) -static void deactivate_buffer(struct go7007_buffer *gobuf) -{ - int i; - - if (gobuf->state != BUF_STATE_IDLE) { - list_del(&gobuf->stream); - gobuf->state = BUF_STATE_IDLE; - } - if (gobuf->page_count > 0) { - for (i = 0; i < gobuf->page_count; ++i) - page_cache_release(gobuf->pages[i]); - gobuf->page_count = 0; - } -} - -static void abort_queued(struct go7007 *go) -{ - struct go7007_buffer *gobuf, *next; - - list_for_each_entry_safe(gobuf, next, &go->stream, stream) { - deactivate_buffer(gobuf); - } -} - -static int go7007_streamoff(struct go7007 *go) -{ - unsigned long flags; - - mutex_lock(&go->hw_lock); - if (go->streaming) { - go->streaming = 0; - go7007_stream_stop(go); - spin_lock_irqsave(&go->spinlock, flags); - abort_queued(go); - spin_unlock_irqrestore(&go->spinlock, flags); - go7007_reset_encoder(go); - } - mutex_unlock(&go->hw_lock); - v4l2_ctrl_grab(go->mpeg_video_gop_size, false); - v4l2_ctrl_grab(go->mpeg_video_gop_closure, false); - v4l2_ctrl_grab(go->mpeg_video_bitrate, false); - v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, false); - return 0; -} - -static int go7007_release(struct file *file) -{ - struct go7007 *go = video_drvdata(file); - - if (file->private_data == go->bufs_owner && go->buf_count > 0) { - go7007_streamoff(go); - go->in_use = 0; - kfree(go->bufs); - go->bufs = NULL; - go->buf_count = 0; - go->bufs_owner = NULL; - } - return v4l2_fh_release(file); -} - static bool valid_pixelformat(u32 pixelformat) { switch (pixelformat) { @@ -116,15 +57,15 @@ static bool valid_pixelformat(u32 pixelformat) } } -static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format) +static u32 get_frame_type_flag(struct go7007_buffer *vb, int format) { - u8 *f = page_address(gobuf->pages[0]); + u8 *ptr = vb2_plane_vaddr(&vb->vb, 0); switch (format) { case V4L2_PIX_FMT_MJPEG: return V4L2_BUF_FLAG_KEYFRAME; case V4L2_PIX_FMT_MPEG4: - switch ((f[gobuf->frame_offset + 4] >> 6) & 0x3) { + switch ((ptr[vb->frame_offset + 4] >> 6) & 0x3) { case 0: return V4L2_BUF_FLAG_KEYFRAME; case 1: @@ -136,7 +77,7 @@ static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format) } case V4L2_PIX_FMT_MPEG1: case V4L2_PIX_FMT_MPEG2: - switch ((f[gobuf->frame_offset + 5] >> 3) & 0x7) { + switch ((ptr[vb->frame_offset + 5] >> 3) & 0x7) { case 1: return V4L2_BUF_FLAG_KEYFRAME; case 2: @@ -412,7 +353,8 @@ static int vidioc_querycap(struct file *file, void *priv, strlcpy(cap->card, go->name, sizeof(cap->card)); strlcpy(cap->bus_info, go->bus_info, sizeof(cap->bus_info)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; if (go->board_info->num_aud_inputs) cap->device_caps |= V4L2_CAP_AUDIO; @@ -485,293 +427,125 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, { struct go7007 *go = video_drvdata(file); - if (go->streaming) + if (vb2_is_busy(&go->vidq)) return -EBUSY; return set_capture_size(go, fmt, 0); } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req) +static int go7007_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct go7007 *go = video_drvdata(file); - int retval = -EBUSY; - unsigned int count, i; - - if (go->streaming) - return retval; - - if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - req->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - for (i = 0; i < go->buf_count; ++i) - if (go->bufs[i].mapped > 0) - goto unlock_and_return; - - set_formatting(go); - mutex_lock(&go->hw_lock); - if (go->in_use > 0 && go->buf_count == 0) { - mutex_unlock(&go->hw_lock); - goto unlock_and_return; - } + sizes[0] = GO7007_BUF_SIZE; + *num_planes = 1; - if (go->buf_count > 0) - kfree(go->bufs); - - retval = -ENOMEM; - count = req->count; - if (count > 0) { - if (count < 2) - count = 2; - if (count > 32) - count = 32; - - go->bufs = kcalloc(count, sizeof(struct go7007_buffer), - GFP_KERNEL); - - if (!go->bufs) { - mutex_unlock(&go->hw_lock); - goto unlock_and_return; - } - - for (i = 0; i < count; ++i) { - go->bufs[i].go = go; - go->bufs[i].index = i; - go->bufs[i].state = BUF_STATE_IDLE; - go->bufs[i].mapped = 0; - } - - go->in_use = 1; - go->bufs_owner = file->private_data; - } else { - go->in_use = 0; - go->bufs_owner = NULL; - } - - go->buf_count = count; - mutex_unlock(&go->hw_lock); - - memset(req, 0, sizeof(*req)); - - req->count = count; - req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - req->memory = V4L2_MEMORY_MMAP; + if (*num_buffers < 2) + *num_buffers = 2; return 0; - -unlock_and_return: - return retval; } -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) +static void go7007_buf_queue(struct vb2_buffer *vb) { - struct go7007 *go = video_drvdata(file); - int retval = -EINVAL; - unsigned int index; - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return retval; - - index = buf->index; - - if (index >= go->buf_count) - goto unlock_and_return; - - memset(buf, 0, sizeof(*buf)); - buf->index = index; - buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - switch (go->bufs[index].state) { - case BUF_STATE_QUEUED: - buf->flags = V4L2_BUF_FLAG_QUEUED; - break; - case BUF_STATE_DONE: - buf->flags = V4L2_BUF_FLAG_DONE; - break; - default: - buf->flags = 0; - } - - if (go->bufs[index].mapped) - buf->flags |= V4L2_BUF_FLAG_MAPPED; - buf->memory = V4L2_MEMORY_MMAP; - buf->m.offset = index * GO7007_BUF_SIZE; - buf->length = GO7007_BUF_SIZE; - - return 0; - -unlock_and_return: - return retval; -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct go7007 *go = video_drvdata(file); - struct go7007_buffer *gobuf; + struct vb2_queue *vq = vb->vb2_queue; + struct go7007 *go = vb2_get_drv_priv(vq); + struct go7007_buffer *go7007_vb = + container_of(vb, struct go7007_buffer, vb); unsigned long flags; - int retval = -EINVAL; - int ret; - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - buf->memory != V4L2_MEMORY_MMAP) - return retval; - - if (buf->index >= go->buf_count) - goto unlock_and_return; - gobuf = &go->bufs[buf->index]; - if (!gobuf->mapped) - goto unlock_and_return; - - retval = -EBUSY; - if (gobuf->state != BUF_STATE_IDLE) - goto unlock_and_return; - - /* offset will be 0 until we really support USERPTR streaming */ - gobuf->offset = gobuf->user_addr & ~PAGE_MASK; - gobuf->bytesused = 0; - gobuf->frame_offset = 0; - gobuf->modet_active = 0; - if (gobuf->offset > 0) - gobuf->page_count = GO7007_BUF_PAGES + 1; - else - gobuf->page_count = GO7007_BUF_PAGES; - - retval = -ENOMEM; - down_read(¤t->mm->mmap_sem); - ret = get_user_pages(current, current->mm, - gobuf->user_addr & PAGE_MASK, gobuf->page_count, - 1, 1, gobuf->pages, NULL); - up_read(¤t->mm->mmap_sem); - - if (ret != gobuf->page_count) { - int i; - for (i = 0; i < ret; ++i) - page_cache_release(gobuf->pages[i]); - gobuf->page_count = 0; - goto unlock_and_return; - } - - gobuf->state = BUF_STATE_QUEUED; spin_lock_irqsave(&go->spinlock, flags); - list_add_tail(&gobuf->stream, &go->stream); + list_add_tail(&go7007_vb->list, &go->vidq_active); spin_unlock_irqrestore(&go->spinlock, flags); +} - return 0; +static int go7007_buf_prepare(struct vb2_buffer *vb) +{ + struct go7007_buffer *go7007_vb = + container_of(vb, struct go7007_buffer, vb); -unlock_and_return: - return retval; + go7007_vb->modet_active = 0; + go7007_vb->frame_offset = 0; + vb->v4l2_planes[0].bytesused = 0; + return 0; } - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +static int go7007_buf_finish(struct vb2_buffer *vb) { - struct go7007 *go = video_drvdata(file); - struct go7007_buffer *gobuf; - int retval = -EINVAL; - unsigned long flags; - u32 frame_type_flag; - DEFINE_WAIT(wait); - - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return retval; - if (buf->memory != V4L2_MEMORY_MMAP) - return retval; - - if (list_empty(&go->stream)) - goto unlock_and_return; - gobuf = list_entry(go->stream.next, - struct go7007_buffer, stream); - - retval = -EAGAIN; - if (gobuf->state != BUF_STATE_DONE && - !(file->f_flags & O_NONBLOCK)) { - for (;;) { - prepare_to_wait(&go->frame_waitq, &wait, - TASK_INTERRUPTIBLE); - if (gobuf->state == BUF_STATE_DONE) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - schedule(); - } - finish_wait(&go->frame_waitq, &wait); - } - if (gobuf->state != BUF_STATE_DONE) - goto unlock_and_return; - - spin_lock_irqsave(&go->spinlock, flags); - deactivate_buffer(gobuf); - spin_unlock_irqrestore(&go->spinlock, flags); - frame_type_flag = get_frame_type_flag(gobuf, go->format); - gobuf->state = BUF_STATE_IDLE; - - memset(buf, 0, sizeof(*buf)); - buf->index = gobuf->index; - buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf->bytesused = gobuf->bytesused; - buf->flags = V4L2_BUF_FLAG_MAPPED | frame_type_flag; + struct vb2_queue *vq = vb->vb2_queue; + struct go7007 *go = vb2_get_drv_priv(vq); + struct go7007_buffer *go7007_vb = + container_of(vb, struct go7007_buffer, vb); + u32 frame_type_flag = get_frame_type_flag(go7007_vb, go->format); + struct v4l2_buffer *buf = &vb->v4l2_buf; + + buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_BFRAME | + V4L2_BUF_FLAG_PFRAME); + buf->flags |= frame_type_flag; buf->field = V4L2_FIELD_NONE; - buf->timestamp = gobuf->timestamp; - buf->sequence = gobuf->seq; - buf->memory = V4L2_MEMORY_MMAP; - buf->m.offset = gobuf->index * GO7007_BUF_SIZE; - buf->length = GO7007_BUF_SIZE; - buf->reserved = gobuf->modet_active; - return 0; - -unlock_and_return: - return retval; } -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) +static int go7007_start_streaming(struct vb2_queue *q, unsigned int count) { - struct go7007 *go = video_drvdata(file); - int retval = 0; - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; + struct go7007 *go = vb2_get_drv_priv(q); + int ret; + set_formatting(go); mutex_lock(&go->hw_lock); - - if (!go->streaming) { - go->streaming = 1; - go->next_seq = 0; - go->active_buf = NULL; - if (go7007_start_encoder(go) < 0) - retval = -EIO; - else - retval = 0; - } + go->next_seq = 0; + go->active_buf = NULL; + q->streaming = 1; + if (go7007_start_encoder(go) < 0) + ret = -EIO; + else + ret = 0; mutex_unlock(&go->hw_lock); + if (ret) { + q->streaming = 0; + return ret; + } call_all(&go->v4l2_dev, video, s_stream, 1); v4l2_ctrl_grab(go->mpeg_video_gop_size, true); v4l2_ctrl_grab(go->mpeg_video_gop_closure, true); v4l2_ctrl_grab(go->mpeg_video_bitrate, true); v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, true); - - return retval; + return ret; } -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) +static int go7007_stop_streaming(struct vb2_queue *q) { - struct go7007 *go = video_drvdata(file); + struct go7007 *go = vb2_get_drv_priv(q); + unsigned long flags; - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - go7007_streamoff(go); + q->streaming = 0; + go7007_stream_stop(go); + mutex_lock(&go->hw_lock); + go7007_reset_encoder(go); + mutex_unlock(&go->hw_lock); call_all(&go->v4l2_dev, video, s_stream, 0); + spin_lock_irqsave(&go->spinlock, flags); + INIT_LIST_HEAD(&go->vidq_active); + spin_unlock_irqrestore(&go->spinlock, flags); + v4l2_ctrl_grab(go->mpeg_video_gop_size, false); + v4l2_ctrl_grab(go->mpeg_video_gop_closure, false); + v4l2_ctrl_grab(go->mpeg_video_bitrate, false); + v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, false); return 0; } +static struct vb2_ops go7007_video_qops = { + .queue_setup = go7007_queue_setup, + .buf_queue = go7007_buf_queue, + .buf_prepare = go7007_buf_prepare, + .buf_finish = go7007_buf_finish, + .start_streaming = go7007_start_streaming, + .stop_streaming = go7007_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + static int vidioc_g_parm(struct file *filp, void *priv, struct v4l2_streamparm *parm) { @@ -895,7 +669,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) { struct go7007 *go = video_drvdata(file); - if (go->streaming) + if (vb2_is_busy(&go->vidq)) return -EBUSY; go->std = std; @@ -1006,7 +780,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int input) if (input >= go->board_info->num_inputs) return -EINVAL; - if (go->streaming) + if (vb2_is_busy(&go->vidq)) return -EBUSY; go->input = input; @@ -1193,95 +967,6 @@ static int vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop * } #endif -static ssize_t go7007_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -static void go7007_vm_open(struct vm_area_struct *vma) -{ - struct go7007_buffer *gobuf = vma->vm_private_data; - - ++gobuf->mapped; -} - -static void go7007_vm_close(struct vm_area_struct *vma) -{ - struct go7007_buffer *gobuf = vma->vm_private_data; - unsigned long flags; - - if (--gobuf->mapped == 0) { - spin_lock_irqsave(&gobuf->go->spinlock, flags); - deactivate_buffer(gobuf); - spin_unlock_irqrestore(&gobuf->go->spinlock, flags); - } -} - -/* Copied from videobuf-dma-sg.c */ -static int go7007_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct page *page; - - page = alloc_page(GFP_USER | __GFP_DMA32); - if (!page) - return VM_FAULT_OOM; - clear_user_highpage(page, (unsigned long)vmf->virtual_address); - vmf->page = page; - return 0; -} - -static struct vm_operations_struct go7007_vm_ops = { - .open = go7007_vm_open, - .close = go7007_vm_close, - .fault = go7007_vm_fault, -}; - -static int go7007_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct go7007 *go = video_drvdata(file); - unsigned int index; - - if (go->status != STATUS_ONLINE) - return -EIO; - if (!(vma->vm_flags & VM_SHARED)) - return -EINVAL; /* only support VM_SHARED mapping */ - if (vma->vm_end - vma->vm_start != GO7007_BUF_SIZE) - return -EINVAL; /* must map exactly one full buffer */ - index = vma->vm_pgoff / GO7007_BUF_PAGES; - if (index >= go->buf_count) - return -EINVAL; /* trying to map beyond requested buffers */ - if (index * GO7007_BUF_PAGES != vma->vm_pgoff) - return -EINVAL; /* offset is not aligned on buffer boundary */ - if (go->bufs[index].mapped > 0) - return -EBUSY; - go->bufs[index].mapped = 1; - go->bufs[index].user_addr = vma->vm_start; - vma->vm_ops = &go7007_vm_ops; - vma->vm_flags |= VM_DONTEXPAND; - vma->vm_flags &= ~VM_IO; - vma->vm_private_data = &go->bufs[index]; - return 0; -} - -static unsigned int go7007_poll(struct file *file, poll_table *wait) -{ - unsigned long req_events = poll_requested_events(wait); - struct go7007 *go = video_drvdata(file); - struct go7007_buffer *gobuf; - unsigned int res = v4l2_ctrl_poll(file, wait); - - if (!(req_events & (POLLIN | POLLRDNORM))) - return res; - if (list_empty(&go->stream)) - return POLLERR; - gobuf = list_entry(go->stream.next, struct go7007_buffer, stream); - poll_wait(file, &go->frame_waitq, wait); - if (gobuf->state == BUF_STATE_DONE) - return res | POLLIN | POLLRDNORM; - return res; -} - static void go7007_vfl_release(struct video_device *vfd) { video_device_release(vfd); @@ -1290,11 +975,11 @@ static void go7007_vfl_release(struct video_device *vfd) static struct v4l2_file_operations go7007_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, - .release = go7007_release, - .ioctl = video_ioctl2, - .read = go7007_read, - .mmap = go7007_mmap, - .poll = go7007_poll, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, }; static const struct v4l2_ioctl_ops video_ioctl_ops = { @@ -1303,10 +988,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .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_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, .vidioc_g_std = vidioc_g_std, .vidioc_s_std = vidioc_s_std, .vidioc_querystd = vidioc_querystd, @@ -1316,8 +1001,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_enumaudio = vidioc_enumaudio, .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, @@ -1379,10 +1064,27 @@ int go7007_v4l2_init(struct go7007 *go) { int rv; + mutex_init(&go->serialize_lock); + mutex_init(&go->queue_lock); + + INIT_LIST_HEAD(&go->vidq_active); + go->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + go->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; + go->vidq.ops = &go7007_video_qops; + go->vidq.mem_ops = &vb2_vmalloc_memops; + go->vidq.drv_priv = go; + go->vidq.buf_struct_size = sizeof(struct go7007_buffer); + go->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + go->vidq.lock = &go->queue_lock; + rv = vb2_queue_init(&go->vidq); + if (rv) + return rv; go->video_dev = video_device_alloc(); if (go->video_dev == NULL) return -ENOMEM; *go->video_dev = go7007_template; + go->video_dev->lock = &go->serialize_lock; + go->video_dev->queue = &go->vidq; set_bit(V4L2_FL_USE_FH_PRIO, &go->video_dev->flags); video_set_drvdata(go->video_dev, go); go->video_dev->v4l2_dev = &go->v4l2_dev; @@ -1436,16 +1138,5 @@ int go7007_v4l2_init(struct go7007 *go) void go7007_v4l2_remove(struct go7007 *go) { - unsigned long flags; - - mutex_lock(&go->hw_lock); - if (go->streaming) { - go->streaming = 0; - go7007_stream_stop(go); - spin_lock_irqsave(&go->spinlock, flags); - abort_queued(go); - spin_unlock_irqrestore(&go->spinlock, flags); - } - mutex_unlock(&go->hw_lock); v4l2_ctrl_handler_free(&go->hdl); } diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c index 4c73945..fa9de3c 100644 --- a/drivers/staging/media/go7007/saa7134-go7007.c +++ b/drivers/staging/media/go7007/saa7134-go7007.c @@ -236,7 +236,7 @@ static void saa7134_go7007_irq_ts_done(struct saa7134_dev *dev, struct go7007 *go = video_get_drvdata(dev->empress_dev); struct saa7134_go7007 *saa = go->hpi_context; - if (!go->streaming) + if (!vb2_is_streaming(&go->vidq)) return; if (0 != (status & 0x000f0000)) printk(KERN_DEBUG "saa7134-go7007: irq: lost %ld\n", -- cgit v0.10.2 From 6bb0e65d6761b115e4169a5499fccc76ea90dd99 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 06:34:22 -0300 Subject: [media] go7007: embed struct video_device Do not allocate it, but just embed in the go7007 struct. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index 075de4d..0fd3f10 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -639,7 +639,6 @@ struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev) mutex_init(&go->hw_lock); init_waitqueue_head(&go->frame_waitq); spin_lock_init(&go->spinlock); - go->video_dev = NULL; go->status = STATUS_INIT; memset(&go->i2c_adapter, 0, sizeof(go->i2c_adapter)); go->i2c_adapter_online = 0; diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index 30148eb..0914fa3 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -156,7 +156,7 @@ struct go7007 { int tuner_type; int channel_number; /* for multi-channel boards like Adlink PCI-MPG24 */ char name[64]; - struct video_device *video_dev; + struct video_device vdev; void *boot_fw; unsigned boot_fw_len; struct v4l2_device v4l2_dev; diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index c95538c..2a1cda2 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -1324,7 +1324,7 @@ static void go7007_usb_disconnect(struct usb_interface *intf) go->status = STATUS_SHUTDOWN; v4l2_device_disconnect(&go->v4l2_dev); - video_unregister_device(go->video_dev); + video_unregister_device(&go->vdev); mutex_unlock(&go->serialize_lock); mutex_unlock(&go->queue_lock); diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index d210d33..3beb7c4 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -967,11 +967,6 @@ static int vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop * } #endif -static void go7007_vfl_release(struct video_device *vfd) -{ - video_device_release(vfd); -} - static struct v4l2_file_operations go7007_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, @@ -1022,7 +1017,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { static struct video_device go7007_template = { .name = "go7007", .fops = &go7007_fops, - .release = go7007_vfl_release, + .release = video_device_release_empty, .ioctl_ops = &video_ioctl_ops, .tvnorms = V4L2_STD_ALL, }; @@ -1062,6 +1057,7 @@ int go7007_v4l2_ctrl_init(struct go7007 *go) int go7007_v4l2_init(struct go7007 *go) { + struct video_device *vdev = &go->vdev; int rv; mutex_init(&go->serialize_lock); @@ -1079,22 +1075,19 @@ int go7007_v4l2_init(struct go7007 *go) rv = vb2_queue_init(&go->vidq); if (rv) return rv; - go->video_dev = video_device_alloc(); - if (go->video_dev == NULL) - return -ENOMEM; - *go->video_dev = go7007_template; - go->video_dev->lock = &go->serialize_lock; - go->video_dev->queue = &go->vidq; - set_bit(V4L2_FL_USE_FH_PRIO, &go->video_dev->flags); - video_set_drvdata(go->video_dev, go); - go->video_dev->v4l2_dev = &go->v4l2_dev; + *vdev = go7007_template; + vdev->lock = &go->serialize_lock; + vdev->queue = &go->vidq; + set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags); + video_set_drvdata(vdev, go); + vdev->v4l2_dev = &go->v4l2_dev; if (!v4l2_device_has_op(&go->v4l2_dev, video, querystd)) - v4l2_disable_ioctl(go->video_dev, VIDIOC_QUERYSTD); + v4l2_disable_ioctl(vdev, VIDIOC_QUERYSTD); if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) { - v4l2_disable_ioctl(go->video_dev, VIDIOC_S_FREQUENCY); - v4l2_disable_ioctl(go->video_dev, VIDIOC_G_FREQUENCY); - v4l2_disable_ioctl(go->video_dev, VIDIOC_S_TUNER); - v4l2_disable_ioctl(go->video_dev, VIDIOC_G_TUNER); + v4l2_disable_ioctl(vdev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(vdev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(vdev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(vdev, VIDIOC_G_TUNER); } else { struct v4l2_frequency f = { .type = V4L2_TUNER_ANALOG_TV, @@ -1104,16 +1097,16 @@ int go7007_v4l2_init(struct go7007 *go) call_all(&go->v4l2_dev, tuner, s_frequency, &f); } if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV)) { - v4l2_disable_ioctl(go->video_dev, VIDIOC_G_STD); - v4l2_disable_ioctl(go->video_dev, VIDIOC_S_STD); - go->video_dev->tvnorms = 0; + v4l2_disable_ioctl(vdev, VIDIOC_G_STD); + v4l2_disable_ioctl(vdev, VIDIOC_S_STD); + vdev->tvnorms = 0; } if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) - v4l2_disable_ioctl(go->video_dev, VIDIOC_ENUM_FRAMESIZES); + v4l2_disable_ioctl(vdev, VIDIOC_ENUM_FRAMESIZES); if (go->board_info->num_aud_inputs == 0) { - v4l2_disable_ioctl(go->video_dev, VIDIOC_G_AUDIO); - v4l2_disable_ioctl(go->video_dev, VIDIOC_S_AUDIO); - v4l2_disable_ioctl(go->video_dev, VIDIOC_ENUMAUDIO); + v4l2_disable_ioctl(vdev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(vdev, VIDIOC_S_AUDIO); + v4l2_disable_ioctl(vdev, VIDIOC_ENUMAUDIO); } /* Setup correct crystal frequency on this board */ if (go->board_info->sensor_flags & GO7007_SENSOR_SAA7115) @@ -1124,14 +1117,11 @@ int go7007_v4l2_init(struct go7007 *go) go7007_s_input(go); if (go->board_info->sensor_flags & GO7007_SENSOR_TV) go7007_s_std(go); - rv = video_register_device(go->video_dev, VFL_TYPE_GRABBER, -1); - if (rv < 0) { - video_device_release(go->video_dev); - go->video_dev = NULL; + rv = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (rv < 0) return rv; - } dev_info(go->dev, "registered device %s [v4l2]\n", - video_device_node_name(go->video_dev)); + video_device_node_name(vdev)); return 0; } diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c index fa9de3c..752f1bd 100644 --- a/drivers/staging/media/go7007/saa7134-go7007.c +++ b/drivers/staging/media/go7007/saa7134-go7007.c @@ -471,7 +471,7 @@ static int saa7134_go7007_init(struct saa7134_dev *dev) * V4L2 and ALSA interfaces */ if (go7007_register_encoder(go, go->board_info->num_i2c_devs) < 0) goto initfail; - dev->empress_dev = go->video_dev; + dev->empress_dev = &go->vdev; video_set_drvdata(dev->empress_dev, go); go->status = STATUS_ONLINE; -- cgit v0.10.2 From 793d7b7ffe7e9d35e8c841b9115ee60a362b078e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 12:10:35 -0300 Subject: [media] go7007: remove cropping functions Remove these dummy cropping functions: cropping was never implemented. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 3beb7c4..93de97a 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -842,95 +842,6 @@ static int vidioc_log_status(struct file *file, void *priv) return call_all(&go->v4l2_dev, core, log_status); } -static int vidioc_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cropcap) -{ - struct go7007 *go = video_drvdata(file); - - if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - /* These specify the raw input of the sensor */ - switch (go->standard) { - case GO7007_STD_NTSC: - cropcap->bounds.top = 0; - cropcap->bounds.left = 0; - cropcap->bounds.width = 720; - cropcap->bounds.height = 480; - cropcap->defrect.top = 0; - cropcap->defrect.left = 0; - cropcap->defrect.width = 720; - cropcap->defrect.height = 480; - break; - case GO7007_STD_PAL: - cropcap->bounds.top = 0; - cropcap->bounds.left = 0; - cropcap->bounds.width = 720; - cropcap->bounds.height = 576; - cropcap->defrect.top = 0; - cropcap->defrect.left = 0; - cropcap->defrect.width = 720; - cropcap->defrect.height = 576; - break; - case GO7007_STD_OTHER: - cropcap->bounds.top = 0; - cropcap->bounds.left = 0; - cropcap->bounds.width = go->board_info->sensor_width; - cropcap->bounds.height = go->board_info->sensor_height; - cropcap->defrect.top = 0; - cropcap->defrect.left = 0; - cropcap->defrect.width = go->board_info->sensor_width; - cropcap->defrect.height = go->board_info->sensor_height; - break; - } - - return 0; -} - -static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) -{ - struct go7007 *go = video_drvdata(file); - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - /* These specify the raw input of the sensor */ - switch (go->standard) { - case GO7007_STD_NTSC: - crop->c.top = 0; - crop->c.left = 0; - crop->c.width = 720; - crop->c.height = 480; - break; - case GO7007_STD_PAL: - crop->c.top = 0; - crop->c.left = 0; - crop->c.width = 720; - crop->c.height = 576; - break; - case GO7007_STD_OTHER: - crop->c.top = 0; - crop->c.left = 0; - crop->c.width = go->board_info->sensor_width; - crop->c.height = go->board_info->sensor_height; - break; - } - - return 0; -} - -/* FIXME: vidioc_s_crop is not really implemented!!! - */ -static int vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop *crop) -{ - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return 0; -} - /* FIXME: Those ioctls are private, and not needed, since several standard extended controls already provide streaming control. @@ -1006,9 +917,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_s_parm = vidioc_s_parm, .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_enum_frameintervals = vidioc_enum_frameintervals, - .vidioc_cropcap = vidioc_cropcap, - .vidioc_g_crop = vidioc_g_crop, - .vidioc_s_crop = vidioc_s_crop, .vidioc_log_status = vidioc_log_status, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -- cgit v0.10.2 From b20cc073c2e6a206ebe6449a9c1f1db98376981b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 7 Mar 2013 04:58:35 -0300 Subject: [media] s2250: add comment describing the hardware Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/s2250-board.c b/drivers/staging/media/go7007/s2250-board.c index cb36427..beaa98b 100644 --- a/drivers/staging/media/go7007/s2250-board.c +++ b/drivers/staging/media/go7007/s2250-board.c @@ -29,6 +29,13 @@ MODULE_DESCRIPTION("Sensoray 2250/2251 i2c v4l2 subdev driver"); MODULE_LICENSE("GPL v2"); +/* + * Note: this board has two i2c devices: a vpx3226f and a tlv320aic23b. + * Due to the unusual way these are accessed on this device we do not + * reuse the i2c drivers, but instead they are implemented in this + * driver. It would be nice to improve on this, though. + */ + #define TLV320_ADDRESS 0x34 #define VPX322_ADDR_ANALOGCONTROL1 0x02 #define VPX322_ADDR_BRIGHTNESS0 0x0127 -- cgit v0.10.2 From e129c97494096fbda451619d746d661a05abba64 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 13:28:39 -0300 Subject: [media] go7007-loader: renamed from s2250-loader All s2250 names are renamed to go7007. This will be the generic go7007 firmware loader for any go7007 device, not just for the s2250/1. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/Kconfig b/drivers/staging/media/go7007/Kconfig index 46cb7bf..957277c 100644 --- a/drivers/staging/media/go7007/Kconfig +++ b/drivers/staging/media/go7007/Kconfig @@ -1,13 +1,10 @@ config VIDEO_GO7007 tristate "WIS GO7007 MPEG encoder support" - depends on VIDEO_DEV && PCI && I2C + depends on VIDEO_DEV && I2C depends on SND select VIDEOBUF2_VMALLOC - depends on RC_CORE select VIDEO_TUNER - select VIDEO_TVEEPROM select SND_PCM - select CRC32 select VIDEO_SONY_BTF_MPX if MEDIA_SUBDRV_AUTOSELECT select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TW2804 if MEDIA_SUBDRV_AUTOSELECT @@ -20,7 +17,7 @@ config VIDEO_GO7007 encoder chip. To compile this driver as a module, choose M here: the - module will be called go7007 + module will be called go7007. config VIDEO_GO7007_USB tristate "WIS GO7007 USB support" @@ -31,14 +28,25 @@ config VIDEO_GO7007_USB encoder chip over USB. To compile this driver as a module, choose M here: the - module will be called go7007-usb + module will be called go7007-usb. + +config VIDEO_GO7007_LOADER + tristate "WIS GO7007 Loader support" + depends on VIDEO_GO7007 && DVB_USB + default y + ---help--- + This is a go7007 firmware loader driver for the WIS GO7007 + MPEG encoder chip over USB. + + To compile this driver as a module, choose M here: the + module will be called go7007-loader. config VIDEO_GO7007_USB_S2250_BOARD tristate "Sensoray 2250/2251 support" - depends on VIDEO_GO7007_USB && DVB_USB + depends on VIDEO_GO7007_USB && USB default N ---help--- This is a video4linux driver for the Sensoray 2250/2251 device. To compile this driver as a module, choose M here: the - module will be called s2250 + module will be called s2250. diff --git a/drivers/staging/media/go7007/Makefile b/drivers/staging/media/go7007/Makefile index f9c8e0f..507d012 100644 --- a/drivers/staging/media/go7007/Makefile +++ b/drivers/staging/media/go7007/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_VIDEO_GO7007) += go7007.o obj-$(CONFIG_VIDEO_GO7007_USB) += go7007-usb.o -obj-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD) += s2250.o s2250-loader.o +obj-$(CONFIG_VIDEO_GO7007_LOADER) += go7007-loader.o +obj-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD) += s2250.o go7007-y := go7007-v4l2.o go7007-driver.o go7007-i2c.o go7007-fw.o \ snd-go7007.o @@ -11,8 +12,8 @@ s2250-y := s2250-board.o #obj-$(CONFIG_VIDEO_SAA7134) += saa7134-go7007.o #ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/video/saa7134 -DSAA7134_MPEG_GO7007=3 -# S2250 needs cypress ezusb loader from dvb-usb-v2 -ccflags-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD:m=y) += -Idrivers/media/usb/dvb-usb-v2 +# 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 diff --git a/drivers/staging/media/go7007/go7007-loader.c b/drivers/staging/media/go7007/go7007-loader.c new file mode 100644 index 0000000..730a4f8 --- /dev/null +++ b/drivers/staging/media/go7007/go7007-loader.c @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2008 Sensoray Company 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 + +#define S2250_LOADER_FIRMWARE "s2250_loader.fw" +#define S2250_FIRMWARE "2250.fw" + +typedef struct device_extension_s { + struct kref kref; + int minor; + struct usb_device *usbdev; +} device_extension_t, *pdevice_extension_t; + +#define USB_go7007_loader_MAJOR 240 +#define USB_go7007_loader_MINOR_BASE 0 +#define MAX_DEVICES 256 + +static pdevice_extension_t go7007_dev_table[MAX_DEVICES]; +static DEFINE_MUTEX(go7007_dev_table_mutex); + +#define to_go7007_loader_dev_common(d) container_of(d, device_extension_t, kref) +static void go7007_loader_delete(struct kref *kref) +{ + pdevice_extension_t s = to_go7007_loader_dev_common(kref); + go7007_dev_table[s->minor] = NULL; + kfree(s); +} + +static int go7007_loader_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *usbdev; + int minor, ret; + pdevice_extension_t s = NULL; + const struct firmware *fw; + + usbdev = usb_get_dev(interface_to_usbdev(interface)); + if (!usbdev) { + dev_err(&interface->dev, "Enter go7007_loader_probe failed\n"); + return -1; + } + dev_info(&interface->dev, "vendor id 0x%x, device id 0x%x devnum:%d\n", + usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, + usbdev->devnum); + + if (usbdev->descriptor.bNumConfigurations != 1) { + dev_err(&interface->dev, "can't handle multiple config\n"); + return -1; + } + mutex_lock(&go7007_dev_table_mutex); + + for (minor = 0; minor < MAX_DEVICES; minor++) { + if (go7007_dev_table[minor] == NULL) + break; + } + + if (minor < 0 || minor >= MAX_DEVICES) { + dev_err(&interface->dev, "Invalid minor: %d\n", minor); + goto failed; + } + + /* Allocate dev data structure */ + s = kmalloc(sizeof(device_extension_t), GFP_KERNEL); + if (s == NULL) + goto failed; + + go7007_dev_table[minor] = s; + + dev_info(&interface->dev, + "Device %d on Bus %d Minor %d\n", + usbdev->devnum, usbdev->bus->busnum, minor); + + memset(s, 0, sizeof(device_extension_t)); + s->usbdev = usbdev; + dev_info(&interface->dev, "loading go7007-loader\n"); + + kref_init(&(s->kref)); + + mutex_unlock(&go7007_dev_table_mutex); + + if (request_firmware(&fw, S2250_LOADER_FIRMWARE, &usbdev->dev)) { + dev_err(&interface->dev, + "unable to load firmware from file \"%s\"\n", + S2250_LOADER_FIRMWARE); + goto failed2; + } + ret = usbv2_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); + release_firmware(fw); + if (0 != ret) { + dev_err(&interface->dev, "loader download failed\n"); + goto failed2; + } + + if (request_firmware(&fw, S2250_FIRMWARE, &usbdev->dev)) { + dev_err(&interface->dev, + "unable to load firmware from file \"%s\"\n", + S2250_FIRMWARE); + goto failed2; + } + ret = usbv2_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); + release_firmware(fw); + if (0 != ret) { + dev_err(&interface->dev, "firmware download failed\n"); + goto failed2; + } + + usb_set_intfdata(interface, s); + return 0; + +failed: + mutex_unlock(&go7007_dev_table_mutex); +failed2: + if (s) + kref_put(&(s->kref), go7007_loader_delete); + + dev_err(&interface->dev, "probe failed\n"); + return -1; +} + +static void go7007_loader_disconnect(struct usb_interface *interface) +{ + pdevice_extension_t s; + dev_info(&interface->dev, "disconnect\n"); + s = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + kref_put(&(s->kref), go7007_loader_delete); +} + +static const struct usb_device_id go7007_loader_ids[] = { + {USB_DEVICE(0x1943, 0xa250)}, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, go7007_loader_ids); + +static struct usb_driver go7007_loader_driver = { + .name = "go7007-loader", + .probe = go7007_loader_probe, + .disconnect = go7007_loader_disconnect, + .id_table = go7007_loader_ids, +}; + +module_usb_driver(go7007_loader_driver); + +MODULE_AUTHOR(""); +MODULE_DESCRIPTION("firmware loader for go7007 USB devices"); +MODULE_LICENSE("GPL v2"); +MODULE_FIRMWARE(S2250_LOADER_FIRMWARE); +MODULE_FIRMWARE(S2250_FIRMWARE); diff --git a/drivers/staging/media/go7007/s2250-loader.c b/drivers/staging/media/go7007/s2250-loader.c deleted file mode 100644 index 6453ec0..0000000 --- a/drivers/staging/media/go7007/s2250-loader.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2008 Sensoray Company 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 - -#define S2250_LOADER_FIRMWARE "s2250_loader.fw" -#define S2250_FIRMWARE "s2250.fw" - -typedef struct device_extension_s { - struct kref kref; - int minor; - struct usb_device *usbdev; -} device_extension_t, *pdevice_extension_t; - -#define USB_s2250loader_MAJOR 240 -#define USB_s2250loader_MINOR_BASE 0 -#define MAX_DEVICES 256 - -static pdevice_extension_t s2250_dev_table[MAX_DEVICES]; -static DEFINE_MUTEX(s2250_dev_table_mutex); - -#define to_s2250loader_dev_common(d) container_of(d, device_extension_t, kref) -static void s2250loader_delete(struct kref *kref) -{ - pdevice_extension_t s = to_s2250loader_dev_common(kref); - s2250_dev_table[s->minor] = NULL; - kfree(s); -} - -static int s2250loader_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_device *usbdev; - int minor, ret; - pdevice_extension_t s = NULL; - const struct firmware *fw; - - usbdev = usb_get_dev(interface_to_usbdev(interface)); - if (!usbdev) { - dev_err(&interface->dev, "Enter s2250loader_probe failed\n"); - return -1; - } - dev_info(&interface->dev, "Enter s2250loader_probe 2.6 kernel\n"); - dev_info(&interface->dev, "vendor id 0x%x, device id 0x%x devnum:%d\n", - usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, - usbdev->devnum); - - if (usbdev->descriptor.bNumConfigurations != 1) { - dev_err(&interface->dev, "can't handle multiple config\n"); - return -1; - } - mutex_lock(&s2250_dev_table_mutex); - - for (minor = 0; minor < MAX_DEVICES; minor++) { - if (s2250_dev_table[minor] == NULL) - break; - } - - if (minor < 0 || minor >= MAX_DEVICES) { - dev_err(&interface->dev, "Invalid minor: %d\n", minor); - goto failed; - } - - /* Allocate dev data structure */ - s = kmalloc(sizeof(device_extension_t), GFP_KERNEL); - if (s == NULL) - goto failed; - - s2250_dev_table[minor] = s; - - dev_info(&interface->dev, - "s2250loader_probe: Device %d on Bus %d Minor %d\n", - usbdev->devnum, usbdev->bus->busnum, minor); - - memset(s, 0, sizeof(device_extension_t)); - s->usbdev = usbdev; - dev_info(&interface->dev, "loading 2250 loader\n"); - - kref_init(&(s->kref)); - - mutex_unlock(&s2250_dev_table_mutex); - - if (request_firmware(&fw, S2250_LOADER_FIRMWARE, &usbdev->dev)) { - dev_err(&interface->dev, - "s2250: unable to load firmware from file \"%s\"\n", - S2250_LOADER_FIRMWARE); - goto failed2; - } - ret = usbv2_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); - release_firmware(fw); - if (0 != ret) { - dev_err(&interface->dev, "loader download failed\n"); - goto failed2; - } - - if (request_firmware(&fw, S2250_FIRMWARE, &usbdev->dev)) { - dev_err(&interface->dev, - "s2250: unable to load firmware from file \"%s\"\n", - S2250_FIRMWARE); - goto failed2; - } - ret = usbv2_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); - release_firmware(fw); - if (0 != ret) { - dev_err(&interface->dev, "firmware_s2250 download failed\n"); - goto failed2; - } - - usb_set_intfdata(interface, s); - return 0; - -failed: - mutex_unlock(&s2250_dev_table_mutex); -failed2: - if (s) - kref_put(&(s->kref), s2250loader_delete); - - dev_err(&interface->dev, "probe failed\n"); - return -1; -} - -static void s2250loader_disconnect(struct usb_interface *interface) -{ - pdevice_extension_t s; - dev_info(&interface->dev, "s2250: disconnect\n"); - s = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - kref_put(&(s->kref), s2250loader_delete); -} - -static const struct usb_device_id s2250loader_ids[] = { - {USB_DEVICE(0x1943, 0xa250)}, - {} /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, s2250loader_ids); - -static struct usb_driver s2250loader_driver = { - .name = "s2250-loader", - .probe = s2250loader_probe, - .disconnect = s2250loader_disconnect, - .id_table = s2250loader_ids, -}; - -module_usb_driver(s2250loader_driver); - -MODULE_AUTHOR(""); -MODULE_DESCRIPTION("firmware loader for Sensoray 2250/2251"); -MODULE_LICENSE("GPL v2"); -MODULE_FIRMWARE(S2250_LOADER_FIRMWARE); -MODULE_FIRMWARE(S2250_FIRMWARE); diff --git a/drivers/staging/media/go7007/s2250-loader.h b/drivers/staging/media/go7007/s2250-loader.h deleted file mode 100644 index b7c301a..0000000 --- a/drivers/staging/media/go7007/s2250-loader.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -#ifndef _S2250_LOADER_H_ -#define _S2250_LOADER_H_ - -extern int s2250loader_init(void); -extern void s2250loader_cleanup(void); - -#endif -- cgit v0.10.2 From 0ee3d4d53e4e170e9a9a70214de54b9f5d18d30c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 06:45:14 -0300 Subject: [media] go7007-loader: add support for the other devices and move fw files Add support for the other devices that need to load the boot firmware. All firmware files are now placed in a single go7007 directory. Also remove the device_extension_s stuff: this is clearly a left-over from the olden days. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index 0fd3f10..4378223 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -90,7 +90,7 @@ EXPORT_SYMBOL(go7007_read_addr); static int go7007_load_encoder(struct go7007 *go) { const struct firmware *fw_entry; - char fw_name[] = "go7007fw.bin"; + char fw_name[] = "go7007/go7007fw.bin"; void *bounce; int fw_len, rv = 0; u16 intr_val, intr_data; @@ -126,7 +126,7 @@ static int go7007_load_encoder(struct go7007 *go) return rv; } -MODULE_FIRMWARE("go7007fw.bin"); +MODULE_FIRMWARE("go7007/go7007fw.bin"); /* * Boot the encoder and register the I2C adapter if requested. Do the diff --git a/drivers/staging/media/go7007/go7007-loader.c b/drivers/staging/media/go7007/go7007-loader.c index 730a4f8..4ce53d6 100644 --- a/drivers/staging/media/go7007/go7007-loader.c +++ b/drivers/staging/media/go7007/go7007-loader.c @@ -22,86 +22,67 @@ #include #include -#define S2250_LOADER_FIRMWARE "s2250_loader.fw" -#define S2250_FIRMWARE "2250.fw" - -typedef struct device_extension_s { - struct kref kref; - int minor; - struct usb_device *usbdev; -} device_extension_t, *pdevice_extension_t; - -#define USB_go7007_loader_MAJOR 240 -#define USB_go7007_loader_MINOR_BASE 0 -#define MAX_DEVICES 256 - -static pdevice_extension_t go7007_dev_table[MAX_DEVICES]; -static DEFINE_MUTEX(go7007_dev_table_mutex); +struct fw_config { + u16 vendor; + u16 product; + const char * const fw_name1; + const char * const fw_name2; +}; -#define to_go7007_loader_dev_common(d) container_of(d, device_extension_t, kref) -static void go7007_loader_delete(struct kref *kref) -{ - pdevice_extension_t s = to_go7007_loader_dev_common(kref); - go7007_dev_table[s->minor] = NULL; - kfree(s); -} +struct fw_config fw_configs[] = { + { 0x1943, 0xa250, "go7007/s2250-1.fw", "go7007/s2250-2.fw" }, + { 0x093b, 0xa002, "go7007/px-m402u.fw", NULL }, + { 0x093b, 0xa004, "go7007/px-tv402u.fw", NULL }, + { 0x0eb1, 0x6666, "go7007/lr192.fw", NULL }, + { 0x0eb1, 0x6668, "go7007/wis-startrek.fw", NULL }, + { 0, 0, NULL, NULL } +}; +MODULE_FIRMWARE("go7007/s2250-1.fw"); +MODULE_FIRMWARE("go7007/s2250-2.fw"); +MODULE_FIRMWARE("go7007/px-m402u.fw"); +MODULE_FIRMWARE("go7007/px-tv402u.fw"); +MODULE_FIRMWARE("go7007/lr192.fw"); +MODULE_FIRMWARE("go7007/wis-startrek.fw"); static int go7007_loader_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *usbdev; - int minor, ret; - pdevice_extension_t s = NULL; const struct firmware *fw; + u16 vendor, product; + const char *fw1, *fw2; + int ret; + int i; usbdev = usb_get_dev(interface_to_usbdev(interface)); - if (!usbdev) { - dev_err(&interface->dev, "Enter go7007_loader_probe failed\n"); - return -1; - } - dev_info(&interface->dev, "vendor id 0x%x, device id 0x%x devnum:%d\n", - usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, - usbdev->devnum); + if (!usbdev) + goto failed2; if (usbdev->descriptor.bNumConfigurations != 1) { dev_err(&interface->dev, "can't handle multiple config\n"); - return -1; - } - mutex_lock(&go7007_dev_table_mutex); - - for (minor = 0; minor < MAX_DEVICES; minor++) { - if (go7007_dev_table[minor] == NULL) - break; + return -ENODEV; } - if (minor < 0 || minor >= MAX_DEVICES) { - dev_err(&interface->dev, "Invalid minor: %d\n", minor); - goto failed; - } - - /* Allocate dev data structure */ - s = kmalloc(sizeof(device_extension_t), GFP_KERNEL); - if (s == NULL) - goto failed; - - go7007_dev_table[minor] = s; + vendor = le16_to_cpu(usbdev->descriptor.idVendor); + product = le16_to_cpu(usbdev->descriptor.idProduct); - dev_info(&interface->dev, - "Device %d on Bus %d Minor %d\n", - usbdev->devnum, usbdev->bus->busnum, minor); + for (i = 0; fw_configs[i].fw_name1; i++) + if (fw_configs[i].vendor == vendor && + fw_configs[i].product == product) + break; - memset(s, 0, sizeof(device_extension_t)); - s->usbdev = usbdev; - dev_info(&interface->dev, "loading go7007-loader\n"); + /* Should never happen */ + if (fw_configs[i].fw_name1 == NULL) + goto failed2; - kref_init(&(s->kref)); + fw1 = fw_configs[i].fw_name1; + fw2 = fw_configs[i].fw_name2; - mutex_unlock(&go7007_dev_table_mutex); + dev_info(&interface->dev, "loading firmware %s\n", fw1); - if (request_firmware(&fw, S2250_LOADER_FIRMWARE, &usbdev->dev)) { + if (request_firmware(&fw, fw1, &usbdev->dev)) { dev_err(&interface->dev, - "unable to load firmware from file \"%s\"\n", - S2250_LOADER_FIRMWARE); + "unable to load firmware from file \"%s\"\n", fw1); goto failed2; } ret = usbv2_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); @@ -111,10 +92,12 @@ static int go7007_loader_probe(struct usb_interface *interface, goto failed2; } - if (request_firmware(&fw, S2250_FIRMWARE, &usbdev->dev)) { + if (fw2 == NULL) + return 0; + + if (request_firmware(&fw, fw2, &usbdev->dev)) { dev_err(&interface->dev, - "unable to load firmware from file \"%s\"\n", - S2250_FIRMWARE); + "unable to load firmware from file \"%s\"\n", fw2); goto failed2; } ret = usbv2_cypress_load_firmware(usbdev, fw, CYPRESS_FX2); @@ -123,31 +106,25 @@ static int go7007_loader_probe(struct usb_interface *interface, dev_err(&interface->dev, "firmware download failed\n"); goto failed2; } - - usb_set_intfdata(interface, s); return 0; -failed: - mutex_unlock(&go7007_dev_table_mutex); failed2: - if (s) - kref_put(&(s->kref), go7007_loader_delete); - dev_err(&interface->dev, "probe failed\n"); - return -1; + return -ENODEV; } static void go7007_loader_disconnect(struct usb_interface *interface) { - pdevice_extension_t s; dev_info(&interface->dev, "disconnect\n"); - s = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); - kref_put(&(s->kref), go7007_loader_delete); } static const struct usb_device_id go7007_loader_ids[] = { - {USB_DEVICE(0x1943, 0xa250)}, + { USB_DEVICE(0x1943, 0xa250) }, + { USB_DEVICE(0x093b, 0xa002) }, + { USB_DEVICE(0x093b, 0xa004) }, + { USB_DEVICE(0x0eb1, 0x6666) }, + { USB_DEVICE(0x0eb1, 0x6668) }, {} /* Terminating entry */ }; @@ -163,7 +140,5 @@ static struct usb_driver go7007_loader_driver = { module_usb_driver(go7007_loader_driver); MODULE_AUTHOR(""); -MODULE_DESCRIPTION("firmware loader for go7007 USB devices"); +MODULE_DESCRIPTION("firmware loader for go7007-usb"); MODULE_LICENSE("GPL v2"); -MODULE_FIRMWARE(S2250_LOADER_FIRMWARE); -MODULE_FIRMWARE(S2250_FIRMWARE); diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 2a1cda2..bd23d7d 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -76,7 +76,7 @@ struct go7007_usb { static struct go7007_usb_board board_matrix_ii = { .flags = GO7007_USB_EZUSB, .main_info = { - .firmware = "go7007tv.bin", + .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_HAS_AUDIO | GO7007_BOARD_USE_ONBOARD_I2C, .audio_flags = GO7007_AUDIO_I2S_MODE_1 | @@ -117,7 +117,7 @@ static struct go7007_usb_board board_matrix_ii = { static struct go7007_usb_board board_matrix_reload = { .flags = GO7007_USB_EZUSB, .main_info = { - .firmware = "go7007tv.bin", + .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_HAS_AUDIO | GO7007_BOARD_USE_ONBOARD_I2C, .audio_flags = GO7007_AUDIO_I2S_MODE_1 | @@ -155,7 +155,7 @@ static struct go7007_usb_board board_matrix_reload = { static struct go7007_usb_board board_star_trek = { .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, .main_info = { - .firmware = "go7007tv.bin", + .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_HAS_AUDIO, /* | GO7007_BOARD_HAS_TUNER, */ .sensor_flags = GO7007_SENSOR_656 | @@ -203,7 +203,7 @@ static struct go7007_usb_board board_star_trek = { static struct go7007_usb_board board_px_tv402u = { .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, .main_info = { - .firmware = "go7007tv.bin", + .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_HAS_AUDIO | GO7007_BOARD_HAS_TUNER, .sensor_flags = GO7007_SENSOR_656 | @@ -278,7 +278,7 @@ static struct go7007_usb_board board_px_tv402u = { static struct go7007_usb_board board_xmen = { .flags = 0, .main_info = { - .firmware = "go7007tv.bin", + .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_USE_ONBOARD_I2C, .hpi_buffer_cap = 0, .sensor_flags = GO7007_SENSOR_VREF_POLAR, @@ -313,7 +313,7 @@ static struct go7007_usb_board board_xmen = { static struct go7007_usb_board board_matrix_revolution = { .flags = GO7007_USB_EZUSB, .main_info = { - .firmware = "go7007tv.bin", + .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_HAS_AUDIO | GO7007_BOARD_USE_ONBOARD_I2C, .audio_flags = GO7007_AUDIO_I2S_MODE_1 | @@ -351,7 +351,7 @@ static struct go7007_usb_board board_matrix_revolution = { static struct go7007_usb_board board_lifeview_lr192 = { .flags = GO7007_USB_EZUSB, .main_info = { - .firmware = "go7007tv.bin", + .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_HAS_AUDIO | GO7007_BOARD_USE_ONBOARD_I2C, .audio_flags = GO7007_AUDIO_I2S_MODE_1 | @@ -379,7 +379,7 @@ static struct go7007_usb_board board_lifeview_lr192 = { static struct go7007_usb_board board_endura = { .flags = 0, .main_info = { - .firmware = "go7007tv.bin", + .firmware = "go7007/go7007tv.bin", .flags = 0, .audio_flags = GO7007_AUDIO_I2S_MODE_1 | GO7007_AUDIO_I2S_MASTER | @@ -404,7 +404,7 @@ static struct go7007_usb_board board_endura = { static struct go7007_usb_board board_adlink_mpg24 = { .flags = 0, .main_info = { - .firmware = "go7007tv.bin", + .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_USE_ONBOARD_I2C, .audio_flags = GO7007_AUDIO_I2S_MODE_1 | GO7007_AUDIO_I2S_MASTER | @@ -437,7 +437,7 @@ static struct go7007_usb_board board_adlink_mpg24 = { static struct go7007_usb_board board_sensoray_2250 = { .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, .main_info = { - .firmware = "go7007tv.bin", + .firmware = "go7007/go7007tv.bin", .audio_flags = GO7007_AUDIO_I2S_MODE_1 | GO7007_AUDIO_I2S_MASTER | GO7007_AUDIO_WORD_16, @@ -486,7 +486,7 @@ static struct go7007_usb_board board_sensoray_2250 = { }, }; -MODULE_FIRMWARE("go7007tv.bin"); +MODULE_FIRMWARE("go7007/go7007tv.bin"); static const struct usb_device_id go7007_usb_id_table[] = { { diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c index 752f1bd..d56f4fc 100644 --- a/drivers/staging/media/go7007/saa7134-go7007.c +++ b/drivers/staging/media/go7007/saa7134-go7007.c @@ -65,7 +65,7 @@ struct saa7134_go7007 { }; static struct go7007_board_info board_voyager = { - .firmware = "go7007tv.bin", + .firmware = "go7007/go7007tv.bin", .flags = 0, .sensor_flags = GO7007_SENSOR_656 | GO7007_SENSOR_VALID_ENABLE | @@ -430,6 +430,7 @@ static struct go7007_hpi_ops saa7134_go7007_hpi_ops = { .send_firmware = saa7134_go7007_send_firmware, .send_command = saa7134_go7007_send_command, }; +MODULE_FIRMWARE("go7007/go7007tv.bin"); /********************* Add/remove functions *********************/ -- cgit v0.10.2 From 98ded5904b0dca23146d4d80ad91ab800f35b576 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 9 Mar 2013 12:59:44 -0300 Subject: [media] MAINTAINERS: add the go7007 driver Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index b74fe21..924a21f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7586,6 +7586,11 @@ M: David Täht S: Odd Fixes F: drivers/staging/frontier/ +STAGING - GO7007 MPEG CODEC +M: Hans Verkuil +S: Maintained +F: drivers/staging/media/go7007/ + STAGING - INDUSTRIAL IO M: Jonathan Cameron L: linux-iio@vger.kernel.org -- cgit v0.10.2 From 3e4c8478d4b3bff3ca6fb36f47e9f1c6600ecde9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 11 Mar 2013 18:58:21 -0300 Subject: [media] go7007: a small improvement to querystd handling Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 93de97a..4e5da87 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -652,12 +652,12 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std) static int go7007_s_std(struct go7007 *go) { - if (go->std & V4L2_STD_525_60) { - go->standard = GO7007_STD_NTSC; - go->sensor_framerate = 30000; - } else { + if (go->std & V4L2_STD_625_50) { go->standard = GO7007_STD_PAL; go->sensor_framerate = 25025; + } else { + go->standard = GO7007_STD_NTSC; + go->sensor_framerate = 30000; } call_all(&go->v4l2_dev, core, s_std, go->std); -- cgit v0.10.2 From 7e4bfb9ec0663d08bcd1c4d10bc13412b0f66d36 Mon Sep 17 00:00:00 2001 From: Volokh Konstantin Date: Sun, 17 Mar 2013 07:16:37 -0300 Subject: [media] go7007: Restore b_frame control Signed-off-by: Volokh Konstantin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index 0914fa3..5f9b389 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -166,6 +166,7 @@ struct go7007 { struct v4l2_ctrl *mpeg_video_gop_closure; struct v4l2_ctrl *mpeg_video_bitrate; struct v4l2_ctrl *mpeg_video_aspect_ratio; + struct v4l2_ctrl *mpeg_video_b_frames; enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status; spinlock_t spinlock; struct mutex hw_lock; diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 4e5da87..0dc3160 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -161,6 +161,7 @@ static void set_formatting(struct go7007 *go) } go->gop_size = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_size); go->closed_gop = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_closure); + go->ipb = v4l2_ctrl_g_ctrl(go->mpeg_video_b_frames) != 0; go->bitrate = v4l2_ctrl_g_ctrl(go->mpeg_video_bitrate); go->gop_header_enable = 1; go->dvd_mode = 0; @@ -168,9 +169,9 @@ static void set_formatting(struct go7007 *go) go->dvd_mode = go->bitrate == 9800000 && go->gop_size == 15 && + go->ipb == 0 && go->closed_gop; go->repeat_seqhead = go->dvd_mode; - go->ipb = 0; switch (v4l2_ctrl_g_ctrl(go->mpeg_video_aspect_ratio)) { default: @@ -935,7 +936,7 @@ int go7007_v4l2_ctrl_init(struct go7007 *go) struct v4l2_ctrl_handler *hdl = &go->hdl; struct v4l2_ctrl *ctrl; - v4l2_ctrl_handler_init(hdl, 12); + v4l2_ctrl_handler_init(hdl, 13); go->mpeg_video_gop_size = v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, 34, 1, 15); go->mpeg_video_gop_closure = v4l2_ctrl_new_std(hdl, NULL, @@ -943,6 +944,9 @@ int go7007_v4l2_ctrl_init(struct go7007 *go) go->mpeg_video_bitrate = v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_MPEG_VIDEO_BITRATE, 64000, 10000000, 1, 9800000); + go->mpeg_video_b_frames = v4l2_ctrl_new_std(hdl, NULL, + V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 2, 2, 0); + go->mpeg_video_aspect_ratio = v4l2_ctrl_new_std_menu(hdl, NULL, V4L2_CID_MPEG_VIDEO_ASPECT, V4L2_MPEG_VIDEO_ASPECT_16x9, 0, -- cgit v0.10.2 From 778ca511537da58d9154ab8e1c1f0d1bf738aec8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 17 Mar 2013 10:47:02 -0300 Subject: [media] go7007: add back 'repeat sequence header' control But now as a proper standard MPEG control. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index 5f9b389..cfa4c84 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -167,6 +167,7 @@ struct go7007 { struct v4l2_ctrl *mpeg_video_bitrate; struct v4l2_ctrl *mpeg_video_aspect_ratio; struct v4l2_ctrl *mpeg_video_b_frames; + struct v4l2_ctrl *mpeg_video_rep_seqheader; enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status; spinlock_t spinlock; struct mutex hw_lock; diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 0dc3160..45be518 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -163,6 +163,7 @@ static void set_formatting(struct go7007 *go) go->closed_gop = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_closure); go->ipb = v4l2_ctrl_g_ctrl(go->mpeg_video_b_frames) != 0; go->bitrate = v4l2_ctrl_g_ctrl(go->mpeg_video_bitrate); + go->repeat_seqhead = v4l2_ctrl_g_ctrl(go->mpeg_video_rep_seqheader); go->gop_header_enable = 1; go->dvd_mode = 0; if (go->format == V4L2_PIX_FMT_MPEG2) @@ -170,8 +171,8 @@ static void set_formatting(struct go7007 *go) go->bitrate == 9800000 && go->gop_size == 15 && go->ipb == 0 && + go->repeat_seqhead == 1 && go->closed_gop; - go->repeat_seqhead = go->dvd_mode; switch (v4l2_ctrl_g_ctrl(go->mpeg_video_aspect_ratio)) { default: @@ -946,6 +947,8 @@ int go7007_v4l2_ctrl_init(struct go7007 *go) 64000, 10000000, 1, 9800000); go->mpeg_video_b_frames = v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 2, 2, 0); + go->mpeg_video_rep_seqheader = v4l2_ctrl_new_std(hdl, NULL, + V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, 0, 1, 1, 1); go->mpeg_video_aspect_ratio = v4l2_ctrl_new_std_menu(hdl, NULL, V4L2_CID_MPEG_VIDEO_ASPECT, -- cgit v0.10.2 From ac41fa2a41ba2eb224c982c2c8849169aca6310f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 17 Mar 2013 10:11:32 -0300 Subject: [media] go7007: correct a header check: MPEG4 has a different GOP code Actually it's called "Group of VOP" start code in MPEG4 terminology. 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 diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index 4378223..3c0b258 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -435,16 +435,18 @@ static void write_bitmap_word(struct go7007 *go) void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) { struct go7007_buffer *vb = go->active_buf; - int i, seq_start_code = -1, frame_start_code = -1; + int i, seq_start_code = -1, gop_start_code = -1, frame_start_code = -1; switch (go->format) { case V4L2_PIX_FMT_MPEG4: seq_start_code = 0xB0; + gop_start_code = 0xB3; frame_start_code = 0xB6; break; case V4L2_PIX_FMT_MPEG1: case V4L2_PIX_FMT_MPEG2: seq_start_code = 0xB3; + gop_start_code = 0xB8; frame_start_code = 0x00; break; } @@ -526,7 +528,7 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length) go->format == V4L2_PIX_FMT_MPEG2 || go->format == V4L2_PIX_FMT_MPEG4) && (buf[i] == seq_start_code || - buf[i] == 0xB8 || /* GOP code */ + buf[i] == gop_start_code || buf[i] == frame_start_code)) { if (vb == NULL || go->seen_frame) vb = frame_boundary(go, vb); -- cgit v0.10.2 From 0a6ecbb40ebe372028088b3e6b71a3adf9b1b674 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 17 Mar 2013 10:56:20 -0300 Subject: [media] go7007: drop firmware name in board config, make configs const The firmware is always the same, so drop it from the board configs. Also make the board configs const. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index 3c0b258..3d7705e 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -624,7 +624,8 @@ EXPORT_SYMBOL(go7007_parse_video_stream); /* * Allocate a new go7007 struct. Used by the hardware-specific probe. */ -struct go7007 *go7007_alloc(struct go7007_board_info *board, struct device *dev) +struct go7007 *go7007_alloc(const struct go7007_board_info *board, + struct device *dev) { struct go7007 *go; int i; @@ -677,7 +678,7 @@ EXPORT_SYMBOL(go7007_alloc); void go7007_update_board(struct go7007 *go) { - struct go7007_board_info *board = go->board_info; + const struct go7007_board_info *board = go->board_info; if (board->sensor_flags & GO7007_SENSOR_TV) { go->standard = GO7007_STD_NTSC; diff --git a/drivers/staging/media/go7007/go7007-fw.c b/drivers/staging/media/go7007/go7007-fw.c index 524ba48..c2d0e58af 100644 --- a/drivers/staging/media/go7007/go7007-fw.c +++ b/drivers/staging/media/go7007/go7007-fw.c @@ -36,6 +36,8 @@ #include "go7007-priv.h" +#define GO7007_FW_NAME "go7007/go7007tv.bin" + /* Constants used in the source firmware image to describe code segments */ #define FLAG_MODE_MJPEG (1) @@ -1568,10 +1570,10 @@ int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen) default: return -1; } - if (request_firmware(&fw_entry, go->board_info->firmware, go->dev)) { + if (request_firmware(&fw_entry, GO7007_FW_NAME, go->dev)) { dev_err(go->dev, "unable to load firmware from file \"%s\"\n", - go->board_info->firmware); + GO7007_FW_NAME); return -1; } code = kzalloc(codespace * 2, GFP_KERNEL); @@ -1586,7 +1588,7 @@ int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen) if (chunk_len + 2 > srclen) { dev_err(go->dev, "firmware file \"%s\" appears to be corrupted\n", - go->board_info->firmware); + GO7007_FW_NAME); goto fw_failed; } if (chunk_flags & mode_flag) { @@ -1622,3 +1624,5 @@ fw_failed: release_firmware(fw_entry); return -1; } + +MODULE_FIRMWARE(GO7007_FW_NAME); diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index cfa4c84..31adc70 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -75,7 +75,6 @@ struct go7007; #define GO7007_AUDIO_OKI_MODE (1<<17) struct go7007_board_info { - char *firmware; unsigned int flags; int hpi_buffer_cap; unsigned int sensor_flags; @@ -151,7 +150,7 @@ enum go7007_parser_state { struct go7007 { struct device *dev; u8 bus_info[32]; - struct go7007_board_info *board_info; + const struct go7007_board_info *board_info; unsigned int board_id; int tuner_type; int channel_number; /* for multi-channel boards like Adlink PCI-MPG24 */ @@ -273,7 +272,7 @@ int go7007_reset_encoder(struct go7007 *go); int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs); int go7007_start_encoder(struct go7007 *go); void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length); -struct go7007 *go7007_alloc(struct go7007_board_info *board, +struct go7007 *go7007_alloc(const struct go7007_board_info *board, struct device *dev); void go7007_update_board(struct go7007 *go); diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index bd23d7d..31c18f5 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -63,7 +63,7 @@ struct go7007_usb_board { }; struct go7007_usb { - struct go7007_usb_board *board; + const struct go7007_usb_board *board; struct mutex i2c_lock; struct usb_device *usbdev; struct urb *video_urbs[8]; @@ -73,10 +73,9 @@ struct go7007_usb { /*********************** Product specification data ***********************/ -static struct go7007_usb_board board_matrix_ii = { +static const struct go7007_usb_board board_matrix_ii = { .flags = GO7007_USB_EZUSB, .main_info = { - .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_HAS_AUDIO | GO7007_BOARD_USE_ONBOARD_I2C, .audio_flags = GO7007_AUDIO_I2S_MODE_1 | @@ -114,10 +113,9 @@ static struct go7007_usb_board board_matrix_ii = { }, }; -static struct go7007_usb_board board_matrix_reload = { +static const struct go7007_usb_board board_matrix_reload = { .flags = GO7007_USB_EZUSB, .main_info = { - .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_HAS_AUDIO | GO7007_BOARD_USE_ONBOARD_I2C, .audio_flags = GO7007_AUDIO_I2S_MODE_1 | @@ -152,10 +150,9 @@ static struct go7007_usb_board board_matrix_reload = { }, }; -static struct go7007_usb_board board_star_trek = { +static const struct go7007_usb_board board_star_trek = { .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, .main_info = { - .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_HAS_AUDIO, /* | GO7007_BOARD_HAS_TUNER, */ .sensor_flags = GO7007_SENSOR_656 | @@ -200,10 +197,9 @@ static struct go7007_usb_board board_star_trek = { }, }; -static struct go7007_usb_board board_px_tv402u = { +static const struct go7007_usb_board board_px_tv402u = { .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, .main_info = { - .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_HAS_AUDIO | GO7007_BOARD_HAS_TUNER, .sensor_flags = GO7007_SENSOR_656 | @@ -275,10 +271,9 @@ static struct go7007_usb_board board_px_tv402u = { }, }; -static struct go7007_usb_board board_xmen = { +static const struct go7007_usb_board board_xmen = { .flags = 0, .main_info = { - .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_USE_ONBOARD_I2C, .hpi_buffer_cap = 0, .sensor_flags = GO7007_SENSOR_VREF_POLAR, @@ -310,10 +305,9 @@ static struct go7007_usb_board board_xmen = { }, }; -static struct go7007_usb_board board_matrix_revolution = { +static const struct go7007_usb_board board_matrix_revolution = { .flags = GO7007_USB_EZUSB, .main_info = { - .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_HAS_AUDIO | GO7007_BOARD_USE_ONBOARD_I2C, .audio_flags = GO7007_AUDIO_I2S_MODE_1 | @@ -348,10 +342,9 @@ static struct go7007_usb_board board_matrix_revolution = { }, }; -static struct go7007_usb_board board_lifeview_lr192 = { +static const struct go7007_usb_board board_lifeview_lr192 = { .flags = GO7007_USB_EZUSB, .main_info = { - .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_HAS_AUDIO | GO7007_BOARD_USE_ONBOARD_I2C, .audio_flags = GO7007_AUDIO_I2S_MODE_1 | @@ -376,10 +369,9 @@ static struct go7007_usb_board board_lifeview_lr192 = { }, }; -static struct go7007_usb_board board_endura = { +static const struct go7007_usb_board board_endura = { .flags = 0, .main_info = { - .firmware = "go7007/go7007tv.bin", .flags = 0, .audio_flags = GO7007_AUDIO_I2S_MODE_1 | GO7007_AUDIO_I2S_MASTER | @@ -401,10 +393,9 @@ static struct go7007_usb_board board_endura = { }, }; -static struct go7007_usb_board board_adlink_mpg24 = { +static const struct go7007_usb_board board_adlink_mpg24 = { .flags = 0, .main_info = { - .firmware = "go7007/go7007tv.bin", .flags = GO7007_BOARD_USE_ONBOARD_I2C, .audio_flags = GO7007_AUDIO_I2S_MODE_1 | GO7007_AUDIO_I2S_MASTER | @@ -434,10 +425,9 @@ static struct go7007_usb_board board_adlink_mpg24 = { }, }; -static struct go7007_usb_board board_sensoray_2250 = { +static const struct go7007_usb_board board_sensoray_2250 = { .flags = GO7007_USB_EZUSB | GO7007_USB_EZUSB_I2C, .main_info = { - .firmware = "go7007/go7007tv.bin", .audio_flags = GO7007_AUDIO_I2S_MODE_1 | GO7007_AUDIO_I2S_MASTER | GO7007_AUDIO_WORD_16, @@ -486,8 +476,6 @@ static struct go7007_usb_board board_sensoray_2250 = { }, }; -MODULE_FIRMWARE("go7007/go7007tv.bin"); - static const struct usb_device_id go7007_usb_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | @@ -1041,7 +1029,7 @@ static int go7007_usb_probe(struct usb_interface *intf, { struct go7007 *go; struct go7007_usb *usb; - struct go7007_usb_board *board; + const struct go7007_usb_board *board; struct usb_device *usbdev = interface_to_usbdev(intf); unsigned num_i2c_devs; char *name; diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c index d56f4fc..aee9ace 100644 --- a/drivers/staging/media/go7007/saa7134-go7007.c +++ b/drivers/staging/media/go7007/saa7134-go7007.c @@ -64,8 +64,7 @@ struct saa7134_go7007 { dma_addr_t bottom_dma; }; -static struct go7007_board_info board_voyager = { - .firmware = "go7007/go7007tv.bin", +static const struct go7007_board_info board_voyager = { .flags = 0, .sensor_flags = GO7007_SENSOR_656 | GO7007_SENSOR_VALID_ENABLE | -- cgit v0.10.2 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 diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 07d9c11..9e7ce8b 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 399050a..720f42d 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 0000000..2263a91 --- /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 v0.10.2 From 1f1aed2ed4450381a322f5e727e89bd21e7a89fe Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 17 Mar 2013 10:15:03 -0300 Subject: [media] go7007: add support for ADS Tech DVD Xpress DX2 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 diff --git a/drivers/staging/media/go7007/Kconfig b/drivers/staging/media/go7007/Kconfig index 957277c..b10f996 100644 --- a/drivers/staging/media/go7007/Kconfig +++ b/drivers/staging/media/go7007/Kconfig @@ -9,6 +9,7 @@ config VIDEO_GO7007 select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TW2804 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TW9903 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_TW9906 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_UDA1342 if MEDIA_SUBDRV_AUTOSELECT default N diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/staging/media/go7007/go7007-driver.c index 3d7705e..a5ca99d 100644 --- a/drivers/staging/media/go7007/go7007-driver.c +++ b/drivers/staging/media/go7007/go7007-driver.c @@ -166,15 +166,24 @@ static int go7007_init_encoder(struct go7007 *go) go7007_write_addr(go, 0x1000, 0x0811); go7007_write_addr(go, 0x1000, 0x0c11); } - if (go->board_id == GO7007_BOARDID_MATRIX_REV) { + switch (go->board_id) { + case GO7007_BOARDID_MATRIX_REV: /* Set GPIO pin 0 to be an output (audio clock control) */ go7007_write_addr(go, 0x3c82, 0x0001); go7007_write_addr(go, 0x3c80, 0x00fe); - } - if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) { + break; + case GO7007_BOARDID_ADLINK_MPG24: /* set GPIO5 to be an output, currently low */ go7007_write_addr(go, 0x3c82, 0x0000); go7007_write_addr(go, 0x3c80, 0x00df); + break; + case GO7007_BOARDID_ADS_USBAV_709: + /* GPIO pin 0: audio clock control */ + /* pin 2: TW9906 reset */ + /* pin 3: capture LED */ + go7007_write_addr(go, 0x3c82, 0x000d); + go7007_write_addr(go, 0x3c80, 0x00f2); + break; } return 0; } @@ -282,6 +291,12 @@ int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs) go->i2c_adapter_online = 1; } if (go->i2c_adapter_online) { + if (go->board_id == GO7007_BOARDID_ADS_USBAV_709) { + /* Reset the TW9906 */ + go7007_write_addr(go, 0x3c82, 0x0009); + msleep(50); + go7007_write_addr(go, 0x3c82, 0x000d); + } for (i = 0; i < num_i2c_devs; ++i) init_i2c_module(&go->i2c_adapter, &go->board_info->i2c_devs[i]); diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index 31adc70..8bde187 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -43,6 +43,7 @@ struct go7007; #define GO7007_BOARDID_ENDURA 11 #define GO7007_BOARDID_ADLINK_MPG24 12 #define GO7007_BOARDID_SENSORAY_2250 13 /* Sensoray 2250/2251 */ +#define GO7007_BOARDID_ADS_USBAV_709 14 /* Various characteristics of each board */ #define GO7007_BOARD_HAS_AUDIO (1<<0) diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 31c18f5..0823506 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -476,6 +476,43 @@ static const struct go7007_usb_board board_sensoray_2250 = { }, }; +static const struct go7007_usb_board board_ads_usbav_709 = { + .flags = GO7007_USB_EZUSB, + .main_info = { + .flags = GO7007_BOARD_HAS_AUDIO | + GO7007_BOARD_USE_ONBOARD_I2C, + .audio_flags = GO7007_AUDIO_I2S_MODE_1 | + GO7007_AUDIO_I2S_MASTER | + GO7007_AUDIO_WORD_16, + .audio_rate = 48000, + .audio_bclk_div = 8, + .audio_main_div = 2, + .hpi_buffer_cap = 7, + .sensor_flags = GO7007_SENSOR_656 | + GO7007_SENSOR_TV | + GO7007_SENSOR_VBI, + .num_i2c_devs = 1, + .i2c_devs = { + { + .type = "tw9906", + .is_video = 1, + .addr = 0x44, + }, + }, + .num_inputs = 2, + .inputs = { + { + .video_input = 0, + .name = "Composite", + }, + { + .video_input = 10, + .name = "S-Video", + }, + }, + }, +}; + static const struct usb_device_id go7007_usb_id_table[] = { { .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | @@ -577,6 +614,14 @@ static const struct usb_device_id go7007_usb_id_table[] = { .bcdDevice_hi = 0x1, .driver_info = (kernel_ulong_t)GO7007_BOARDID_SENSORAY_2250, }, + { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, + .idVendor = 0x06e1, /* Vendor ID of ADS Technologies */ + .idProduct = 0x0709, /* Product ID of DVD Xpress DX2 */ + .bcdDevice_lo = 0x204, + .bcdDevice_hi = 0x204, + .driver_info = (kernel_ulong_t)GO7007_BOARDID_ADS_USBAV_709, + }, { } /* Terminating entry */ }; @@ -1086,6 +1131,10 @@ static int go7007_usb_probe(struct usb_interface *intf, name = "Sensoray 2250/2251"; board = &board_sensoray_2250; break; + case GO7007_BOARDID_ADS_USBAV_709: + name = "ADS Tech DVD Xpress DX2"; + board = &board_ads_usbav_709; + break; default: printk(KERN_ERR "go7007-usb: unknown board ID %d!\n", (unsigned int)id->driver_info); diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 45be518..24ba50e 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -512,6 +512,9 @@ static int go7007_start_streaming(struct vb2_queue *q, unsigned int count) v4l2_ctrl_grab(go->mpeg_video_gop_closure, true); v4l2_ctrl_grab(go->mpeg_video_bitrate, true); v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, true); + /* Turn on Capture LED */ + if (go->board_id == GO7007_BOARDID_ADS_USBAV_709) + go7007_write_addr(go, 0x3c82, 0x0005); return ret; } @@ -534,6 +537,9 @@ static int go7007_stop_streaming(struct vb2_queue *q) v4l2_ctrl_grab(go->mpeg_video_gop_closure, false); v4l2_ctrl_grab(go->mpeg_video_bitrate, false); v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, false); + /* Turn on Capture LED */ + if (go->board_id == GO7007_BOARDID_ADS_USBAV_709) + go7007_write_addr(go, 0x3c82, 0x000d); return 0; } -- cgit v0.10.2 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 diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index aa044f4..b81f274 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -551,53 +551,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... * @t2 - with this struct. diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index ec7c9c0..1d93c48 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 v0.10.2 From 6c2afac434f00267c484239ad9210c1a075e7f16 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 15:19:33 -0300 Subject: [media] v4l2-subdev: remove obsolete dv_preset ops These ops are no longer used, so it's time to remove them. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index c42703a..5298d67 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -279,14 +279,6 @@ struct v4l2_mbus_frame_desc { s_routing: see s_routing in audio_ops, except this version is for video devices. - s_dv_preset: set dv (Digital Video) preset in the sub device. Similar to - s_std() - - g_dv_preset: get current dv (Digital Video) preset in the sub device. - - query_dv_preset: query dv preset in the sub device. This is similar to - querystd() - s_dv_timings(): Set custom dv timings in the sub device. This is used when sub device is capable of setting detailed timing information in the hardware to generate/detect the video signal. @@ -331,14 +323,6 @@ struct v4l2_subdev_video_ops { struct v4l2_subdev_frame_interval *interval); int (*enum_framesizes)(struct v4l2_subdev *sd, struct v4l2_frmsizeenum *fsize); int (*enum_frameintervals)(struct v4l2_subdev *sd, struct v4l2_frmivalenum *fival); - int (*enum_dv_presets) (struct v4l2_subdev *sd, - struct v4l2_dv_enum_preset *preset); - int (*s_dv_preset)(struct v4l2_subdev *sd, - struct v4l2_dv_preset *preset); - int (*g_dv_preset)(struct v4l2_subdev *sd, - struct v4l2_dv_preset *preset); - int (*query_dv_preset)(struct v4l2_subdev *sd, - struct v4l2_dv_preset *preset); int (*s_dv_timings)(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings); int (*g_dv_timings)(struct v4l2_subdev *sd, -- cgit v0.10.2 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 diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 7157af3..f129551 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 de1e9ab..1fbd957 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 72c22fd..83aa39d 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 a4175cd..e10c243 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 v0.10.2 From 098cbc38c27dee66e5bc7f088c30b96e5cc96510 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 24 Mar 2013 06:09:29 -0300 Subject: [media] DocBook/media/v4l: remove the documentation of the obsolete dv_preset API This API is no longer used by any driver and so can be removed from the documentation. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml index ae06afb..1ddf354 100644 --- a/Documentation/DocBook/media/v4l/common.xml +++ b/Documentation/DocBook/media/v4l/common.xml @@ -750,15 +750,6 @@ header can be used to get the timings of the formats in the standards. - - DV Presets: Digital Video (DV) presets (deprecated). - These are IDs representing a -video timing at the input/output. Presets are pre-defined timings implemented -by the hardware according to video standards. A __u32 data type is used to represent -a preset unlike the bit mask that is used in &v4l2-std-id; allowing future extensions -to support as many different presets as needed. This API is deprecated in favor of the DV Timings -API. - To enumerate and query the attributes of the DV timings supported by a device, applications use the &VIDIOC-ENUM-DV-TIMINGS; and &VIDIOC-DV-TIMINGS-CAP; ioctls. @@ -766,11 +757,6 @@ API. &VIDIOC-S-DV-TIMINGS; ioctl and to get current DV timings they use the &VIDIOC-G-DV-TIMINGS; ioctl. To detect the DV timings as seen by the video receiver applications use the &VIDIOC-QUERY-DV-TIMINGS; ioctl. - To enumerate and query the attributes of DV presets supported by a device, -applications use the &VIDIOC-ENUM-DV-PRESETS; ioctl. To get the current DV preset, -applications use the &VIDIOC-G-DV-PRESET; ioctl and to set a preset they use the -&VIDIOC-S-DV-PRESET; ioctl. To detect the preset as seen by the video receiver applications -use the &VIDIOC-QUERY-DV-PRESET; ioctl. Applications can make use of the and flags to decide what ioctls are available to set the video timings for the device. diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index 104a1a2..effa509 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2625,8 +2625,8 @@ interfaces and should not be implemented in new drivers. . - &VIDIOC-G-DV-PRESET;, &VIDIOC-S-DV-PRESET;, &VIDIOC-ENUM-DV-PRESETS; and - &VIDIOC-QUERY-DV-PRESET; ioctls. Use the DV Timings API (). + VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET, VIDIOC_ENUM_DV_PRESETS and + VIDIOC_QUERY_DV_PRESET ioctls. Use the DV Timings API (). VIDIOC_SUBDEV_G_CROP and diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index a3cce18..32a10ee 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -544,7 +544,6 @@ and discussions on the V4L mailing list. &sub-encoder-cmd; &sub-enumaudio; &sub-enumaudioout; - &sub-enum-dv-presets; &sub-enum-dv-timings; &sub-enum-fmt; &sub-enum-framesizes; @@ -558,7 +557,6 @@ and discussions on the V4L mailing list. &sub-g-audioout; &sub-g-crop; &sub-g-ctrl; - &sub-g-dv-preset; &sub-g-dv-timings; &sub-g-enc-index; &sub-g-ext-ctrls; @@ -582,7 +580,6 @@ and discussions on the V4L mailing list. &sub-querybuf; &sub-querycap; &sub-queryctrl; - &sub-query-dv-preset; &sub-query-dv-timings; &sub-querystd; &sub-reqbufs; diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml b/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml deleted file mode 100644 index fced5fb..0000000 --- a/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml +++ /dev/null @@ -1,240 +0,0 @@ - - - ioctl VIDIOC_ENUM_DV_PRESETS - &manvol; - - - - VIDIOC_ENUM_DV_PRESETS - Enumerate supported Digital Video presets - - - - - - int ioctl - int fd - int request - struct v4l2_dv_enum_preset *argp - - - - - - Arguments - - - - fd - - &fd; - - - - request - - VIDIOC_ENUM_DV_PRESETS - - - - argp - - - - - - - - - Description - - This ioctl is deprecated. - New drivers and applications should use &VIDIOC-ENUM-DV-TIMINGS; instead. - - - To query the attributes of a DV preset, applications initialize the -index field and zero the reserved array of &v4l2-dv-enum-preset; -and call the VIDIOC_ENUM_DV_PRESETS ioctl with a pointer to this -structure. Drivers fill the rest of the structure or return an -&EINVAL; when the index is out of bounds. To enumerate all DV Presets supported, -applications shall begin at index zero, incrementing by one until the -driver returns EINVAL. Drivers may enumerate a -different set of DV presets after switching the video input or -output. - - - struct <structname>v4l2_dv_enum_presets</structname> - - &cs-str; - - - __u32 - index - Number of the DV preset, set by the -application. - - - __u32 - preset - This field identifies one of the DV preset values listed in . - - - __u8 - name[24] - Name of the preset, a NUL-terminated ASCII string, for example: "720P-60", "1080I-60". This information is -intended for the user. - - - __u32 - width - Width of the active video in pixels for the DV preset. - - - __u32 - height - Height of the active video in lines for the DV preset. - - - __u32 - reserved[4] - Reserved for future extensions. Drivers must set the array to zero. - - - -
- - - struct <structname>DV Presets</structname> - - &cs-str; - - - Preset - Preset value - Description - - - - - - - - V4L2_DV_INVALID - 0 - Invalid preset value. - - - V4L2_DV_480P59_94 - 1 - 720x480 progressive video at 59.94 fps as per BT.1362. - - - V4L2_DV_576P50 - 2 - 720x576 progressive video at 50 fps as per BT.1362. - - - V4L2_DV_720P24 - 3 - 1280x720 progressive video at 24 fps as per SMPTE 296M. - - - V4L2_DV_720P25 - 4 - 1280x720 progressive video at 25 fps as per SMPTE 296M. - - - V4L2_DV_720P30 - 5 - 1280x720 progressive video at 30 fps as per SMPTE 296M. - - - V4L2_DV_720P50 - 6 - 1280x720 progressive video at 50 fps as per SMPTE 296M. - - - V4L2_DV_720P59_94 - 7 - 1280x720 progressive video at 59.94 fps as per SMPTE 274M. - - - V4L2_DV_720P60 - 8 - 1280x720 progressive video at 60 fps as per SMPTE 274M/296M. - - - V4L2_DV_1080I29_97 - 9 - 1920x1080 interlaced video at 29.97 fps as per BT.1120/SMPTE 274M. - - - V4L2_DV_1080I30 - 10 - 1920x1080 interlaced video at 30 fps as per BT.1120/SMPTE 274M. - - - V4L2_DV_1080I25 - 11 - 1920x1080 interlaced video at 25 fps as per BT.1120. - - - V4L2_DV_1080I50 - 12 - 1920x1080 interlaced video at 50 fps as per SMPTE 296M. - - - V4L2_DV_1080I60 - 13 - 1920x1080 interlaced video at 60 fps as per SMPTE 296M. - - - V4L2_DV_1080P24 - 14 - 1920x1080 progressive video at 24 fps as per SMPTE 296M. - - - V4L2_DV_1080P25 - 15 - 1920x1080 progressive video at 25 fps as per SMPTE 296M. - - - V4L2_DV_1080P30 - 16 - 1920x1080 progressive video at 30 fps as per SMPTE 296M. - - - V4L2_DV_1080P50 - 17 - 1920x1080 progressive video at 50 fps as per BT.1120. - - - V4L2_DV_1080P60 - 18 - 1920x1080 progressive video at 60 fps as per BT.1120. - - - -
-
- - - &return-value; - - - - EINVAL - - The &v4l2-dv-enum-preset; index -is out of bounds. - - - - ENODATA - - Digital video presets are not supported for this input or output. - - - - -
diff --git a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml index 3c9a813..493a39a 100644 --- a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml @@ -278,11 +278,6 @@ input/output interface to linux-media@vger.kernel.org on 19 Oct 2009. &cs-def; - V4L2_IN_CAP_PRESETS - 0x00000001 - This input supports setting DV presets by using VIDIOC_S_DV_PRESET. - - V4L2_IN_CAP_DV_TIMINGS 0x00000002 This input supports setting video timings by using VIDIOC_S_DV_TIMINGS. diff --git a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml index f4ab079..2654e09 100644 --- a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml +++ b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml @@ -163,11 +163,6 @@ input/output interface to linux-media@vger.kernel.org on 19 Oct 2009. &cs-def; - V4L2_OUT_CAP_PRESETS - 0x00000001 - This output supports setting DV presets by using VIDIOC_S_DV_PRESET. - - V4L2_OUT_CAP_DV_TIMINGS 0x00000002 This output supports setting video timings by using VIDIOC_S_DV_TIMINGS. diff --git a/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml b/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml deleted file mode 100644 index b9ea376..0000000 --- a/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml +++ /dev/null @@ -1,113 +0,0 @@ - - - ioctl VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET - &manvol; - - - - VIDIOC_G_DV_PRESET - VIDIOC_S_DV_PRESET - Query or select the DV preset of the current input or output - - - - - - int ioctl - int fd - int request - struct v4l2_dv_preset *argp - - - - - - Arguments - - - - fd - - &fd; - - - - request - - VIDIOC_G_DV_PRESET, VIDIOC_S_DV_PRESET - - - - argp - - - - - - - - - Description - - These ioctls are deprecated. - New drivers and applications should use &VIDIOC-G-DV-TIMINGS; and &VIDIOC-S-DV-TIMINGS; - instead. - - - To query and select the current DV preset, applications -use the VIDIOC_G_DV_PRESET and VIDIOC_S_DV_PRESET -ioctls which take a pointer to a &v4l2-dv-preset; type as argument. -Applications must zero the reserved array in &v4l2-dv-preset;. -VIDIOC_G_DV_PRESET returns a dv preset in the field -preset of &v4l2-dv-preset;. - - VIDIOC_S_DV_PRESET accepts a pointer to a &v4l2-dv-preset; -that has the preset value to be set. Applications must zero the reserved array in &v4l2-dv-preset;. -If the preset is not supported, it returns an &EINVAL; - - - - &return-value; - - - - EINVAL - - This ioctl is not supported, or the -VIDIOC_S_DV_PRESET,VIDIOC_S_DV_PRESET parameter was unsuitable. - - - - ENODATA - - Digital video presets are not supported for this input or output. - - - - EBUSY - - The device is busy and therefore can not change the preset. - - - - - - struct <structname>v4l2_dv_preset</structname> - - &cs-str; - - - __u32 - preset - Preset value to represent the digital video timings - - - __u32 - reserved[4] - Reserved fields for future use - - - -
-
-
diff --git a/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml b/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml deleted file mode 100644 index 68b49d0..0000000 --- a/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - ioctl VIDIOC_QUERY_DV_PRESET - &manvol; - - - - VIDIOC_QUERY_DV_PRESET - Sense the DV preset received by the current -input - - - - - - int ioctl - int fd - int request - struct v4l2_dv_preset *argp - - - - - - Arguments - - - - fd - - &fd; - - - - request - - VIDIOC_QUERY_DV_PRESET - - - - argp - - - - - - - - - Description - - This ioctl is deprecated. - New drivers and applications should use &VIDIOC-QUERY-DV-TIMINGS; instead. - - - The hardware may be able to detect the current DV preset -automatically, similar to sensing the video standard. To do so, applications -call VIDIOC_QUERY_DV_PRESET with a pointer to a -&v4l2-dv-preset; type. Once the hardware detects a preset, that preset is -returned in the preset field of &v4l2-dv-preset;. If the preset could not be -detected because there was no signal, or the signal was unreliable, or the -signal did not map to a supported preset, then the value V4L2_DV_INVALID is -returned. - - - - &return-value; - - - - ENODATA - - Digital video presets are not supported for this input or output. - - - - - -- cgit v0.10.2 From 81b8cd9284945a323009482418c3d80de1d59d25 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Feb 2013 15:22:56 -0300 Subject: [media] videodev2.h: remove obsolete DV_PRESET API This API is now obsolete and can be removed. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index b5f5cdd..9d57dba 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -981,52 +981,6 @@ struct v4l2_standard { __u32 reserved[4]; }; -/* The DV Preset API is deprecated in favor of the DV Timings API. - New drivers shouldn't use this anymore! */ - -/* - * V I D E O T I M I N G S D V P R E S E T - */ -struct v4l2_dv_preset { - __u32 preset; - __u32 reserved[4]; -}; - -/* - * D V P R E S E T S E N U M E R A T I O N - */ -struct v4l2_dv_enum_preset { - __u32 index; - __u32 preset; - __u8 name[32]; /* Name of the preset timing */ - __u32 width; - __u32 height; - __u32 reserved[4]; -}; - -/* - * D V P R E S E T V A L U E S - */ -#define V4L2_DV_INVALID 0 -#define V4L2_DV_480P59_94 1 /* BT.1362 */ -#define V4L2_DV_576P50 2 /* BT.1362 */ -#define V4L2_DV_720P24 3 /* SMPTE 296M */ -#define V4L2_DV_720P25 4 /* SMPTE 296M */ -#define V4L2_DV_720P30 5 /* SMPTE 296M */ -#define V4L2_DV_720P50 6 /* SMPTE 296M */ -#define V4L2_DV_720P59_94 7 /* SMPTE 274M */ -#define V4L2_DV_720P60 8 /* SMPTE 274M/296M */ -#define V4L2_DV_1080I29_97 9 /* BT.1120/ SMPTE 274M */ -#define V4L2_DV_1080I30 10 /* BT.1120/ SMPTE 274M */ -#define V4L2_DV_1080I25 11 /* BT.1120 */ -#define V4L2_DV_1080I50 12 /* SMPTE 296M */ -#define V4L2_DV_1080I60 13 /* SMPTE 296M */ -#define V4L2_DV_1080P24 14 /* SMPTE 296M */ -#define V4L2_DV_1080P25 15 /* SMPTE 296M */ -#define V4L2_DV_1080P30 16 /* SMPTE 296M */ -#define V4L2_DV_1080P50 17 /* BT.1120 */ -#define V4L2_DV_1080P60 18 /* BT.1120 */ - /* * D V B T T I M I N G S */ @@ -1240,7 +1194,6 @@ struct v4l2_input { #define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ /* capabilities flags */ -#define V4L2_IN_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ #define V4L2_IN_CAP_DV_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ #define V4L2_IN_CAP_CUSTOM_TIMINGS V4L2_IN_CAP_DV_TIMINGS /* For compatibility */ #define V4L2_IN_CAP_STD 0x00000004 /* Supports S_STD */ @@ -1264,7 +1217,6 @@ struct v4l2_output { #define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 /* capabilities flags */ -#define V4L2_OUT_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ #define V4L2_OUT_CAP_DV_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ #define V4L2_OUT_CAP_CUSTOM_TIMINGS V4L2_OUT_CAP_DV_TIMINGS /* For compatibility */ #define V4L2_OUT_CAP_STD 0x00000004 /* Supports S_STD */ @@ -1981,12 +1933,6 @@ struct v4l2_create_buffers { #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) -/* These four DV Preset ioctls are deprecated in favor of the DV Timings - ioctls. */ -#define VIDIOC_ENUM_DV_PRESETS _IOWR('V', 83, struct v4l2_dv_enum_preset) -#define VIDIOC_S_DV_PRESET _IOWR('V', 84, struct v4l2_dv_preset) -#define VIDIOC_G_DV_PRESET _IOWR('V', 85, struct v4l2_dv_preset) -#define VIDIOC_QUERY_DV_PRESET _IOR('V', 86, struct v4l2_dv_preset) #define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings) #define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings) #define VIDIOC_DQEVENT _IOR('V', 89, struct v4l2_event) -- cgit v0.10.2 From 4e5f1130070ebfdde1b0ea6277e881404e5f34ce Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 24 Mar 2013 06:08:00 -0300 Subject: [media] DocBook/media/v4l: Update version number and document 3.10 changes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index effa509..5dab338 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2493,6 +2493,19 @@ that used it. It was originally scheduled for removal in 2.6.35.
+
+ V4L2 in Linux 3.10 + + + Removed 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. + + + +
+
Relation of V4L2 to other Linux multimedia APIs diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 32a10ee..dae009a 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -124,6 +124,7 @@ Remote Controller chapter. 2010 2011 2012 + 2013 Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab, Pawel Osciak @@ -140,6 +141,17 @@ structs, ioctls) must be noted in more detail in the history chapter applications. --> + 3.10 + 2013-03-24 + hv + 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. + + + + 3.9 2012-12-03 sa, sn -- cgit v0.10.2 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 diff --git a/drivers/media/i2c/sony-btf-mpx.c b/drivers/media/i2c/sony-btf-mpx.c index bc73e8f..38cbea9 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 v0.10.2 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 diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c index c46d2e8..85bc314 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 9e2fa41..db40835 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index db40835..704f283 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 v0.10.2 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 diff --git a/drivers/media/i2c/tw9906.c b/drivers/media/i2c/tw9906.c index 2263a91..d94325b 100644 --- a/drivers/media/i2c/tw9906.c +++ b/drivers/media/i2c/tw9906.c @@ -17,7 +17,6 @@ #include #include -#include #include #include #include -- cgit v0.10.2 From 0a522228c1105de7b898bbacc703d5d6191767a8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Mar 2013 06:18:04 -0300 Subject: [media] saa7134-go7007: convert to a subdev and the control framework The only thing missing after this to make the Sensoray model 614 board work is to hook it up to the saa7134 driver, but that will have to wait until this driver goes out of staging. Signed-off-by: Pete Eberlein [hans.verkuil@cisco.com: updated to make it merge correctly] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/Makefile b/drivers/staging/media/go7007/Makefile index 507d012..bbc8a32 100644 --- a/drivers/staging/media/go7007/Makefile +++ b/drivers/staging/media/go7007/Makefile @@ -10,7 +10,7 @@ s2250-y := s2250-board.o # Uncomment when the saa7134 patches get into upstream #obj-$(CONFIG_VIDEO_SAA7134) += saa7134-go7007.o -#ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/video/saa7134 -DSAA7134_MPEG_GO7007=3 +#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 diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c index aee9ace..7ccbfe7 100644 --- a/drivers/staging/media/go7007/saa7134-go7007.c +++ b/drivers/staging/media/go7007/saa7134-go7007.c @@ -28,12 +28,15 @@ #include #include #include +#include +#include -#include "saa7134-reg.h" #include "saa7134.h" +#include "saa7134-reg.h" +#include "go7007.h" #include "go7007-priv.h" -#define GO7007_HPI_DEBUG +/*#define GO7007_HPI_DEBUG*/ enum hpi_address { HPI_ADDR_VIDEO_BUFFER = 0xe4, @@ -57,6 +60,7 @@ enum gpio_command { }; struct saa7134_go7007 { + struct v4l2_subdev sd; struct saa7134_dev *dev; u8 *top; u8 *bottom; @@ -64,6 +68,11 @@ struct saa7134_go7007 { dma_addr_t bottom_dma; }; +static inline struct saa7134_go7007 *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct saa7134_go7007, sd); +} + static const struct go7007_board_info board_voyager = { .flags = 0, .sensor_flags = GO7007_SENSOR_656 | @@ -83,7 +92,6 @@ static const struct go7007_board_info board_voyager = { }, }, }; -MODULE_FIRMWARE("go7007tv.bin"); /********************* Driver for GPIO HPI interface *********************/ @@ -379,47 +387,6 @@ static int saa7134_go7007_send_firmware(struct go7007 *go, u8 *data, int len) return 0; } -static int saa7134_go7007_send_command(struct go7007 *go, unsigned int cmd, - void *arg) -{ - struct saa7134_go7007 *saa = go->hpi_context; - struct saa7134_dev *dev = saa->dev; - - switch (cmd) { - case VIDIOC_S_STD: - { - v4l2_std_id *std = arg; - return saa7134_s_std_internal(dev, NULL, std); - } - case VIDIOC_G_STD: - { - v4l2_std_id *std = arg; - *std = dev->tvnorm->id; - return 0; - } - case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *ctrl = arg; - if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER) - return saa7134_queryctrl(NULL, NULL, ctrl); - } - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER) - return saa7134_g_ctrl_internal(dev, NULL, ctrl); - } - case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_USER) - return saa7134_s_ctrl_internal(dev, NULL, ctrl); - } - } - return -EINVAL; - -} - static struct go7007_hpi_ops saa7134_go7007_hpi_ops = { .interface_reset = saa7134_go7007_interface_reset, .write_interrupt = saa7134_go7007_write_interrupt, @@ -427,16 +394,63 @@ static struct go7007_hpi_ops saa7134_go7007_hpi_ops = { .stream_start = saa7134_go7007_stream_start, .stream_stop = saa7134_go7007_stream_stop, .send_firmware = saa7134_go7007_send_firmware, - .send_command = saa7134_go7007_send_command, }; MODULE_FIRMWARE("go7007/go7007tv.bin"); +/* --------------------------------------------------------------------------*/ + +static int saa7134_go7007_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) +{ + struct saa7134_go7007 *saa = to_state(sd); + struct saa7134_dev *dev = saa->dev; + + return saa7134_s_std_internal(dev, NULL, norm); +} + +static int saa7134_go7007_queryctrl(struct v4l2_subdev *sd, + struct v4l2_queryctrl *query) +{ + return saa7134_queryctrl(NULL, NULL, query); +} +static int saa7134_go7007_s_ctrl(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + struct saa7134_go7007 *saa = to_state(sd); + struct saa7134_dev *dev = saa->dev; + return saa7134_s_ctrl_internal(dev, NULL, ctrl); +} + +static int saa7134_go7007_g_ctrl(struct v4l2_subdev *sd, + struct v4l2_control *ctrl) +{ + struct saa7134_go7007 *saa = to_state(sd); + struct saa7134_dev *dev = saa->dev; + return saa7134_g_ctrl_internal(dev, NULL, ctrl); +} + +/* --------------------------------------------------------------------------*/ + +static const struct v4l2_subdev_core_ops saa7134_go7007_core_ops = { + .g_ctrl = saa7134_go7007_g_ctrl, + .s_ctrl = saa7134_go7007_s_ctrl, + .queryctrl = saa7134_go7007_queryctrl, + .s_std = saa7134_go7007_s_std, +}; + +static const struct v4l2_subdev_ops saa7134_go7007_sd_ops = { + .core = &saa7134_go7007_core_ops, +}; + +/* --------------------------------------------------------------------------*/ + + /********************* Add/remove functions *********************/ static int saa7134_go7007_init(struct saa7134_dev *dev) { struct go7007 *go; struct saa7134_go7007 *saa; + struct v4l2_subdev *sd; printk(KERN_DEBUG "saa7134-go7007: probing new SAA713X board\n"); @@ -444,6 +458,12 @@ static int saa7134_go7007_init(struct saa7134_dev *dev) if (saa == NULL) return -ENOMEM; + /* Init the subdevice interface */ + sd = &saa->sd; + v4l2_subdev_init(sd, &saa7134_go7007_sd_ops); + v4l2_set_subdevdata(sd, saa); + strncpy(sd->name, "saa7134-go7007", sizeof(sd->name)); + /* Allocate a couple pages for receiving the compressed stream */ saa->top = (u8 *)get_zeroed_page(GFP_KERNEL); if (!saa->top) @@ -471,8 +491,12 @@ static int saa7134_go7007_init(struct saa7134_dev *dev) * V4L2 and ALSA interfaces */ if (go7007_register_encoder(go, go->board_info->num_i2c_devs) < 0) goto initfail; + + /* Register the subdevice interface with the go7007 device */ + if (v4l2_device_register_subdev(&go->v4l2_dev, sd) < 0) + printk(KERN_INFO "saa7134-go7007: register subdev failed\n"); + dev->empress_dev = &go->vdev; - video_set_drvdata(dev->empress_dev, go); go->status = STATUS_ONLINE; return 0; @@ -506,6 +530,7 @@ static int saa7134_go7007_fini(struct saa7134_dev *dev) go->status = STATUS_SHUTDOWN; free_page((unsigned long)saa->top); free_page((unsigned long)saa->bottom); + v4l2_device_unregister_subdev(&saa->sd); kfree(saa); video_unregister_device(&go->vdev); -- cgit v0.10.2 From 7118b4431b185a101e700ac79fa011000b2b71c3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Mar 2013 06:52:19 -0300 Subject: [media] go7007: update the README Include the patch required to add support for the go7007 to saa7134. To be applied once the driver is moved out of staging. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/README b/drivers/staging/media/go7007/README index aeba132..3af0d90 100644 --- a/drivers/staging/media/go7007/README +++ b/drivers/staging/media/go7007/README @@ -1,11 +1,137 @@ Todo: - - checkpatch.pl cleanups - - sparse cleanups - - lots of little modules, should be merged together - and added to the build. - - testing? - - handle churn in v4l layer. + - create an API for motion detection + - let s2250-board use i2c subdevs as well instead of hardcoding + support for the i2c devices. + - when the driver is moved out of staging, support for saa7134-go7007 + should be added to the saa7134 driver. The patch for that is + included below. -Please send patches to Greg Kroah-Hartman and Cc: Ross -Cohen as well. +Patch for saa7134: +diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c +index dc68cf1..9a53794 100644 +--- a/drivers/media/pci/saa7134/saa7134-cards.c ++++ b/drivers/media/pci/saa7134/saa7134-cards.c +@@ -5790,6 +5790,29 @@ struct saa7134_board saa7134_boards[] = { + .gpio = 0x6010000, + } }, + }, ++ [SAA7134_BOARD_WIS_VOYAGER] = { ++ .name = "WIS Voyager or compatible", ++ .audio_clock = 0x00200000, ++ .tuner_type = TUNER_PHILIPS_TDA8290, ++ .radio_type = UNSET, ++ .tuner_addr = ADDR_UNSET, ++ .radio_addr = ADDR_UNSET, ++ .mpeg = SAA7134_MPEG_GO7007, ++ .inputs = { { ++ .name = name_comp1, ++ .vmux = 0, ++ .amux = LINE2, ++ }, { ++ .name = name_tv, ++ .vmux = 3, ++ .amux = TV, ++ .tv = 1, ++ }, { ++ .name = name_svideo, ++ .vmux = 6, ++ .amux = LINE1, ++ } }, ++ }, + + }; + +@@ -7037,6 +7060,12 @@ struct pci_device_id saa7134_pci_tbl[] = { + .subdevice = 0x0911, + .driver_data = SAA7134_BOARD_SENSORAY811_911, + }, { ++ .vendor = PCI_VENDOR_ID_PHILIPS, ++ .device = PCI_DEVICE_ID_PHILIPS_SAA7133, ++ .subvendor = 0x1905, /* WIS */ ++ .subdevice = 0x7007, ++ .driver_data = SAA7134_BOARD_WIS_VOYAGER, ++ }, { + /* --- boards without eeprom + subsystem ID --- */ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, +diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c +index 8fd24e7..0a849ea 100644 +--- a/drivers/media/pci/saa7134/saa7134-core.c ++++ b/drivers/media/pci/saa7134/saa7134-core.c +@@ -156,6 +156,8 @@ static void request_module_async(struct work_struct *work){ + request_module("saa7134-empress"); + if (card_is_dvb(dev)) + request_module("saa7134-dvb"); ++ if (card_is_go7007(dev)) ++ request_module("saa7134-go7007"); + if (alsa) { + if (dev->pci->device != PCI_DEVICE_ID_PHILIPS_SAA7130) + request_module("saa7134-alsa"); +@@ -557,8 +559,12 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id) + saa7134_irq_vbi_done(dev,status); + + if ((report & SAA7134_IRQ_REPORT_DONE_RA2) && +- card_has_mpeg(dev)) +- saa7134_irq_ts_done(dev,status); ++ card_has_mpeg(dev)) { ++ if (dev->mops->irq_ts_done != NULL) ++ dev->mops->irq_ts_done(dev, status); ++ else ++ saa7134_irq_ts_done(dev, status); ++ } + + if (report & SAA7134_IRQ_REPORT_GPIO16) { + switch (dev->has_remote) { +diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h +index 62169dd..5fad39a 100644 +--- a/drivers/media/pci/saa7134/saa7134.h ++++ b/drivers/media/pci/saa7134/saa7134.h +@@ -334,6 +334,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_WIS_VOYAGER 192 + + #define SAA7134_MAXBOARDS 32 + #define SAA7134_INPUT_MAX 8 +@@ -364,6 +365,7 @@ enum saa7134_mpeg_type { + SAA7134_MPEG_UNUSED, + SAA7134_MPEG_EMPRESS, + SAA7134_MPEG_DVB, ++ SAA7134_MPEG_GO7007, + }; + + enum saa7134_mpeg_ts_type { +@@ -403,6 +405,7 @@ struct saa7134_board { + #define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name) + #define card_is_empress(dev) (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg) + #define card_is_dvb(dev) (SAA7134_MPEG_DVB == saa7134_boards[dev->board].mpeg) ++#define card_is_go7007(dev) (SAA7134_MPEG_GO7007 == saa7134_boards[dev->board].mpeg) + #define card_has_mpeg(dev) (SAA7134_MPEG_UNUSED != saa7134_boards[dev->board].mpeg) + #define card(dev) (saa7134_boards[dev->board]) + #define card_in(dev,n) (saa7134_boards[dev->board].inputs[n]) +@@ -535,6 +538,8 @@ struct saa7134_mpeg_ops { + int (*init)(struct saa7134_dev *dev); + int (*fini)(struct saa7134_dev *dev); + void (*signal_change)(struct saa7134_dev *dev); ++ void (*irq_ts_done)(struct saa7134_dev *dev, ++ unsigned long status); + }; + + /* global device status */ +diff --git a/drivers/staging/media/go7007/Makefile b/drivers/staging/media/go7007/Makefile +index 9c6ad4a..1b23689 100644 +--- a/drivers/staging/media/go7007/Makefile ++++ b/drivers/staging/media/go7007/Makefile +@@ -8,8 +8,7 @@ go7007-y := go7007-v4l2.o go7007-driver.o go7007-i2c.o go7007-fw.o \ + + s2250-y := s2250-board.o + +-# Uncomment when the saa7134 patches get into upstream +-#obj-$(CONFIG_VIDEO_SAA7134) += saa7134-go7007.o +-#ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/pci/saa7134 ++obj-$(CONFIG_VIDEO_SAA7134) += saa7134-go7007.o ++ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/pci/saa7134 + + ccflags-$(CONFIG_VIDEO_GO7007_LOADER:m=y) += -Idrivers/media/common -- cgit v0.10.2 From 59aea928d57f171453474a883f087e4fccb83e94 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 17 Mar 2013 09:23:25 -0300 Subject: [media] go7007: don't continue if firmware can't be loaded The go7007 driver would continue during probe if no firmware could be loaded. Without firmware the probe() should return an error, so do that. Also move the registration of devices to the end of the probe() sequence: once devices appear the full driver functionality should be available. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index 0823506..a734ead 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -930,7 +930,11 @@ static void go7007_usb_release(struct go7007 *go) struct urb *vurb, *aurb; int i; - usb_kill_urb(usb->intr_urb); + if (usb->intr_urb) { + usb_kill_urb(usb->intr_urb); + kfree(usb->intr_urb->transfer_buffer); + usb_free_urb(usb->intr_urb); + } /* Free USB-related structs */ for (i = 0; i < 8; ++i) { @@ -947,8 +951,6 @@ static void go7007_usb_release(struct go7007 *go) usb_free_urb(aurb); } } - kfree(usb->intr_urb->transfer_buffer); - usb_free_urb(usb->intr_urb); kfree(go->hpi_context); } @@ -1141,21 +1143,16 @@ static int go7007_usb_probe(struct usb_interface *intf, return 0; } - usb = kzalloc(sizeof(struct go7007_usb), GFP_KERNEL); - if (usb == NULL) + go = go7007_alloc(&board->main_info, &intf->dev); + if (go == NULL) return -ENOMEM; - /* Allocate the URB and buffer for receiving incoming interrupts */ - usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL); - if (usb->intr_urb == NULL) - goto allocfail; - usb->intr_urb->transfer_buffer = kmalloc(2*sizeof(u16), GFP_KERNEL); - if (usb->intr_urb->transfer_buffer == NULL) - goto allocfail; + usb = kzalloc(sizeof(struct go7007_usb), GFP_KERNEL); + if (usb == NULL) { + kfree(go); + return -ENOMEM; + } - go = go7007_alloc(&board->main_info, &intf->dev); - if (go == NULL) - goto allocfail; usb->board = board; usb->usbdev = usbdev; usb_make_path(usbdev, go->bus_info, sizeof(go->bus_info)); @@ -1166,6 +1163,15 @@ static int go7007_usb_probe(struct usb_interface *intf, else go->hpi_ops = &go7007_usb_onboard_hpi_ops; go->hpi_context = usb; + + /* Allocate the URB and buffer for receiving incoming interrupts */ + usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL); + if (usb->intr_urb == NULL) + goto allocfail; + usb->intr_urb->transfer_buffer = kmalloc(2*sizeof(u16), GFP_KERNEL); + if (usb->intr_urb->transfer_buffer == NULL) + goto allocfail; + if (go->board_id == GO7007_BOARDID_SENSORAY_2250) usb_fill_bulk_urb(usb->intr_urb, usb->usbdev, usb_rcvbulkpipe(usb->usbdev, 4), @@ -1181,7 +1187,7 @@ static int go7007_usb_probe(struct usb_interface *intf, /* Boot the GO7007 */ if (go7007_boot_encoder(go, go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) < 0) - goto initfail; + goto allocfail; /* Register the EZ-USB I2C adapter, if we're using it */ if (board->flags & GO7007_USB_EZUSB_I2C) { @@ -1193,7 +1199,7 @@ static int go7007_usb_probe(struct usb_interface *intf, if (i2c_add_adapter(&go->i2c_adapter) < 0) { printk(KERN_ERR "go7007-usb: error: i2c_add_adapter failed\n"); - goto initfail; + goto allocfail; } go->i2c_adapter_online = 1; } @@ -1244,7 +1250,7 @@ static int go7007_usb_probe(struct usb_interface *intf, /* Board strapping indicates tuner model */ if (go7007_usb_vendor_request(go, 0x41, 0, 0, go->usb_buf, 3, 1) < 0) { printk(KERN_ERR "go7007-usb: GPIO read failed!\n"); - goto initfail; + goto allocfail; } switch (go->usb_buf[0] >> 6) { case 1: @@ -1276,7 +1282,7 @@ static int go7007_usb_probe(struct usb_interface *intf, if (go7007_usb_vendor_request(go, 0x40, 0x7f02, 0, NULL, 0, 0) < 0) { printk(KERN_ERR "go7007-usb: GPIO write failed!\n"); - goto initfail; + goto allocfail; } } @@ -1290,11 +1296,6 @@ static int go7007_usb_probe(struct usb_interface *intf, "port will result in stream corruption, even " "at low bitrates!\n"); - /* Do any final GO7007 initialization, then register the - * V4L2 and ALSA interfaces */ - if (go7007_register_encoder(go, num_i2c_devs) < 0) - goto initfail; - /* Allocate the URBs and buffers for receiving the video stream */ if (board->flags & GO7007_USB_EZUSB) { v_urb_len = 1024; @@ -1306,46 +1307,45 @@ static int go7007_usb_probe(struct usb_interface *intf, for (i = 0; i < 8; ++i) { usb->video_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); if (usb->video_urbs[i] == NULL) - goto initfail; + goto allocfail; usb->video_urbs[i]->transfer_buffer = kmalloc(v_urb_len, GFP_KERNEL); if (usb->video_urbs[i]->transfer_buffer == NULL) - goto initfail; + goto allocfail; usb_fill_bulk_urb(usb->video_urbs[i], usb->usbdev, video_pipe, usb->video_urbs[i]->transfer_buffer, v_urb_len, go7007_usb_read_video_pipe_complete, go); } /* Allocate the URBs and buffers for receiving the audio stream */ - if ((board->flags & GO7007_USB_EZUSB) && go->audio_enabled) + if ((board->flags & GO7007_USB_EZUSB) && + (board->flags & GO7007_BOARD_HAS_AUDIO)) { for (i = 0; i < 8; ++i) { usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL); if (usb->audio_urbs[i] == NULL) - goto initfail; + goto allocfail; usb->audio_urbs[i]->transfer_buffer = kmalloc(4096, GFP_KERNEL); if (usb->audio_urbs[i]->transfer_buffer == NULL) - goto initfail; + goto allocfail; usb_fill_bulk_urb(usb->audio_urbs[i], usb->usbdev, usb_rcvbulkpipe(usb->usbdev, 8), usb->audio_urbs[i]->transfer_buffer, 4096, go7007_usb_read_audio_pipe_complete, go); } + } + /* Do any final GO7007 initialization, then register the + * V4L2 and ALSA interfaces */ + if (go7007_register_encoder(go, num_i2c_devs) < 0) + goto allocfail; go->status = STATUS_ONLINE; return 0; -initfail: - go->status = STATUS_SHUTDOWN; - return 0; - allocfail: - if (usb->intr_urb) { - kfree(usb->intr_urb->transfer_buffer); - usb_free_urb(usb->intr_urb); - } - kfree(usb); + go7007_usb_release(go); + kfree(go); return -ENOMEM; } diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c index 7ccbfe7..d35d5c2 100644 --- a/drivers/staging/media/go7007/saa7134-go7007.c +++ b/drivers/staging/media/go7007/saa7134-go7007.c @@ -454,9 +454,22 @@ static int saa7134_go7007_init(struct saa7134_dev *dev) printk(KERN_DEBUG "saa7134-go7007: probing new SAA713X board\n"); + go = go7007_alloc(&board_voyager, &dev->pci->dev); + if (go == NULL) + return -ENOMEM; + saa = kzalloc(sizeof(struct saa7134_go7007), GFP_KERNEL); - if (saa == NULL) + if (saa == NULL) { + kfree(go); return -ENOMEM; + } + + go->board_id = GO7007_BOARDID_PCI_VOYAGER; + snprintf(go->bus_info, sizeof(go->bus_info), "PCI:%s", pci_name(dev->pci)); + strncpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name)); + go->hpi_ops = &saa7134_go7007_hpi_ops; + go->hpi_context = saa; + saa->dev = dev; /* Init the subdevice interface */ sd = &saa->sd; @@ -472,25 +485,15 @@ static int saa7134_go7007_init(struct saa7134_dev *dev) if (!saa->bottom) goto allocfail; - go = go7007_alloc(&board_voyager, &dev->pci->dev); - if (go == NULL) - goto allocfail; - go->board_id = GO7007_BOARDID_PCI_VOYAGER; - snprintf(go->bus_info, sizeof(go->bus_info), "PCI:%s", pci_name(dev->pci)); - strncpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name)); - go->hpi_ops = &saa7134_go7007_hpi_ops; - go->hpi_context = saa; - saa->dev = dev; - /* Boot the GO7007 */ if (go7007_boot_encoder(go, go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) < 0) - goto initfail; + goto allocfail; /* Do any final GO7007 initialization, then register the * V4L2 and ALSA interfaces */ if (go7007_register_encoder(go, go->board_info->num_i2c_devs) < 0) - goto initfail; + goto allocfail; /* Register the subdevice interface with the go7007 device */ if (v4l2_device_register_subdev(&go->v4l2_dev, sd) < 0) @@ -501,16 +504,13 @@ static int saa7134_go7007_init(struct saa7134_dev *dev) go->status = STATUS_ONLINE; return 0; -initfail: - go->status = STATUS_SHUTDOWN; - return 0; - allocfail: if (saa->top) free_page((unsigned long)saa->top); if (saa->bottom) free_page((unsigned long)saa->bottom); kfree(saa); + kfree(go); return -ENOMEM; } -- cgit v0.10.2 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 diff --git a/drivers/media/i2c/tw9903.c b/drivers/media/i2c/tw9903.c index f0d0ef5..87880b1 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 d94325b..accd79e 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 v0.10.2 From 70f31c91e12c504b86ce67b2f92d11a19d1e262a Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Mon, 25 Mar 2013 02:22:19 -0300 Subject: [media] go7007: 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: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 24ba50e..50eb69a 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -17,7 +17,6 @@ #include #include -#include #include #include #include -- cgit v0.10.2 From 136d9f3a41bc528773430f2723cf27963bbd6fbc Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Mon, 25 Mar 2013 06:56:35 -0300 Subject: [media] go7007: using strlcpy instead of strncpy For NUL terminated string, need always set '\0' in the end. Signed-off-by: Chen Gang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c index d35d5c2..d80b235 100644 --- a/drivers/staging/media/go7007/saa7134-go7007.c +++ b/drivers/staging/media/go7007/saa7134-go7007.c @@ -466,7 +466,7 @@ static int saa7134_go7007_init(struct saa7134_dev *dev) go->board_id = GO7007_BOARDID_PCI_VOYAGER; snprintf(go->bus_info, sizeof(go->bus_info), "PCI:%s", pci_name(dev->pci)); - strncpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name)); + strlcpy(go->name, saa7134_boards[dev->board].name, sizeof(go->name)); go->hpi_ops = &saa7134_go7007_hpi_ops; go->hpi_context = saa; saa->dev = dev; -- cgit v0.10.2 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 diff --git a/drivers/media/i2c/tw2804.c b/drivers/media/i2c/tw2804.c index 441b766..c5dc2c3b 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 v0.10.2 From c535cc6c714bd21b3afad35baa926b3b9eb51361 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Mon, 25 Mar 2013 05:27:12 -0300 Subject: [media] staging: lirc_sir: remove dead code lirc_sir uses the CONFIG_SA1100_BITSY Kconfig macro. But its Kconfig symbol was removed in v2.4.13. So remove dead code associated with it. Signed-off-by: Paul Bolle Signed-off-by: Alexander Shiyan Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/lirc/lirc_sir.c b/drivers/staging/media/lirc/lirc_sir.c index 63a554c..f781c53 100644 --- a/drivers/staging/media/lirc/lirc_sir.c +++ b/drivers/staging/media/lirc/lirc_sir.c @@ -787,12 +787,6 @@ static int init_hardware(void) spin_lock_irqsave(&hardware_lock, flags); /* reset UART */ #ifdef LIRC_ON_SA1100 -#ifdef CONFIG_SA1100_BITSY - if (machine_is_bitsy()) { - pr_info("Power on IR module\n"); - set_bitsy_egpio(EGPIO_BITSY_IR_ON); - } -#endif #ifdef CONFIG_SA1100_COLLIE sa1100_irda_set_power_collie(3); /* power on */ #endif @@ -942,10 +936,6 @@ static void drop_hardware(void) Ser2UTCR3 = sr.utcr3; Ser2HSCR0 = sr.hscr0; -#ifdef CONFIG_SA1100_BITSY - if (machine_is_bitsy()) - clr_bitsy_egpio(EGPIO_BITSY_IR_ON); -#endif #ifdef CONFIG_SA1100_COLLIE sa1100_irda_set_power_collie(0); /* power off */ #endif -- cgit v0.10.2 From dcae5dacbce518513abf7776cb450b7bd95d722b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Mar 2013 05:35:17 -0300 Subject: [media] solo6x10: sync to latest code from Bluecherry's git repo Synced to commit e9815ac5503ae60cfbf6ff8037035de8f62e2846 from branch next in git repository https://github.com/bluecherrydvr/solo6x10.git Only removed some code under #if LINUX_VERSION_CODE < some-kernel-version, renamed the driver back to solo6x10 from solo6x10-edge, removed the unnecessary compat.h header and kept the slab.h includes. Otherwise the code is identical. Signed-off-by: Hans Verkuil Signed-off-by: Ismael Luceno Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/Makefile b/drivers/staging/media/solo6x10/Makefile index 337e38c..9bbde29 100644 --- a/drivers/staging/media/solo6x10/Makefile +++ b/drivers/staging/media/solo6x10/Makefile @@ -1,3 +1,3 @@ -solo6x10-y := core.o i2c.o p2m.o v4l2.o tw28.o gpio.o disp.o enc.o v4l2-enc.o g723.o +solo6x10-y := core.o i2c.o p2m.o v4l2.o tw28.o gpio.o disp.o enc.o v4l2-enc.o g723.o eeprom.o obj-$(CONFIG_SOLO6X10) += solo6x10.o diff --git a/drivers/staging/media/solo6x10/TODO b/drivers/staging/media/solo6x10/TODO index d09dd03..7b8db75 100644 --- a/drivers/staging/media/solo6x10/TODO +++ b/drivers/staging/media/solo6x10/TODO @@ -1,24 +1,15 @@ -TODO (staging => main): - - * Motion detection flags need to be moved to v4l2 - * Some private CIDs need to be moved to v4l2 - -TODO (general): - - * encoder on/off controls - * mpeg cid bitrate mode (vbr/cbr) - * mpeg cid bitrate/bitrate-peak - * mpeg encode of user data - * mpeg decode of user data - * switch between 4 frames/irq to 1 when using mjpeg (and then back - when not) - * implement a CID control for motion areas/thresholds - * implement CID controls for mozaic areas - * allow for higher level of interval (for < 1 fps) - * sound: - - implement playback via external sound jack - - implement loopback of external sound jack with incoming audio? - - implement pause/resume +- batch up desc requests for more efficient use of p2m? +- encoder on/off controls +- mpeg cid bitrate mode (vbr/cbr) +- mpeg cid bitrate/bitrate-peak +- mpeg encode of user data +- mpeg decode of user data +- implement CID controls for mozaic areas + +- sound + - implement playback via external sound jack + - implement loopback of external sound jack with incoming audio? + - implement pause/resume (make use of in bc-server) Please send patches to the linux media list and Cc Ismael Luceno . diff --git a/drivers/staging/media/solo6x10/core.c b/drivers/staging/media/solo6x10/core.c index fd83d6d..75d98cc 100644 --- a/drivers/staging/media/solo6x10/core.c +++ b/drivers/staging/media/solo6x10/core.c @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -21,29 +26,79 @@ #include #include #include -#include #include +#include +#include +#include +#include + #include "solo6x10.h" #include "tw28.h" -MODULE_DESCRIPTION("Softlogic 6x10 MP4/H.264 Encoder/Decoder V4L2/ALSA Driver"); -MODULE_AUTHOR("Ben Collins "); +MODULE_DESCRIPTION("Softlogic 6x10 MPEG4/H.264/G.723 CODEC V4L2/ALSA Driver"); +MODULE_AUTHOR("Bluecherry "); MODULE_VERSION(SOLO6X10_VERSION); MODULE_LICENSE("GPL"); -void solo_irq_on(struct solo_dev *solo_dev, u32 mask) +unsigned video_nr = -1; +module_param(video_nr, uint, 0644); +MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)"); + +static int full_eeprom; /* default is only top 64B */ +module_param(full_eeprom, uint, 0644); +MODULE_PARM_DESC(full_eeprom, "Allow access to full 128B EEPROM (dangerous)"); + + +static void solo_set_time(struct solo_dev *solo_dev) { - solo_dev->irq_mask |= mask; - solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask); + struct timespec ts; + + ktime_get_ts(&ts); + + solo_reg_write(solo_dev, SOLO_TIMER_SEC, ts.tv_sec); + solo_reg_write(solo_dev, SOLO_TIMER_USEC, ts.tv_nsec / NSEC_PER_USEC); } -void solo_irq_off(struct solo_dev *solo_dev, u32 mask) +static void solo_timer_sync(struct solo_dev *solo_dev) { - solo_dev->irq_mask &= ~mask; - solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask); + u32 sec, usec; + struct timespec ts; + long diff; + + if (solo_dev->type != SOLO_DEV_6110) + return; + + if (++solo_dev->time_sync < 60) + return; + + solo_dev->time_sync = 0; + + sec = solo_reg_read(solo_dev, SOLO_TIMER_SEC); + usec = solo_reg_read(solo_dev, SOLO_TIMER_USEC); + + ktime_get_ts(&ts); + + diff = (long)ts.tv_sec - (long)sec; + diff = (diff * 1000000) + + ((long)(ts.tv_nsec / NSEC_PER_USEC) - (long)usec); + + if (diff > 1000 || diff < -1000) { + solo_set_time(solo_dev); + } else if (diff) { + long usec_lsb = solo_dev->usec_lsb; + + usec_lsb -= diff / 4; + if (usec_lsb < 0) + usec_lsb = 0; + else if (usec_lsb > 255) + usec_lsb = 255; + + solo_dev->usec_lsb = usec_lsb; + solo_reg_write(solo_dev, SOLO_TIMER_USEC_LSB, + solo_dev->usec_lsb); + } } -/* XXX We should check the return value of the sub-device ISR's */ static irqreturn_t solo_isr(int irq, void *data) { struct solo_dev *solo_dev = data; @@ -60,11 +115,8 @@ static irqreturn_t solo_isr(int irq, void *data) status &= solo_dev->irq_mask; } - if (status & SOLO_IRQ_PCI_ERR) { - u32 err = solo_reg_read(solo_dev, SOLO_PCI_ERR); - solo_p2m_error_isr(solo_dev, err); - solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_PCI_ERR); - } + if (status & SOLO_IRQ_PCI_ERR) + solo_p2m_error_isr(solo_dev); for (i = 0; i < SOLO_NR_P2M; i++) if (status & SOLO_IRQ_P2M(i)) @@ -73,12 +125,10 @@ static irqreturn_t solo_isr(int irq, void *data) if (status & SOLO_IRQ_IIC) solo_i2c_isr(solo_dev); - if (status & SOLO_IRQ_VIDEO_IN) + if (status & SOLO_IRQ_VIDEO_IN) { solo_video_in_isr(solo_dev); - - /* Call this first so enc gets detected flag set */ - if (status & SOLO_IRQ_MOTION) - solo_motion_isr(solo_dev); + solo_timer_sync(solo_dev); + } if (status & SOLO_IRQ_ENCODER) solo_enc_v4l2_isr(solo_dev); @@ -86,6 +136,9 @@ static irqreturn_t solo_isr(int irq, void *data) if (status & SOLO_IRQ_G723) solo_g723_isr(solo_dev); + /* Clear all interrupts handled */ + solo_reg_write(solo_dev, SOLO_IRQ_STAT, status); + return IRQ_HANDLED; } @@ -96,6 +149,9 @@ static void free_solo_dev(struct solo_dev *solo_dev) if (!solo_dev) return; + if (solo_dev->dev.parent) + device_unregister(&solo_dev->dev); + pdev = solo_dev->pdev; /* If we never initialized the PCI device, then nothing else @@ -105,21 +161,22 @@ static void free_solo_dev(struct solo_dev *solo_dev) return; } - /* Bring down the sub-devices first */ - solo_g723_exit(solo_dev); - solo_enc_v4l2_exit(solo_dev); - solo_enc_exit(solo_dev); - solo_v4l2_exit(solo_dev); - solo_disp_exit(solo_dev); - solo_gpio_exit(solo_dev); - solo_p2m_exit(solo_dev); - solo_i2c_exit(solo_dev); - - /* Now cleanup the PCI device */ if (solo_dev->reg_base) { + /* Bring down the sub-devices first */ + solo_g723_exit(solo_dev); + solo_enc_v4l2_exit(solo_dev); + solo_enc_exit(solo_dev); + solo_v4l2_exit(solo_dev); + solo_disp_exit(solo_dev); + solo_gpio_exit(solo_dev); + solo_p2m_exit(solo_dev); + solo_i2c_exit(solo_dev); + + /* Now cleanup the PCI device */ solo_irq_off(solo_dev, ~0); pci_iounmap(pdev, solo_dev->reg_base); - free_irq(pdev->irq, solo_dev); + if (pdev->irq) + free_irq(pdev->irq, solo_dev); } pci_release_regions(pdev); @@ -129,29 +186,346 @@ static void free_solo_dev(struct solo_dev *solo_dev) kfree(solo_dev); } -static int solo_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) +static ssize_t eeprom_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + unsigned short *p = (unsigned short *)buf; + int i; + + if (count & 0x1) + dev_warn(dev, "EEPROM Write not aligned (truncating)\n"); + + if (!full_eeprom && count > 64) { + dev_warn(dev, "EEPROM Write truncated to 64 bytes\n"); + count = 64; + } else if (full_eeprom && count > 128) { + dev_warn(dev, "EEPROM Write truncated to 128 bytes\n"); + count = 128; + } + + solo_eeprom_ewen(solo_dev, 1); + + for (i = full_eeprom ? 0 : 32; i < min((int)(full_eeprom ? 64 : 32), + (int)(count / 2)); i++) + solo_eeprom_write(solo_dev, i, cpu_to_be16(p[i])); + + solo_eeprom_ewen(solo_dev, 0); + + return count; +} + +static ssize_t eeprom_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + unsigned short *p = (unsigned short *)buf; + int count = (full_eeprom ? 128 : 64); + int i; + + for (i = (full_eeprom ? 0 : 32); i < (count / 2); i++) + p[i] = be16_to_cpu(solo_eeprom_read(solo_dev, i)); + + return count; +} + +static ssize_t video_type_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return -EPERM; +} + +static ssize_t video_type_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + + return sprintf(buf, "%s", solo_dev->video_type == + SOLO_VO_FMT_TYPE_NTSC ? "NTSC" : "PAL"); +} + +static ssize_t p2m_timeouts_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + + return sprintf(buf, "%d\n", solo_dev->p2m_timeouts); +} + +static ssize_t sdram_size_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + + return sprintf(buf, "%dMegs\n", solo_dev->sdram_size >> 20); +} + +static ssize_t tw28xx_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + + return sprintf(buf, "tw2815[%d] tw2864[%d] tw2865[%d]\n", + hweight32(solo_dev->tw2815), + hweight32(solo_dev->tw2864), + hweight32(solo_dev->tw2865)); +} + +static ssize_t input_map_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + unsigned int val; + char *out = buf; + + val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_0); + out += sprintf(out, "Channel 0 => Input %d\n", val & 0x1f); + out += sprintf(out, "Channel 1 => Input %d\n", (val >> 5) & 0x1f); + out += sprintf(out, "Channel 2 => Input %d\n", (val >> 10) & 0x1f); + out += sprintf(out, "Channel 3 => Input %d\n", (val >> 15) & 0x1f); + out += sprintf(out, "Channel 4 => Input %d\n", (val >> 20) & 0x1f); + out += sprintf(out, "Channel 5 => Input %d\n", (val >> 25) & 0x1f); + + val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_1); + out += sprintf(out, "Channel 6 => Input %d\n", val & 0x1f); + out += sprintf(out, "Channel 7 => Input %d\n", (val >> 5) & 0x1f); + out += sprintf(out, "Channel 8 => Input %d\n", (val >> 10) & 0x1f); + out += sprintf(out, "Channel 9 => Input %d\n", (val >> 15) & 0x1f); + out += sprintf(out, "Channel 10 => Input %d\n", (val >> 20) & 0x1f); + out += sprintf(out, "Channel 11 => Input %d\n", (val >> 25) & 0x1f); + + val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_2); + out += sprintf(out, "Channel 12 => Input %d\n", val & 0x1f); + out += sprintf(out, "Channel 13 => Input %d\n", (val >> 5) & 0x1f); + out += sprintf(out, "Channel 14 => Input %d\n", (val >> 10) & 0x1f); + out += sprintf(out, "Channel 15 => Input %d\n", (val >> 15) & 0x1f); + out += sprintf(out, "Spot Output => Input %d\n", (val >> 20) & 0x1f); + + return out - buf; +} + +static ssize_t p2m_timeout_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + unsigned long ms; + + int ret = kstrtoul(buf, 10, &ms); + if (ret < 0 || ms > 200) + return -EINVAL; + solo_dev->p2m_jiffies = msecs_to_jiffies(ms); + + return count; +} + +static ssize_t p2m_timeout_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + + return sprintf(buf, "%ums\n", jiffies_to_msecs(solo_dev->p2m_jiffies)); +} + +static ssize_t intervals_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + char *out = buf; + int fps = solo_dev->fps; + int i; + + for (i = 0; i < solo_dev->nr_chans; i++) { + out += sprintf(out, "Channel %d: %d/%d (0x%08x)\n", + i, solo_dev->v4l2_enc[i]->interval, fps, + solo_reg_read(solo_dev, SOLO_CAP_CH_INTV(i))); + } + + return out - buf; +} + +static ssize_t sdram_offsets_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + char *out = buf; + + out += sprintf(out, "DISP: 0x%08x @ 0x%08x\n", + SOLO_DISP_EXT_ADDR, + SOLO_DISP_EXT_SIZE); + + out += sprintf(out, "EOSD: 0x%08x @ 0x%08x (0x%08x * %d)\n", + SOLO_EOSD_EXT_ADDR, + SOLO_EOSD_EXT_AREA(solo_dev), + SOLO_EOSD_EXT_SIZE(solo_dev), + SOLO_EOSD_EXT_AREA(solo_dev) / + SOLO_EOSD_EXT_SIZE(solo_dev)); + + out += sprintf(out, "MOTI: 0x%08x @ 0x%08x\n", + SOLO_MOTION_EXT_ADDR(solo_dev), + SOLO_MOTION_EXT_SIZE); + + out += sprintf(out, "G723: 0x%08x @ 0x%08x\n", + SOLO_G723_EXT_ADDR(solo_dev), + SOLO_G723_EXT_SIZE); + + out += sprintf(out, "CAPT: 0x%08x @ 0x%08x (0x%08x * %d)\n", + SOLO_CAP_EXT_ADDR(solo_dev), + SOLO_CAP_EXT_SIZE(solo_dev), + SOLO_CAP_PAGE_SIZE, + SOLO_CAP_EXT_SIZE(solo_dev) / SOLO_CAP_PAGE_SIZE); + + out += sprintf(out, "EREF: 0x%08x @ 0x%08x (0x%08x * %d)\n", + SOLO_EREF_EXT_ADDR(solo_dev), + SOLO_EREF_EXT_AREA(solo_dev), + SOLO_EREF_EXT_SIZE, + SOLO_EREF_EXT_AREA(solo_dev) / SOLO_EREF_EXT_SIZE); + + out += sprintf(out, "MPEG: 0x%08x @ 0x%08x\n", + SOLO_MP4E_EXT_ADDR(solo_dev), + SOLO_MP4E_EXT_SIZE(solo_dev)); + + out += sprintf(out, "JPEG: 0x%08x @ 0x%08x\n", + SOLO_JPEG_EXT_ADDR(solo_dev), + SOLO_JPEG_EXT_SIZE(solo_dev)); + + return out - buf; +} + +static ssize_t sdram_show(struct file *file, struct kobject *kobj, + struct bin_attribute *a, char *buf, + loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + const int size = solo_dev->sdram_size; + + if (off >= size) + return 0; + + if (off + count > size) + count = size - off; + + if (solo_p2m_dma(solo_dev, 0, buf, off, count, 0, 0)) + return -EIO; + + return count; +} + +static const struct device_attribute solo_dev_attrs[] = { + __ATTR(eeprom, 0640, eeprom_show, eeprom_store), + __ATTR(video_type, 0644, video_type_show, video_type_store), + __ATTR(p2m_timeout, 0644, p2m_timeout_show, p2m_timeout_store), + __ATTR_RO(p2m_timeouts), + __ATTR_RO(sdram_size), + __ATTR_RO(tw28xx), + __ATTR_RO(input_map), + __ATTR_RO(intervals), + __ATTR_RO(sdram_offsets), +}; + +static void solo_device_release(struct device *dev) +{ + /* Do nothing */ +} + +static int solo_sysfs_init(struct solo_dev *solo_dev) +{ + struct bin_attribute *sdram_attr = &solo_dev->sdram_attr; + struct device *dev = &solo_dev->dev; + const char *driver; + int i; + + if (solo_dev->type == SOLO_DEV_6110) + driver = "solo6110"; + else + driver = "solo6010"; + + dev->release = solo_device_release; + dev->parent = &solo_dev->pdev->dev; + set_dev_node(dev, dev_to_node(&solo_dev->pdev->dev)); + dev_set_name(dev, "%s-%d-%d", driver, solo_dev->vfd->num, + solo_dev->nr_chans); + + if (device_register(dev)) { + dev->parent = NULL; + return -ENOMEM; + } + + for (i = 0; i < ARRAY_SIZE(solo_dev_attrs); i++) { + if (device_create_file(dev, &solo_dev_attrs[i])) { + device_unregister(dev); + return -ENOMEM; + } + } + + sdram_attr->attr.name = "sdram"; + sdram_attr->attr.mode = 0440; + sdram_attr->read = sdram_show; + sdram_attr->size = solo_dev->sdram_size; + + if (device_create_bin_file(dev, sdram_attr)) { + device_unregister(dev); + return -ENOMEM; + } + + return 0; +} + +static int solo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct solo_dev *solo_dev; int ret; - int sdram; u8 chip_id; - u32 reg; solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL); if (solo_dev == NULL) return -ENOMEM; + if (id->driver_data == SOLO_DEV_6010) + dev_info(&pdev->dev, "Probing Softlogic 6010\n"); + else + dev_info(&pdev->dev, "Probing Softlogic 6110\n"); + + solo_dev->type = id->driver_data; solo_dev->pdev = pdev; spin_lock_init(&solo_dev->reg_io_lock); pci_set_drvdata(pdev, solo_dev); + /* Only for during init */ + solo_dev->p2m_jiffies = msecs_to_jiffies(100); + ret = pci_enable_device(pdev); if (ret) goto fail_probe; pci_set_master(pdev); + /* RETRY/TRDY Timeout disabled */ + pci_write_config_byte(pdev, 0x40, 0x00); + pci_write_config_byte(pdev, 0x41, 0x00); + ret = pci_request_regions(pdev, SOLO6X10_NAME); if (ret) goto fail_probe; @@ -163,7 +537,7 @@ static int solo_pci_probe(struct pci_dev *pdev, } chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) & - SOLO_CHIP_ID_MASK; + SOLO_CHIP_ID_MASK; switch (chip_id) { case 7: solo_dev->nr_chans = 16; @@ -174,52 +548,50 @@ static int solo_pci_probe(struct pci_dev *pdev, solo_dev->nr_ext = 2; break; default: - dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, " - "defaulting to 4 channels\n", + dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, assuming 4 ch\n", chip_id); case 5: solo_dev->nr_chans = 4; solo_dev->nr_ext = 1; } - solo_dev->flags = id->driver_data; - /* Disable all interrupts to start */ solo_irq_off(solo_dev, ~0); - reg = SOLO_SYS_CFG_SDRAM64BIT; /* Initial global settings */ - if (!(solo_dev->flags & FLAGS_6110)) - reg |= SOLO6010_SYS_CFG_INPUTDIV(25) | - SOLO6010_SYS_CFG_FEEDBACKDIV((SOLO_CLOCK_MHZ * 2) - 2) | - SOLO6010_SYS_CFG_OUTDIV(3); - solo_reg_write(solo_dev, SOLO_SYS_CFG, reg); - - if (solo_dev->flags & FLAGS_6110) { - u32 sys_clock_MHz = SOLO_CLOCK_MHZ; - u32 pll_DIVQ; - u32 pll_DIVF; - - if (sys_clock_MHz < 125) { - pll_DIVQ = 3; - pll_DIVF = (sys_clock_MHz * 4) / 3; + if (solo_dev->type == SOLO_DEV_6010) { + solo_dev->clock_mhz = 108; + solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT + | SOLO_SYS_CFG_INPUTDIV(25) + | SOLO_SYS_CFG_FEEDBACKDIV(solo_dev->clock_mhz * 2 - 2) + | SOLO_SYS_CFG_OUTDIV(3); + solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config); + } else { + u32 divq, divf; + + solo_dev->clock_mhz = 135; + + if (solo_dev->clock_mhz < 125) { + divq = 3; + divf = (solo_dev->clock_mhz * 4) / 3 - 1; } else { - pll_DIVQ = 2; - pll_DIVF = (sys_clock_MHz * 2) / 3; + divq = 2; + divf = (solo_dev->clock_mhz * 2) / 3 - 1; } - solo_reg_write(solo_dev, SOLO6110_PLL_CONFIG, - SOLO6110_PLL_RANGE_5_10MHZ | - SOLO6110_PLL_DIVR(9) | - SOLO6110_PLL_DIVQ_EXP(pll_DIVQ) | - SOLO6110_PLL_DIVF(pll_DIVF) | SOLO6110_PLL_FSEN); - mdelay(1); /* PLL Locking time (1ms) */ + solo_reg_write(solo_dev, SOLO_PLL_CONFIG, + (1 << 20) | /* PLL_RANGE */ + (8 << 15) | /* PLL_DIVR */ + (divq << 12) | + (divf << 4) | + (1 << 1) /* PLL_FSEN */); - solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 3 << 8); /* ? */ - } else - solo_reg_write(solo_dev, SOLO_DMA_CTRL1, 1 << 8); /* ? */ + solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT; + } - solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, SOLO_CLOCK_MHZ - 1); + solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config); + solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, + solo_dev->clock_mhz - 1); /* PLL locking time of 1ms */ mdelay(1); @@ -237,14 +609,27 @@ static int solo_pci_probe(struct pci_dev *pdev, goto fail_probe; /* Setup the DMA engine */ - sdram = (solo_dev->nr_chans >= 8) ? 2 : 1; solo_reg_write(solo_dev, SOLO_DMA_CTRL, SOLO_DMA_CTRL_REFRESH_CYCLE(1) | - SOLO_DMA_CTRL_SDRAM_SIZE(sdram) | + SOLO_DMA_CTRL_SDRAM_SIZE(2) | SOLO_DMA_CTRL_SDRAM_CLK_INVERT | SOLO_DMA_CTRL_READ_CLK_SELECT | SOLO_DMA_CTRL_LATENCY(1)); + /* Undocumented crap */ + solo_reg_write(solo_dev, SOLO_DMA_CTRL1, + solo_dev->type == SOLO_DEV_6010 ? 0x100 : 0x300); + + if (solo_dev->type != SOLO_DEV_6010) { + solo_dev->usec_lsb = 0x3f; + solo_set_time(solo_dev); + } + + /* Disable watchdog */ + solo_reg_write(solo_dev, SOLO_WATCHDOG, 0); + + /* Initialize sub components */ + ret = solo_p2m_init(solo_dev); if (ret) goto fail_probe; @@ -261,7 +646,7 @@ static int solo_pci_probe(struct pci_dev *pdev, if (ret) goto fail_probe; - ret = solo_v4l2_init(solo_dev); + ret = solo_v4l2_init(solo_dev, video_nr); if (ret) goto fail_probe; @@ -269,7 +654,7 @@ static int solo_pci_probe(struct pci_dev *pdev, if (ret) goto fail_probe; - ret = solo_enc_v4l2_init(solo_dev); + ret = solo_enc_v4l2_init(solo_dev, video_nr); if (ret) goto fail_probe; @@ -277,6 +662,13 @@ static int solo_pci_probe(struct pci_dev *pdev, if (ret) goto fail_probe; + ret = solo_sysfs_init(solo_dev); + if (ret) + goto fail_probe; + + /* Now that init is over, set this lower */ + solo_dev->p2m_jiffies = msecs_to_jiffies(20); + return 0; fail_probe: @@ -291,21 +683,31 @@ static void solo_pci_remove(struct pci_dev *pdev) free_solo_dev(solo_dev); } -static struct pci_device_id solo_id_table[] = { +static DEFINE_PCI_DEVICE_TABLE(solo_id_table) = { /* 6010 based cards */ - {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010)}, - {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6110), - .driver_data = FLAGS_6110}, - {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4)}, - {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9)}, - {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16)}, - {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4)}, - {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9)}, - {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16)}, + { PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010), + .driver_data = SOLO_DEV_6010 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4), + .driver_data = SOLO_DEV_6010 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9), + .driver_data = SOLO_DEV_6010 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16), + .driver_data = SOLO_DEV_6010 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4), + .driver_data = SOLO_DEV_6010 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9), + .driver_data = SOLO_DEV_6010 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16), + .driver_data = SOLO_DEV_6010 }, /* 6110 based cards */ - {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4)}, - {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8)}, - {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16)}, + { PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6110), + .driver_data = SOLO_DEV_6110 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4), + .driver_data = SOLO_DEV_6110 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8), + .driver_data = SOLO_DEV_6110 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16), + .driver_data = SOLO_DEV_6110 }, {0,} }; diff --git a/drivers/staging/media/solo6x10/disp.c b/drivers/staging/media/solo6x10/disp.c index 884c0eb..ddd85e7 100644 --- a/drivers/staging/media/solo6x10/disp.c +++ b/drivers/staging/media/solo6x10/disp.c @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -21,6 +26,7 @@ #include #include #include + #include "solo6x10.h" #define SOLO_VCLK_DELAY 3 @@ -30,8 +36,8 @@ #define SOLO_MOT_THRESH_H 64 #define SOLO_MOT_THRESH_SIZE 8192 #define SOLO_MOT_THRESH_REAL (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H) -#define SOLO_MOT_FLAG_SIZE 512 -#define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 32) +#define SOLO_MOT_FLAG_SIZE 1024 +#define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 16) static unsigned video_type; module_param(video_type, uint, 0644); @@ -73,7 +79,12 @@ static void solo_vin_config(struct solo_dev *solo_dev) solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT, SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0)); - solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0); + /* On 6110, initialize mozaic darkness stength */ + if (solo_dev->type == SOLO_DEV_6010) + solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0); + else + solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 16 << 22); + solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2); if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { @@ -97,21 +108,30 @@ static void solo_vin_config(struct solo_dev *solo_dev) SOLO_VI_PB_HSTOP(16 + 720)); } -static void solo_disp_config(struct solo_dev *solo_dev) +static void solo_vout_config_cursor(struct solo_dev *dev) +{ + int i; + + /* Load (blank) cursor bitmap mask (2bpp) */ + for (i = 0; i < 20; i++) + solo_reg_write(dev, SOLO_VO_CURSOR_MASK(i), 0); + + solo_reg_write(dev, SOLO_VO_CURSOR_POS, 0); + + solo_reg_write(dev, SOLO_VO_CURSOR_CLR, + (0x80 << 24) | (0x80 << 16) | (0x10 << 8) | 0x80); + solo_reg_write(dev, SOLO_VO_CURSOR_CLR2, (0xe0 << 8) | 0x80); +} + +static void solo_vout_config(struct solo_dev *solo_dev) { solo_dev->vout_hstart = 6; solo_dev->vout_vstart = 8; - solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR, - (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88); - solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR, - (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f); - solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR, - (16 << 24) | (128 << 16) | (16 << 8) | 128); - solo_reg_write(solo_dev, SOLO_VO_FMT_ENC, solo_dev->video_type | SOLO_VO_USER_COLOR_SET_NAV | + SOLO_VO_USER_COLOR_SET_NAH | SOLO_VO_NA_COLOR_Y(0) | SOLO_VO_NA_COLOR_CB(0) | SOLO_VO_NA_COLOR_CR(0)); @@ -130,19 +150,31 @@ static void solo_disp_config(struct solo_dev *solo_dev) SOLO_VO_H_LEN(solo_dev->video_hsize) | SOLO_VO_V_LEN(solo_dev->video_vsize)); - solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 5); + /* Border & background colors */ + solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR, + (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88); + solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR, + (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f); + solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR, + (16 << 24) | (128 << 16) | (16 << 8) | 128); + + solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); + + solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 0); + + solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0); + solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0); solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON | SOLO_VO_DISP_ERASE_COUNT(8) | SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR)); - solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); - /* Enable channels we support */ - solo_reg_write(solo_dev, SOLO_VI_CH_ENA, (1 << solo_dev->nr_chans) - 1); + solo_vout_config_cursor(solo_dev); - /* Disable the watchdog */ - solo_reg_write(solo_dev, SOLO_WATCHDOG, 0); + /* Enable channels we support */ + solo_reg_write(solo_dev, SOLO_VI_CH_ENA, + (1 << solo_dev->nr_chans) - 1); } static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off, @@ -156,26 +188,53 @@ static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off, buf[i] = val; for (i = 0; i < reg_size; i += sizeof(buf)) - ret |= solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_VIN, 1, buf, + ret |= solo_p2m_dma(solo_dev, 1, buf, SOLO_MOTION_EXT_ADDR(solo_dev) + off + i, - sizeof(buf)); + sizeof(buf), 0, 0); return ret; } -void solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val) +int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val) { if (ch > solo_dev->nr_chans) - return; + return -EINVAL; - solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + - (ch * SOLO_MOT_THRESH_SIZE * 2), - val, SOLO_MOT_THRESH_REAL); + return solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + + (ch * SOLO_MOT_THRESH_SIZE * 2), + val, SOLO_MOT_THRESH_SIZE); +} + +int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, u16 val, + u16 block) +{ + u16 buf[64]; + u32 addr; + int re; + + addr = SOLO_MOTION_EXT_ADDR(solo_dev) + + SOLO_MOT_FLAG_AREA + + (SOLO_MOT_THRESH_SIZE * 2 * ch) + + (block * 2); + + /* Read and write only on a 128-byte boundary; 4-byte writes with + solo_p2m_dma silently failed. Bluecherry bug #908. */ + re = solo_p2m_dma(solo_dev, 0, &buf, addr & ~0x7f, sizeof(buf), 0, 0); + if (re) + return re; + + buf[(addr & 0x7f) / 2] = val; + + re = solo_p2m_dma(solo_dev, 1, &buf, addr & ~0x7f, sizeof(buf), 0, 0); + if (re) + return re; + + return 0; } /* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k * threshold and working table for each channel. Atleast that's what the - * spec says. However, this code (take from rdk) has some mystery 8k + * spec says. However, this code (taken from rdk) has some mystery 8k * block right after the flag area, before the first thresh table. */ static void solo_motion_config(struct solo_dev *solo_dev) { @@ -188,9 +247,9 @@ static void solo_motion_config(struct solo_dev *solo_dev) /* Clear working cache table */ solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + - SOLO_MOT_THRESH_SIZE + - (i * SOLO_MOT_THRESH_SIZE * 2), - 0x0000, SOLO_MOT_THRESH_REAL); + (i * SOLO_MOT_THRESH_SIZE * 2) + + SOLO_MOT_THRESH_SIZE, 0x0000, + SOLO_MOT_THRESH_SIZE); /* Set default threshold table */ solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH); @@ -202,8 +261,8 @@ static void solo_motion_config(struct solo_dev *solo_dev) solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL, SOLO_VI_MOTION_FRAME_COUNT(3) | SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16) - | /* SOLO_VI_MOTION_INTR_START_STOP | */ - SOLO_VI_MOTION_SAMPLE_COUNT(10)); + /* | SOLO_VI_MOTION_INTR_START_STOP */ + | SOLO_VI_MOTION_SAMPLE_COUNT(10)); solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0); solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); @@ -226,7 +285,7 @@ int solo_disp_init(struct solo_dev *solo_dev) solo_vin_config(solo_dev); solo_motion_config(solo_dev); - solo_disp_config(solo_dev); + solo_vout_config(solo_dev); for (i = 0; i < solo_dev->nr_chans; i++) solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1); @@ -238,8 +297,6 @@ void solo_disp_exit(struct solo_dev *solo_dev) { int i; - solo_irq_off(solo_dev, SOLO_IRQ_MOTION); - solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0); solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0); solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0); diff --git a/drivers/staging/media/solo6x10/eeprom.c b/drivers/staging/media/solo6x10/eeprom.c new file mode 100644 index 0000000..9d1c9bb --- /dev/null +++ b/drivers/staging/media/solo6x10/eeprom.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +#include +#include + +#include "solo6x10.h" + +/* Control */ +#define EE_SHIFT_CLK 0x04 +#define EE_CS 0x08 +#define EE_DATA_WRITE 0x02 +#define EE_DATA_READ 0x01 +#define EE_ENB (0x80 | EE_CS) + +#define eeprom_delay() udelay(100) +#if 0 +#define eeprom_delay() solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) +#define eeprom_delay() ({ \ + int i, ret; \ + udelay(100); \ + for (i = ret = 0; i < 1000 && !ret; i++) \ + ret = solo_eeprom_reg_read(solo_dev); \ +}) +#endif +#define ADDR_LEN 6 + +/* Commands */ +#define EE_EWEN_CMD 4 +#define EE_EWDS_CMD 4 +#define EE_WRITE_CMD 5 +#define EE_READ_CMD 6 +#define EE_ERASE_CMD 7 + +static unsigned int solo_eeprom_reg_read(struct solo_dev *solo_dev) +{ + return solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) & EE_DATA_READ; +} + +static void solo_eeprom_reg_write(struct solo_dev *solo_dev, u32 data) +{ + solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data); + eeprom_delay(); +} + +static void solo_eeprom_cmd(struct solo_dev *solo_dev, int cmd) +{ + int i; + + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ACCESS_EN); + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); + + for (i = 4 + ADDR_LEN; i >= 0; i--) { + int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0; + + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | dataval); + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | + EE_SHIFT_CLK | dataval); + } + + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); +} + +unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en) +{ + int ewen_cmd = (w_en ? 0x3f : 0) | (EE_EWEN_CMD << ADDR_LEN); + unsigned int retval = 0; + int i; + + solo_eeprom_cmd(solo_dev, ewen_cmd); + + for (i = 0; i < 16; i++) { + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | + EE_SHIFT_CLK); + retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); + retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); + } + + solo_eeprom_reg_write(solo_dev, ~EE_CS); + retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); + + return retval; +} + +unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc) +{ + int read_cmd = loc | (EE_READ_CMD << ADDR_LEN); + unsigned short retval = 0; + int i; + + solo_eeprom_cmd(solo_dev, read_cmd); + + for (i = 0; i < 16; i++) { + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | + EE_SHIFT_CLK); + retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); + } + + solo_eeprom_reg_write(solo_dev, ~EE_CS); + + return retval; +} + +int solo_eeprom_write(struct solo_dev *solo_dev, int loc, + unsigned short data) +{ + int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN); + unsigned int retval; + int i; + + solo_eeprom_cmd(solo_dev, write_cmd); + + for (i = 15; i >= 0; i--) { + unsigned int dataval = (data >> i) & 1; + + solo_eeprom_reg_write(solo_dev, EE_ENB); + solo_eeprom_reg_write(solo_dev, + EE_ENB | (dataval << 1) | EE_SHIFT_CLK); + } + + solo_eeprom_reg_write(solo_dev, EE_ENB); + solo_eeprom_reg_write(solo_dev, ~EE_CS); + solo_eeprom_reg_write(solo_dev, EE_ENB); + + for (i = retval = 0; i < 10000 && !retval; i++) + retval = solo_eeprom_reg_read(solo_dev); + + solo_eeprom_reg_write(solo_dev, ~EE_CS); + + return !retval; +} diff --git a/drivers/staging/media/solo6x10/enc.c b/drivers/staging/media/solo6x10/enc.c index de50259..94d5735 100644 --- a/drivers/staging/media/solo6x10/enc.c +++ b/drivers/staging/media/solo6x10/enc.c @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -18,30 +23,41 @@ */ #include +#include +#include #include -#include "solo6x10.h" -#include "osd-font.h" -#define CAPTURE_MAX_BANDWIDTH 32 /* D1 4channel (D1 == 4) */ -#define OSG_BUFFER_SIZE 1024 +#include "solo6x10.h" #define VI_PROG_HSIZE (1280 - 16) #define VI_PROG_VSIZE (1024 - 16) +#define IRQ_LEVEL 2 + static void solo_capture_config(struct solo_dev *solo_dev) { - int i, j; unsigned long height; unsigned long width; - unsigned char *buf; + void *buf; + int i; solo_reg_write(solo_dev, SOLO_CAP_BASE, - SOLO_CAP_MAX_PAGE(SOLO_CAP_EXT_MAX_PAGE * - solo_dev->nr_chans) | - SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16)); - solo_reg_write(solo_dev, SOLO_CAP_BTW, - (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | - SOLO_CAP_MAX_BANDWIDTH(CAPTURE_MAX_BANDWIDTH)); + SOLO_CAP_MAX_PAGE((SOLO_CAP_EXT_SIZE(solo_dev) + - SOLO_CAP_PAGE_SIZE) >> 16) + | SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16)); + + /* XXX: Undocumented bits at b17 and b24 */ + if (solo_dev->type == SOLO_DEV_6110) { + /* NOTE: Ref driver has (62 << 24) here as well, but it causes + * wacked out frame timing on 4-port 6110. */ + solo_reg_write(solo_dev, SOLO_CAP_BTW, + (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | + SOLO_CAP_MAX_BANDWIDTH(36)); + } else { + solo_reg_write(solo_dev, SOLO_CAP_BTW, + (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | + SOLO_CAP_MAX_BANDWIDTH(32)); + } /* Set scale 1, 9 dimension */ width = solo_dev->video_hsize; @@ -96,115 +112,212 @@ static void solo_capture_config(struct solo_dev *solo_dev) solo_reg_write(solo_dev, SOLO_VE_OSD_BASE, SOLO_EOSD_EXT_ADDR >> 16); solo_reg_write(solo_dev, SOLO_VE_OSD_CLR, 0xF0 << 16 | 0x80 << 8 | 0x80); - solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, 0); + + if (solo_dev->type == SOLO_DEV_6010) + solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, + SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW); + else + solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, SOLO_VE_OSD_V_DOUBLE + | SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW); /* Clear OSG buffer */ - buf = kzalloc(OSG_BUFFER_SIZE, GFP_KERNEL); + buf = kzalloc(SOLO_EOSD_EXT_SIZE(solo_dev), GFP_KERNEL); if (!buf) return; for (i = 0; i < solo_dev->nr_chans; i++) { - for (j = 0; j < SOLO_EOSD_EXT_SIZE; j += OSG_BUFFER_SIZE) { - solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_MP4E, 1, buf, - SOLO_EOSD_EXT_ADDR + - (i * SOLO_EOSD_EXT_SIZE) + j, - OSG_BUFFER_SIZE); - } + solo_p2m_dma(solo_dev, 1, buf, + SOLO_EOSD_EXT_ADDR + + (SOLO_EOSD_EXT_SIZE(solo_dev) * i), + SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0); } kfree(buf); } +/* Should be called with enable_lock held */ int solo_osd_print(struct solo_enc_dev *solo_enc) { struct solo_dev *solo_dev = solo_enc->solo_dev; - char *str = solo_enc->osd_text; - u8 *buf; + unsigned char *str = solo_enc->osd_text; + u8 *buf = solo_enc->osd_buf; u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH); - int len = strlen(str); + const struct font_desc *vga = find_font("VGA8x16"); + const unsigned char *vga_data; + int len; int i, j; - int x = 1, y = 1; + + if (WARN_ON_ONCE(!vga)) + return -ENODEV; + + len = strlen(str); if (len == 0) { + /* Disable OSD on this channel */ reg &= ~(1 << solo_enc->ch); solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); return 0; } - buf = kzalloc(SOLO_EOSD_EXT_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; + memset(buf, 0, SOLO_EOSD_EXT_SIZE_MAX); + vga_data = (const unsigned char *)vga->data; for (i = 0; i < len; i++) { + unsigned char c = str[i]; + for (j = 0; j < 16; j++) { - buf[(j*2) + (i%2) + ((x + (i/2)) * 32) + (y * 2048)] = - (solo_osd_font[(str[i] * 4) + (j / 4)] - >> ((3 - (j % 4)) * 8)) & 0xff; + buf[(j * 2) + (i % 2) + (i / 2 * 32)] = + bitrev8(vga_data[(c * 16) + j]); } } - solo_p2m_dma(solo_dev, 0, 1, buf, SOLO_EOSD_EXT_ADDR + - (solo_enc->ch * SOLO_EOSD_EXT_SIZE), SOLO_EOSD_EXT_SIZE); + solo_p2m_dma(solo_dev, 1, buf, + SOLO_EOSD_EXT_ADDR + + (solo_enc->ch * SOLO_EOSD_EXT_SIZE(solo_dev)), + SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0); + + /* Enable OSD on this channel */ reg |= (1 << solo_enc->ch); solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); - kfree(buf); - return 0; } +/** + * Set channel Quality Profile (0-3). + */ +void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch, + unsigned int qp) +{ + unsigned long flags; + unsigned int idx, reg; + + if ((ch > 31) || (qp > 3)) + return; + + if (solo_dev->type == SOLO_DEV_6010) + return; + + if (ch < 16) { + idx = 0; + reg = SOLO_VE_JPEG_QP_CH_L; + } else { + ch -= 16; + idx = 1; + reg = SOLO_VE_JPEG_QP_CH_H; + } + ch *= 2; + + spin_lock_irqsave(&solo_dev->jpeg_qp_lock, flags); + + solo_dev->jpeg_qp[idx] &= ~(3 << ch); + solo_dev->jpeg_qp[idx] |= (qp & 3) << ch; + + solo_reg_write(solo_dev, reg, solo_dev->jpeg_qp[idx]); + + spin_unlock_irqrestore(&solo_dev->jpeg_qp_lock, flags); +} + +int solo_g_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch) +{ + int idx; + + if (solo_dev->type == SOLO_DEV_6010) + return 2; + + if (WARN_ON_ONCE(ch > 31)) + return 2; + + if (ch < 16) { + idx = 0; + } else { + ch -= 16; + idx = 1; + } + ch *= 2; + + return (solo_dev->jpeg_qp[idx] >> ch) & 3; +} + +#define SOLO_QP_INIT 0xaaaaaaaa + static void solo_jpeg_config(struct solo_dev *solo_dev) { - u32 reg; - if (solo_dev->flags & FLAGS_6110) - reg = (4 << 24) | (3 << 16) | (2 << 8) | (1 << 0); - else - reg = (2 << 24) | (2 << 16) | (2 << 8) | (2 << 0); - solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, reg); - solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, 0); - solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, 0); + if (solo_dev->type == SOLO_DEV_6010) { + solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, + (2 << 24) | (2 << 16) | (2 << 8) | 2); + } else { + solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, + (4 << 24) | (3 << 16) | (2 << 8) | 1); + } + + spin_lock_init(&solo_dev->jpeg_qp_lock); + + /* Initialize Quality Profile for all channels */ + solo_dev->jpeg_qp[0] = solo_dev->jpeg_qp[1] = SOLO_QP_INIT; + solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, SOLO_QP_INIT); + solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, SOLO_QP_INIT); + solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG, (SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) | ((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff)); solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff); - /* que limit, samp limit, pos limit */ - solo_reg_write(solo_dev, 0x0688, (0 << 16) | (30 << 8) | 60); + if (solo_dev->type == SOLO_DEV_6110) { + solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG1, + (0 << 16) | (30 << 8) | 60); + } } static void solo_mp4e_config(struct solo_dev *solo_dev) { int i; - u32 reg; + u32 cfg; - /* We can only use VE_INTR_CTRL(0) if we want to support mjpeg */ solo_reg_write(solo_dev, SOLO_VE_CFG0, - SOLO_VE_INTR_CTRL(0) | + SOLO_VE_INTR_CTRL(IRQ_LEVEL) | SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) | SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16)); - solo_reg_write(solo_dev, SOLO_VE_CFG1, - SOLO_VE_INSERT_INDEX | SOLO_VE_MOTION_MODE(0)); + + cfg = SOLO_VE_BYTE_ALIGN(2) | SOLO_VE_INSERT_INDEX + | SOLO_VE_MOTION_MODE(0); + if (solo_dev->type != SOLO_DEV_6010) { + cfg |= SOLO_VE_MPEG_SIZE_H( + (SOLO_MP4E_EXT_SIZE(solo_dev) >> 24) & 0x0f); + cfg |= SOLO_VE_JPEG_SIZE_H( + (SOLO_JPEG_EXT_SIZE(solo_dev) >> 24) & 0x0f); + } + solo_reg_write(solo_dev, SOLO_VE_CFG1, cfg); solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0); solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0); solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0); + if (solo_dev->type == SOLO_DEV_6110) + solo_reg_write(solo_dev, SOLO_VE_WMRK_ENABLE, 0); solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0); solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0); - reg = SOLO_VE_LITTLE_ENDIAN | SOLO_COMP_ATTR_FCODE(1) | - SOLO_COMP_TIME_INC(0) | SOLO_COMP_TIME_WIDTH(15); - if (solo_dev->flags & FLAGS_6110) - reg |= SOLO_DCT_INTERVAL(10); - else - reg |= SOLO_DCT_INTERVAL(36 / 4); - solo_reg_write(solo_dev, SOLO_VE_ATTR, reg); + solo_reg_write(solo_dev, SOLO_VE_ATTR, + SOLO_VE_LITTLE_ENDIAN | + SOLO_COMP_ATTR_FCODE(1) | + SOLO_COMP_TIME_INC(0) | + SOLO_COMP_TIME_WIDTH(15) | + SOLO_DCT_INTERVAL(solo_dev->type == SOLO_DEV_6010 ? 9 : 10)); - for (i = 0; i < solo_dev->nr_chans; i++) + for (i = 0; i < solo_dev->nr_chans; i++) { solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i), (SOLO_EREF_EXT_ADDR(solo_dev) + (i * SOLO_EREF_EXT_SIZE)) >> 16); + solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE_E(i), + (SOLO_EREF_EXT_ADDR(solo_dev) + + ((i + 16) * SOLO_EREF_EXT_SIZE)) >> 16); + } - if (solo_dev->flags & FLAGS_6110) - solo_reg_write(solo_dev, 0x0634, 0x00040008); /* ? */ + if (solo_dev->type == SOLO_DEV_6110) { + solo_reg_write(solo_dev, SOLO_VE_COMPT_MOT, 0x00040008); + } else { + for (i = 0; i < solo_dev->nr_chans; i++) + solo_reg_write(solo_dev, SOLO_VE_CH_MOT(i), 0x100); + } } int solo_enc_init(struct solo_dev *solo_dev) @@ -220,8 +333,6 @@ int solo_enc_init(struct solo_dev *solo_dev) solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); } - solo_irq_on(solo_dev, SOLO_IRQ_ENCODER); - return 0; } @@ -229,8 +340,6 @@ void solo_enc_exit(struct solo_dev *solo_dev) { int i; - solo_irq_off(solo_dev, SOLO_IRQ_ENCODER); - for (i = 0; i < solo_dev->nr_chans; i++) { solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); diff --git a/drivers/staging/media/solo6x10/g723.c b/drivers/staging/media/solo6x10/g723.c index 2cd0de2..183222e 100644 --- a/drivers/staging/media/solo6x10/g723.c +++ b/drivers/staging/media/solo6x10/g723.c @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -21,17 +26,18 @@ #include #include #include -#include #include -#include +#include +#include + #include #include #include #include + #include "solo6x10.h" #include "tw28.h" -#define G723_INTR_ORDER 0 #define G723_FDMA_PAGES 32 #define G723_PERIOD_BYTES 48 #define G723_PERIOD_BLOCK 1024 @@ -46,36 +52,40 @@ /* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page * is broken down to 20 * 48 byte regions (one for each channel possible) * with the rest of the page being dummy data. */ -#define MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX) -#define IRQ_PAGES 4 /* 0 - 4 */ -#define PERIODS_MIN (1 << IRQ_PAGES) +#define G723_MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX) +#define G723_INTR_ORDER 4 /* 0 - 4 */ +#define PERIODS_MIN (1 << G723_INTR_ORDER) #define PERIODS_MAX G723_FDMA_PAGES struct solo_snd_pcm { - int on; - spinlock_t lock; - struct solo_dev *solo_dev; - unsigned char g723_buf[G723_PERIOD_BYTES]; + int on; + spinlock_t lock; + struct solo_dev *solo_dev; + unsigned char *g723_buf; + dma_addr_t g723_dma; }; static void solo_g723_config(struct solo_dev *solo_dev) { int clk_div; - clk_div = SOLO_CLOCK_MHZ / (SAMPLERATE * (BITRATE * 2) * 2); + clk_div = (solo_dev->clock_mhz * 1000000) + / (SAMPLERATE * (BITRATE * 2) * 2); solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE, - SOLO_AUDIO_BITRATE(BITRATE) | - SOLO_AUDIO_CLK_DIV(clk_div)); + SOLO_AUDIO_BITRATE(BITRATE) + | SOLO_AUDIO_CLK_DIV(clk_div)); solo_reg_write(solo_dev, SOLO_AUDIO_FDMA_INTR, - SOLO_AUDIO_FDMA_INTERVAL(IRQ_PAGES) | - SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER) | - SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16)); + SOLO_AUDIO_FDMA_INTERVAL(1) + | SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER) + | SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16)); solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, - SOLO_AUDIO_ENABLE | SOLO_AUDIO_I2S_MODE | - SOLO_AUDIO_I2S_MULTI(3) | SOLO_AUDIO_MODE(OUTMODE_MASK)); + SOLO_AUDIO_ENABLE + | SOLO_AUDIO_I2S_MODE + | SOLO_AUDIO_I2S_MULTI(3) + | SOLO_AUDIO_MODE(OUTMODE_MASK)); } void solo_g723_isr(struct solo_dev *solo_dev) @@ -85,8 +95,6 @@ void solo_g723_isr(struct solo_dev *solo_dev) struct snd_pcm_substream *ss; struct solo_snd_pcm *solo_pcm; - solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_G723); - for (ss = pstr->substream; ss != NULL; ss = ss->next) { if (snd_pcm_substream_chip(ss) == NULL) continue; @@ -115,18 +123,18 @@ static int snd_solo_hw_free(struct snd_pcm_substream *ss) return snd_pcm_lib_free_pages(ss); } -static struct snd_pcm_hardware snd_solo_pcm_hw = { +static const struct snd_pcm_hardware snd_solo_pcm_hw = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_U8, .rates = SNDRV_PCM_RATE_8000, - .rate_min = 8000, - .rate_max = 8000, + .rate_min = SAMPLERATE, + .rate_max = SAMPLERATE, .channels_min = 1, .channels_max = 1, - .buffer_bytes_max = MAX_BUFFER, + .buffer_bytes_max = G723_MAX_BUFFER, .period_bytes_min = G723_PERIOD_BYTES, .period_bytes_max = G723_PERIOD_BYTES, .periods_min = PERIODS_MIN, @@ -140,7 +148,13 @@ static int snd_solo_pcm_open(struct snd_pcm_substream *ss) solo_pcm = kzalloc(sizeof(*solo_pcm), GFP_KERNEL); if (solo_pcm == NULL) - return -ENOMEM; + goto oom; + + solo_pcm->g723_buf = pci_alloc_consistent(solo_dev->pdev, + G723_PERIOD_BYTES, + &solo_pcm->g723_dma); + if (solo_pcm->g723_buf == NULL) + goto oom; spin_lock_init(&solo_pcm->lock); solo_pcm->solo_dev = solo_dev; @@ -149,6 +163,10 @@ static int snd_solo_pcm_open(struct snd_pcm_substream *ss) snd_pcm_substream_chip(ss) = solo_pcm; return 0; + +oom: + kfree(solo_pcm); + return -ENOMEM; } static int snd_solo_pcm_close(struct snd_pcm_substream *ss) @@ -156,6 +174,8 @@ static int snd_solo_pcm_close(struct snd_pcm_substream *ss) struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); snd_pcm_substream_chip(ss) = solo_pcm->solo_dev; + pci_free_consistent(solo_pcm->solo_dev->pdev, G723_PERIOD_BYTES, + solo_pcm->g723_buf, solo_pcm->g723_dma); kfree(solo_pcm); return 0; @@ -220,12 +240,11 @@ static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel, for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) { int page = (pos / G723_FRAMES_PER_PAGE) + i; - err = solo_p2m_dma(solo_dev, SOLO_P2M_DMA_ID_G723E, 0, - solo_pcm->g723_buf, - SOLO_G723_EXT_ADDR(solo_dev) + - (page * G723_PERIOD_BLOCK) + - (ss->number * G723_PERIOD_BYTES), - G723_PERIOD_BYTES); + err = solo_p2m_dma_t(solo_dev, 0, solo_pcm->g723_dma, + SOLO_G723_EXT_ADDR(solo_dev) + + (page * G723_PERIOD_BLOCK) + + (ss->number * G723_PERIOD_BYTES), + G723_PERIOD_BYTES, 0, 0); if (err) return err; @@ -325,7 +344,7 @@ static int solo_snd_pcm_init(struct solo_dev *solo_dev) ret = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), - MAX_BUFFER, MAX_BUFFER); + G723_MAX_BUFFER, G723_MAX_BUFFER); if (ret < 0) return ret; @@ -368,6 +387,7 @@ int solo_g723_init(struct solo_dev *solo_dev) strcpy(card->mixername, "SOLO-6x10"); kctl = snd_solo_capture_volume; kctl.count = solo_dev->nr_chans; + ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev)); if (ret < 0) return ret; @@ -393,8 +413,12 @@ snd_error: void solo_g723_exit(struct solo_dev *solo_dev) { + if (!solo_dev->snd_card) + return; + solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, 0); solo_irq_off(solo_dev, SOLO_IRQ_G723); snd_card_free(solo_dev->snd_card); + solo_dev->snd_card = NULL; } diff --git a/drivers/staging/media/solo6x10/gpio.c b/drivers/staging/media/solo6x10/gpio.c index 0925e6f..73276dc 100644 --- a/drivers/staging/media/solo6x10/gpio.c +++ b/drivers/staging/media/solo6x10/gpio.c @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -19,7 +24,9 @@ #include #include -#include +#include +#include + #include "solo6x10.h" static void solo_gpio_mode(struct solo_dev *solo_dev, diff --git a/drivers/staging/media/solo6x10/i2c.c b/drivers/staging/media/solo6x10/i2c.c index 398070a..01aa417 100644 --- a/drivers/staging/media/solo6x10/i2c.c +++ b/drivers/staging/media/solo6x10/i2c.c @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -26,6 +31,7 @@ * thread context, ACK the interrupt, and move on. -- BenC */ #include + #include "solo6x10.h" u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off) @@ -173,10 +179,9 @@ int solo_i2c_isr(struct solo_dev *solo_dev) u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL); int ret = -EINVAL; - solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_IIC); - if (status & (SOLO_IIC_STATE_TRNS | SOLO_IIC_STATE_SIG_ERR) || - solo_dev->i2c_id < 0) { + if (CHK_FLAGS(status, SOLO_IIC_STATE_TRNS | SOLO_IIC_STATE_SIG_ERR) + || solo_dev->i2c_id < 0) { solo_i2c_stop(solo_dev); return -ENXIO; } @@ -239,7 +244,8 @@ static int solo_i2c_master_xfer(struct i2c_adapter *adap, timeout = HZ / 2; for (;;) { - prepare_to_wait(&solo_dev->i2c_wait, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(&solo_dev->i2c_wait, &wait, + TASK_INTERRUPTIBLE); if (solo_dev->i2c_state == IIC_STATE_STOP) break; @@ -267,7 +273,7 @@ static u32 solo_i2c_functionality(struct i2c_adapter *adap) return I2C_FUNC_I2C; } -static struct i2c_algorithm solo_i2c_algo = { +static const struct i2c_algorithm solo_i2c_algo = { .master_xfer = solo_i2c_master_xfer, .functionality = solo_i2c_functionality, }; @@ -288,7 +294,8 @@ int solo_i2c_init(struct solo_dev *solo_dev) for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { struct i2c_adapter *adap = &solo_dev->i2c_adap[i]; - snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d", SOLO6X10_NAME, i); + snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d", + SOLO6X10_NAME, i); adap->algo = &solo_i2c_algo; adap->algo_data = solo_dev; adap->retries = 1; @@ -311,9 +318,6 @@ int solo_i2c_init(struct solo_dev *solo_dev) return ret; } - dev_info(&solo_dev->pdev->dev, "Enabled %d i2c adapters\n", - SOLO_I2C_ADAPTERS); - return 0; } diff --git a/drivers/staging/media/solo6x10/offsets.h b/drivers/staging/media/solo6x10/offsets.h index 3d7e569..f005dca 100644 --- a/drivers/staging/media/solo6x10/offsets.h +++ b/drivers/staging/media/solo6x10/offsets.h @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -20,55 +25,61 @@ #ifndef __SOLO6X10_OFFSETS_H #define __SOLO6X10_OFFSETS_H -/* Offsets and sizes of the external address */ #define SOLO_DISP_EXT_ADDR 0x00000000 #define SOLO_DISP_EXT_SIZE 0x00480000 -#define SOLO_DEC2LIVE_EXT_ADDR (SOLO_DISP_EXT_ADDR + SOLO_DISP_EXT_SIZE) -#define SOLO_DEC2LIVE_EXT_SIZE 0x00240000 - -#define SOLO_OSG_EXT_ADDR (SOLO_DEC2LIVE_EXT_ADDR + SOLO_DEC2LIVE_EXT_SIZE) -#define SOLO_OSG_EXT_SIZE 0x00120000 +#define SOLO_EOSD_EXT_ADDR \ + (SOLO_DISP_EXT_ADDR + SOLO_DISP_EXT_SIZE) +#define SOLO_EOSD_EXT_SIZE(__solo) \ + (__solo->type == SOLO_DEV_6010 ? 0x10000 : 0x20000) +#define SOLO_EOSD_EXT_SIZE_MAX 0x20000 +#define SOLO_EOSD_EXT_AREA(__solo) \ + (SOLO_EOSD_EXT_SIZE(__solo) * 32) -#define SOLO_EOSD_EXT_ADDR (SOLO_OSG_EXT_ADDR + SOLO_OSG_EXT_SIZE) -#define SOLO_EOSD_EXT_SIZE 0x00010000 - -#define SOLO_MOTION_EXT_ADDR(__solo) (SOLO_EOSD_EXT_ADDR + \ - (SOLO_EOSD_EXT_SIZE * __solo->nr_chans)) +#define SOLO_MOTION_EXT_ADDR(__solo) \ + (SOLO_EOSD_EXT_ADDR + SOLO_EOSD_EXT_AREA(__solo)) #define SOLO_MOTION_EXT_SIZE 0x00080000 #define SOLO_G723_EXT_ADDR(__solo) \ - (SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE) + (SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE) #define SOLO_G723_EXT_SIZE 0x00010000 #define SOLO_CAP_EXT_ADDR(__solo) \ - (SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE) -#define SOLO_CAP_EXT_MAX_PAGE (18 + 15) -#define SOLO_CAP_EXT_SIZE (SOLO_CAP_EXT_MAX_PAGE * 65536) + (SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE) + +/* 18 is the maximum number of pages required for PAL@D1, the largest frame + * possible */ +#define SOLO_CAP_PAGE_SIZE (18 << 16) + +/* Always allow the encoder enough for 16 channels, even if we have less. The + * exception is if we have card with only 32Megs of memory. */ +#define SOLO_CAP_EXT_SIZE(__solo) \ + ((((__solo->sdram_size <= (32 << 20)) ? 4 : 16) + 1) \ + * SOLO_CAP_PAGE_SIZE) -/* This +1 is very important -- Why?! -- BenC */ #define SOLO_EREF_EXT_ADDR(__solo) \ - (SOLO_CAP_EXT_ADDR(__solo) + \ - (SOLO_CAP_EXT_SIZE * (__solo->nr_chans + 1))) + (SOLO_CAP_EXT_ADDR(__solo) + SOLO_CAP_EXT_SIZE(__solo)) #define SOLO_EREF_EXT_SIZE 0x00140000 +#define SOLO_EREF_EXT_AREA(__solo) \ + (SOLO_EREF_EXT_SIZE * __solo->nr_chans * 2) + +#define __SOLO_JPEG_MIN_SIZE(__solo) (__solo->nr_chans * 0x00080000) #define SOLO_MP4E_EXT_ADDR(__solo) \ - (SOLO_EREF_EXT_ADDR(__solo) + \ - (SOLO_EREF_EXT_SIZE * __solo->nr_chans)) -#define SOLO_MP4E_EXT_SIZE(__solo) (0x00080000 * __solo->nr_chans) + (SOLO_EREF_EXT_ADDR(__solo) + SOLO_EREF_EXT_AREA(__solo)) +#define SOLO_MP4E_EXT_SIZE(__solo) \ + max((__solo->nr_chans * 0x00080000), \ + min(((__solo->sdram_size - SOLO_MP4E_EXT_ADDR(__solo)) - \ + __SOLO_JPEG_MIN_SIZE(__solo)), 0x00ff0000)) -#define SOLO_DREF_EXT_ADDR(__solo) \ +#define __SOLO_JPEG_MIN_SIZE(__solo) (__solo->nr_chans * 0x00080000) +#define SOLO_JPEG_EXT_ADDR(__solo) \ (SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo)) -#define SOLO_DREF_EXT_SIZE 0x00140000 +#define SOLO_JPEG_EXT_SIZE(__solo) \ + max(__SOLO_JPEG_MIN_SIZE(__solo), \ + min((__solo->sdram_size - SOLO_JPEG_EXT_ADDR(__solo)), 0x00ff0000)) -#define SOLO_MP4D_EXT_ADDR(__solo) \ - (SOLO_DREF_EXT_ADDR(__solo) + \ - (SOLO_DREF_EXT_SIZE * __solo->nr_chans)) -#define SOLO_MP4D_EXT_SIZE 0x00080000 - -#define SOLO_JPEG_EXT_ADDR(__solo) \ - (SOLO_MP4D_EXT_ADDR(__solo) + \ - (SOLO_MP4D_EXT_SIZE * __solo->nr_chans)) -#define SOLO_JPEG_EXT_SIZE(__solo) (0x00080000 * __solo->nr_chans) +#define SOLO_SDRAM_END(__solo) \ + (SOLO_JPEG_EXT_ADDR(__solo) + SOLO_JPEG_EXT_SIZE(__solo)) #endif /* __SOLO6X10_OFFSETS_H */ diff --git a/drivers/staging/media/solo6x10/osd-font.h b/drivers/staging/media/solo6x10/osd-font.h deleted file mode 100644 index 591e0e8..0000000 --- a/drivers/staging/media/solo6x10/osd-font.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins - * - * 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. - */ - -#ifndef __SOLO6X10_OSD_FONT_H -#define __SOLO6X10_OSD_FONT_H - -static const unsigned int solo_osd_font[] = { - 0x00000000, 0x0000c0c8, 0xccfefe0c, 0x08000000, - 0x00000000, 0x10103838, 0x7c7cfefe, 0x00000000, /* 0 */ - 0x00000000, 0xfefe7c7c, 0x38381010, 0x10000000, - 0x00000000, 0x7c82fefe, 0xfefefe7c, 0x00000000, - 0x00000000, 0x00001038, 0x10000000, 0x00000000, - 0x00000000, 0x0010387c, 0xfe7c3810, 0x00000000, - 0x00000000, 0x00384444, 0x44380000, 0x00000000, - 0x00000000, 0x38448282, 0x82443800, 0x00000000, - 0x00000000, 0x007c7c7c, 0x7c7c0000, 0x00000000, - 0x00000000, 0x6c6c6c6c, 0x6c6c6c6c, 0x00000000, - 0x00000000, 0x061e7efe, 0xfe7e1e06, 0x00000000, - 0x00000000, 0xc0f0fcfe, 0xfefcf0c0, 0x00000000, - 0x00000000, 0xc6cedefe, 0xfedecec6, 0x00000000, - 0x00000000, 0xc6e6f6fe, 0xfef6e6c6, 0x00000000, - 0x00000000, 0x12367efe, 0xfe7e3612, 0x00000000, - 0x00000000, 0x90d8fcfe, 0xfefcd890, 0x00000000, - 0x00000038, 0x7cc692ba, 0x92c67c38, 0x00000000, - 0x00000038, 0x7cc6aa92, 0xaac67c38, 0x00000000, - 0x00000038, 0x7830107c, 0xbaa8680c, 0x00000000, - 0x00000038, 0x3c18127c, 0xb8382c60, 0x00000000, - 0x00000044, 0xaa6c8254, 0x38eec67c, 0x00000000, - 0x00000082, 0x44288244, 0x38c6827c, 0x00000000, - 0x00000038, 0x444444fe, 0xfeeec6fe, 0x00000000, - 0x00000018, 0x78187818, 0x3c7e7e3c, 0x00000000, - 0x00000000, 0x3854929a, 0x82443800, 0x00000000, - 0x00000000, 0x00c0c8cc, 0xfefe0c08, 0x00000000, - 0x0000e0a0, 0xe040e00e, 0x8a0ea40e, 0x00000000, - 0x0000e0a0, 0xe040e00e, 0x0a8e440e, 0x00000000, - 0x0000007c, 0x82829292, 0x929282fe, 0x00000000, - 0x000000f8, 0xfc046494, 0x946404fc, 0x00000000, - 0x0000003f, 0x7f404c52, 0x524c407f, 0x00000000, - 0x0000007c, 0x82ba82ba, 0x82ba82fe, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x183c3c3c, 0x18180018, 0x18000000, /* 32 ! */ - 0x00000066, 0x66240000, 0x00000000, 0x00000000, - 0x00000000, 0x6c6cfe6c, 0x6c6cfe6c, 0x6c000000, /* 34 " # */ - 0x00001010, 0x7cd6d616, 0x7cd0d6d6, 0x7c101000, - 0x00000000, 0x0086c660, 0x30180cc6, 0xc2000000, /* 36 $ % */ - 0x00000000, 0x386c6c38, 0xdc766666, 0xdc000000, - 0x0000000c, 0x0c0c0600, 0x00000000, 0x00000000, /* 38 & ' */ - 0x00000000, 0x30180c0c, 0x0c0c0c18, 0x30000000, - 0x00000000, 0x0c183030, 0x30303018, 0x0c000000, /* 40 ( ) */ - 0x00000000, 0x0000663c, 0xff3c6600, 0x00000000, - 0x00000000, 0x00001818, 0x7e181800, 0x00000000, /* 42 * + */ - 0x00000000, 0x00000000, 0x00000e0e, 0x0c060000, - 0x00000000, 0x00000000, 0x7e000000, 0x00000000, /* 44 , - */ - 0x00000000, 0x00000000, 0x00000006, 0x06000000, - 0x00000000, 0x80c06030, 0x180c0602, 0x00000000, /* 46 . / */ - 0x0000007c, 0xc6e6f6de, 0xcec6c67c, 0x00000000, - 0x00000030, 0x383c3030, 0x303030fc, 0x00000000, /* 48 0 1 */ - 0x0000007c, 0xc6c06030, 0x180cc6fe, 0x00000000, - 0x0000007c, 0xc6c0c07c, 0xc0c0c67c, 0x00000000, /* 50 2 3 */ - 0x00000060, 0x70786c66, 0xfe6060f0, 0x00000000, - 0x000000fe, 0x0606067e, 0xc0c0c67c, 0x00000000, /* 52 4 5 */ - 0x00000038, 0x0c06067e, 0xc6c6c67c, 0x00000000, - 0x000000fe, 0xc6c06030, 0x18181818, 0x00000000, /* 54 6 7 */ - 0x0000007c, 0xc6c6c67c, 0xc6c6c67c, 0x00000000, - 0x0000007c, 0xc6c6c6fc, 0xc0c06038, 0x00000000, /* 56 8 9 */ - 0x00000000, 0x18180000, 0x00181800, 0x00000000, - 0x00000000, 0x18180000, 0x0018180c, 0x00000000, /* 58 : ; */ - 0x00000060, 0x30180c06, 0x0c183060, 0x00000000, - 0x00000000, 0x007e0000, 0x007e0000, 0x00000000, - 0x00000006, 0x0c183060, 0x30180c06, 0x00000000, - 0x0000007c, 0xc6c66030, 0x30003030, 0x00000000, - 0x0000007c, 0xc6f6d6d6, 0x7606067c, 0x00000000, - 0x00000010, 0x386cc6c6, 0xfec6c6c6, 0x00000000, /* 64 @ A */ - 0x0000007e, 0xc6c6c67e, 0xc6c6c67e, 0x00000000, - 0x00000078, 0xcc060606, 0x0606cc78, 0x00000000, /* 66 */ - 0x0000003e, 0x66c6c6c6, 0xc6c6663e, 0x00000000, - 0x000000fe, 0x0606063e, 0x060606fe, 0x00000000, /* 68 */ - 0x000000fe, 0x0606063e, 0x06060606, 0x00000000, - 0x00000078, 0xcc060606, 0xf6c6ccb8, 0x00000000, /* 70 */ - 0x000000c6, 0xc6c6c6fe, 0xc6c6c6c6, 0x00000000, - 0x0000003c, 0x18181818, 0x1818183c, 0x00000000, /* 72 */ - 0x00000060, 0x60606060, 0x6066663c, 0x00000000, - 0x000000c6, 0xc666361e, 0x3666c6c6, 0x00000000, /* 74 */ - 0x00000006, 0x06060606, 0x060606fe, 0x00000000, - 0x000000c6, 0xeefed6c6, 0xc6c6c6c6, 0x00000000, /* 76 */ - 0x000000c6, 0xcedefef6, 0xe6c6c6c6, 0x00000000, - 0x00000038, 0x6cc6c6c6, 0xc6c66c38, 0x00000000, /* 78 */ - 0x0000007e, 0xc6c6c67e, 0x06060606, 0x00000000, - 0x00000038, 0x6cc6c6c6, 0xc6d67c38, 0x60000000, /* 80 */ - 0x0000007e, 0xc6c6c67e, 0x66c6c6c6, 0x00000000, - 0x0000007c, 0xc6c60c38, 0x60c6c67c, 0x00000000, /* 82 */ - 0x0000007e, 0x18181818, 0x18181818, 0x00000000, - 0x000000c6, 0xc6c6c6c6, 0xc6c6c67c, 0x00000000, /* 84 */ - 0x000000c6, 0xc6c6c6c6, 0xc66c3810, 0x00000000, - 0x000000c6, 0xc6c6c6c6, 0xd6d6fe6c, 0x00000000, /* 86 */ - 0x000000c6, 0xc6c66c38, 0x6cc6c6c6, 0x00000000, - 0x00000066, 0x66666666, 0x3c181818, 0x00000000, /* 88 */ - 0x000000fe, 0xc0603018, 0x0c0606fe, 0x00000000, - 0x0000003c, 0x0c0c0c0c, 0x0c0c0c3c, 0x00000000, /* 90 */ - 0x00000002, 0x060c1830, 0x60c08000, 0x00000000, - 0x0000003c, 0x30303030, 0x3030303c, 0x00000000, /* 92 */ - 0x00001038, 0x6cc60000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00fe0000, - 0x00001818, 0x30000000, 0x00000000, 0x00000000, - 0x00000000, 0x00003c60, 0x7c66667c, 0x00000000, - 0x0000000c, 0x0c0c7ccc, 0xcccccc7c, 0x00000000, - 0x00000000, 0x00007cc6, 0x0606c67c, 0x00000000, - 0x00000060, 0x60607c66, 0x6666667c, 0x00000000, - 0x00000000, 0x00007cc6, 0xfe06c67c, 0x00000000, - 0x00000078, 0x0c0c0c3e, 0x0c0c0c0c, 0x00000000, - 0x00000000, 0x00007c66, 0x6666667c, 0x60603e00, - 0x0000000c, 0x0c0c7ccc, 0xcccccccc, 0x00000000, - 0x00000030, 0x30003830, 0x30303078, 0x00000000, - 0x00000030, 0x30003c30, 0x30303030, 0x30301f00, - 0x0000000c, 0x0c0ccc6c, 0x3c6ccccc, 0x00000000, - 0x00000030, 0x30303030, 0x30303030, 0x00000000, - 0x00000000, 0x000066fe, 0xd6d6d6d6, 0x00000000, - 0x00000000, 0x000078cc, 0xcccccccc, 0x00000000, - 0x00000000, 0x00007cc6, 0xc6c6c67c, 0x00000000, - 0x00000000, 0x00007ccc, 0xcccccc7c, 0x0c0c0c00, - 0x00000000, 0x00007c66, 0x6666667c, 0x60606000, - 0x00000000, 0x000076dc, 0x0c0c0c0c, 0x00000000, - 0x00000000, 0x00007cc6, 0x1c70c67c, 0x00000000, - 0x00000000, 0x1818fe18, 0x18181870, 0x00000000, - 0x00000000, 0x00006666, 0x6666663c, 0x00000000, - 0x00000000, 0x0000c6c6, 0xc66c3810, 0x00000000, - 0x00000000, 0x0000c6d6, 0xd6d6fe6c, 0x00000000, - 0x00000000, 0x0000c66c, 0x38386cc6, 0x00000000, - 0x00000000, 0x00006666, 0x6666667c, 0x60603e00, - 0x00000000, 0x0000fe60, 0x30180cfe, 0x00000000, - 0x00000070, 0x1818180e, 0x18181870, 0x00000000, - 0x00000018, 0x18181800, 0x18181818, 0x00000000, - 0x0000000e, 0x18181870, 0x1818180e, 0x00000000, - 0x000000dc, 0x76000000, 0x00000000, 0x00000000, - 0x00000000, 0x0010386c, 0xc6c6fe00, 0x00000000 -}; - -#endif /* __SOLO6X10_OSD_FONT_H */ diff --git a/drivers/staging/media/solo6x10/p2m.c b/drivers/staging/media/solo6x10/p2m.c index 58ab61b..b3a9339 100644 --- a/drivers/staging/media/solo6x10/p2m.c +++ b/drivers/staging/media/solo6x10/p2m.c @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -18,28 +23,38 @@ */ #include +#include #include -#include + #include "solo6x10.h" -/* #define SOLO_TEST_P2M */ +static int multi_p2m; +module_param(multi_p2m, uint, 0644); +MODULE_PARM_DESC(multi_p2m, + "Use multiple P2M DMA channels (default: no, 6010-only)"); -int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr, - void *sys_addr, u32 ext_addr, u32 size) +static int desc_mode; +module_param(desc_mode, uint, 0644); +MODULE_PARM_DESC(desc_mode, + "Allow use of descriptor mode DMA (default: no, 6010-only)"); + +int solo_p2m_dma(struct solo_dev *solo_dev, int wr, + void *sys_addr, u32 ext_addr, u32 size, + int repeat, u32 ext_size) { dma_addr_t dma_addr; int ret; - WARN_ON(!size); - BUG_ON(id >= SOLO_NR_P2M); - - if (!size) + if (WARN_ON_ONCE((unsigned long)sys_addr & 0x03)) + return -EINVAL; + if (WARN_ON_ONCE(!size)) return -EINVAL; dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size, wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - ret = solo_p2m_dma_t(solo_dev, id, wr, dma_addr, ext_addr, size); + ret = solo_p2m_dma_t(solo_dev, wr, dma_addr, ext_addr, size, + repeat, ext_size); pci_unmap_single(solo_dev->pdev, dma_addr, size, wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); @@ -47,221 +62,141 @@ int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr, return ret; } -int solo_p2m_dma_t(struct solo_dev *solo_dev, u8 id, int wr, - dma_addr_t dma_addr, u32 ext_addr, u32 size) -{ - struct p2m_desc *desc = kzalloc(sizeof(*desc) * 2, GFP_DMA); - int ret; - - if (desc == NULL) - return -ENOMEM; - - solo_p2m_push_desc(&desc[1], wr, dma_addr, ext_addr, size, 0, 0); - ret = solo_p2m_dma_desc(solo_dev, id, desc, 2); - kfree(desc); - - return ret; -} - -void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr, - u32 ext_addr, u32 size, int repeat, u32 ext_size) -{ - desc->ta = cpu_to_le32(dma_addr); - desc->fa = cpu_to_le32(ext_addr); - - desc->ext = cpu_to_le32(SOLO_P2M_COPY_SIZE(size >> 2)); - desc->ctrl = cpu_to_le32(SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) | - (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON); - - /* Ext size only matters when we're repeating */ - if (repeat) { - desc->ext |= cpu_to_le32(SOLO_P2M_EXT_INC(ext_size >> 2)); - desc->ctrl |= cpu_to_le32(SOLO_P2M_PCI_INC(size >> 2) | - SOLO_P2M_REPEAT(repeat)); - } -} - -int solo_p2m_dma_desc(struct solo_dev *solo_dev, u8 id, - struct p2m_desc *desc, int desc_count) +/* Mutex must be held for p2m_id before calling this!! */ +int solo_p2m_dma_desc(struct solo_dev *solo_dev, + struct solo_p2m_desc *desc, dma_addr_t desc_dma, + int desc_cnt) { struct solo_p2m_dev *p2m_dev; unsigned int timeout; + unsigned int config = 0; int ret = 0; - u32 config = 0; - dma_addr_t desc_dma = 0; + int p2m_id = 0; - BUG_ON(id >= SOLO_NR_P2M); - BUG_ON(!desc_count || desc_count > SOLO_NR_P2M_DESC); + /* Get next ID. According to Softlogic, 6110 has problems on !=0 P2M */ + if (solo_dev->type != SOLO_DEV_6110 && multi_p2m) { + p2m_id = atomic_inc_return(&solo_dev->p2m_count) % SOLO_NR_P2M; + if (p2m_id < 0) + p2m_id = -p2m_id; + } - p2m_dev = &solo_dev->p2m_dev[id]; + p2m_dev = &solo_dev->p2m_dev[p2m_id]; - mutex_lock(&p2m_dev->mutex); - - solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0); + if (mutex_lock_interruptible(&p2m_dev->mutex)) + return -EINTR; INIT_COMPLETION(p2m_dev->completion); p2m_dev->error = 0; - /* Enable the descriptors */ - config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(id)); - desc_dma = pci_map_single(solo_dev->pdev, desc, - desc_count * sizeof(*desc), - PCI_DMA_TODEVICE); - solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), desc_dma); - solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), desc_count - 1); - solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config | - SOLO_P2M_DESC_MODE); - - /* Should have all descriptors completed from one interrupt */ - timeout = wait_for_completion_timeout(&p2m_dev->completion, HZ); - - solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0); + if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && desc_mode) { + /* For 6010 with more than one desc, we can do a one-shot */ + p2m_dev->desc_count = p2m_dev->desc_idx = 0; + config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(p2m_id)); + + solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(p2m_id), desc_dma); + solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(p2m_id), desc_cnt); + solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config | + SOLO_P2M_DESC_MODE); + } else { + /* For single descriptors and 6110, we need to run each desc */ + p2m_dev->desc_count = desc_cnt; + p2m_dev->desc_idx = 1; + p2m_dev->descs = desc; + + solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(p2m_id), + desc[1].dma_addr); + solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(p2m_id), + desc[1].ext_addr); + solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(p2m_id), + desc[1].cfg); + solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), + desc[1].ctrl); + } - /* Reset back to non-descriptor mode */ - solo_reg_write(solo_dev, SOLO_P2M_CONFIG(id), config); - solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(id), 0); - solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(id), 0); - pci_unmap_single(solo_dev->pdev, desc_dma, - desc_count * sizeof(*desc), - PCI_DMA_TODEVICE); + timeout = wait_for_completion_timeout(&p2m_dev->completion, + solo_dev->p2m_jiffies); - if (p2m_dev->error) + if (WARN_ON_ONCE(p2m_dev->error)) ret = -EIO; - else if (timeout == 0) + else if (timeout == 0) { + solo_dev->p2m_timeouts++; ret = -EAGAIN; - - mutex_unlock(&p2m_dev->mutex); - - WARN_ON_ONCE(ret); - - return ret; -} - -int solo_p2m_dma_sg(struct solo_dev *solo_dev, u8 id, - struct p2m_desc *pdesc, int wr, - struct scatterlist *sg, u32 sg_off, - u32 ext_addr, u32 size) -{ - int i; - int idx; - - BUG_ON(id >= SOLO_NR_P2M); - - if (WARN_ON_ONCE(!size)) - return -EINVAL; - - memset(pdesc, 0, sizeof(*pdesc)); - - /* Should rewrite this to handle > SOLO_NR_P2M_DESC transactions */ - for (i = 0, idx = 1; idx < SOLO_NR_P2M_DESC && sg && size > 0; - i++, sg = sg_next(sg)) { - struct p2m_desc *desc = &pdesc[idx]; - u32 sg_len = sg_dma_len(sg); - u32 len; - - if (sg_off >= sg_len) { - sg_off -= sg_len; - continue; - } - - sg_len -= sg_off; - len = min(sg_len, size); - - solo_p2m_push_desc(desc, wr, sg_dma_address(sg) + sg_off, - ext_addr, len, 0, 0); - - size -= len; - ext_addr += len; - idx++; - - sg_off = 0; } - WARN_ON_ONCE(size || i >= SOLO_NR_P2M_DESC); + solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), 0); - return solo_p2m_dma_desc(solo_dev, id, pdesc, idx); -} + /* Don't write here for the no_desc_mode case, because config is 0. + * We can't test no_desc_mode again, it might race. */ + if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && config) + solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config); -#ifdef SOLO_TEST_P2M + mutex_unlock(&p2m_dev->mutex); -#define P2M_TEST_CHAR 0xbe + return ret; +} -static unsigned long long p2m_test(struct solo_dev *solo_dev, u8 id, - u32 base, int size) +void solo_p2m_fill_desc(struct solo_p2m_desc *desc, int wr, + dma_addr_t dma_addr, u32 ext_addr, u32 size, + int repeat, u32 ext_size) { - u8 *wr_buf; - u8 *rd_buf; - int i; - unsigned long long err_cnt = 0; + WARN_ON_ONCE(dma_addr & 0x03); + WARN_ON_ONCE(!size); - wr_buf = kmalloc(size, GFP_KERNEL); - if (!wr_buf) { - printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n"); - return size; - } + desc->cfg = SOLO_P2M_COPY_SIZE(size >> 2); + desc->ctrl = SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) | + (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON; - rd_buf = kmalloc(size, GFP_KERNEL); - if (!rd_buf) { - printk(SOLO6X10_NAME ": Failed to malloc for p2m_test\n"); - kfree(wr_buf); - return size; + if (repeat) { + desc->cfg |= SOLO_P2M_EXT_INC(ext_size >> 2); + desc->ctrl |= SOLO_P2M_PCI_INC(size >> 2) | + SOLO_P2M_REPEAT(repeat); } - memset(wr_buf, P2M_TEST_CHAR, size); - memset(rd_buf, P2M_TEST_CHAR + 1, size); - - solo_p2m_dma(solo_dev, id, 1, wr_buf, base, size); - solo_p2m_dma(solo_dev, id, 0, rd_buf, base, size); - - for (i = 0; i < size; i++) - if (wr_buf[i] != rd_buf[i]) - err_cnt++; - - kfree(wr_buf); - kfree(rd_buf); - - return err_cnt; + desc->dma_addr = dma_addr; + desc->ext_addr = ext_addr; } -#define TEST_CHUNK_SIZE (8 * 1024) - -static void run_p2m_test(struct solo_dev *solo_dev) +int solo_p2m_dma_t(struct solo_dev *solo_dev, int wr, + dma_addr_t dma_addr, u32 ext_addr, u32 size, + int repeat, u32 ext_size) { - unsigned long long errs = 0; - u32 size = SOLO_JPEG_EXT_ADDR(solo_dev) + SOLO_JPEG_EXT_SIZE(solo_dev); - int i, d; + struct solo_p2m_desc desc[2]; - dev_warn(&solo_dev->pdev->dev, "Testing %u bytes of external ram\n", - size); + solo_p2m_fill_desc(&desc[1], wr, dma_addr, ext_addr, size, repeat, + ext_size); - for (i = 0; i < size; i += TEST_CHUNK_SIZE) - for (d = 0; d < 4; d++) - errs += p2m_test(solo_dev, d, i, TEST_CHUNK_SIZE); - - dev_warn(&solo_dev->pdev->dev, "Found %llu errors during p2m test\n", - errs); - - return; + /* No need for desc_dma since we know it is a single-shot */ + return solo_p2m_dma_desc(solo_dev, desc, 0, 1); } -#else -#define run_p2m_test(__solo) do {} while (0) -#endif void solo_p2m_isr(struct solo_dev *solo_dev, int id) { struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id]; + struct solo_p2m_desc *desc; + + if (p2m_dev->desc_count <= p2m_dev->desc_idx) { + complete(&p2m_dev->completion); + return; + } - solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_P2M(id)); + /* Setup next descriptor */ + p2m_dev->desc_idx++; + desc = &p2m_dev->descs[p2m_dev->desc_idx]; - complete(&p2m_dev->completion); + solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0); + solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), desc->dma_addr); + solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), desc->ext_addr); + solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id), desc->cfg); + solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), desc->ctrl); } -void solo_p2m_error_isr(struct solo_dev *solo_dev, u32 status) +void solo_p2m_error_isr(struct solo_dev *solo_dev) { + unsigned int err = solo_reg_read(solo_dev, SOLO_PCI_ERR); struct solo_p2m_dev *p2m_dev; int i; - if (!(status & SOLO_PCI_ERR_P2M)) + if (!(err & SOLO_PCI_ERR_P2M)) return; for (i = 0; i < SOLO_NR_P2M; i++) { @@ -280,6 +215,52 @@ void solo_p2m_exit(struct solo_dev *solo_dev) solo_irq_off(solo_dev, SOLO_IRQ_P2M(i)); } +static int solo_p2m_test(struct solo_dev *solo_dev, int base, int size) +{ + u32 *wr_buf; + u32 *rd_buf; + int i; + int ret = -EIO; + int order = get_order(size); + + wr_buf = (u32 *)__get_free_pages(GFP_KERNEL, order); + if (wr_buf == NULL) + return -1; + + rd_buf = (u32 *)__get_free_pages(GFP_KERNEL, order); + if (rd_buf == NULL) { + free_pages((unsigned long)wr_buf, order); + return -1; + } + + for (i = 0; i < (size >> 3); i++) + *(wr_buf + i) = (i << 16) | (i + 1); + + for (i = (size >> 3); i < (size >> 2); i++) + *(wr_buf + i) = ~((i << 16) | (i + 1)); + + memset(rd_buf, 0x55, size); + + if (solo_p2m_dma(solo_dev, 1, wr_buf, base, size, 0, 0)) + goto test_fail; + + if (solo_p2m_dma(solo_dev, 0, rd_buf, base, size, 0, 0)) + goto test_fail; + + for (i = 0; i < (size >> 2); i++) { + if (*(wr_buf + i) != *(rd_buf + i)) + goto test_fail; + } + + ret = 0; + +test_fail: + free_pages((unsigned long)wr_buf, order); + free_pages((unsigned long)rd_buf, order); + + return ret; +} + int solo_p2m_init(struct solo_dev *solo_dev) { struct solo_p2m_dev *p2m_dev; @@ -294,13 +275,57 @@ int solo_p2m_init(struct solo_dev *solo_dev) solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0); solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i), SOLO_P2M_CSC_16BIT_565 | - SOLO_P2M_DMA_INTERVAL(3) | SOLO_P2M_DESC_INTR_OPT | + SOLO_P2M_DMA_INTERVAL(0) | SOLO_P2M_PCI_MASTER_MODE); solo_irq_on(solo_dev, SOLO_IRQ_P2M(i)); } - run_p2m_test(solo_dev); + /* Find correct SDRAM size */ + for (solo_dev->sdram_size = 0, i = 2; i >= 0; i--) { + solo_reg_write(solo_dev, SOLO_DMA_CTRL, + SOLO_DMA_CTRL_REFRESH_CYCLE(1) | + SOLO_DMA_CTRL_SDRAM_SIZE(i) | + SOLO_DMA_CTRL_SDRAM_CLK_INVERT | + SOLO_DMA_CTRL_READ_CLK_SELECT | + SOLO_DMA_CTRL_LATENCY(1)); + + solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config | + SOLO_SYS_CFG_RESET); + solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config); + + switch (i) { + case 2: + if (solo_p2m_test(solo_dev, 0x07ff0000, 0x00010000) || + solo_p2m_test(solo_dev, 0x05ff0000, 0x00010000)) + continue; + break; + + case 1: + if (solo_p2m_test(solo_dev, 0x03ff0000, 0x00010000)) + continue; + break; + + default: + if (solo_p2m_test(solo_dev, 0x01ff0000, 0x00010000)) + continue; + } + + solo_dev->sdram_size = (32 << 20) << i; + break; + } + + if (!solo_dev->sdram_size) { + dev_err(&solo_dev->pdev->dev, "Error detecting SDRAM size\n"); + return -EIO; + } + + if (SOLO_SDRAM_END(solo_dev) > solo_dev->sdram_size) { + dev_err(&solo_dev->pdev->dev, + "SDRAM is not large enough (%u < %u)\n", + solo_dev->sdram_size, SOLO_SDRAM_END(solo_dev)); + return -EIO; + } return 0; } diff --git a/drivers/staging/media/solo6x10/registers.h b/drivers/staging/media/solo6x10/registers.h index aca5444..5e5c7e6 100644 --- a/drivers/staging/media/solo6x10/registers.h +++ b/drivers/staging/media/solo6x10/registers.h @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -22,18 +27,18 @@ #include "offsets.h" -/* Global 6X10 system configuration */ +/* Global 6010 system configuration */ #define SOLO_SYS_CFG 0x0000 -#define SOLO6010_SYS_CFG_FOUT_EN 0x00000001 /* 6010 only */ -#define SOLO6010_SYS_CFG_PLL_BYPASS 0x00000002 /* 6010 only */ -#define SOLO6010_SYS_CFG_PLL_PWDN 0x00000004 /* 6010 only */ -#define SOLO6010_SYS_CFG_OUTDIV(__n) (((__n) & 0x003) << 3) /* 6010 only */ -#define SOLO6010_SYS_CFG_FEEDBACKDIV(__n) (((__n) & 0x1ff) << 5) /* 6010 only */ -#define SOLO6010_SYS_CFG_INPUTDIV(__n) (((__n) & 0x01f) << 14) /* 6010 only */ +#define SOLO_SYS_CFG_FOUT_EN 0x00000001 +#define SOLO_SYS_CFG_PLL_BYPASS 0x00000002 +#define SOLO_SYS_CFG_PLL_PWDN 0x00000004 +#define SOLO_SYS_CFG_OUTDIV(__n) (((__n) & 0x003) << 3) +#define SOLO_SYS_CFG_FEEDBACKDIV(__n) (((__n) & 0x1ff) << 5) +#define SOLO_SYS_CFG_INPUTDIV(__n) (((__n) & 0x01f) << 14) #define SOLO_SYS_CFG_CLOCK_DIV 0x00080000 #define SOLO_SYS_CFG_NCLK_DELAY(__n) (((__n) & 0x003) << 24) #define SOLO_SYS_CFG_PCLK_DELAY(__n) (((__n) & 0x00f) << 26) -#define SOLO_SYS_CFG_SDRAM64BIT 0x40000000 /* 6110: must be set */ +#define SOLO_SYS_CFG_SDRAM64BIT 0x40000000 #define SOLO_SYS_CFG_RESET 0x80000000 #define SOLO_DMA_CTRL 0x0004 @@ -45,7 +50,9 @@ #define SOLO_DMA_CTRL_READ_DATA_SELECT (1<<3) #define SOLO_DMA_CTRL_READ_CLK_SELECT (1<<2) #define SOLO_DMA_CTRL_LATENCY(n) ((n)<<0) -#define SOLO_DMA_CTRL1 0x0008 + +/* Some things we set in this are undocumented. Why Softlogic?!?! */ +#define SOLO_DMA_CTRL1 0x0008 #define SOLO_SYS_VCLK 0x000C #define SOLO_VCLK_INVERT (1<<22) @@ -61,7 +68,7 @@ #define SOLO_VCLK_VIN0001_DELAY(n) ((n)<<0) #define SOLO_IRQ_STAT 0x0010 -#define SOLO_IRQ_ENABLE 0x0014 +#define SOLO_IRQ_MASK 0x0014 #define SOLO_IRQ_P2M(n) (1<<((n)+17)) #define SOLO_IRQ_GPIO (1<<16) #define SOLO_IRQ_VIDEO_LOSS (1<<15) @@ -82,22 +89,7 @@ #define SOLO_CHIP_OPTION 0x001C #define SOLO_CHIP_ID_MASK 0x00000007 -#define SOLO6110_PLL_CONFIG 0x0020 -#define SOLO6110_PLL_RANGE_BYPASS (0 << 20) -#define SOLO6110_PLL_RANGE_5_10MHZ (1 << 20) -#define SOLO6110_PLL_RANGE_8_16MHZ (2 << 20) -#define SOLO6110_PLL_RANGE_13_26MHZ (3 << 20) -#define SOLO6110_PLL_RANGE_21_42MHZ (4 << 20) -#define SOLO6110_PLL_RANGE_34_68MHZ (5 << 20) -#define SOLO6110_PLL_RANGE_54_108MHZ (6 << 20) -#define SOLO6110_PLL_RANGE_88_200MHZ (7 << 20) -#define SOLO6110_PLL_DIVR(x) (((x) - 1) << 15) -#define SOLO6110_PLL_DIVQ_EXP(x) ((x) << 12) -#define SOLO6110_PLL_DIVF(x) (((x) - 1) << 4) -#define SOLO6110_PLL_RESET (1 << 3) -#define SOLO6110_PLL_BYPASS (1 << 2) -#define SOLO6110_PLL_FSEN (1 << 1) -#define SOLO6110_PLL_FB (1 << 0) +#define SOLO_PLL_CONFIG 0x0020 /* 6110 Only */ #define SOLO_EEPROM_CTRL 0x0060 #define SOLO_EEPROM_ACCESS_EN (1<<7) @@ -105,7 +97,7 @@ #define SOLO_EEPROM_CLK (1<<2) #define SOLO_EEPROM_DO (1<<1) #define SOLO_EEPROM_DI (1<<0) -#define SOLO_EEPROM_ENABLE (EEPROM_ACCESS_EN | EEPROM_CS) +#define SOLO_EEPROM_ENABLE (SOLO_EEPROM_ACCESS_EN | SOLO_EEPROM_CS) #define SOLO_PCI_ERR 0x0070 #define SOLO_PCI_ERR_FATAL 0x00000001 @@ -274,8 +266,8 @@ #define SOLO_VO_FI_CHANGE (1<<20) #define SOLO_VO_USER_COLOR_SET_VSYNC (1<<19) #define SOLO_VO_USER_COLOR_SET_HSYNC (1<<18) -#define SOLO_VO_USER_COLOR_SET_NAV (1<<17) -#define SOLO_VO_USER_COLOR_SET_NAH (1<<16) +#define SOLO_VO_USER_COLOR_SET_NAH (1<<17) +#define SOLO_VO_USER_COLOR_SET_NAV (1<<16) #define SOLO_VO_NA_COLOR_Y(Y) ((Y)<<8) #define SOLO_VO_NA_COLOR_CB(CB) (((CB)/16)<<4) #define SOLO_VO_NA_COLOR_CR(CR) (((CR)/16)<<0) @@ -401,12 +393,13 @@ #define SOLO_VE_BLOCK_BASE(n) ((n)<<0) #define SOLO_VE_CFG1 0x0614 -#define SOLO6110_VE_MPEG_SIZE_H(n) ((n)<<28) /* 6110 only */ -#define SOLO6010_VE_BYTE_ALIGN(n) ((n)<<24) /* 6010 only */ -#define SOLO6110_VE_JPEG_SIZE_H(n) ((n)<<20) /* 6110 only */ +#define SOLO_VE_BYTE_ALIGN(n) ((n)<<24) #define SOLO_VE_INSERT_INDEX (1<<18) #define SOLO_VE_MOTION_MODE(n) ((n)<<16) #define SOLO_VE_MOTION_BASE(n) ((n)<<0) +#define SOLO_VE_MPEG_SIZE_H(n) ((n)<<28) /* 6110 Only */ +#define SOLO_VE_JPEG_SIZE_H(n) ((n)<<20) /* 6110 Only */ +#define SOLO_VE_INSERT_INDEX_JPEG (1<<19) /* 6110 Only */ #define SOLO_VE_WMRK_POLY 0x061C #define SOLO_VE_VMRK_INIT_KEY 0x0620 @@ -420,6 +413,7 @@ #define SOLO_COMP_TIME_INC(n) ((n)<<25) #define SOLO_COMP_TIME_WIDTH(n) ((n)<<21) #define SOLO_DCT_INTERVAL(n) ((n)<<16) +#define SOLO_VE_COMPT_MOT 0x0634 /* 6110 Only */ #define SOLO_VE_STATE(n) (0x0640+((n)*4)) @@ -428,14 +422,21 @@ #define SOLO_VE_JPEG_QP_CH_H 0x0678 #define SOLO_VE_JPEG_CFG 0x067C #define SOLO_VE_JPEG_CTRL 0x0680 - +#define SOLO_VE_CODE_ENCRYPT 0x0684 /* 6110 Only */ +#define SOLO_VE_JPEG_CFG1 0x0688 /* 6110 Only */ +#define SOLO_VE_WMRK_ENABLE 0x068C /* 6110 Only */ #define SOLO_VE_OSD_CH 0x0690 #define SOLO_VE_OSD_BASE 0x0694 #define SOLO_VE_OSD_CLR 0x0698 #define SOLO_VE_OSD_OPT 0x069C +#define SOLO_VE_OSD_V_DOUBLE (1<<16) /* 6110 Only */ +#define SOLO_VE_OSD_H_SHADOW (1<<15) +#define SOLO_VE_OSD_V_SHADOW (1<<14) +#define SOLO_VE_OSD_H_OFFSET(n) ((n & 0x7f)<<7) +#define SOLO_VE_OSD_V_OFFSET(n) (n & 0x7f) #define SOLO_VE_CH_INTL(ch) (0x0700+((ch)*4)) -#define SOLO6010_VE_CH_MOT(ch) (0x0740+((ch)*4)) /* 6010 only */ +#define SOLO_VE_CH_MOT(ch) (0x0740+((ch)*4)) #define SOLO_VE_CH_QP(ch) (0x0780+((ch)*4)) #define SOLO_VE_CH_QP_E(ch) (0x07C0+((ch)*4)) #define SOLO_VE_CH_GOP(ch) (0x0800+((ch)*4)) @@ -447,7 +448,7 @@ #define SOLO_VE_JPEG_QUE(n) (0x0A04+((n)*8)) #define SOLO_VD_CFG0 0x0900 -#define SOLO6010_VD_CFG_NO_WRITE_NO_WINDOW (1<<24) /* 6010 only */ +#define SOLO_VD_CFG_NO_WRITE_NO_WINDOW (1<<24) #define SOLO_VD_CFG_BUSY_WIAT_CODE (1<<23) #define SOLO_VD_CFG_BUSY_WIAT_REF (1<<22) #define SOLO_VD_CFG_BUSY_WIAT_RES (1<<21) @@ -599,9 +600,9 @@ #define SOLO_UART_RX_DATA_POP (1<<8) #define SOLO_TIMER_CLOCK_NUM 0x0be0 -#define SOLO_TIMER_WATCHDOG 0x0be4 #define SOLO_TIMER_USEC 0x0be8 #define SOLO_TIMER_SEC 0x0bec +#define SOLO_TIMER_USEC_LSB 0x0d20 /* 6110 Only */ #define SOLO_AUDIO_CONTROL 0x0D00 #define SOLO_AUDIO_ENABLE (1<<31) @@ -629,9 +630,10 @@ #define SOLO_AUDIO_EVOL(ch, value) ((value)<<((ch)%10)) #define SOLO_AUDIO_STA 0x0D14 - -#define SOLO_WATCHDOG 0x0BE4 -#define WATCHDOG_STAT(status) (status<<8) -#define WATCHDOG_TIME(sec) (sec&0xff) +/* + * Watchdog configuration + */ +#define SOLO_WATCHDOG 0x0be4 +#define SOLO_WATCHDOG_SET(status, sec) (status << 8 | (sec & 0xff)) #endif /* __SOLO6X10_REGISTERS_H */ diff --git a/drivers/staging/media/solo6x10/solo6x10-jpeg.h b/drivers/staging/media/solo6x10/solo6x10-jpeg.h index 50defec..c5218ce 100644 --- a/drivers/staging/media/solo6x10/solo6x10-jpeg.h +++ b/drivers/staging/media/solo6x10/solo6x10-jpeg.h @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -20,7 +25,7 @@ #ifndef __SOLO6X10_JPEG_H #define __SOLO6X10_JPEG_H -static unsigned char jpeg_header[] = { +static const unsigned char jpeg_header[] = { 0xff, 0xd8, 0xff, 0xfe, 0x00, 0x0d, 0x42, 0x6c, 0x75, 0x65, 0x63, 0x68, 0x65, 0x72, 0x72, 0x79, 0x20, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x20, 0x16, @@ -102,4 +107,87 @@ static unsigned char jpeg_header[] = { /* This is the byte marker for the start of SOF0: 0xffc0 marker */ #define SOF0_START 575 +/* This is the byte marker for the start of the DQT */ +#define DQT_START 17 +#define DQT_LEN 138 +const unsigned char jpeg_dqt[4][DQT_LEN] = { + { + 0xff, 0xdb, 0x00, 0x43, 0x00, + 0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07, + 0x07, 0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, + 0x0d, 0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13, + 0x0f, 0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a, + 0x1c, 0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22, + 0x2c, 0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c, + 0x30, 0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39, + 0x3d, 0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, + 0xff, 0xdb, 0x00, 0x43, 0x01, + 0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0d, + 0x0d, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 + }, { + 0xff, 0xdb, 0x00, 0x43, 0x00, + 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, + 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, + 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, + 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, + 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, + 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, + 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, + 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, + 0xff, 0xdb, 0x00, 0x43, 0x01, + 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, + 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 + }, { + 0xff, 0xdb, 0x00, 0x43, 0x00, + 0x20, 0x16, 0x18, 0x1c, 0x18, 0x14, 0x20, 0x1c, + 0x1a, 0x1c, 0x24, 0x22, 0x20, 0x26, 0x30, 0x50, + 0x34, 0x30, 0x2c, 0x2c, 0x30, 0x62, 0x46, 0x4a, + 0x3a, 0x50, 0x74, 0x66, 0x7a, 0x78, 0x72, 0x66, + 0x70, 0x6e, 0x80, 0x90, 0xb8, 0x9c, 0x80, 0x88, + 0xae, 0x8a, 0x6e, 0x70, 0xa0, 0xda, 0xa2, 0xae, + 0xbe, 0xc4, 0xce, 0xd0, 0xce, 0x7c, 0x9a, 0xe2, + 0xf2, 0xe0, 0xc8, 0xf0, 0xb8, 0xca, 0xce, 0xc6, + 0xff, 0xdb, 0x00, 0x43, 0x01, + 0x22, 0x24, 0x24, 0x30, 0x2a, 0x30, 0x5e, 0x34, + 0x34, 0x5e, 0xc6, 0x84, 0x70, 0x84, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6 + }, { + 0xff, 0xdb, 0x00, 0x43, 0x00, + 0x30, 0x21, 0x24, 0x2a, 0x24, 0x1e, 0x30, 0x2a, + 0x27, 0x2a, 0x36, 0x33, 0x30, 0x39, 0x48, 0x78, + 0x4e, 0x48, 0x42, 0x42, 0x48, 0x93, 0x69, 0x6f, + 0x57, 0x78, 0xae, 0x99, 0xb7, 0xb4, 0xab, 0x99, + 0xa8, 0xa5, 0xc0, 0xd8, 0xff, 0xea, 0xc0, 0xcc, + 0xff, 0xcf, 0xa5, 0xa8, 0xf0, 0xff, 0xf3, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xba, 0xe7, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xdb, 0x00, 0x43, 0x01, + 0x33, 0x36, 0x36, 0x48, 0x3f, 0x48, 0x8d, 0x4e, + 0x4e, 0x8d, 0xff, 0xc6, 0xa8, 0xc6, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + } +}; + #endif /* __SOLO6X10_JPEG_H */ diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index abee721..a75d939 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -20,20 +25,20 @@ #ifndef __SOLO6X10_H #define __SOLO6X10_H -#include #include #include -#include #include #include #include -#include -#include -#include +#include +#include #include +#include #include + #include #include + #include "registers.h" #ifndef PCI_VENDOR_ID_SOFTLOGIC @@ -58,19 +63,24 @@ #define PCI_DEVICE_ID_BC_6110_16 0x5310 #endif /* Bluecherry */ +/* Used in pci_device_id, and solo_dev->type */ +#define SOLO_DEV_6010 0 +#define SOLO_DEV_6110 1 + #define SOLO6X10_NAME "solo6x10" #define SOLO_MAX_CHANNELS 16 /* Make sure these two match */ -#define SOLO6X10_VERSION "2.1.0" #define SOLO6X10_VER_MAJOR 2 -#define SOLO6X10_VER_MINOR 0 -#define SOLO6X10_VER_SUB 0 +#define SOLO6X10_VER_MINOR 4 +#define SOLO6X10_VER_SUB 4 #define SOLO6X10_VER_NUM \ KERNEL_VERSION(SOLO6X10_VER_MAJOR, SOLO6X10_VER_MINOR, SOLO6X10_VER_SUB) - -#define FLAGS_6110 1 +#define SOLO6X10_VERSION \ + __stringify(SOLO6X10_VER_MAJOR) "." \ + __stringify(SOLO6X10_VER_MINOR) "." \ + __stringify(SOLO6X10_VER_SUB) /* * The SOLO6x10 actually has 8 i2c channels, but we only use 2. @@ -84,16 +94,7 @@ /* DMA Engine setup */ #define SOLO_NR_P2M 4 #define SOLO_NR_P2M_DESC 256 -/* MPEG and JPEG share the same interrupt and locks so they must be together - * in the same dma channel. */ -#define SOLO_P2M_DMA_ID_MP4E 0 -#define SOLO_P2M_DMA_ID_JPEG 0 -#define SOLO_P2M_DMA_ID_MP4D 1 -#define SOLO_P2M_DMA_ID_G723D 1 -#define SOLO_P2M_DMA_ID_DISP 2 -#define SOLO_P2M_DMA_ID_OSG 2 -#define SOLO_P2M_DMA_ID_G723E 3 -#define SOLO_P2M_DMA_ID_VIN 3 +#define SOLO_P2M_DESC_SIZE (SOLO_NR_P2M_DESC * 16) /* Encoder standard modes */ #define SOLO_ENC_MODE_CIF 2 @@ -103,12 +104,6 @@ #define SOLO_DEFAULT_GOP 30 #define SOLO_DEFAULT_QP 3 -/* There is 8MB memory available for solo to buffer MPEG4 frames. - * This gives us 512 * 16kbyte queues. */ -#define SOLO_NR_RING_BUFS 512 - -#define SOLO_CLOCK_MHZ 108 - #ifndef V4L2_BUF_FLAG_MOTION_ON #define V4L2_BUF_FLAG_MOTION_ON 0x0400 #define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800 @@ -128,64 +123,67 @@ enum SOLO_I2C_STATE { IIC_STATE_STOP }; -struct p2m_desc { - u32 ctrl; - u32 ext; - u32 ta; - u32 fa; +/* Defined in Table 4-16, Page 68-69 of the 6010 Datasheet */ +struct solo_p2m_desc { + u32 ctrl; + u32 cfg; + u32 dma_addr; + u32 ext_addr; }; struct solo_p2m_dev { struct mutex mutex; struct completion completion; + int desc_count; + int desc_idx; + struct solo_p2m_desc *descs; int error; }; -#define OSD_TEXT_MAX 30 - -enum solo_enc_types { - SOLO_ENC_TYPE_STD, - SOLO_ENC_TYPE_EXT, -}; +#define OSD_TEXT_MAX 44 struct solo_enc_dev { - struct solo_dev *solo_dev; + struct solo_dev *solo_dev; /* V4L2 Items */ struct video_device *vfd; /* General accounting */ - wait_queue_head_t thread_wait; - spinlock_t lock; + struct mutex enable_lock; + spinlock_t motion_lock; atomic_t readers; + atomic_t mpeg_readers; u8 ch; u8 mode, gop, qp, interlaced, interval; - u8 reset_gop; u8 bw_weight; - u8 motion_detected; u16 motion_thresh; u16 width; u16 height; + + /* OSD buffers */ char osd_text[OSD_TEXT_MAX + 1]; -}; + u8 osd_buf[SOLO_EOSD_EXT_SIZE_MAX] + __aligned(4); -struct solo_enc_buf { - u8 vop; - u8 ch; - enum solo_enc_types type; - u32 off; - u32 size; - u32 jpeg_off; - u32 jpeg_size; - struct timeval ts; + /* VOP stuff */ + unsigned char vop[64]; + int vop_len; + unsigned char jpeg_header[1024]; + int jpeg_len; + + /* File handles that are listening for buffers */ + struct list_head listeners; }; /* The SOLO6x10 PCI Device */ struct solo_dev { /* General stuff */ struct pci_dev *pdev; + int type; + unsigned int time_sync; + unsigned int usec_lsb; + unsigned int clock_mhz; u8 __iomem *reg_base; int nr_chans; int nr_ext; - u32 flags; u32 irq_mask; u32 motion_mask; spinlock_t reg_io_lock; @@ -206,6 +204,9 @@ struct solo_dev { /* P2M DMA Engine */ struct solo_p2m_dev p2m_dev[SOLO_NR_P2M]; + atomic_t p2m_count; + int p2m_jiffies; + unsigned int p2m_timeouts; /* V4L2 Display items */ struct video_device *vfd; @@ -219,9 +220,6 @@ struct solo_dev { u16 enc_bw_remain; /* IDX into hw mp4 encoder */ u8 enc_idx; - /* Our software ring of enc buf references */ - u16 enc_wr_idx; - struct solo_enc_buf enc_buf[SOLO_NR_RING_BUFS]; /* Current video settings */ u32 video_type; @@ -230,11 +228,32 @@ struct solo_dev { u16 vin_hstart, vin_vstart; u8 fps; + /* JPEG Qp setting */ + spinlock_t jpeg_qp_lock; + u32 jpeg_qp[2]; + /* Audio components */ struct snd_card *snd_card; struct snd_pcm *snd_pcm; atomic_t snd_users; int g723_hw_idx; + + /* sysfs stuffs */ + struct device dev; + int sdram_size; + struct bin_attribute sdram_attr; + unsigned int sys_config; + + /* Ring thread */ + struct task_struct *ring_thread; + wait_queue_head_t ring_thread_wait; + atomic_t enc_users; + atomic_t disp_users; + + /* VOP_HEADER handling */ + void *vh_buf; + dma_addr_t vh_dma; + int vh_size; }; static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg) @@ -255,7 +274,8 @@ static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg) return ret; } -static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, u32 data) +static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, + u32 data) { unsigned long flags; u16 val; @@ -270,8 +290,17 @@ static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, u32 data) spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags); } -void solo_irq_on(struct solo_dev *solo_dev, u32 mask); -void solo_irq_off(struct solo_dev *solo_dev, u32 mask); +static inline void solo_irq_on(struct solo_dev *dev, u32 mask) +{ + dev->irq_mask |= mask; + solo_reg_write(dev, SOLO_IRQ_MASK, dev->irq_mask); +} + +static inline void solo_irq_off(struct solo_dev *dev, u32 mask) +{ + dev->irq_mask &= ~mask; + solo_reg_write(dev, SOLO_IRQ_MASK, dev->irq_mask); +} /* Init/exit routeines for subsystems */ int solo_disp_init(struct solo_dev *solo_dev); @@ -286,13 +315,13 @@ void solo_i2c_exit(struct solo_dev *solo_dev); int solo_p2m_init(struct solo_dev *solo_dev); void solo_p2m_exit(struct solo_dev *solo_dev); -int solo_v4l2_init(struct solo_dev *solo_dev); +int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr); void solo_v4l2_exit(struct solo_dev *solo_dev); int solo_enc_init(struct solo_dev *solo_dev); void solo_enc_exit(struct solo_dev *solo_dev); -int solo_enc_v4l2_init(struct solo_dev *solo_dev); +int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr); void solo_enc_v4l2_exit(struct solo_dev *solo_dev); int solo_g723_init(struct solo_dev *solo_dev); @@ -301,7 +330,7 @@ void solo_g723_exit(struct solo_dev *solo_dev); /* ISR's */ int solo_i2c_isr(struct solo_dev *solo_dev); void solo_p2m_isr(struct solo_dev *solo_dev, int id); -void solo_p2m_error_isr(struct solo_dev *solo_dev, u32 status); +void solo_p2m_error_isr(struct solo_dev *solo_dev); void solo_enc_v4l2_isr(struct solo_dev *solo_dev); void solo_g723_isr(struct solo_dev *solo_dev); void solo_motion_isr(struct solo_dev *solo_dev); @@ -313,24 +342,39 @@ void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off, u8 data); /* P2M DMA */ -int solo_p2m_dma_t(struct solo_dev *solo_dev, u8 id, int wr, - dma_addr_t dma_addr, u32 ext_addr, u32 size); -int solo_p2m_dma(struct solo_dev *solo_dev, u8 id, int wr, - void *sys_addr, u32 ext_addr, u32 size); -int solo_p2m_dma_sg(struct solo_dev *solo_dev, u8 id, - struct p2m_desc *pdesc, int wr, - struct scatterlist *sglist, u32 sg_off, - u32 ext_addr, u32 size); -void solo_p2m_push_desc(struct p2m_desc *desc, int wr, dma_addr_t dma_addr, - u32 ext_addr, u32 size, int repeat, u32 ext_size); -int solo_p2m_dma_desc(struct solo_dev *solo_dev, u8 id, - struct p2m_desc *desc, int desc_count); +int solo_p2m_dma_t(struct solo_dev *solo_dev, int wr, + dma_addr_t dma_addr, u32 ext_addr, u32 size, + int repeat, u32 ext_size); +int solo_p2m_dma(struct solo_dev *solo_dev, int wr, + void *sys_addr, u32 ext_addr, u32 size, + int repeat, u32 ext_size); +void solo_p2m_fill_desc(struct solo_p2m_desc *desc, int wr, + dma_addr_t dma_addr, u32 ext_addr, u32 size, + int repeat, u32 ext_size); +int solo_p2m_dma_desc(struct solo_dev *solo_dev, + struct solo_p2m_desc *desc, dma_addr_t desc_dma, + int desc_cnt); /* Set the threshold for motion detection */ -void solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val); +int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val); +int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, u16 val, + u16 block); #define SOLO_DEF_MOT_THRESH 0x0300 /* Write text on OSD */ int solo_osd_print(struct solo_enc_dev *solo_enc); +/* EEPROM commands */ +unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en); +unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc); +int solo_eeprom_write(struct solo_dev *solo_dev, int loc, + unsigned short data); + +/* JPEG Qp functions */ +void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch, + unsigned int qp); +int solo_g_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch); + +#define CHK_FLAGS(v, flags) (((v) & (flags)) == (flags)) + #endif /* __SOLO6X10_H */ diff --git a/drivers/staging/media/solo6x10/tw28.c b/drivers/staging/media/solo6x10/tw28.c index db56b42..365ab10 100644 --- a/drivers/staging/media/solo6x10/tw28.c +++ b/drivers/staging/media/solo6x10/tw28.c @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -18,12 +23,12 @@ */ #include +#include + #include "solo6x10.h" #include "tw28.h" -/* XXX: Some of these values are masked into an 8-bit regs, and shifted - * around for other 8-bit regs. What are the magic bits in these values? */ -#define DEFAULT_HDELAY_NTSC (32 - 4) +#define DEFAULT_HDELAY_NTSC (32 - 8) #define DEFAULT_HACTIVE_NTSC (720 + 16) #define DEFAULT_VDELAY_NTSC (7 - 2) #define DEFAULT_VACTIVE_NTSC (240 + 4) @@ -33,15 +38,16 @@ #define DEFAULT_VDELAY_PAL (6) #define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL) -static u8 tbl_tw2864_template[] = { - 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ - 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ - 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x20 */ - 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x30 */ - 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, + +static const u8 tbl_tw2864_ntsc_template[] = { + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ + 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ + 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */ + 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x30 */ + 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ @@ -61,14 +67,49 @@ static u8 tbl_tw2864_template[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00, 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */ - 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81, - 0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ + 0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81, + 0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */ 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00, }; -static u8 tbl_tw2865_ntsc_template[] = { +static const u8 tbl_tw2864_pal_template[] = { + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */ + 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */ + 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */ + 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */ + 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00, + 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ + 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00, + 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */ + 0x00, 0x28, 0x44, 0x44, 0xa0, 0x90, 0x5a, 0x01, + 0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */ + 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44, + 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ + 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00, + 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */ + 0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81, + 0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ + 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, + 0x83, 0xb5, 0x09, 0x00, 0xa0, 0x00, 0x01, 0x20, /* 0xf0 */ + 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00, +}; + +static const u8 tbl_tw2865_ntsc_template[] = { 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ @@ -103,7 +144,7 @@ static u8 tbl_tw2865_ntsc_template[] = { 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0, }; -static u8 tbl_tw2865_pal_template[] = { +static const u8 tbl_tw2865_pal_template[] = { 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */ 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */ @@ -180,8 +221,8 @@ static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off, msleep_interruptible(1); } -/* printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n", - addr, off, val); */ +/* printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n", */ +/* addr, off, val); */ } static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr) @@ -216,16 +257,17 @@ static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr) for (i = 0; i < 0xff; i++) { /* Skip read only registers */ - if (i >= 0xb8 && i <= 0xc1) - continue; - if ((i & ~0x30) == 0x00 || - (i & ~0x30) == 0x0c || - (i & ~0x30) == 0x0d) - continue; - if (i >= 0xc4 && i <= 0xc7) + switch (i) { + case 0xb8 ... 0xc1: + case 0xc4 ... 0xc7: + case 0xfd: continue; - if (i == 0xfd) + } + switch (i & ~0x30) { + case 0x00: + case 0x0c ... 0x0d: continue; + } tw_write_and_verify(solo_dev, dev_addr, i, tbl_tw2865_common[i]); @@ -236,11 +278,15 @@ static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr) static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr) { - u8 tbl_tw2864_common[sizeof(tbl_tw2864_template)]; + u8 tbl_tw2864_common[256]; int i; - memcpy(tbl_tw2864_common, tbl_tw2864_template, - sizeof(tbl_tw2864_common)); + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) + memcpy(tbl_tw2864_common, tbl_tw2864_pal_template, + sizeof(tbl_tw2864_common)); + else + memcpy(tbl_tw2864_common, tbl_tw2864_ntsc_template, + sizeof(tbl_tw2864_common)); if (solo_dev->tw2865 == 0) { /* IRQ Mode */ @@ -285,33 +331,19 @@ static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr) } } - /* NTSC or PAL */ - if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) { - for (i = 0; i < 4; i++) { - tbl_tw2864_common[0x07 | (i << 4)] |= 0x10; - tbl_tw2864_common[0x08 | (i << 4)] |= 0x06; - tbl_tw2864_common[0x0a | (i << 4)] |= 0x08; - tbl_tw2864_common[0x0b | (i << 4)] |= 0x13; - tbl_tw2864_common[0x0e | (i << 4)] |= 0x01; - } - tbl_tw2864_common[0x9d] = 0x90; - tbl_tw2864_common[0xf3] = 0x00; - tbl_tw2864_common[0xf4] = 0xa0; - } - for (i = 0; i < 0xff; i++) { /* Skip read only registers */ - if (i >= 0xb8 && i <= 0xc1) - continue; - if ((i & ~0x30) == 0x00 || - (i & ~0x30) == 0x0c || - (i & ~0x30) == 0x0d) - continue; - if (i == 0x74 || i == 0x77 || i == 0x78 || - i == 0x79 || i == 0x7a) + switch (i) { + case 0xb8 ... 0xc1: + case 0xfd: continue; - if (i == 0xfd) + } + switch (i & ~0x30) { + case 0x00: + case 0x0c: + case 0x0d: continue; + } tw_write_and_verify(solo_dev, dev_addr, i, tbl_tw2864_common[i]); @@ -544,8 +576,8 @@ int solo_tw28_init(struct solo_dev *solo_dev) int i; u8 value; - /* Detect techwell chip type */ - for (i = 0; i < TW_NUM_CHIP; i++) { + /* Detect techwell chip type(s) */ + for (i = 0; i < solo_dev->nr_chans / 4; i++) { value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, TW_CHIP_OFFSET_ADDR(i), 0xFF); @@ -560,7 +592,8 @@ int solo_tw28_init(struct solo_dev *solo_dev) break; default: value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, - TW_CHIP_OFFSET_ADDR(i), 0x59); + TW_CHIP_OFFSET_ADDR(i), + 0x59); if ((value >> 3) == 0x04) { solo_dev->tw2815 |= 1 << i; solo_dev->tw28_cnt++; @@ -568,8 +601,11 @@ int solo_tw28_init(struct solo_dev *solo_dev) } } - if (!solo_dev->tw28_cnt) + if (solo_dev->tw28_cnt != (solo_dev->nr_chans >> 2)) { + dev_err(&solo_dev->pdev->dev, + "Could not initialize any techwell chips\n"); return -EINVAL; + } saa7128_setup(solo_dev); @@ -582,17 +618,6 @@ int solo_tw28_init(struct solo_dev *solo_dev) tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i)); } - dev_info(&solo_dev->pdev->dev, "Initialized %d tw28xx chip%s:", - solo_dev->tw28_cnt, solo_dev->tw28_cnt == 1 ? "" : "s"); - - if (solo_dev->tw2865) - printk(" tw2865[%d]", hweight32(solo_dev->tw2865)); - if (solo_dev->tw2864) - printk(" tw2864[%d]", hweight32(solo_dev->tw2864)); - if (solo_dev->tw2815) - printk(" tw2815[%d]", hweight32(solo_dev->tw2815)); - printk("\n"); - return 0; } @@ -610,7 +635,7 @@ int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch) chip_num = ch / 4; ch %= 4; - val = tw_readbyte(solo_dev, chip_num, TW286X_AV_STAT_ADDR, + val = tw_readbyte(solo_dev, chip_num, TW286x_AV_STAT_ADDR, TW_AV_STAT_ADDR) & 0x0f; return val & (1 << ch) ? 1 : 0; @@ -626,7 +651,7 @@ u16 tw28_get_audio_status(struct solo_dev *solo_dev) int i; for (i = 0; i < solo_dev->tw28_cnt; i++) { - val = (tw_readbyte(solo_dev, i, TW286X_AV_STAT_ADDR, + val = (tw_readbyte(solo_dev, i, TW286x_AV_STAT_ADDR, TW_AV_STAT_ADDR) & 0xf0) >> 4; status |= val << (i * 4); } @@ -635,7 +660,8 @@ u16 tw28_get_audio_status(struct solo_dev *solo_dev) } #endif -int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val) +int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, + s32 val) { char sval; u8 chip_num; @@ -676,6 +702,7 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val) break; case V4L2_CID_SATURATION: + /* 286x chips have a U and V component for saturation */ if (is_tw286x(solo_dev, chip_num)) { solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, TW_CHIP_OFFSET_ADDR(chip_num), diff --git a/drivers/staging/media/solo6x10/tw28.h b/drivers/staging/media/solo6x10/tw28.h index a44a03a..a03b429 100644 --- a/drivers/staging/media/solo6x10/tw28.h +++ b/drivers/staging/media/solo6x10/tw28.h @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -36,7 +41,7 @@ #define TW_AUDIO_INPUT_GAIN_ADDR(n) (0x60 + ((n > 1) ? 1 : 0)) /* tw286x */ -#define TW286X_AV_STAT_ADDR 0xfd +#define TW286x_AV_STAT_ADDR 0xfd #define TW286x_HUE_ADDR(n) (0x06 | ((n) << 4)) #define TW286x_SATURATIONU_ADDR(n) (0x04 | ((n) << 4)) #define TW286x_SATURATIONV_ADDR(n) (0x05 | ((n) << 4)) diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index 310b126..bb4d60a 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -21,33 +26,100 @@ #include #include #include + #include #include #include + #include "solo6x10.h" #include "tw28.h" #include "solo6x10-jpeg.h" -#define MIN_VID_BUFFERS 4 -#define FRAME_BUF_SIZE (128 * 1024) +#define MIN_VID_BUFFERS 2 +#define FRAME_BUF_SIZE (196 * 1024) #define MP4_QS 16 +#define DMA_ALIGN 4096 -static int solo_enc_thread(void *data); - -extern unsigned video_nr; +enum solo_enc_types { + SOLO_ENC_TYPE_STD, + SOLO_ENC_TYPE_EXT, +}; struct solo_enc_fh { struct solo_enc_dev *enc; u32 fmt; - u16 rd_idx; u8 enc_on; enum solo_enc_types type; struct videobuf_queue vidq; struct list_head vidq_active; - struct task_struct *kthread; - struct p2m_desc desc[SOLO_NR_P2M_DESC]; + int desc_count; + int desc_nelts; + struct solo_p2m_desc *desc_items; + dma_addr_t desc_dma; + spinlock_t av_lock; + struct list_head list; +}; + +struct solo_videobuf { + struct videobuf_buffer vb; + unsigned int flags; +}; + +/* 6010 M4V */ +static unsigned char vop_6010_ntsc_d1[] = { + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, + 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40, + 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, + 0x1f, 0x4c, 0x58, 0x10, 0xf0, 0x71, 0x18, 0x3f, +}; + +static unsigned char vop_6010_ntsc_cif[] = { + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, + 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40, + 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, + 0x1f, 0x4c, 0x2c, 0x10, 0x78, 0x51, 0x18, 0x3f, +}; + +static unsigned char vop_6010_pal_d1[] = { + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, + 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40, + 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, + 0x1f, 0x4c, 0x58, 0x11, 0x20, 0x71, 0x18, 0x3f, +}; + +static unsigned char vop_6010_pal_cif[] = { + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, + 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40, + 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, + 0x1f, 0x4c, 0x2c, 0x10, 0x90, 0x51, 0x18, 0x3f, +}; + +/* 6110 h.264 */ +static unsigned char vop_6110_ntsc_d1[] = { + 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, + 0x9a, 0x74, 0x05, 0x81, 0xec, 0x80, 0x00, 0x00, + 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, +}; + +static unsigned char vop_6110_ntsc_cif[] = { + 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, + 0x9a, 0x74, 0x0b, 0x0f, 0xc8, 0x00, 0x00, 0x00, + 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00, +}; + +static unsigned char vop_6110_pal_d1[] = { + 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, + 0x9a, 0x74, 0x05, 0x80, 0x93, 0x20, 0x00, 0x00, + 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, +}; + +static unsigned char vop_6110_pal_cif[] = { + 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, + 0x9a, 0x74, 0x0b, 0x04, 0xb2, 0x00, 0x00, 0x00, + 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00, }; + static const u32 solo_user_ctrls[] = { V4L2_CID_BRIGHTNESS, V4L2_CID_CONTRAST, @@ -82,79 +154,179 @@ static const u32 *solo_ctrl_classes[] = { NULL }; +struct vop_header { + /* VE_STATUS0 */ + u32 mpeg_size:20, sad_motion_flag:1, video_motion_flag:1, vop_type:2, + channel:5, source_fl:1, interlace:1, progressive:1; + + /* VE_STATUS1 */ + u32 vsize:8, hsize:8, last_queue:4, nop0:8, scale:4; + + /* VE_STATUS2 */ + u32 mpeg_off; + + /* VE_STATUS3 */ + u32 jpeg_off; + + /* VE_STATUS4 */ + u32 jpeg_size:20, interval:10, nop1:2; + + /* VE_STATUS5/6 */ + u32 sec, usec; + + /* VE_STATUS7/8/9 */ + u32 nop2[3]; + + /* VE_STATUS10 */ + u32 mpeg_size_alt:20, nop3:12; + + u32 end_nops[5]; +} __packed; + +struct solo_enc_buf { + enum solo_enc_types type; + struct vop_header *vh; + int motion; +}; + static int solo_is_motion_on(struct solo_enc_dev *solo_enc) { struct solo_dev *solo_dev = solo_enc->solo_dev; - u8 ch = solo_enc->ch; - if (solo_dev->motion_mask & (1 << ch)) - return 1; - return 0; + return (solo_dev->motion_mask >> solo_enc->ch) & 1; +} + +static int solo_motion_detected(struct solo_enc_dev *solo_enc) +{ + struct solo_dev *solo_dev = solo_enc->solo_dev; + unsigned long flags; + u32 ch_mask = 1 << solo_enc->ch; + int ret = 0; + + spin_lock_irqsave(&solo_enc->motion_lock, flags); + if (solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS) & ch_mask) { + solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, ch_mask); + ret = 1; + } + spin_unlock_irqrestore(&solo_enc->motion_lock, flags); + + return ret; } static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on) { struct solo_dev *solo_dev = solo_enc->solo_dev; - u8 ch = solo_enc->ch; + u32 mask = 1 << solo_enc->ch; + unsigned long flags; - spin_lock(&solo_enc->lock); + spin_lock_irqsave(&solo_enc->motion_lock, flags); if (on) - solo_dev->motion_mask |= (1 << ch); + solo_dev->motion_mask |= mask; else - solo_dev->motion_mask &= ~(1 << ch); + solo_dev->motion_mask &= ~mask; - /* Do this regardless of if we are turning on or off */ - solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR, - 1 << solo_enc->ch); - solo_enc->motion_detected = 0; + solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, mask); solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(solo_dev->motion_mask) | (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16)); - if (solo_dev->motion_mask) - solo_irq_on(solo_dev, SOLO_IRQ_MOTION); - else - solo_irq_off(solo_dev, SOLO_IRQ_MOTION); - - spin_unlock(&solo_enc->lock); + spin_unlock_irqrestore(&solo_enc->motion_lock, flags); } -/* Should be called with solo_enc->lock held */ +/* MUST be called with solo_enc->enable_lock held */ static void solo_update_mode(struct solo_enc_dev *solo_enc) { struct solo_dev *solo_dev = solo_enc->solo_dev; - - assert_spin_locked(&solo_enc->lock); + int vop_len; + unsigned char *vop; solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0; solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1); - switch (solo_enc->mode) { - case SOLO_ENC_MODE_CIF: + if (solo_enc->mode == SOLO_ENC_MODE_CIF) { solo_enc->width = solo_dev->video_hsize >> 1; solo_enc->height = solo_dev->video_vsize; - break; - case SOLO_ENC_MODE_D1: + if (solo_dev->type == SOLO_DEV_6110) { + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { + vop = vop_6110_ntsc_cif; + vop_len = sizeof(vop_6110_ntsc_cif); + } else { + vop = vop_6110_pal_cif; + vop_len = sizeof(vop_6110_pal_cif); + } + } else { + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { + vop = vop_6010_ntsc_cif; + vop_len = sizeof(vop_6010_ntsc_cif); + } else { + vop = vop_6010_pal_cif; + vop_len = sizeof(vop_6010_pal_cif); + } + } + } else { solo_enc->width = solo_dev->video_hsize; solo_enc->height = solo_dev->video_vsize << 1; solo_enc->bw_weight <<= 2; - break; - default: - WARN(1, "mode is unknown\n"); + if (solo_dev->type == SOLO_DEV_6110) { + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { + vop = vop_6110_ntsc_d1; + vop_len = sizeof(vop_6110_ntsc_d1); + } else { + vop = vop_6110_pal_d1; + vop_len = sizeof(vop_6110_pal_d1); + } + } else { + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { + vop = vop_6010_ntsc_d1; + vop_len = sizeof(vop_6010_ntsc_d1); + } else { + vop = vop_6010_pal_d1; + vop_len = sizeof(vop_6010_pal_d1); + } + } } + + memcpy(solo_enc->vop, vop, vop_len); + + /* Some fixups for 6010/M4V */ + if (solo_dev->type == SOLO_DEV_6010) { + u16 fps = solo_dev->fps * 1000; + u16 interval = solo_enc->interval * 1000; + + vop = solo_enc->vop; + + /* Frame rate and interval */ + vop[22] = fps >> 4; + vop[23] = ((fps << 4) & 0xf0) | 0x0c + | ((interval >> 13) & 0x3); + vop[24] = (interval >> 5) & 0xff; + vop[25] = ((interval << 3) & 0xf8) | 0x04; + } + + solo_enc->vop_len = vop_len; + + /* Now handle the jpeg header */ + vop = solo_enc->jpeg_header; + vop[SOF0_START + 5] = 0xff & (solo_enc->height >> 8); + vop[SOF0_START + 6] = 0xff & solo_enc->height; + vop[SOF0_START + 7] = 0xff & (solo_enc->width >> 8); + vop[SOF0_START + 8] = 0xff & solo_enc->width; + + memcpy(vop + DQT_START, + jpeg_dqt[solo_g_jpeg_qp(solo_dev, solo_enc->ch)], DQT_LEN); } -/* Should be called with solo_enc->lock held */ -static int solo_enc_on(struct solo_enc_fh *fh) +/* MUST be called with solo_enc->enable_lock held */ +static int __solo_enc_on(struct solo_enc_fh *fh) { struct solo_enc_dev *solo_enc = fh->enc; u8 ch = solo_enc->ch; struct solo_dev *solo_dev = solo_enc->solo_dev; u8 interval; - assert_spin_locked(&solo_enc->lock); + BUG_ON(!mutex_is_locked(&solo_enc->enable_lock)); if (fh->enc_on) return 0; @@ -170,13 +342,20 @@ static int solo_enc_on(struct solo_enc_fh *fh) } fh->enc_on = 1; - fh->rd_idx = solo_enc->solo_dev->enc_wr_idx; + list_add(&fh->list, &solo_enc->listeners); if (fh->type == SOLO_ENC_TYPE_EXT) solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1); - if (atomic_inc_return(&solo_enc->readers) > 1) + /* Reset the encoder if we are the first mpeg reader, else only reset + * on the first mjpeg reader. */ + if (fh->fmt == V4L2_PIX_FMT_MPEG) { + atomic_inc(&solo_enc->readers); + if (atomic_inc_return(&solo_enc->mpeg_readers) > 1) + return 0; + } else if (atomic_inc_return(&solo_enc->readers) > 1) { return 0; + } /* Disable all encoding for this channel */ solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0); @@ -203,701 +382,414 @@ static int solo_enc_on(struct solo_enc_fh *fh) /* Enables the standard encoder */ solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode); - /* Settle down Beavis... */ - mdelay(10); - return 0; } -static void solo_enc_off(struct solo_enc_fh *fh) +static int solo_enc_on(struct solo_enc_fh *fh) { struct solo_enc_dev *solo_enc = fh->enc; - struct solo_dev *solo_dev = solo_enc->solo_dev; - - if (!fh->enc_on) - return; - - if (fh->kthread) { - kthread_stop(fh->kthread); - fh->kthread = NULL; - } - - solo_dev->enc_bw_remain += solo_enc->bw_weight; - fh->enc_on = 0; + int ret; - if (atomic_dec_return(&solo_enc->readers) > 0) - return; + mutex_lock(&solo_enc->enable_lock); + ret = __solo_enc_on(fh); + mutex_unlock(&solo_enc->enable_lock); - solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0); - solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0); + return ret; } -static int solo_start_fh_thread(struct solo_enc_fh *fh) +static void __solo_enc_off(struct solo_enc_fh *fh) { struct solo_enc_dev *solo_enc = fh->enc; + struct solo_dev *solo_dev = solo_enc->solo_dev; - fh->kthread = kthread_run(solo_enc_thread, fh, SOLO6X10_NAME "_enc"); - - /* Oops, we had a problem */ - if (IS_ERR(fh->kthread)) { - spin_lock(&solo_enc->lock); - solo_enc_off(fh); - spin_unlock(&solo_enc->lock); - - return PTR_ERR(fh->kthread); - } + BUG_ON(!mutex_is_locked(&solo_enc->enable_lock)); - return 0; -} + if (!fh->enc_on) + return; -static void enc_reset_gop(struct solo_dev *solo_dev, u8 ch) -{ - BUG_ON(ch >= solo_dev->nr_chans); - solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), 1); - solo_dev->v4l2_enc[ch]->reset_gop = 1; -} + list_del(&fh->list); + fh->enc_on = 0; -static int enc_gop_reset(struct solo_dev *solo_dev, u8 ch, u8 vop) -{ - BUG_ON(ch >= solo_dev->nr_chans); - if (!solo_dev->v4l2_enc[ch]->reset_gop) - return 0; - if (vop) - return 1; - solo_dev->v4l2_enc[ch]->reset_gop = 0; - solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), - solo_dev->v4l2_enc[ch]->gop); - return 0; -} + if (fh->fmt == V4L2_PIX_FMT_MPEG) + atomic_dec(&solo_enc->mpeg_readers); -static void enc_write_sg(struct scatterlist *sglist, void *buf, int size) -{ - struct scatterlist *sg; - u8 *src = buf; + if (atomic_dec_return(&solo_enc->readers) > 0) + return; - for (sg = sglist; sg && size > 0; sg = sg_next(sg)) { - u8 *p = sg_virt(sg); - size_t len = sg_dma_len(sg); - int i; + solo_dev->enc_bw_remain += solo_enc->bw_weight; - for (i = 0; i < len && size; i++) - p[i] = *(src++); - } + solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0); + solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0); } -static int enc_get_mpeg_dma_sg(struct solo_dev *solo_dev, - struct p2m_desc *desc, - struct scatterlist *sglist, int skip, - unsigned int off, unsigned int size) +static void solo_enc_off(struct solo_enc_fh *fh) { - int ret; - - if (off > SOLO_MP4E_EXT_SIZE(solo_dev)) - return -EINVAL; - - if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) { - return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, - desc, 0, sglist, skip, - SOLO_MP4E_EXT_ADDR(solo_dev) + off, size); - } - - /* Buffer wrap */ - ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0, - sglist, skip, SOLO_MP4E_EXT_ADDR(solo_dev) + off, - SOLO_MP4E_EXT_SIZE(solo_dev) - off); - - ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_MP4E, desc, 0, - sglist, skip + SOLO_MP4E_EXT_SIZE(solo_dev) - off, - SOLO_MP4E_EXT_ADDR(solo_dev), - size + off - SOLO_MP4E_EXT_SIZE(solo_dev)); + struct solo_enc_dev *solo_enc = fh->enc; - return ret; + mutex_lock(&solo_enc->enable_lock); + __solo_enc_off(fh); + mutex_unlock(&solo_enc->enable_lock); } -static int enc_get_mpeg_dma_t(struct solo_dev *solo_dev, - dma_addr_t buf, unsigned int off, - unsigned int size) +static int enc_get_mpeg_dma(struct solo_dev *solo_dev, dma_addr_t dma, + unsigned int off, unsigned int size) { int ret; if (off > SOLO_MP4E_EXT_SIZE(solo_dev)) return -EINVAL; + /* Single shot */ if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) { - return solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf, - SOLO_MP4E_EXT_ADDR(solo_dev) + off, size); + return solo_p2m_dma_t(solo_dev, 0, dma, + SOLO_MP4E_EXT_ADDR(solo_dev) + off, size, + 0, 0); } /* Buffer wrap */ - ret = solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, buf, + ret = solo_p2m_dma_t(solo_dev, 0, dma, SOLO_MP4E_EXT_ADDR(solo_dev) + off, - SOLO_MP4E_EXT_SIZE(solo_dev) - off); - - ret |= solo_p2m_dma_t(solo_dev, SOLO_P2M_DMA_ID_MP4E, 0, - buf + SOLO_MP4E_EXT_SIZE(solo_dev) - off, - SOLO_MP4E_EXT_ADDR(solo_dev), - size + off - SOLO_MP4E_EXT_SIZE(solo_dev)); - - return ret; -} + SOLO_MP4E_EXT_SIZE(solo_dev) - off, 0, 0); -static int enc_get_mpeg_dma(struct solo_dev *solo_dev, void *buf, - unsigned int off, unsigned int size) -{ - int ret; - - dma_addr_t dma_addr = pci_map_single(solo_dev->pdev, buf, size, - PCI_DMA_FROMDEVICE); - ret = enc_get_mpeg_dma_t(solo_dev, dma_addr, off, size); - pci_unmap_single(solo_dev->pdev, dma_addr, size, PCI_DMA_FROMDEVICE); + if (!ret) { + ret = solo_p2m_dma_t(solo_dev, 0, + dma + SOLO_MP4E_EXT_SIZE(solo_dev) - off, + SOLO_MP4E_EXT_ADDR(solo_dev), + size + off - SOLO_MP4E_EXT_SIZE(solo_dev), 0, 0); + } return ret; } -static int enc_get_jpeg_dma_sg(struct solo_dev *solo_dev, - struct p2m_desc *desc, - struct scatterlist *sglist, int skip, - unsigned int off, unsigned int size) +/* Build a descriptor queue out of an SG list and send it to the P2M for + * processing. */ +static int solo_send_desc(struct solo_enc_fh *fh, int skip, + struct videobuf_dmabuf *vbuf, int off, int size, + unsigned int base, unsigned int base_size) { + struct solo_dev *solo_dev = fh->enc->solo_dev; + struct scatterlist *sg; + int i; int ret; - if (off > SOLO_JPEG_EXT_SIZE(solo_dev)) + if (WARN_ON_ONCE(size > FRAME_BUF_SIZE)) return -EINVAL; - if (off + size <= SOLO_JPEG_EXT_SIZE(solo_dev)) { - return solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, - desc, 0, sglist, skip, - SOLO_JPEG_EXT_ADDR(solo_dev) + off, size); - } - - /* Buffer wrap */ - ret = solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0, - sglist, skip, SOLO_JPEG_EXT_ADDR(solo_dev) + off, - SOLO_JPEG_EXT_SIZE(solo_dev) - off); + fh->desc_count = 1; + + for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) { + struct solo_p2m_desc *desc; + dma_addr_t dma; + int len; + int left = base_size - off; + + desc = &fh->desc_items[fh->desc_count++]; + dma = sg_dma_address(sg); + len = sg_dma_len(sg); + + /* We assume this is smaller than the scatter size */ + BUG_ON(skip >= len); + if (skip) { + len -= skip; + dma += skip; + size -= skip; + skip = 0; + } - ret |= solo_p2m_dma_sg(solo_dev, SOLO_P2M_DMA_ID_JPEG, desc, 0, - sglist, skip + SOLO_JPEG_EXT_SIZE(solo_dev) - off, - SOLO_JPEG_EXT_ADDR(solo_dev), - size + off - SOLO_JPEG_EXT_SIZE(solo_dev)); + len = min(len, size); - return ret; -} + if (len <= left) { + /* Single descriptor */ + solo_p2m_fill_desc(desc, 0, dma, base + off, + len, 0, 0); + } else { + /* Buffer wrap */ + /* XXX: Do these as separate DMA requests, to avoid + timeout errors triggered by awkwardly sized + descriptors. See + + */ + ret = solo_p2m_dma_t(solo_dev, 0, dma, base + off, + left, 0, 0); + if (ret) + return ret; + + ret = solo_p2m_dma_t(solo_dev, 0, dma + left, base, + len - left, 0, 0); + if (ret) + return ret; + + fh->desc_count--; + } -/* Returns true of __chk is within the first __range bytes of __off */ -#define OFF_IN_RANGE(__off, __range, __chk) \ - ((__off <= __chk) && ((__off + __range) >= __chk)) + size -= len; + if (size <= 0) + break; -static void solo_jpeg_header(struct solo_enc_dev *solo_enc, - struct videobuf_dmabuf *vbuf) -{ - struct scatterlist *sg; - void *src = jpeg_header; - size_t copied = 0; - size_t to_copy = sizeof(jpeg_header); - - for (sg = vbuf->sglist; sg && copied < to_copy; sg = sg_next(sg)) { - size_t this_copy = min(sg_dma_len(sg), - (unsigned int)(to_copy - copied)); - u8 *p = sg_virt(sg); - - memcpy(p, src + copied, this_copy); - - if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 5)) - p[(SOF0_START + 5) - copied] = - 0xff & (solo_enc->height >> 8); - if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 6)) - p[(SOF0_START + 6) - copied] = 0xff & solo_enc->height; - if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 7)) - p[(SOF0_START + 7) - copied] = - 0xff & (solo_enc->width >> 8); - if (OFF_IN_RANGE(copied, this_copy, SOF0_START + 8)) - p[(SOF0_START + 8) - copied] = 0xff & solo_enc->width; - - copied += this_copy; + off += len; + if (off >= base_size) + off -= base_size; + + /* Because we may use two descriptors per loop */ + if (fh->desc_count >= (fh->desc_nelts - 1)) { + ret = solo_p2m_dma_desc(solo_dev, fh->desc_items, + fh->desc_dma, + fh->desc_count - 1); + if (ret) + return ret; + fh->desc_count = 1; + } } -} - -static int solo_fill_jpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf, - struct videobuf_buffer *vb, - struct videobuf_dmabuf *vbuf) -{ - struct solo_dev *solo_dev = fh->enc->solo_dev; - int size = enc_buf->jpeg_size; - - /* Copy the header first (direct write) */ - solo_jpeg_header(fh->enc, vbuf); - - vb->size = size + sizeof(jpeg_header); - - /* Grab the jpeg frame */ - return enc_get_jpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist, - sizeof(jpeg_header), - enc_buf->jpeg_off, size); -} - -static inline int vop_interlaced(__le32 *vh) -{ - return (__le32_to_cpu(vh[0]) >> 30) & 1; -} -static inline u32 vop_size(__le32 *vh) -{ - return __le32_to_cpu(vh[0]) & 0xFFFFF; -} - -static inline u8 vop_hsize(__le32 *vh) -{ - return (__le32_to_cpu(vh[1]) >> 8) & 0xFF; -} - -static inline u8 vop_vsize(__le32 *vh) -{ - return __le32_to_cpu(vh[1]) & 0xFF; -} - -/* must be called with *bits % 8 = 0 */ -static void write_bytes(u8 **out, unsigned *bits, const u8 *src, unsigned count) -{ - memcpy(*out, src, count); - *out += count; - *bits += count * 8; -} - -static void write_bits(u8 **out, unsigned *bits, u32 value, unsigned count) -{ - - value <<= 32 - count; // shift to the right + if (fh->desc_count <= 1) + return 0; - while (count--) { - **out <<= 1; - **out |= !!(value & (1 << 31)); /* MSB */ - value <<= 1; - if (++(*bits) % 8 == 0) - (*out)++; - } + return solo_p2m_dma_desc(solo_dev, fh->desc_items, fh->desc_dma, + fh->desc_count - 1); } -static void write_ue(u8 **out, unsigned *bits, unsigned value) /* H.264 only */ +static int solo_fill_jpeg(struct solo_enc_fh *fh, struct videobuf_buffer *vb, + struct videobuf_dmabuf *vbuf, struct vop_header *vh) { - uint32_t max = 0, cnt = 0; + struct solo_enc_dev *solo_enc = fh->enc; + struct solo_dev *solo_dev = solo_enc->solo_dev; + struct solo_videobuf *svb = (struct solo_videobuf *)vb; + int frame_size; - while (value > max) { - max = (max + 2) * 2 - 2; - cnt++; - } - write_bits(out, bits, 1, cnt + 1); - write_bits(out, bits, ~(max - value), cnt); -} + svb->flags |= V4L2_BUF_FLAG_KEYFRAME; -static void write_se(u8 **out, unsigned *bits, int value) /* H.264 only */ -{ - if (value <= 0) - write_ue(out, bits, -value * 2); - else - write_ue(out, bits, value * 2 - 1); -} + if (vb->bsize < (vh->jpeg_size + solo_enc->jpeg_len)) + return -EIO; -static void write_mpeg4_end(u8 **out, unsigned *bits) -{ - write_bits(out, bits, 0, 1); - /* align on 32-bit boundary */ - if (*bits % 32) - write_bits(out, bits, 0xFFFFFFFF, 32 - *bits % 32); -} + vb->width = solo_enc->width; + vb->height = solo_enc->height; + vb->size = vh->jpeg_size + solo_enc->jpeg_len; -static void write_h264_end(u8 **out, unsigned *bits, int align) -{ - write_bits(out, bits, 1, 1); - while ((*bits) % 8) - write_bits(out, bits, 0, 1); - if (align) - while ((*bits) % 32) - write_bits(out, bits, 0, 1); -} + sg_copy_from_buffer(vbuf->sglist, vbuf->sglen, + solo_enc->jpeg_header, + solo_enc->jpeg_len); -static void mpeg4_write_vol(u8 **out, struct solo_dev *solo_dev, - __le32 *vh, unsigned fps, unsigned interval) -{ - static const u8 hdr[] = { - 0, 0, 1, 0x00 /* video_object_start_code */, - 0, 0, 1, 0x20 /* video_object_layer_start_code */ - }; - unsigned bits = 0; - unsigned width = vop_hsize(vh) << 4; - unsigned height = vop_vsize(vh) << 4; - unsigned interlaced = vop_interlaced(vh); - - write_bytes(out, &bits, hdr, sizeof(hdr)); - write_bits(out, &bits, 0, 1); /* random_accessible_vol */ - write_bits(out, &bits, 0x04, 8); /* video_object_type_indication: main */ - write_bits(out, &bits, 1, 1); /* is_object_layer_identifier */ - write_bits(out, &bits, 2, 4); /* video_object_layer_verid: table V2-39 */ - write_bits(out, &bits, 0, 3); /* video_object_layer_priority */ - if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) - write_bits(out, &bits, 3, 4); /* aspect_ratio_info, assuming 4:3 */ - else - write_bits(out, &bits, 2, 4); - write_bits(out, &bits, 1, 1); /* vol_control_parameters */ - write_bits(out, &bits, 1, 2); /* chroma_format: 4:2:0 */ - write_bits(out, &bits, 1, 1); /* low_delay */ - write_bits(out, &bits, 0, 1); /* vbv_parameters */ - write_bits(out, &bits, 0, 2); /* video_object_layer_shape: rectangular */ - write_bits(out, &bits, 1, 1); /* marker_bit */ - write_bits(out, &bits, fps, 16); /* vop_time_increment_resolution */ - write_bits(out, &bits, 1, 1); /* marker_bit */ - write_bits(out, &bits, 1, 1); /* fixed_vop_rate */ - write_bits(out, &bits, interval, 15); /* fixed_vop_time_increment */ - write_bits(out, &bits, 1, 1); /* marker_bit */ - write_bits(out, &bits, width, 13); /* video_object_layer_width */ - write_bits(out, &bits, 1, 1); /* marker_bit */ - write_bits(out, &bits, height, 13); /* video_object_layer_height */ - write_bits(out, &bits, 1, 1); /* marker_bit */ - write_bits(out, &bits, interlaced, 1); /* interlaced */ - write_bits(out, &bits, 1, 1); /* obmc_disable */ - write_bits(out, &bits, 0, 2); /* sprite_enable */ - write_bits(out, &bits, 0, 1); /* not_8_bit */ - write_bits(out, &bits, 1, 0); /* quant_type */ - write_bits(out, &bits, 0, 1); /* load_intra_quant_mat */ - write_bits(out, &bits, 0, 1); /* load_nonintra_quant_mat */ - write_bits(out, &bits, 0, 1); /* quarter_sample */ - write_bits(out, &bits, 1, 1); /* complexity_estimation_disable */ - write_bits(out, &bits, 1, 1); /* resync_marker_disable */ - write_bits(out, &bits, 0, 1); /* data_partitioned */ - write_bits(out, &bits, 0, 1); /* newpred_enable */ - write_bits(out, &bits, 0, 1); /* reduced_resolution_vop_enable */ - write_bits(out, &bits, 0, 1); /* scalability */ - write_mpeg4_end(out, &bits); -} + frame_size = (vh->jpeg_size + solo_enc->jpeg_len + (DMA_ALIGN - 1)) + & ~(DMA_ALIGN - 1); -static void h264_write_vol(u8 **out, struct solo_dev *solo_dev, __le32 *vh) -{ - static const u8 sps[] = { - 0, 0, 0, 1 /* start code */, 0x67, 66 /* profile_idc */, - 0 /* constraints */, 30 /* level_idc */ - }; - static const u8 pps[] = { - 0, 0, 0, 1 /* start code */, 0x68 - }; - - unsigned bits = 0; - unsigned mbs_w = vop_hsize(vh); - unsigned mbs_h = vop_vsize(vh); - - write_bytes(out, &bits, sps, sizeof(sps)); - write_ue(out, &bits, 0); /* seq_parameter_set_id */ - write_ue(out, &bits, 5); /* log2_max_frame_num_minus4 */ - write_ue(out, &bits, 0); /* pic_order_cnt_type */ - write_ue(out, &bits, 6); /* log2_max_pic_order_cnt_lsb_minus4 */ - write_ue(out, &bits, 1); /* max_num_ref_frames */ - write_bits(out, &bits, 0, 1); /* gaps_in_frame_num_value_allowed_flag */ - write_ue(out, &bits, mbs_w - 1); /* pic_width_in_mbs_minus1 */ - write_ue(out, &bits, mbs_h - 1); /* pic_height_in_map_units_minus1 */ - write_bits(out, &bits, 1, 1); /* frame_mbs_only_flag */ - write_bits(out, &bits, 1, 1); /* direct_8x8_frame_field_flag */ - write_bits(out, &bits, 0, 1); /* frame_cropping_flag */ - write_bits(out, &bits, 0, 1); /* vui_parameters_present_flag */ - write_h264_end(out, &bits, 0); - - write_bytes(out, &bits, pps, sizeof(pps)); - write_ue(out, &bits, 0); /* pic_parameter_set_id */ - write_ue(out, &bits, 0); /* seq_parameter_set_id */ - write_bits(out, &bits, 0, 1); /* entropy_coding_mode_flag */ - write_bits(out, &bits, 0, 1); /* bottom_field_pic_order_in_frame_present_flag */ - write_ue(out, &bits, 0); /* num_slice_groups_minus1 */ - write_ue(out, &bits, 0); /* num_ref_idx_l0_default_active_minus1 */ - write_ue(out, &bits, 0); /* num_ref_idx_l1_default_active_minus1 */ - write_bits(out, &bits, 0, 1); /* weighted_pred_flag */ - write_bits(out, &bits, 0, 2); /* weighted_bipred_idc */ - write_se(out, &bits, 0); /* pic_init_qp_minus26 */ - write_se(out, &bits, 0); /* pic_init_qs_minus26 */ - write_se(out, &bits, 2); /* chroma_qp_index_offset */ - write_bits(out, &bits, 0, 1); /* deblocking_filter_control_present_flag */ - write_bits(out, &bits, 1, 1); /* constrained_intra_pred_flag */ - write_bits(out, &bits, 0, 1); /* redundant_pic_cnt_present_flag */ - write_h264_end(out, &bits, 1); + return solo_send_desc(fh, solo_enc->jpeg_len, vbuf, vh->jpeg_off, + frame_size, SOLO_JPEG_EXT_ADDR(solo_dev), + SOLO_JPEG_EXT_SIZE(solo_dev)); } -static int solo_fill_mpeg(struct solo_enc_fh *fh, struct solo_enc_buf *enc_buf, - struct videobuf_buffer *vb, - struct videobuf_dmabuf *vbuf) +static int solo_fill_mpeg(struct solo_enc_fh *fh, struct videobuf_buffer *vb, + struct videobuf_dmabuf *vbuf, struct vop_header *vh) { struct solo_enc_dev *solo_enc = fh->enc; struct solo_dev *solo_dev = solo_enc->solo_dev; - -#define VH_WORDS 16 -#define MAX_VOL_HEADER_LENGTH 64 - - __le32 vh[VH_WORDS]; - int ret; - int frame_size, frame_off; + struct solo_videobuf *svb = (struct solo_videobuf *)vb; + int frame_off, frame_size; int skip = 0; - if (WARN_ON_ONCE(enc_buf->size <= sizeof(vh))) - return -EINVAL; - - /* First get the hardware vop header (not real mpeg) */ - ret = enc_get_mpeg_dma(solo_dev, vh, enc_buf->off, sizeof(vh)); - if (WARN_ON_ONCE(ret)) - return ret; + if (vb->bsize < vh->mpeg_size) + return -EIO; - if (WARN_ON_ONCE(vop_size(vh) > enc_buf->size)) - return -EINVAL; + vb->width = vh->hsize << 4; + vb->height = vh->vsize << 4; + vb->size = vh->mpeg_size; - vb->width = vop_hsize(vh) << 4; - vb->height = vop_vsize(vh) << 4; - vb->size = vop_size(vh); + /* If this is a key frame, add extra header */ + if (!vh->vop_type) { + sg_copy_from_buffer(vbuf->sglist, vbuf->sglen, + solo_enc->vop, + solo_enc->vop_len); - /* If this is a key frame, add extra m4v header */ - if (!enc_buf->vop) { - u8 header[MAX_VOL_HEADER_LENGTH], *out = header; + skip = solo_enc->vop_len; + vb->size += solo_enc->vop_len; - if (solo_dev->flags & FLAGS_6110) - h264_write_vol(&out, solo_dev, vh); - else - mpeg4_write_vol(&out, solo_dev, vh, - solo_dev->fps * 1000, - solo_enc->interval * 1000); - skip = out - header; - enc_write_sg(vbuf->sglist, header, skip); - /* Adjust the dma buffer past this header */ - vb->size += skip; + svb->flags |= V4L2_BUF_FLAG_KEYFRAME; + } else { + svb->flags |= V4L2_BUF_FLAG_PFRAME; } /* Now get the actual mpeg payload */ - frame_off = (enc_buf->off + sizeof(vh)) % SOLO_MP4E_EXT_SIZE(solo_dev); - frame_size = enc_buf->size - sizeof(vh); - - ret = enc_get_mpeg_dma_sg(solo_dev, fh->desc, vbuf->sglist, - skip, frame_off, frame_size); - WARN_ON_ONCE(ret); + frame_off = (vh->mpeg_off + sizeof(*vh)) + % SOLO_MP4E_EXT_SIZE(solo_dev); + frame_size = (vh->mpeg_size + skip + (DMA_ALIGN - 1)) + & ~(DMA_ALIGN - 1); - return ret; + return solo_send_desc(fh, skip, vbuf, frame_off, frame_size, + SOLO_MP4E_EXT_ADDR(solo_dev), + SOLO_MP4E_EXT_SIZE(solo_dev)); } -static void solo_enc_fillbuf(struct solo_enc_fh *fh, - struct videobuf_buffer *vb) +static int solo_enc_fillbuf(struct solo_enc_fh *fh, + struct videobuf_buffer *vb, + struct solo_enc_buf *enc_buf) { struct solo_enc_dev *solo_enc = fh->enc; - struct solo_dev *solo_dev = solo_enc->solo_dev; - struct solo_enc_buf *enc_buf = NULL; - struct videobuf_dmabuf *vbuf; + struct solo_videobuf *svb = (struct solo_videobuf *)vb; + struct videobuf_dmabuf *vbuf = NULL; + struct vop_header *vh = enc_buf->vh; int ret; - int error = 1; - u16 idx = fh->rd_idx; - - while (idx != solo_dev->enc_wr_idx) { - struct solo_enc_buf *ebuf = &solo_dev->enc_buf[idx]; - idx = (idx + 1) % SOLO_NR_RING_BUFS; - - if (ebuf->ch != solo_enc->ch) - continue; - - if (fh->fmt == V4L2_PIX_FMT_MPEG) { - if (fh->type == ebuf->type) { - enc_buf = ebuf; - break; - } - } else { - /* For mjpeg, keep reading to the newest frame */ - enc_buf = ebuf; - } + vbuf = videobuf_to_dma(vb); + if (WARN_ON_ONCE(!vbuf)) { + ret = -EIO; + goto vbuf_error; } - fh->rd_idx = idx; - - if (WARN_ON_ONCE(!enc_buf)) - goto buf_err; + /* Setup some common flags for both types */ + svb->flags = V4L2_BUF_FLAG_TIMECODE; + vb->ts.tv_sec = vh->sec; + vb->ts.tv_usec = vh->usec; - if ((fh->fmt == V4L2_PIX_FMT_MPEG && - vb->bsize < enc_buf->size) || - (fh->fmt == V4L2_PIX_FMT_MJPEG && - vb->bsize < (enc_buf->jpeg_size + sizeof(jpeg_header)))) { - WARN_ON_ONCE(1); - goto buf_err; + /* Check for motion flags */ + if (solo_is_motion_on(solo_enc)) { + svb->flags |= V4L2_BUF_FLAG_MOTION_ON; + if (enc_buf->motion) + svb->flags |= V4L2_BUF_FLAG_MOTION_DETECTED; } - vbuf = videobuf_to_dma(vb); - if (WARN_ON_ONCE(!vbuf)) - goto buf_err; - if (fh->fmt == V4L2_PIX_FMT_MPEG) - ret = solo_fill_mpeg(fh, enc_buf, vb, vbuf); + ret = solo_fill_mpeg(fh, vb, vbuf, vh); else - ret = solo_fill_jpeg(fh, enc_buf, vb, vbuf); + ret = solo_fill_jpeg(fh, vb, vbuf, vh); - if (!ret) - error = 0; +vbuf_error: + /* On error, we push this buffer back into the queue. The + * videobuf-core doesn't handle error packets very well. Plus + * we recover nicely internally anyway. */ + if (ret) { + unsigned long flags; -buf_err: - if (error) { - vb->state = VIDEOBUF_ERROR; + spin_lock_irqsave(&fh->av_lock, flags); + list_add(&vb->queue, &fh->vidq_active); + vb->state = VIDEOBUF_QUEUED; + spin_unlock_irqrestore(&fh->av_lock, flags); } else { - vb->field_count++; - vb->ts = enc_buf->ts; vb->state = VIDEOBUF_DONE; - } + vb->field_count++; + vb->width = solo_enc->width; + vb->height = solo_enc->height; - wake_up(&vb->done); + wake_up(&vb->done); + } - return; + return ret; } -static void solo_enc_thread_try(struct solo_enc_fh *fh) +static void solo_enc_handle_one(struct solo_enc_dev *solo_enc, + struct solo_enc_buf *enc_buf) { - struct solo_enc_dev *solo_enc = fh->enc; - struct solo_dev *solo_dev = solo_enc->solo_dev; - struct videobuf_buffer *vb; + struct solo_enc_fh *fh; - for (;;) { - spin_lock(&solo_enc->lock); + mutex_lock(&solo_enc->enable_lock); + + list_for_each_entry(fh, &solo_enc->listeners, list) { + struct videobuf_buffer *vb; + unsigned long flags; + + if (fh->type != enc_buf->type) + continue; - if (fh->rd_idx == solo_dev->enc_wr_idx) - break; if (list_empty(&fh->vidq_active)) - break; + continue; + + spin_lock_irqsave(&fh->av_lock, flags); vb = list_first_entry(&fh->vidq_active, struct videobuf_buffer, queue); - if (!waitqueue_active(&vb->done)) - break; - list_del(&vb->queue); + vb->state = VIDEOBUF_ACTIVE; - spin_unlock(&solo_enc->lock); - - solo_enc_fillbuf(fh, vb); - } - - assert_spin_locked(&solo_enc->lock); - spin_unlock(&solo_enc->lock); -} - -static int solo_enc_thread(void *data) -{ - struct solo_enc_fh *fh = data; - struct solo_enc_dev *solo_enc = fh->enc; - DECLARE_WAITQUEUE(wait, current); + spin_unlock_irqrestore(&fh->av_lock, flags); - set_freezable(); - add_wait_queue(&solo_enc->thread_wait, &wait); - - for (;;) { - long timeout = schedule_timeout_interruptible(HZ); - if (timeout == -ERESTARTSYS || kthread_should_stop()) - break; - solo_enc_thread_try(fh); - try_to_freeze(); + solo_enc_fillbuf(fh, vb, enc_buf); } - remove_wait_queue(&solo_enc->thread_wait, &wait); - - return 0; + mutex_unlock(&solo_enc->enable_lock); } -void solo_motion_isr(struct solo_dev *solo_dev) +void solo_enc_v4l2_isr(struct solo_dev *solo_dev) { - u32 status; - int i; - - solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_MOTION); - - status = solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS); - - for (i = 0; i < solo_dev->nr_chans; i++) { - struct solo_enc_dev *solo_enc = solo_dev->v4l2_enc[i]; - - BUG_ON(solo_enc == NULL); - - if (solo_enc->motion_detected) - continue; - if (!(status & (1 << i))) - continue; - - solo_enc->motion_detected = 1; - } + wake_up_interruptible_all(&solo_dev->ring_thread_wait); } -void solo_enc_v4l2_isr(struct solo_dev *solo_dev) +static void solo_handle_ring(struct solo_dev *solo_dev) { - struct solo_enc_buf *enc_buf; - u32 mpeg_current, mpeg_next, mpeg_size; - u32 jpeg_current, jpeg_next, jpeg_size; - u32 reg_mpeg_size; - u8 cur_q, vop_type; - u8 ch; - enum solo_enc_types enc_type; - - solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_ENCODER); - - cur_q = ((solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xF) + 1) % MP4_QS; - - reg_mpeg_size = ((solo_reg_read(solo_dev, SOLO_VE_STATE(0)) & 0xFFFFF) + 64 + 8) & ~7; + for (;;) { + struct solo_enc_dev *solo_enc; + struct solo_enc_buf enc_buf; + u32 mpeg_current, off; + u8 ch; + u8 cur_q; + + /* Check if the hardware has any new ones in the queue */ + cur_q = solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xff; + if (cur_q == solo_dev->enc_idx) + break; - while (solo_dev->enc_idx != cur_q) { mpeg_current = solo_reg_read(solo_dev, SOLO_VE_MPEG4_QUE(solo_dev->enc_idx)); - jpeg_current = solo_reg_read(solo_dev, - SOLO_VE_JPEG_QUE(solo_dev->enc_idx)); solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS; - mpeg_next = solo_reg_read(solo_dev, - SOLO_VE_MPEG4_QUE(solo_dev->enc_idx)); - jpeg_next = solo_reg_read(solo_dev, - SOLO_VE_JPEG_QUE(solo_dev->enc_idx)); ch = (mpeg_current >> 24) & 0x1f; + off = mpeg_current & 0x00ffffff; + if (ch >= SOLO_MAX_CHANNELS) { ch -= SOLO_MAX_CHANNELS; - enc_type = SOLO_ENC_TYPE_EXT; + enc_buf.type = SOLO_ENC_TYPE_EXT; } else - enc_type = SOLO_ENC_TYPE_STD; - - vop_type = (mpeg_current >> 29) & 3; - - mpeg_current &= 0x00ffffff; - mpeg_next &= 0x00ffffff; - jpeg_current &= 0x00ffffff; - jpeg_next &= 0x00ffffff; - - mpeg_size = (SOLO_MP4E_EXT_SIZE(solo_dev) + - mpeg_next - mpeg_current) % - SOLO_MP4E_EXT_SIZE(solo_dev); - - jpeg_size = (SOLO_JPEG_EXT_SIZE(solo_dev) + - jpeg_next - jpeg_current) % - SOLO_JPEG_EXT_SIZE(solo_dev); + enc_buf.type = SOLO_ENC_TYPE_STD; - /* XXX I think this means we had a ring overflow? */ - if (mpeg_current > mpeg_next && mpeg_size != reg_mpeg_size) { - enc_reset_gop(solo_dev, ch); + solo_enc = solo_dev->v4l2_enc[ch]; + if (solo_enc == NULL) { + dev_err(&solo_dev->pdev->dev, + "Got spurious packet for channel %d\n", ch); continue; } - /* When resetting the GOP, skip frames until I-frame */ - if (enc_gop_reset(solo_dev, ch, vop_type)) + /* FAIL... */ + if (enc_get_mpeg_dma(solo_dev, solo_dev->vh_dma, off, + sizeof(struct vop_header))) continue; - enc_buf = &solo_dev->enc_buf[solo_dev->enc_wr_idx]; + enc_buf.vh = (struct vop_header *)solo_dev->vh_buf; + enc_buf.vh->mpeg_off -= SOLO_MP4E_EXT_ADDR(solo_dev); + enc_buf.vh->jpeg_off -= SOLO_JPEG_EXT_ADDR(solo_dev); - enc_buf->vop = vop_type; - enc_buf->ch = ch; - enc_buf->off = mpeg_current; - enc_buf->size = mpeg_size; - enc_buf->jpeg_off = jpeg_current; - enc_buf->jpeg_size = jpeg_size; - enc_buf->type = enc_type; + /* Sanity check */ + if (enc_buf.vh->mpeg_off != off) + continue; + + if (solo_motion_detected(solo_enc)) + enc_buf.motion = 1; + else + enc_buf.motion = 0; + + solo_enc_handle_one(solo_enc, &enc_buf); + } +} - do_gettimeofday(&enc_buf->ts); +static int solo_ring_thread(void *data) +{ + struct solo_dev *solo_dev = data; + DECLARE_WAITQUEUE(wait, current); - solo_dev->enc_wr_idx = (solo_dev->enc_wr_idx + 1) % - SOLO_NR_RING_BUFS; + set_freezable(); + add_wait_queue(&solo_dev->ring_thread_wait, &wait); - wake_up_interruptible(&solo_dev->v4l2_enc[ch]->thread_wait); + for (;;) { + long timeout = schedule_timeout_interruptible(HZ); + if (timeout == -ERESTARTSYS || kthread_should_stop()) + break; + solo_irq_off(solo_dev, SOLO_IRQ_ENCODER); + solo_handle_ring(solo_dev); + solo_irq_on(solo_dev, SOLO_IRQ_ENCODER); + try_to_freeze(); } - return; + remove_wait_queue(&solo_dev->ring_thread_wait, &wait); + + return 0; } static int solo_enc_buf_setup(struct videobuf_queue *vq, unsigned int *count, @@ -915,17 +807,12 @@ static int solo_enc_buf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field) { - struct solo_enc_fh *fh = vq->priv_data; - struct solo_enc_dev *solo_enc = fh->enc; - vb->size = FRAME_BUF_SIZE; if (vb->baddr != 0 && vb->bsize < vb->size) return -EINVAL; - /* These properties only change when queue is idle */ - vb->width = solo_enc->width; - vb->height = solo_enc->height; - vb->field = field; + /* This property only change when queue is idle */ + vb->field = field; if (vb->state == VIDEOBUF_NEEDS_INIT) { int rc = videobuf_iolock(vq, vb, NULL); @@ -933,7 +820,7 @@ static int solo_enc_buf_prepare(struct videobuf_queue *vq, struct videobuf_dmabuf *dma = videobuf_to_dma(vb); videobuf_dma_unmap(vq->dev, dma); videobuf_dma_free(dma); - vb->state = VIDEOBUF_NEEDS_INIT; + return rc; } } @@ -949,20 +836,18 @@ static void solo_enc_buf_queue(struct videobuf_queue *vq, vb->state = VIDEOBUF_QUEUED; list_add_tail(&vb->queue, &fh->vidq_active); - wake_up_interruptible(&fh->enc->thread_wait); } static void solo_enc_buf_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) { struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - videobuf_dma_unmap(vq->dev, dma); videobuf_dma_free(dma); vb->state = VIDEOBUF_NEEDS_INIT; } -static struct videobuf_queue_ops solo_enc_video_qops = { +static const struct videobuf_queue_ops solo_enc_video_qops = { .buf_setup = solo_enc_buf_setup, .buf_prepare = solo_enc_buf_prepare, .buf_queue = solo_enc_buf_queue, @@ -984,27 +869,78 @@ static int solo_enc_mmap(struct file *file, struct vm_area_struct *vma) return videobuf_mmap_mapper(&fh->vidq, vma); } +static int solo_ring_start(struct solo_dev *solo_dev) +{ + if (atomic_inc_return(&solo_dev->enc_users) > 1) + return 0; + + solo_dev->ring_thread = kthread_run(solo_ring_thread, solo_dev, + SOLO6X10_NAME "_ring"); + if (IS_ERR(solo_dev->ring_thread)) { + int err = PTR_ERR(solo_dev->ring_thread); + solo_dev->ring_thread = NULL; + return err; + } + + solo_irq_on(solo_dev, SOLO_IRQ_ENCODER); + + return 0; +} + +static void solo_ring_stop(struct solo_dev *solo_dev) +{ + if (atomic_dec_return(&solo_dev->enc_users) > 0) + return; + + if (solo_dev->ring_thread) { + kthread_stop(solo_dev->ring_thread); + solo_dev->ring_thread = NULL; + } + + solo_irq_off(solo_dev, SOLO_IRQ_ENCODER); +} + static int solo_enc_open(struct file *file) { struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; struct solo_enc_fh *fh; + int ret; + + ret = solo_ring_start(solo_dev); + if (ret) + return ret; fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (fh == NULL) + if (fh == NULL) { + solo_ring_stop(solo_dev); + return -ENOMEM; + } + + fh->desc_nelts = 32; + fh->desc_items = pci_alloc_consistent(solo_dev->pdev, + sizeof(struct solo_p2m_desc) * + fh->desc_nelts, &fh->desc_dma); + if (fh->desc_items == NULL) { + kfree(fh); + solo_ring_stop(solo_dev); return -ENOMEM; + } fh->enc = solo_enc; + spin_lock_init(&fh->av_lock); file->private_data = fh; INIT_LIST_HEAD(&fh->vidq_active); fh->fmt = V4L2_PIX_FMT_MPEG; fh->type = SOLO_ENC_TYPE_STD; videobuf_queue_sg_init(&fh->vidq, &solo_enc_video_qops, - &solo_enc->solo_dev->pdev->dev, - &solo_enc->lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct videobuf_buffer), fh, NULL); + &solo_dev->pdev->dev, + &fh->av_lock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct solo_videobuf), + fh, NULL); return 0; } @@ -1013,22 +949,12 @@ static ssize_t solo_enc_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { struct solo_enc_fh *fh = file->private_data; - struct solo_enc_dev *solo_enc = fh->enc; + int ret; /* Make sure the encoder is on */ - if (!fh->enc_on) { - int ret; - - spin_lock(&solo_enc->lock); - ret = solo_enc_on(fh); - spin_unlock(&solo_enc->lock); - if (ret) - return ret; - - ret = solo_start_fh_thread(fh); - if (ret) - return ret; - } + ret = solo_enc_on(fh); + if (ret) + return ret; return videobuf_read_stream(&fh->vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); @@ -1037,17 +963,21 @@ static ssize_t solo_enc_read(struct file *file, char __user *data, static int solo_enc_release(struct file *file) { struct solo_enc_fh *fh = file->private_data; - struct solo_enc_dev *solo_enc = fh->enc; + struct solo_dev *solo_dev = fh->enc->solo_dev; + + solo_enc_off(fh); videobuf_stop(&fh->vidq); videobuf_mmap_free(&fh->vidq); - spin_lock(&solo_enc->lock); - solo_enc_off(fh); - spin_unlock(&solo_enc->lock); + pci_free_consistent(fh->enc->solo_dev->pdev, + sizeof(struct solo_p2m_desc) * + fh->desc_nelts, fh->desc_items, fh->desc_dma); kfree(fh); + solo_ring_stop(solo_dev); + return 0; } @@ -1095,7 +1025,8 @@ static int solo_enc_enum_input(struct file *file, void *priv, return 0; } -static int solo_enc_set_input(struct file *file, void *priv, unsigned int index) +static int solo_enc_set_input(struct file *file, void *priv, + unsigned int index) { if (index) return -EINVAL; @@ -1144,8 +1075,8 @@ static int solo_enc_try_fmt_cap(struct file *file, void *priv, pix->pixelformat != V4L2_PIX_FMT_MJPEG) return -EINVAL; - /* We cannot change width/height in mid read */ - if (atomic_read(&solo_enc->readers) > 0) { + /* We cannot change width/height in mid mpeg */ + if (atomic_read(&solo_enc->mpeg_readers) > 0) { if (pix->width != solo_enc->width || pix->height != solo_enc->height) return -EBUSY; @@ -1183,11 +1114,11 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv, struct v4l2_pix_format *pix = &f->fmt.pix; int ret; - spin_lock(&solo_enc->lock); + mutex_lock(&solo_enc->enable_lock); ret = solo_enc_try_fmt_cap(file, priv, f); if (ret) { - spin_unlock(&solo_enc->lock); + mutex_unlock(&solo_enc->enable_lock); return ret; } @@ -1201,14 +1132,10 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv, if (pix->priv) fh->type = SOLO_ENC_TYPE_EXT; - ret = solo_enc_on(fh); - - spin_unlock(&solo_enc->lock); - if (ret) - return ret; + mutex_unlock(&solo_enc->enable_lock); - return solo_start_fh_thread(fh); + return 0; } static int solo_enc_get_fmt_cap(struct file *file, void *priv, @@ -1245,7 +1172,8 @@ static int solo_enc_querybuf(struct file *file, void *priv, return videobuf_querybuf(&fh->vidq, buf); } -static int solo_enc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +static int solo_enc_qbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) { struct solo_enc_fh *fh = priv; @@ -1256,50 +1184,21 @@ static int solo_enc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { struct solo_enc_fh *fh = priv; - struct solo_enc_dev *solo_enc = fh->enc; + struct solo_videobuf *svb; int ret; /* Make sure the encoder is on */ - if (!fh->enc_on) { - spin_lock(&solo_enc->lock); - ret = solo_enc_on(fh); - spin_unlock(&solo_enc->lock); - if (ret) - return ret; - - ret = solo_start_fh_thread(fh); - if (ret) - return ret; - } + ret = solo_enc_on(fh); + if (ret) + return ret; ret = videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK); if (ret) return ret; - /* Signal motion detection */ - if (solo_is_motion_on(solo_enc)) { - buf->flags |= V4L2_BUF_FLAG_MOTION_ON; - if (solo_enc->motion_detected) { - buf->flags |= V4L2_BUF_FLAG_MOTION_DETECTED; - solo_reg_write(solo_enc->solo_dev, SOLO_VI_MOT_CLEAR, - 1 << solo_enc->ch); - solo_enc->motion_detected = 0; - } - } - - /* Check for key frame on mpeg data */ - if (fh->fmt == V4L2_PIX_FMT_MPEG) { - struct videobuf_dmabuf *vbuf = - videobuf_to_dma(fh->vidq.bufs[buf->index]); - - if (vbuf) { - u8 *p = sg_virt(vbuf->sglist); - if (p[3] == 0x00) - buf->flags |= V4L2_BUF_FLAG_KEYFRAME; - else - buf->flags |= V4L2_BUF_FLAG_PFRAME; - } - } + /* Copy over the flags */ + svb = (struct solo_videobuf *)fh->vidq.bufs[buf->index]; + buf->flags |= svb->flags; return 0; } @@ -1319,11 +1218,16 @@ static int solo_enc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { struct solo_enc_fh *fh = priv; + int ret; if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - return videobuf_streamoff(&fh->vidq); + ret = videobuf_streamoff(&fh->vidq); + if (!ret) + solo_enc_off(fh); + + return ret; } static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id i) @@ -1407,10 +1311,10 @@ static int solo_s_parm(struct file *file, void *priv, struct solo_dev *solo_dev = solo_enc->solo_dev; struct v4l2_captureparm *cp = &sp->parm.capture; - spin_lock(&solo_enc->lock); + mutex_lock(&solo_enc->enable_lock); - if (atomic_read(&solo_enc->readers) > 0) { - spin_unlock(&solo_enc->lock); + if (atomic_read(&solo_enc->mpeg_readers) > 0) { + mutex_unlock(&solo_enc->enable_lock); return -EBUSY; } @@ -1431,10 +1335,9 @@ static int solo_s_parm(struct file *file, void *priv, cp->capability = V4L2_CAP_TIMEPERFRAME; - solo_enc->gop = max(solo_dev->fps / solo_enc->interval, 1); solo_update_mode(solo_enc); - spin_unlock(&solo_enc->lock); + mutex_unlock(&solo_enc->enable_lock); return 0; } @@ -1510,6 +1413,7 @@ static int solo_querymenu(struct file *file, void *priv, int err; qctrl.id = qmenu->id; + err = solo_queryctrl(file, priv, &qctrl); if (err) return err; @@ -1536,6 +1440,8 @@ static int solo_g_ctrl(struct file *file, void *priv, ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC; break; case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + if (atomic_read(&solo_enc->readers) > 0) + return -EBUSY; ctrl->value = solo_enc->gop; break; case V4L2_CID_MOTION_THRESHOLD: @@ -1574,19 +1480,32 @@ static int solo_s_ctrl(struct file *file, void *priv, if (ctrl->value < 1 || ctrl->value > 255) return -ERANGE; solo_enc->gop = ctrl->value; - solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch), - solo_enc->gop); - solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch), - solo_enc->gop); break; case V4L2_CID_MOTION_THRESHOLD: - /* TODO accept value on lower 16-bits and use high - * 16-bits to assign the value to a specific block */ - if (ctrl->value < 0 || ctrl->value > 0xffff) + { + u16 block = (ctrl->value >> 16) & 0xffff; + u16 value = ctrl->value & 0xffff; + + /* Motion thresholds are in a table of 64x64 samples, with + * each sample representing 16x16 pixels of the source. In + * effect, 44x30 samples are used for NTSC, and 44x36 for PAL. + * The 5th sample on the 10th row is (10*64)+5 = 645. + * + * Block is 0 to set the threshold globally, or any positive + * number under 2049 to set block-1 individually. */ + if (block > 2049) return -ERANGE; - solo_enc->motion_thresh = ctrl->value; - solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->value); + + if (block == 0) { + solo_enc->motion_thresh = value; + return solo_set_motion_threshold(solo_dev, + solo_enc->ch, value); + } else { + return solo_set_motion_block(solo_dev, solo_enc->ch, + value, block - 1); + } break; + } case V4L2_CID_MOTION_ENABLE: solo_motion_toggle(solo_enc, ctrl->value); break; @@ -1613,6 +1532,7 @@ static int solo_s_ext_ctrls(struct file *file, void *priv, if (ctrl->size - 1 > OSD_TEXT_MAX) err = -ERANGE; else { + mutex_lock(&solo_enc->enable_lock); err = copy_from_user(solo_enc->osd_text, ctrl->string, OSD_TEXT_MAX); @@ -1621,6 +1541,7 @@ static int solo_s_ext_ctrls(struct file *file, void *priv, err = solo_osd_print(solo_enc); else err = -EFAULT; + mutex_unlock(&solo_enc->enable_lock); } break; default: @@ -1653,11 +1574,13 @@ static int solo_g_ext_ctrls(struct file *file, void *priv, ctrl->size = OSD_TEXT_MAX; err = -ENOSPC; } else { + mutex_lock(&solo_enc->enable_lock); err = copy_to_user(ctrl->string, solo_enc->osd_text, OSD_TEXT_MAX); if (err) err = -EFAULT; + mutex_unlock(&solo_enc->enable_lock); } break; default: @@ -1717,7 +1640,7 @@ static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = { .vidioc_s_ext_ctrls = solo_s_ext_ctrls, }; -static struct video_device solo_enc_template = { +static const struct video_device solo_enc_template = { .name = SOLO6X10_NAME, .fops = &solo_enc_fops, .ioctl_ops = &solo_enc_ioctl_ops, @@ -1728,7 +1651,8 @@ static struct video_device solo_enc_template = { .current_norm = V4L2_STD_NTSC_M, }; -static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, u8 ch) +static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, + u8 ch, unsigned nr) { struct solo_enc_dev *solo_enc; int ret; @@ -1748,8 +1672,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, u8 ch) *solo_enc->vfd = solo_enc_template; solo_enc->vfd->parent = &solo_dev->pdev->dev; - ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, - video_nr); + ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr); if (ret < 0) { video_device_release(solo_enc->vfd); kfree(solo_enc); @@ -1762,12 +1685,12 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, u8 ch) "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num, solo_enc->vfd->num); - if (video_nr != -1) - video_nr++; + INIT_LIST_HEAD(&solo_enc->listeners); + mutex_init(&solo_enc->enable_lock); + spin_lock_init(&solo_enc->motion_lock); - spin_lock_init(&solo_enc->lock); - init_waitqueue_head(&solo_enc->thread_wait); atomic_set(&solo_enc->readers, 0); + atomic_set(&solo_enc->mpeg_readers, 0); solo_enc->qp = SOLO_DEFAULT_QP; solo_enc->gop = solo_dev->fps; @@ -1775,9 +1698,13 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, u8 ch) solo_enc->mode = SOLO_ENC_MODE_CIF; solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH; - spin_lock(&solo_enc->lock); + mutex_lock(&solo_enc->enable_lock); solo_update_mode(solo_enc); - spin_unlock(&solo_enc->lock); + mutex_unlock(&solo_enc->enable_lock); + + /* Initialize this per encoder */ + solo_enc->jpeg_len = sizeof(jpeg_header); + memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len); return solo_enc; } @@ -1791,12 +1718,22 @@ static void solo_enc_free(struct solo_enc_dev *solo_enc) kfree(solo_enc); } -int solo_enc_v4l2_init(struct solo_dev *solo_dev) +int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr) { int i; + atomic_set(&solo_dev->enc_users, 0); + init_waitqueue_head(&solo_dev->ring_thread_wait); + + solo_dev->vh_size = sizeof(struct vop_header); + solo_dev->vh_buf = pci_alloc_consistent(solo_dev->pdev, + solo_dev->vh_size, + &solo_dev->vh_dma); + if (solo_dev->vh_buf == NULL) + return -ENOMEM; + for (i = 0; i < solo_dev->nr_chans; i++) { - solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i); + solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i, nr); if (IS_ERR(solo_dev->v4l2_enc[i])) break; } @@ -1805,11 +1742,15 @@ int solo_enc_v4l2_init(struct solo_dev *solo_dev) int ret = PTR_ERR(solo_dev->v4l2_enc[i]); while (i--) solo_enc_free(solo_dev->v4l2_enc[i]); + pci_free_consistent(solo_dev->pdev, solo_dev->vh_size, + solo_dev->vh_buf, solo_dev->vh_dma); return ret; } - /* D1@MAX-FPS * 4 */ - solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4; + if (solo_dev->type == SOLO_DEV_6010) + solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4; + else + solo_dev->enc_bw_remain = solo_dev->fps * 4 * 5; dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n", solo_dev->v4l2_enc[0]->vfd->num, @@ -1822,8 +1763,9 @@ void solo_enc_v4l2_exit(struct solo_dev *solo_dev) { int i; - solo_irq_off(solo_dev, SOLO_IRQ_MOTION); - for (i = 0; i < solo_dev->nr_chans; i++) solo_enc_free(solo_dev->v4l2_enc[i]); + + pci_free_consistent(solo_dev->pdev, solo_dev->vh_size, + solo_dev->vh_buf, solo_dev->vh_dma); } diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index 87f3c04..ba603ce 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c @@ -1,6 +1,11 @@ /* - * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com - * Copyright (C) 2010 Ben Collins + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks * * 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 @@ -21,47 +26,43 @@ #include #include #include + #include #include -#include +#include + #include "solo6x10.h" #include "tw28.h" -#define SOLO_HW_BPL 2048 #define SOLO_DISP_PIX_FIELD V4L2_FIELD_INTERLACED -/* Image size is two fields, SOLO_HW_BPL is one horizontal line */ +/* Image size is two fields, SOLO_HW_BPL is one horizontal line in hardware */ +#define SOLO_HW_BPL 2048 #define solo_vlines(__solo) (__solo->video_vsize * 2) #define solo_image_size(__solo) (solo_bytesperline(__solo) * \ solo_vlines(__solo)) #define solo_bytesperline(__solo) (__solo->video_hsize * 2) -#define MIN_VID_BUFFERS 4 +#define MIN_VID_BUFFERS 2 /* Simple file handle */ struct solo_filehandle { - struct solo_dev *solo_dev; + struct solo_dev *solo_dev; struct videobuf_queue vidq; struct task_struct *kthread; spinlock_t slock; int old_write; struct list_head vidq_active; - struct p2m_desc desc[SOLO_NR_P2M_DESC]; - int desc_idx; }; -unsigned video_nr = -1; -module_param(video_nr, uint, 0644); -MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)"); - -static void erase_on(struct solo_dev *solo_dev) +static inline void erase_on(struct solo_dev *solo_dev) { solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); solo_dev->erasing = 1; solo_dev->frame_blank = 0; } -static int erase_off(struct solo_dev *solo_dev) +static inline int erase_off(struct solo_dev *solo_dev) { if (!solo_dev->erasing) return 0; @@ -78,8 +79,7 @@ static int erase_off(struct solo_dev *solo_dev) void solo_video_in_isr(struct solo_dev *solo_dev) { - solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_VIDEO_IN); - wake_up_interruptible(&solo_dev->disp_thread_wait); + wake_up_interruptible_all(&solo_dev->disp_thread_wait); } static void solo_win_setup(struct solo_dev *solo_dev, u8 ch, @@ -202,165 +202,61 @@ static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch) return 0; } -static void disp_reset_desc(struct solo_filehandle *fh) -{ - /* We use desc mode, which ignores desc 0 */ - memset(fh->desc, 0, sizeof(*fh->desc)); - fh->desc_idx = 1; -} - -static int disp_flush_descs(struct solo_filehandle *fh) -{ - int ret; - - if (!fh->desc_idx) - return 0; - - ret = solo_p2m_dma_desc(fh->solo_dev, SOLO_P2M_DMA_ID_DISP, - fh->desc, fh->desc_idx); - disp_reset_desc(fh); - - return ret; -} - -static int disp_push_desc(struct solo_filehandle *fh, dma_addr_t dma_addr, - u32 ext_addr, int size, int repeat, int ext_size) -{ - if (fh->desc_idx >= SOLO_NR_P2M_DESC) { - int ret = disp_flush_descs(fh); - if (ret) - return ret; - } - - solo_p2m_push_desc(&fh->desc[fh->desc_idx], 0, dma_addr, ext_addr, - size, repeat, ext_size); - fh->desc_idx++; - - return 0; -} - static void solo_fillbuf(struct solo_filehandle *fh, struct videobuf_buffer *vb) { struct solo_dev *solo_dev = fh->solo_dev; - struct videobuf_dmabuf *vbuf; + dma_addr_t vbuf; unsigned int fdma_addr; - int error = 1; + int error = -1; int i; - struct scatterlist *sg; - dma_addr_t sg_dma; - int sg_size_left; - vbuf = videobuf_to_dma(vb); + vbuf = videobuf_to_dma_contig(vb); if (!vbuf) goto finish_buf; if (erase_off(solo_dev)) { - int i; - - /* Just blit to the entire sg list, ignoring size */ - for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) { - void *p = sg_virt(sg); - size_t len = sg_dma_len(sg); - - for (i = 0; i < len; i += 2) { - ((u8 *)p)[i] = 0x80; - ((u8 *)p)[i + 1] = 0x00; - } + void *p = videobuf_queue_to_vaddr(&fh->vidq, vb); + int image_size = solo_image_size(solo_dev); + for (i = 0; i < image_size; i += 2) { + ((u8 *)p)[i] = 0x80; + ((u8 *)p)[i + 1] = 0x00; } - error = 0; - goto finish_buf; - } - - disp_reset_desc(fh); - sg = vbuf->sglist; - sg_dma = sg_dma_address(sg); - sg_size_left = sg_dma_len(sg); - - fdma_addr = SOLO_DISP_EXT_ADDR + (fh->old_write * - (SOLO_HW_BPL * solo_vlines(solo_dev))); - - for (i = 0; i < solo_vlines(solo_dev); i++) { - int line_len = solo_bytesperline(solo_dev); - int lines; - - if (!sg_size_left) { - sg = sg_next(sg); - if (sg == NULL) - goto finish_buf; - sg_dma = sg_dma_address(sg); - sg_size_left = sg_dma_len(sg); - } - - /* No room for an entire line, so chunk it up */ - if (sg_size_left < line_len) { - int this_addr = fdma_addr; - - while (line_len > 0) { - int this_write; - - if (!sg_size_left) { - sg = sg_next(sg); - if (sg == NULL) - goto finish_buf; - sg_dma = sg_dma_address(sg); - sg_size_left = sg_dma_len(sg); - } - - this_write = min(sg_size_left, line_len); - - if (disp_push_desc(fh, sg_dma, this_addr, - this_write, 0, 0)) - goto finish_buf; - - line_len -= this_write; - sg_size_left -= this_write; - sg_dma += this_write; - this_addr += this_write; - } - - fdma_addr += SOLO_HW_BPL; - continue; - } - - /* Shove as many lines into a repeating descriptor as possible */ - lines = min(sg_size_left / line_len, - solo_vlines(solo_dev) - i); - - if (disp_push_desc(fh, sg_dma, fdma_addr, line_len, - lines - 1, SOLO_HW_BPL)) - goto finish_buf; + } else { + fdma_addr = SOLO_DISP_EXT_ADDR + (fh->old_write * + (SOLO_HW_BPL * solo_vlines(solo_dev))); - i += lines - 1; - fdma_addr += SOLO_HW_BPL * lines; - sg_dma += lines * line_len; - sg_size_left -= lines * line_len; + error = solo_p2m_dma_t(solo_dev, 0, vbuf, fdma_addr, + solo_bytesperline(solo_dev), + solo_vlines(solo_dev), SOLO_HW_BPL); } - error = disp_flush_descs(fh); - finish_buf: if (error) { vb->state = VIDEOBUF_ERROR; } else { - vb->size = solo_vlines(solo_dev) * solo_bytesperline(solo_dev); vb->state = VIDEOBUF_DONE; vb->field_count++; - do_gettimeofday(&vb->ts); } wake_up(&vb->done); - - return; } static void solo_thread_try(struct solo_filehandle *fh) { struct videobuf_buffer *vb; - unsigned int cur_write; + /* Only "break" from this loop if slock is held, otherwise + * just return. */ for (;;) { + unsigned int cur_write; + + cur_write = SOLO_VI_STATUS0_PAGE( + solo_reg_read(fh->solo_dev, SOLO_VI_STATUS0)); + if (cur_write == fh->old_write) + return; + spin_lock(&fh->slock); if (list_empty(&fh->vidq_active)) @@ -372,13 +268,9 @@ static void solo_thread_try(struct solo_filehandle *fh) if (!waitqueue_active(&vb->done)) break; - cur_write = SOLO_VI_STATUS0_PAGE(solo_reg_read(fh->solo_dev, - SOLO_VI_STATUS0)); - if (cur_write == fh->old_write) - break; - fh->old_write = cur_write; list_del(&vb->queue); + vb->state = VIDEOBUF_ACTIVE; spin_unlock(&fh->slock); @@ -413,17 +305,31 @@ static int solo_thread(void *data) static int solo_start_thread(struct solo_filehandle *fh) { + int ret = 0; + + if (atomic_inc_return(&fh->solo_dev->disp_users) == 1) + solo_irq_on(fh->solo_dev, SOLO_IRQ_VIDEO_IN); + fh->kthread = kthread_run(solo_thread, fh, SOLO6X10_NAME "_disp"); - return PTR_RET(fh->kthread); + if (IS_ERR(fh->kthread)) { + ret = PTR_ERR(fh->kthread); + fh->kthread = NULL; + } + + return ret; } static void solo_stop_thread(struct solo_filehandle *fh) { - if (fh->kthread) { - kthread_stop(fh->kthread); - fh->kthread = NULL; - } + if (!fh->kthread) + return; + + kthread_stop(fh->kthread); + fh->kthread = NULL; + + if (atomic_dec_return(&fh->solo_dev->disp_users) == 0) + solo_irq_off(fh->solo_dev, SOLO_IRQ_VIDEO_IN); } static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count, @@ -459,9 +365,7 @@ static int solo_buf_prepare(struct videobuf_queue *vq, if (vb->state == VIDEOBUF_NEEDS_INIT) { int rc = videobuf_iolock(vq, vb, NULL); if (rc < 0) { - struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - videobuf_dma_unmap(vq->dev, dma); - videobuf_dma_free(dma); + videobuf_dma_contig_free(vq, vb); vb->state = VIDEOBUF_NEEDS_INIT; return rc; } @@ -485,14 +389,11 @@ static void solo_buf_queue(struct videobuf_queue *vq, static void solo_buf_release(struct videobuf_queue *vq, struct videobuf_buffer *vb) { - struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - - videobuf_dma_unmap(vq->dev, dma); - videobuf_dma_free(dma); + videobuf_dma_contig_free(vq, vb); vb->state = VIDEOBUF_NEEDS_INIT; } -static struct videobuf_queue_ops solo_video_qops = { +static const struct videobuf_queue_ops solo_video_qops = { .buf_setup = solo_buf_setup, .buf_prepare = solo_buf_prepare, .buf_queue = solo_buf_queue, @@ -535,12 +436,12 @@ static int solo_v4l2_open(struct file *file) return ret; } - videobuf_queue_sg_init(&fh->vidq, &solo_video_qops, - &solo_dev->pdev->dev, &fh->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - SOLO_DISP_PIX_FIELD, - sizeof(struct videobuf_buffer), fh, NULL); - + videobuf_queue_dma_contig_init(&fh->vidq, &solo_video_qops, + &solo_dev->pdev->dev, &fh->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + SOLO_DISP_PIX_FIELD, + sizeof(struct videobuf_buffer), + fh, NULL); return 0; } @@ -557,9 +458,11 @@ static int solo_v4l2_release(struct file *file) { struct solo_filehandle *fh = file->private_data; + solo_stop_thread(fh); + videobuf_stop(&fh->vidq); videobuf_mmap_free(&fh->vidq); - solo_stop_thread(fh); + kfree(fh); return 0; @@ -585,12 +488,12 @@ static int solo_querycap(struct file *file, void *priv, static int solo_enum_ext_input(struct solo_dev *solo_dev, struct v4l2_input *input) { - static const char *dispnames_1[] = { "4UP" }; - static const char *dispnames_2[] = { "4UP-1", "4UP-2" }; - static const char *dispnames_5[] = { + static const char * const dispnames_1[] = { "4UP" }; + static const char * const dispnames_2[] = { "4UP-1", "4UP-2" }; + static const char * const dispnames_5[] = { "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP" }; - const char **dispnames; + const char * const *dispnames; if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext)) return -EINVAL; @@ -640,8 +543,14 @@ static int solo_enum_input(struct file *file, void *priv, static int solo_set_input(struct file *file, void *priv, unsigned int index) { struct solo_filehandle *fh = priv; + int ret = solo_v4l2_set_ch(fh->solo_dev, index); + + if (!ret) { + while (erase_off(fh->solo_dev)) + /* Do nothing */; + } - return solo_v4l2_set_ch(fh->solo_dev, index); + return ret; } static int solo_get_input(struct file *file, void *priv, unsigned int *index) @@ -732,7 +641,8 @@ static int solo_reqbufs(struct file *file, void *priv, return videobuf_reqbufs(&fh->vidq, req); } -static int solo_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) +static int solo_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) { struct solo_filehandle *fh = priv; @@ -901,11 +811,12 @@ static struct video_device solo_v4l2_template = { .current_norm = V4L2_STD_NTSC_M, }; -int solo_v4l2_init(struct solo_dev *solo_dev) +int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) { int ret; int i; + atomic_set(&solo_dev->disp_users, 0); init_waitqueue_head(&solo_dev->disp_thread_wait); solo_dev->vfd = video_device_alloc(); @@ -915,7 +826,7 @@ int solo_v4l2_init(struct solo_dev *solo_dev) *solo_dev->vfd = solo_v4l2_template; solo_dev->vfd->parent = &solo_dev->pdev->dev; - ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, video_nr); + ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr); if (ret < 0) { video_device_release(solo_dev->vfd); solo_dev->vfd = NULL; @@ -927,35 +838,30 @@ int solo_v4l2_init(struct solo_dev *solo_dev) snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)", SOLO6X10_NAME, solo_dev->vfd->num); - if (video_nr != -1) - video_nr++; - - dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with " - "%d inputs (%d extended)\n", solo_dev->vfd->num, - solo_dev->nr_chans, solo_dev->nr_ext); + dev_info(&solo_dev->pdev->dev, + "Display as /dev/video%d with %d inputs (%d extended)\n", + solo_dev->vfd->num, solo_dev->nr_chans, solo_dev->nr_ext); /* Cycle all the channels and clear */ for (i = 0; i < solo_dev->nr_chans; i++) { solo_v4l2_set_ch(solo_dev, i); while (erase_off(solo_dev)) - ;/* Do nothing */ + /* Do nothing */; } /* Set the default display channel */ solo_v4l2_set_ch(solo_dev, 0); while (erase_off(solo_dev)) - ;/* Do nothing */ - - solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN); + /* Do nothing */; return 0; } void solo_v4l2_exit(struct solo_dev *solo_dev) { - solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN); - if (solo_dev->vfd) { - video_unregister_device(solo_dev->vfd); - solo_dev->vfd = NULL; - } + if (solo_dev->vfd == NULL) + return; + + video_unregister_device(solo_dev->vfd); + solo_dev->vfd = NULL; } -- cgit v0.10.2 From 20c5f4925e96719eb83a4f15765a6e653d24bfde Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 12 Mar 2013 18:03:20 -0300 Subject: [media] solo6x10: fix querycap and update driver version Setup correct bus_info, let the v4l2 core set the version and add device_caps support. Also update the module version to 3.0.0 since this is a major upgrade. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index a75d939..d8d61de 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h @@ -71,16 +71,7 @@ #define SOLO_MAX_CHANNELS 16 -/* Make sure these two match */ -#define SOLO6X10_VER_MAJOR 2 -#define SOLO6X10_VER_MINOR 4 -#define SOLO6X10_VER_SUB 4 -#define SOLO6X10_VER_NUM \ - KERNEL_VERSION(SOLO6X10_VER_MAJOR, SOLO6X10_VER_MINOR, SOLO6X10_VER_SUB) -#define SOLO6X10_VERSION \ - __stringify(SOLO6X10_VER_MAJOR) "." \ - __stringify(SOLO6X10_VER_MINOR) "." \ - __stringify(SOLO6X10_VER_SUB) +#define SOLO6X10_VERSION "3.0.0" /* * The SOLO6x10 actually has 8 i2c channels, but we only use 2. diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index bb4d60a..bb5f1b8 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -991,12 +991,11 @@ static int solo_enc_querycap(struct file *file, void *priv, strcpy(cap->driver, SOLO6X10_NAME); snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d", solo_enc->ch); - snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s", + snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(solo_dev->pdev)); - cap->version = SOLO6X10_VER_NUM; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index ba603ce..70da9e2 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c @@ -476,12 +476,11 @@ static int solo_querycap(struct file *file, void *priv, strcpy(cap->driver, SOLO6X10_NAME); strcpy(cap->card, "Softlogic 6x10"); - snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI %s", + snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(solo_dev->pdev)); - cap->version = SOLO6X10_VER_NUM; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } -- cgit v0.10.2 From d9ebd623c1912f8f02fc71d4e645973f51f83362 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Mar 2013 05:36:44 -0300 Subject: [media] solo6x10: add v4l2_device Add support for struct v4l2_device. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/core.c b/drivers/staging/media/solo6x10/core.c index 75d98cc..05ecd48 100644 --- a/drivers/staging/media/solo6x10/core.c +++ b/drivers/staging/media/solo6x10/core.c @@ -181,6 +181,7 @@ static void free_solo_dev(struct solo_dev *solo_dev) pci_release_regions(pdev); pci_disable_device(pdev); + v4l2_device_unregister(&solo_dev->v4l2_dev); pci_set_drvdata(pdev, NULL); kfree(solo_dev); @@ -511,7 +512,9 @@ static int solo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) solo_dev->type = id->driver_data; solo_dev->pdev = pdev; spin_lock_init(&solo_dev->reg_io_lock); - pci_set_drvdata(pdev, solo_dev); + ret = v4l2_device_register(&pdev->dev, &solo_dev->v4l2_dev); + if (ret) + goto fail_probe; /* Only for during init */ solo_dev->p2m_jiffies = msecs_to_jiffies(100); @@ -678,7 +681,8 @@ fail_probe: static void solo_pci_remove(struct pci_dev *pdev) { - struct solo_dev *solo_dev = pci_get_drvdata(pdev); + struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); + struct solo_dev *solo_dev = container_of(v4l2_dev, struct solo_dev, v4l2_dev); free_solo_dev(solo_dev); } diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index d8d61de..6501cb9 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h @@ -37,6 +37,7 @@ #include #include +#include #include #include "registers.h" @@ -178,6 +179,7 @@ struct solo_dev { u32 irq_mask; u32 motion_mask; spinlock_t reg_io_lock; + struct v4l2_device v4l2_dev; /* tw28xx accounting */ u8 tw2865, tw2864, tw2815; diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index bb5f1b8..d085e38 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -1670,7 +1670,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, solo_enc->ch = ch; *solo_enc->vfd = solo_enc_template; - solo_enc->vfd->parent = &solo_dev->pdev->dev; + solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev; ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr); if (ret < 0) { video_device_release(solo_enc->vfd); diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index 70da9e2..3317116 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c @@ -823,7 +823,7 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) return -ENOMEM; *solo_dev->vfd = solo_v4l2_template; - solo_dev->vfd->parent = &solo_dev->pdev->dev; + solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev; ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr); if (ret < 0) { -- cgit v0.10.2 From c813bd3c8dce3564166e2c4f839fd36df7b0ba5d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Mar 2013 05:38:14 -0300 Subject: [media] solo6x10: add control framework Note that the MOTION_THRESHOLD functionality has been temporarily reduced: only the global threshold can be set, not the per-block. This will be addressed in a later patch: controls are not the proper way to do this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index 6501cb9..4035c072 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h @@ -38,6 +38,7 @@ #include #include +#include #include #include "registers.h" @@ -100,12 +101,12 @@ #define V4L2_BUF_FLAG_MOTION_ON 0x0400 #define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800 #endif -#ifndef V4L2_CID_MOTION_ENABLE -#define PRIVATE_CIDS -#define V4L2_CID_MOTION_ENABLE (V4L2_CID_PRIVATE_BASE+0) -#define V4L2_CID_MOTION_THRESHOLD (V4L2_CID_PRIVATE_BASE+1) -#define V4L2_CID_MOTION_TRACE (V4L2_CID_PRIVATE_BASE+2) -#endif + +#define SOLO_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) +#define V4L2_CID_MOTION_ENABLE (SOLO_CID_CUSTOM_BASE+0) +#define V4L2_CID_MOTION_THRESHOLD (SOLO_CID_CUSTOM_BASE+1) +#define V4L2_CID_MOTION_TRACE (SOLO_CID_CUSTOM_BASE+2) +#define V4L2_CID_OSD_TEXT (SOLO_CID_CUSTOM_BASE+3) enum SOLO_I2C_STATE { IIC_STATE_IDLE, @@ -137,6 +138,7 @@ struct solo_p2m_dev { struct solo_enc_dev { struct solo_dev *solo_dev; /* V4L2 Items */ + struct v4l2_ctrl_handler hdl; struct video_device *vfd; /* General accounting */ struct mutex enable_lock; @@ -207,6 +209,7 @@ struct solo_dev { unsigned int frame_blank; u8 cur_disp_ch; wait_queue_head_t disp_thread_wait; + struct v4l2_ctrl_handler disp_hdl; /* V4L2 Encoder items */ struct solo_enc_dev *v4l2_enc[SOLO_MAX_CHANNELS]; diff --git a/drivers/staging/media/solo6x10/tw28.c b/drivers/staging/media/solo6x10/tw28.c index 365ab10..69baf82 100644 --- a/drivers/staging/media/solo6x10/tw28.c +++ b/drivers/staging/media/solo6x10/tw28.c @@ -660,6 +660,11 @@ u16 tw28_get_audio_status(struct solo_dev *solo_dev) } #endif +bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch) +{ + return is_tw286x(solo_dev, ch / 4); +} + int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val) { @@ -676,8 +681,6 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, switch (ctrl) { case V4L2_CID_SHARPNESS: /* Only 286x has sharpness */ - if (val > 0x0f || val < 0) - return -ERANGE; if (is_tw286x(solo_dev, chip_num)) { u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, TW_CHIP_OFFSET_ADDR(chip_num), @@ -687,8 +690,9 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, TW_CHIP_OFFSET_ADDR(chip_num), TW286x_SHARPNESS(chip_num), v); - } else if (val != 0) - return -ERANGE; + } else { + return -EINVAL; + } break; case V4L2_CID_HUE: diff --git a/drivers/staging/media/solo6x10/tw28.h b/drivers/staging/media/solo6x10/tw28.h index a03b429..1a02c87 100644 --- a/drivers/staging/media/solo6x10/tw28.h +++ b/drivers/staging/media/solo6x10/tw28.h @@ -55,6 +55,7 @@ int solo_tw28_init(struct solo_dev *solo_dev); int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val); int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val); +bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch); u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch); void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val); diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index d085e38..8296d8d 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -119,41 +119,6 @@ static unsigned char vop_6110_pal_cif[] = { 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00, }; - -static const u32 solo_user_ctrls[] = { - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_SHARPNESS, - 0 -}; - -static const u32 solo_mpeg_ctrls[] = { - V4L2_CID_MPEG_VIDEO_ENCODING, - V4L2_CID_MPEG_VIDEO_GOP_SIZE, - 0 -}; - -static const u32 solo_private_ctrls[] = { - V4L2_CID_MOTION_ENABLE, - V4L2_CID_MOTION_THRESHOLD, - 0 -}; - -static const u32 solo_fmtx_ctrls[] = { - V4L2_CID_RDS_TX_RADIO_TEXT, - 0 -}; - -static const u32 *solo_ctrl_classes[] = { - solo_user_ctrls, - solo_mpeg_ctrls, - solo_fmtx_ctrls, - solo_private_ctrls, - NULL -}; - struct vop_header { /* VE_STATUS0 */ u32 mpeg_size:20, sad_motion_flag:1, video_motion_flag:1, vop_type:2, @@ -1341,128 +1306,13 @@ static int solo_s_parm(struct file *file, void *priv, return 0; } -static int solo_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) +static int solo_s_ctrl(struct v4l2_ctrl *ctrl) { - struct solo_enc_fh *fh = priv; - struct solo_enc_dev *solo_enc = fh->enc; + struct solo_enc_dev *solo_enc = + container_of(ctrl->handler, struct solo_enc_dev, hdl); struct solo_dev *solo_dev = solo_enc->solo_dev; - - qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id); - if (!qc->id) - return -EINVAL; - - switch (qc->id) { - case V4L2_CID_BRIGHTNESS: - case V4L2_CID_CONTRAST: - case V4L2_CID_SATURATION: - case V4L2_CID_HUE: - return v4l2_ctrl_query_fill(qc, 0x00, 0xff, 1, 0x80); - case V4L2_CID_SHARPNESS: - return v4l2_ctrl_query_fill(qc, 0x00, 0x0f, 1, 0x00); - case V4L2_CID_MPEG_VIDEO_ENCODING: - return v4l2_ctrl_query_fill( - qc, V4L2_MPEG_VIDEO_ENCODING_MPEG_1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC); - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - return v4l2_ctrl_query_fill(qc, 1, 255, 1, solo_dev->fps); -#ifdef PRIVATE_CIDS - case V4L2_CID_MOTION_THRESHOLD: - qc->flags |= V4L2_CTRL_FLAG_SLIDER; - qc->type = V4L2_CTRL_TYPE_INTEGER; - qc->minimum = 0; - qc->maximum = 0xffff; - qc->step = 1; - qc->default_value = SOLO_DEF_MOT_THRESH; - strlcpy(qc->name, "Motion Detection Threshold", - sizeof(qc->name)); - return 0; - case V4L2_CID_MOTION_ENABLE: - qc->type = V4L2_CTRL_TYPE_BOOLEAN; - qc->minimum = 0; - qc->maximum = qc->step = 1; - qc->default_value = 0; - strlcpy(qc->name, "Motion Detection Enable", sizeof(qc->name)); - return 0; -#else - case V4L2_CID_MOTION_THRESHOLD: - return v4l2_ctrl_query_fill(qc, 0, 0xffff, 1, - SOLO_DEF_MOT_THRESH); - case V4L2_CID_MOTION_ENABLE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); -#endif - case V4L2_CID_RDS_TX_RADIO_TEXT: - qc->type = V4L2_CTRL_TYPE_STRING; - qc->minimum = 0; - qc->maximum = OSD_TEXT_MAX; - qc->step = 1; - qc->default_value = 0; - strlcpy(qc->name, "OSD Text", sizeof(qc->name)); - return 0; - } - - return -EINVAL; -} - -static int solo_querymenu(struct file *file, void *priv, - struct v4l2_querymenu *qmenu) -{ - struct v4l2_queryctrl qctrl; int err; - qctrl.id = qmenu->id; - - err = solo_queryctrl(file, priv, &qctrl); - if (err) - return err; - - return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL); -} - -static int solo_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct solo_enc_fh *fh = priv; - struct solo_enc_dev *solo_enc = fh->enc; - struct solo_dev *solo_dev = solo_enc->solo_dev; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - case V4L2_CID_CONTRAST: - case V4L2_CID_SATURATION: - case V4L2_CID_HUE: - case V4L2_CID_SHARPNESS: - return tw28_get_ctrl_val(solo_dev, ctrl->id, solo_enc->ch, - &ctrl->value); - case V4L2_CID_MPEG_VIDEO_ENCODING: - ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC; - break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - if (atomic_read(&solo_enc->readers) > 0) - return -EBUSY; - ctrl->value = solo_enc->gop; - break; - case V4L2_CID_MOTION_THRESHOLD: - ctrl->value = solo_enc->motion_thresh; - break; - case V4L2_CID_MOTION_ENABLE: - ctrl->value = solo_is_motion_on(solo_enc); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int solo_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct solo_enc_fh *fh = priv; - struct solo_enc_dev *solo_enc = fh->enc; - struct solo_dev *solo_dev = solo_enc->solo_dev; - switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: case V4L2_CID_CONTRAST: @@ -1470,20 +1320,15 @@ static int solo_s_ctrl(struct file *file, void *priv, case V4L2_CID_HUE: case V4L2_CID_SHARPNESS: return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch, - ctrl->value); + ctrl->val); case V4L2_CID_MPEG_VIDEO_ENCODING: - if (ctrl->value != V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC) - return -ERANGE; - break; + return 0; case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - if (ctrl->value < 1 || ctrl->value > 255) - return -ERANGE; - solo_enc->gop = ctrl->value; - break; - case V4L2_CID_MOTION_THRESHOLD: - { - u16 block = (ctrl->value >> 16) & 0xffff; - u16 value = ctrl->value & 0xffff; + solo_enc->gop = ctrl->val; + return 0; + case V4L2_CID_MOTION_THRESHOLD: { + u16 block = (ctrl->val >> 16) & 0xffff; + u16 value = ctrl->val & 0xffff; /* Motion thresholds are in a table of 64x64 samples, with * each sample representing 16x16 pixels of the source. In @@ -1492,22 +1337,25 @@ static int solo_s_ctrl(struct file *file, void *priv, * * Block is 0 to set the threshold globally, or any positive * number under 2049 to set block-1 individually. */ - if (block > 2049) - return -ERANGE; - + /* Currently we limit support to block 0 only. A later patch + * will add a new ioctl to set all other blocks. */ if (block == 0) { solo_enc->motion_thresh = value; return solo_set_motion_threshold(solo_dev, solo_enc->ch, value); - } else { - return solo_set_motion_block(solo_dev, solo_enc->ch, - value, block - 1); } - break; + return solo_set_motion_block(solo_dev, solo_enc->ch, + value, block - 1); } case V4L2_CID_MOTION_ENABLE: - solo_motion_toggle(solo_enc, ctrl->value); - break; + solo_motion_toggle(solo_enc, ctrl->val); + return 0; + case V4L2_CID_OSD_TEXT: + mutex_lock(&solo_enc->enable_lock); + strcpy(solo_enc->osd_text, ctrl->string); + err = solo_osd_print(solo_enc); + mutex_unlock(&solo_enc->enable_lock); + return err; default: return -EINVAL; } @@ -1515,86 +1363,6 @@ static int solo_s_ctrl(struct file *file, void *priv, return 0; } -static int solo_s_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct solo_enc_fh *fh = priv; - struct solo_enc_dev *solo_enc = fh->enc; - int i; - - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = (ctrls->controls + i); - int err; - - switch (ctrl->id) { - case V4L2_CID_RDS_TX_RADIO_TEXT: - if (ctrl->size - 1 > OSD_TEXT_MAX) - err = -ERANGE; - else { - mutex_lock(&solo_enc->enable_lock); - err = copy_from_user(solo_enc->osd_text, - ctrl->string, - OSD_TEXT_MAX); - solo_enc->osd_text[OSD_TEXT_MAX] = '\0'; - if (!err) - err = solo_osd_print(solo_enc); - else - err = -EFAULT; - mutex_unlock(&solo_enc->enable_lock); - } - break; - default: - err = -EINVAL; - } - - if (err < 0) { - ctrls->error_idx = i; - return err; - } - } - - return 0; -} - -static int solo_g_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct solo_enc_fh *fh = priv; - struct solo_enc_dev *solo_enc = fh->enc; - int i; - - for (i = 0; i < ctrls->count; i++) { - struct v4l2_ext_control *ctrl = (ctrls->controls + i); - int err; - - switch (ctrl->id) { - case V4L2_CID_RDS_TX_RADIO_TEXT: - if (ctrl->size < OSD_TEXT_MAX) { - ctrl->size = OSD_TEXT_MAX; - err = -ENOSPC; - } else { - mutex_lock(&solo_enc->enable_lock); - err = copy_to_user(ctrl->string, - solo_enc->osd_text, - OSD_TEXT_MAX); - if (err) - err = -EFAULT; - mutex_unlock(&solo_enc->enable_lock); - } - break; - default: - err = -EINVAL; - } - - if (err < 0) { - ctrls->error_idx = i; - return err; - } - } - - return 0; -} - static const struct v4l2_file_operations solo_enc_fops = { .owner = THIS_MODULE, .open = solo_enc_open, @@ -1630,13 +1398,6 @@ static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = { /* Video capture parameters */ .vidioc_s_parm = solo_s_parm, .vidioc_g_parm = solo_g_parm, - /* Controls */ - .vidioc_queryctrl = solo_queryctrl, - .vidioc_querymenu = solo_querymenu, - .vidioc_g_ctrl = solo_g_ctrl, - .vidioc_s_ctrl = solo_s_ctrl, - .vidioc_g_ext_ctrls = solo_g_ext_ctrls, - .vidioc_s_ext_ctrls = solo_s_ext_ctrls, }; static const struct video_device solo_enc_template = { @@ -1650,18 +1411,82 @@ static const struct video_device solo_enc_template = { .current_norm = V4L2_STD_NTSC_M, }; +static const struct v4l2_ctrl_ops solo_ctrl_ops = { + .s_ctrl = solo_s_ctrl, +}; + +static const struct v4l2_ctrl_config solo_motion_threshold_ctrl = { + .ops = &solo_ctrl_ops, + .id = V4L2_CID_MOTION_THRESHOLD, + .name = "Motion Detection Threshold", + .type = V4L2_CTRL_TYPE_INTEGER, + .max = 0xffff, + .def = SOLO_DEF_MOT_THRESH, + .step = 1, + .flags = V4L2_CTRL_FLAG_SLIDER, +}; + +static const struct v4l2_ctrl_config solo_motion_enable_ctrl = { + .ops = &solo_ctrl_ops, + .id = V4L2_CID_MOTION_ENABLE, + .name = "Motion Detection Enable", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config solo_osd_text_ctrl = { + .ops = &solo_ctrl_ops, + .id = V4L2_CID_OSD_TEXT, + .name = "OSD Text", + .type = V4L2_CTRL_TYPE_STRING, + .max = OSD_TEXT_MAX, + .step = 1, +}; + static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, u8 ch, unsigned nr) { struct solo_enc_dev *solo_enc; + struct v4l2_ctrl_handler *hdl; int ret; solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL); if (!solo_enc) return ERR_PTR(-ENOMEM); + hdl = &solo_enc->hdl; + v4l2_ctrl_handler_init(hdl, 10); + v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 128); + v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 128); + v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, + V4L2_CID_HUE, 0, 255, 1, 128); + if (tw28_has_sharpness(solo_dev, ch)) + v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 15, 1, 0); + v4l2_ctrl_new_std_menu(hdl, &solo_ctrl_ops, + V4L2_CID_MPEG_VIDEO_ENCODING, + V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 3, + V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC); + v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps); + v4l2_ctrl_new_custom(hdl, &solo_motion_threshold_ctrl, NULL); + v4l2_ctrl_new_custom(hdl, &solo_motion_enable_ctrl, NULL); + v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL); + if (hdl->error) { + ret = hdl->error; + v4l2_ctrl_handler_free(hdl); + kfree(solo_enc); + return ERR_PTR(ret); + } + solo_enc->vfd = video_device_alloc(); if (!solo_enc->vfd) { + v4l2_ctrl_handler_free(hdl); kfree(solo_enc); return ERR_PTR(-ENOMEM); } @@ -1671,9 +1496,11 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, *solo_enc->vfd = solo_enc_template; solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev; + solo_enc->vfd->ctrl_handler = hdl; ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr); if (ret < 0) { video_device_release(solo_enc->vfd); + v4l2_ctrl_handler_free(hdl); kfree(solo_enc); return ERR_PTR(ret); } @@ -1714,6 +1541,7 @@ static void solo_enc_free(struct solo_enc_dev *solo_enc) return; video_unregister_device(solo_enc->vfd); + v4l2_ctrl_handler_free(&solo_enc->hdl); kfree(solo_enc); } diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index 3317116..4243bbe 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c @@ -687,64 +687,14 @@ static int solo_s_std(struct file *file, void *priv, v4l2_std_id i) return 0; } -static const u32 solo_motion_ctrls[] = { - V4L2_CID_MOTION_TRACE, - 0 -}; - -static const u32 *solo_ctrl_classes[] = { - solo_motion_ctrls, - NULL -}; - -static int solo_disp_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - qc->id = v4l2_ctrl_next(solo_ctrl_classes, qc->id); - if (!qc->id) - return -EINVAL; - - switch (qc->id) { -#ifdef PRIVATE_CIDS - case V4L2_CID_MOTION_TRACE: - qc->type = V4L2_CTRL_TYPE_BOOLEAN; - qc->minimum = 0; - qc->maximum = qc->step = 1; - qc->default_value = 0; - strlcpy(qc->name, "Motion Detection Trace", sizeof(qc->name)); - return 0; -#else - case V4L2_CID_MOTION_TRACE: - return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); -#endif - } - return -EINVAL; -} - -static int solo_disp_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) +static int solo_s_ctrl(struct v4l2_ctrl *ctrl) { - struct solo_filehandle *fh = priv; - struct solo_dev *solo_dev = fh->solo_dev; + struct solo_dev *solo_dev = + container_of(ctrl->handler, struct solo_dev, disp_hdl); switch (ctrl->id) { case V4L2_CID_MOTION_TRACE: - ctrl->value = solo_reg_read(solo_dev, SOLO_VI_MOTION_BAR) - ? 1 : 0; - return 0; - } - return -EINVAL; -} - -static int solo_disp_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct solo_filehandle *fh = priv; - struct solo_dev *solo_dev = fh->solo_dev; - - switch (ctrl->id) { - case V4L2_CID_MOTION_TRACE: - if (ctrl->value) { + if (ctrl->val) { solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, SOLO_VI_MOTION_Y_ADD | SOLO_VI_MOTION_Y_VALUE(0x20) | @@ -760,6 +710,8 @@ static int solo_disp_s_ctrl(struct file *file, void *priv, solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); } return 0; + default: + break; } return -EINVAL; } @@ -793,10 +745,6 @@ static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = { .vidioc_dqbuf = solo_dqbuf, .vidioc_streamon = solo_streamon, .vidioc_streamoff = solo_streamoff, - /* Controls */ - .vidioc_queryctrl = solo_disp_queryctrl, - .vidioc_g_ctrl = solo_disp_g_ctrl, - .vidioc_s_ctrl = solo_disp_s_ctrl, }; static struct video_device solo_v4l2_template = { @@ -810,6 +758,19 @@ static struct video_device solo_v4l2_template = { .current_norm = V4L2_STD_NTSC_M, }; +static const struct v4l2_ctrl_ops solo_ctrl_ops = { + .s_ctrl = solo_s_ctrl, +}; + +static const struct v4l2_ctrl_config solo_motion_trace_ctrl = { + .ops = &solo_ctrl_ops, + .id = V4L2_CID_MOTION_TRACE, + .name = "Motion Detection Trace", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) { int ret; @@ -824,6 +785,11 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) *solo_dev->vfd = solo_v4l2_template; solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev; + v4l2_ctrl_handler_init(&solo_dev->disp_hdl, 1); + v4l2_ctrl_new_custom(&solo_dev->disp_hdl, &solo_motion_trace_ctrl, NULL); + if (solo_dev->disp_hdl.error) + return solo_dev->disp_hdl.error; + solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl; ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr); if (ret < 0) { @@ -862,5 +828,6 @@ void solo_v4l2_exit(struct solo_dev *solo_dev) return; video_unregister_device(solo_dev->vfd); + v4l2_ctrl_handler_free(&solo_dev->disp_hdl); solo_dev->vfd = NULL; } -- cgit v0.10.2 From 016afda4fb298aa2e5515048fcba0271ad6f7320 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 12 Mar 2013 18:43:21 -0300 Subject: [media] solo6x10: fix various format-related compliancy issues - try_fmt should never return -EBUSY. - invalid pix->field values were not mapped to a valid value. - the priv field of struct v4l2_pix_format wasn't zeroed. - the try_fmt error code was not checked in set_fmt. - enum_framesizes/intervals is valid for both MJPEG and MPEG pixel formats. - enum_frameintervals didn't check width and height and reported the wrong range. - s_parm didn't set readbuffers. - don't fail on invalid colorspace, just replace with the valid colorspace. - bytesperline should be 0 for compressed formats. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index 8296d8d..5b2fdfb 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -1039,13 +1039,6 @@ static int solo_enc_try_fmt_cap(struct file *file, void *priv, pix->pixelformat != V4L2_PIX_FMT_MJPEG) return -EINVAL; - /* We cannot change width/height in mid mpeg */ - if (atomic_read(&solo_enc->mpeg_readers) > 0) { - if (pix->width != solo_enc->width || - pix->height != solo_enc->height) - return -EBUSY; - } - if (pix->width < solo_dev->video_hsize || pix->height < solo_dev->video_vsize << 1) { /* Default to CIF 1/2 size */ @@ -1057,14 +1050,20 @@ static int solo_enc_try_fmt_cap(struct file *file, void *priv, pix->height = solo_dev->video_vsize << 1; } - if (pix->field == V4L2_FIELD_ANY) - pix->field = V4L2_FIELD_INTERLACED; - else if (pix->field != V4L2_FIELD_INTERLACED) + switch (pix->field) { + case V4L2_FIELD_NONE: + case V4L2_FIELD_INTERLACED: + break; + case V4L2_FIELD_ANY: + default: pix->field = V4L2_FIELD_INTERLACED; + break; + } /* Just set these */ pix->colorspace = V4L2_COLORSPACE_SMPTE170M; pix->sizeimage = FRAME_BUF_SIZE; + pix->priv = 0; return 0; } @@ -1081,6 +1080,15 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv, mutex_lock(&solo_enc->enable_lock); ret = solo_enc_try_fmt_cap(file, priv, f); + if (ret) + return ret; + + /* We cannot change width/height in mid read */ + if (!ret && atomic_read(&solo_enc->readers) > 0) { + if (pix->width != solo_enc->width || + pix->height != solo_enc->height) + ret = -EBUSY; + } if (ret) { mutex_unlock(&solo_enc->enable_lock); return ret; @@ -1116,6 +1124,7 @@ static int solo_enc_get_fmt_cap(struct file *file, void *priv, V4L2_FIELD_NONE; pix->sizeimage = FRAME_BUF_SIZE; pix->colorspace = V4L2_COLORSPACE_SMPTE170M; + pix->priv = 0; return 0; } @@ -1205,7 +1214,8 @@ static int solo_enum_framesizes(struct file *file, void *priv, struct solo_enc_fh *fh = priv; struct solo_dev *solo_dev = fh->enc->solo_dev; - if (fsize->pixel_format != V4L2_PIX_FMT_MPEG) + if (fsize->pixel_format != V4L2_PIX_FMT_MPEG && + fsize->pixel_format != V4L2_PIX_FMT_MJPEG) return -EINVAL; switch (fsize->index) { @@ -1232,16 +1242,24 @@ static int solo_enum_frameintervals(struct file *file, void *priv, struct solo_enc_fh *fh = priv; struct solo_dev *solo_dev = fh->enc->solo_dev; - if (fintv->pixel_format != V4L2_PIX_FMT_MPEG || fintv->index) + if (fintv->pixel_format != V4L2_PIX_FMT_MPEG && + fintv->pixel_format != V4L2_PIX_FMT_MJPEG) + return -EINVAL; + if (fintv->index) + return -EINVAL; + if ((fintv->width != solo_dev->video_hsize >> 1 || + fintv->height != solo_dev->video_vsize) && + (fintv->width != solo_dev->video_hsize || + fintv->height != solo_dev->video_vsize << 1)) return -EINVAL; fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE; - fintv->stepwise.min.numerator = solo_dev->fps; - fintv->stepwise.min.denominator = 1; + fintv->stepwise.min.denominator = solo_dev->fps; + fintv->stepwise.min.numerator = 15; - fintv->stepwise.max.numerator = solo_dev->fps; - fintv->stepwise.max.denominator = 15; + fintv->stepwise.max.denominator = solo_dev->fps; + fintv->stepwise.max.numerator = 1; fintv->stepwise.step.numerator = 1; fintv->stepwise.step.denominator = 1; @@ -1298,6 +1316,7 @@ static int solo_s_parm(struct file *file, void *priv, solo_enc->interval = cp->timeperframe.numerator; cp->capability = V4L2_CAP_TIMEPERFRAME; + cp->readbuffers = 2; solo_update_mode(solo_enc); diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index 4243bbe..668dc48 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c @@ -34,8 +34,6 @@ #include "solo6x10.h" #include "tw28.h" -#define SOLO_DISP_PIX_FIELD V4L2_FIELD_INTERLACED - /* Image size is two fields, SOLO_HW_BPL is one horizontal line in hardware */ #define SOLO_HW_BPL 2048 #define solo_vlines(__solo) (__solo->video_vsize * 2) @@ -439,7 +437,7 @@ static int solo_v4l2_open(struct file *file) videobuf_queue_dma_contig_init(&fh->vidq, &solo_video_qops, &solo_dev->pdev->dev, &fh->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, - SOLO_DISP_PIX_FIELD, + V4L2_FIELD_INTERLACED, sizeof(struct videobuf_buffer), fh, NULL); return 0; @@ -581,23 +579,16 @@ static int solo_try_fmt_cap(struct file *file, void *priv, struct v4l2_pix_format *pix = &f->fmt.pix; int image_size = solo_image_size(solo_dev); - /* Check supported sizes */ - if (pix->width != solo_dev->video_hsize) - pix->width = solo_dev->video_hsize; - if (pix->height != solo_vlines(solo_dev)) - pix->height = solo_vlines(solo_dev); - if (pix->sizeimage != image_size) - pix->sizeimage = image_size; - - /* Check formats */ - if (pix->field == V4L2_FIELD_ANY) - pix->field = SOLO_DISP_PIX_FIELD; - - if (pix->pixelformat != V4L2_PIX_FMT_UYVY || - pix->field != SOLO_DISP_PIX_FIELD || - pix->colorspace != V4L2_COLORSPACE_SMPTE170M) + if (pix->pixelformat != V4L2_PIX_FMT_UYVY) return -EINVAL; + pix->width = solo_dev->video_hsize; + pix->height = solo_vlines(solo_dev); + pix->sizeimage = image_size; + pix->field = V4L2_FIELD_INTERLACED; + pix->pixelformat = V4L2_PIX_FMT_UYVY; + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; + pix->priv = 0; return 0; } @@ -624,10 +615,11 @@ static int solo_get_fmt_cap(struct file *file, void *priv, pix->width = solo_dev->video_hsize; pix->height = solo_vlines(solo_dev); pix->pixelformat = V4L2_PIX_FMT_UYVY; - pix->field = SOLO_DISP_PIX_FIELD; + pix->field = V4L2_FIELD_INTERLACED; pix->sizeimage = solo_image_size(solo_dev); pix->colorspace = V4L2_COLORSPACE_SMPTE170M; pix->bytesperline = solo_bytesperline(solo_dev); + pix->priv = 0; return 0; } -- cgit v0.10.2 From 941604977c00ebeb6324348ece84d2140b190754 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 12 Mar 2013 18:47:03 -0300 Subject: [media] solo6x10: add support for prio and control event handling Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index 5b2fdfb..7cf3e7b 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -29,6 +29,7 @@ #include #include +#include #include #include "solo6x10.h" @@ -46,7 +47,8 @@ enum solo_enc_types { }; struct solo_enc_fh { - struct solo_enc_dev *enc; + struct v4l2_fh fh; + struct solo_enc_dev *enc; u32 fmt; u8 enc_on; enum solo_enc_types type; @@ -823,7 +825,11 @@ static unsigned int solo_enc_poll(struct file *file, struct poll_table_struct *wait) { struct solo_enc_fh *fh = file->private_data; + unsigned long req_events = poll_requested_events(wait); + unsigned res = v4l2_ctrl_poll(file, wait); + if (!(req_events & (POLLIN | POLLRDNORM))) + return res; return videobuf_poll_stream(file, &fh->vidq, wait); } @@ -892,6 +898,7 @@ static int solo_enc_open(struct file *file) return -ENOMEM; } + v4l2_fh_init(&fh->fh, video_devdata(file)); fh->enc = solo_enc; spin_lock_init(&fh->av_lock); file->private_data = fh; @@ -906,7 +913,7 @@ static int solo_enc_open(struct file *file) V4L2_FIELD_INTERLACED, sizeof(struct solo_videobuf), fh, NULL); - + v4l2_fh_add(&fh->fh); return 0; } @@ -931,6 +938,8 @@ static int solo_enc_release(struct file *file) struct solo_dev *solo_dev = fh->enc->solo_dev; solo_enc_off(fh); + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); videobuf_stop(&fh->vidq); videobuf_mmap_free(&fh->vidq); @@ -1063,6 +1072,7 @@ static int solo_enc_try_fmt_cap(struct file *file, void *priv, /* Just set these */ pix->colorspace = V4L2_COLORSPACE_SMPTE170M; pix->sizeimage = FRAME_BUF_SIZE; + pix->bytesperline = 0; pix->priv = 0; return 0; @@ -1417,6 +1427,10 @@ static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = { /* Video capture parameters */ .vidioc_s_parm = solo_s_parm, .vidioc_g_parm = solo_g_parm, + /* Logging and events */ + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static const struct video_device solo_enc_template = { @@ -1516,6 +1530,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, *solo_enc->vfd = solo_enc_template; solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev; solo_enc->vfd->ctrl_handler = hdl; + set_bit(V4L2_FL_USE_FH_PRIO, &solo_enc->vfd->flags); ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr); if (ret < 0) { video_device_release(solo_enc->vfd); diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index 668dc48..a688949 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c @@ -29,6 +29,7 @@ #include #include +#include #include #include "solo6x10.h" @@ -45,6 +46,7 @@ /* Simple file handle */ struct solo_filehandle { + struct v4l2_fh fh; struct solo_dev *solo_dev; struct videobuf_queue vidq; struct task_struct *kthread; @@ -402,8 +404,12 @@ static unsigned int solo_v4l2_poll(struct file *file, struct poll_table_struct *wait) { struct solo_filehandle *fh = file->private_data; + unsigned long req_events = poll_requested_events(wait); + unsigned res = v4l2_ctrl_poll(file, wait); - return videobuf_poll_stream(file, &fh->vidq, wait); + if (!(req_events & (POLLIN | POLLRDNORM))) + return res; + return res | videobuf_poll_stream(file, &fh->vidq, wait); } static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma) @@ -423,6 +429,7 @@ static int solo_v4l2_open(struct file *file) if (fh == NULL) return -ENOMEM; + v4l2_fh_init(&fh->fh, video_devdata(file)); spin_lock_init(&fh->slock); INIT_LIST_HEAD(&fh->vidq_active); fh->solo_dev = solo_dev; @@ -440,6 +447,7 @@ static int solo_v4l2_open(struct file *file) V4L2_FIELD_INTERLACED, sizeof(struct videobuf_buffer), fh, NULL); + v4l2_fh_add(&fh->fh); return 0; } @@ -461,6 +469,8 @@ static int solo_v4l2_release(struct file *file) videobuf_stop(&fh->vidq); videobuf_mmap_free(&fh->vidq); + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); kfree(fh); return 0; @@ -737,6 +747,10 @@ static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = { .vidioc_dqbuf = solo_dqbuf, .vidioc_streamon = solo_streamon, .vidioc_streamoff = solo_streamoff, + /* Logging and events */ + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device solo_v4l2_template = { @@ -782,6 +796,7 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) if (solo_dev->disp_hdl.error) return solo_dev->disp_hdl.error; solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl; + set_bit(V4L2_FL_USE_FH_PRIO, &solo_dev->vfd->flags); ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr); if (ret < 0) { -- cgit v0.10.2 From 6a2e65d54ebb1284c4d234ec606e4eccab7eb812 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2013 11:56:46 -0300 Subject: [media] solo6x10: move global fields in solo_dev_fh to solo_dev All fields in solo_dev_fh do not belong there since they refer to global properties. After moving all these fields to solo_dev the solo_dev_fh struct can be removed completely. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index 4035c072..830359f 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h @@ -250,6 +250,13 @@ struct solo_dev { void *vh_buf; dma_addr_t vh_dma; int vh_size; + + /* Buffer handling */ + struct videobuf_queue vidq; + struct task_struct *kthread; + spinlock_t slock; + int old_write; + struct list_head vidq_active; }; static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg) diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index a688949..13b7640 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c @@ -44,17 +44,6 @@ #define MIN_VID_BUFFERS 2 -/* Simple file handle */ -struct solo_filehandle { - struct v4l2_fh fh; - struct solo_dev *solo_dev; - struct videobuf_queue vidq; - struct task_struct *kthread; - spinlock_t slock; - int old_write; - struct list_head vidq_active; -}; - static inline void erase_on(struct solo_dev *solo_dev) { solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); @@ -202,10 +191,9 @@ static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch) return 0; } -static void solo_fillbuf(struct solo_filehandle *fh, +static void solo_fillbuf(struct solo_dev *solo_dev, struct videobuf_buffer *vb) { - struct solo_dev *solo_dev = fh->solo_dev; dma_addr_t vbuf; unsigned int fdma_addr; int error = -1; @@ -216,7 +204,7 @@ static void solo_fillbuf(struct solo_filehandle *fh, goto finish_buf; if (erase_off(solo_dev)) { - void *p = videobuf_queue_to_vaddr(&fh->vidq, vb); + void *p = videobuf_queue_to_vaddr(&solo_dev->vidq, vb); int image_size = solo_image_size(solo_dev); for (i = 0; i < image_size; i += 2) { ((u8 *)p)[i] = 0x80; @@ -224,7 +212,7 @@ static void solo_fillbuf(struct solo_filehandle *fh, } error = 0; } else { - fdma_addr = SOLO_DISP_EXT_ADDR + (fh->old_write * + fdma_addr = SOLO_DISP_EXT_ADDR + (solo_dev->old_write * (SOLO_HW_BPL * solo_vlines(solo_dev))); error = solo_p2m_dma_t(solo_dev, 0, vbuf, fdma_addr, @@ -243,7 +231,7 @@ finish_buf: wake_up(&vb->done); } -static void solo_thread_try(struct solo_filehandle *fh) +static void solo_thread_try(struct solo_dev *solo_dev) { struct videobuf_buffer *vb; @@ -253,38 +241,37 @@ static void solo_thread_try(struct solo_filehandle *fh) unsigned int cur_write; cur_write = SOLO_VI_STATUS0_PAGE( - solo_reg_read(fh->solo_dev, SOLO_VI_STATUS0)); - if (cur_write == fh->old_write) + solo_reg_read(solo_dev, SOLO_VI_STATUS0)); + if (cur_write == solo_dev->old_write) return; - spin_lock(&fh->slock); + spin_lock(&solo_dev->slock); - if (list_empty(&fh->vidq_active)) + if (list_empty(&solo_dev->vidq_active)) break; - vb = list_first_entry(&fh->vidq_active, struct videobuf_buffer, + vb = list_first_entry(&solo_dev->vidq_active, struct videobuf_buffer, queue); if (!waitqueue_active(&vb->done)) break; - fh->old_write = cur_write; + solo_dev->old_write = cur_write; list_del(&vb->queue); vb->state = VIDEOBUF_ACTIVE; - spin_unlock(&fh->slock); + spin_unlock(&solo_dev->slock); - solo_fillbuf(fh, vb); + solo_fillbuf(solo_dev, vb); } - assert_spin_locked(&fh->slock); - spin_unlock(&fh->slock); + assert_spin_locked(&solo_dev->slock); + spin_unlock(&solo_dev->slock); } static int solo_thread(void *data) { - struct solo_filehandle *fh = data; - struct solo_dev *solo_dev = fh->solo_dev; + struct solo_dev *solo_dev = data; DECLARE_WAITQUEUE(wait, current); set_freezable(); @@ -294,7 +281,7 @@ static int solo_thread(void *data) long timeout = schedule_timeout_interruptible(HZ); if (timeout == -ERESTARTSYS || kthread_should_stop()) break; - solo_thread_try(fh); + solo_thread_try(solo_dev); try_to_freeze(); } @@ -303,40 +290,39 @@ static int solo_thread(void *data) return 0; } -static int solo_start_thread(struct solo_filehandle *fh) +static int solo_start_thread(struct solo_dev *solo_dev) { int ret = 0; - if (atomic_inc_return(&fh->solo_dev->disp_users) == 1) - solo_irq_on(fh->solo_dev, SOLO_IRQ_VIDEO_IN); + if (atomic_inc_return(&solo_dev->disp_users) == 1) + solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN); - fh->kthread = kthread_run(solo_thread, fh, SOLO6X10_NAME "_disp"); + solo_dev->kthread = kthread_run(solo_thread, solo_dev, SOLO6X10_NAME "_disp"); - if (IS_ERR(fh->kthread)) { - ret = PTR_ERR(fh->kthread); - fh->kthread = NULL; + if (IS_ERR(solo_dev->kthread)) { + ret = PTR_ERR(solo_dev->kthread); + solo_dev->kthread = NULL; } return ret; } -static void solo_stop_thread(struct solo_filehandle *fh) +static void solo_stop_thread(struct solo_dev *solo_dev) { - if (!fh->kthread) + if (!solo_dev->kthread) return; - kthread_stop(fh->kthread); - fh->kthread = NULL; + kthread_stop(solo_dev->kthread); + solo_dev->kthread = NULL; - if (atomic_dec_return(&fh->solo_dev->disp_users) == 0) - solo_irq_off(fh->solo_dev, SOLO_IRQ_VIDEO_IN); + if (atomic_dec_return(&solo_dev->disp_users) == 0) + solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN); } static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) { - struct solo_filehandle *fh = vq->priv_data; - struct solo_dev *solo_dev = fh->solo_dev; + struct solo_dev *solo_dev = vq->priv_data; *size = solo_image_size(solo_dev); @@ -349,8 +335,7 @@ static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count, static int solo_buf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field) { - struct solo_filehandle *fh = vq->priv_data; - struct solo_dev *solo_dev = fh->solo_dev; + struct solo_dev *solo_dev = vq->priv_data; vb->size = solo_image_size(solo_dev); if (vb->baddr != 0 && vb->bsize < vb->size) @@ -378,11 +363,10 @@ static int solo_buf_prepare(struct videobuf_queue *vq, static void solo_buf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { - struct solo_filehandle *fh = vq->priv_data; - struct solo_dev *solo_dev = fh->solo_dev; + struct solo_dev *solo_dev = vq->priv_data; vb->state = VIDEOBUF_QUEUED; - list_add_tail(&vb->queue, &fh->vidq_active); + list_add_tail(&vb->queue, &solo_dev->vidq_active); wake_up_interruptible(&solo_dev->disp_thread_wait); } @@ -403,84 +387,45 @@ static const struct videobuf_queue_ops solo_video_qops = { static unsigned int solo_v4l2_poll(struct file *file, struct poll_table_struct *wait) { - struct solo_filehandle *fh = file->private_data; + struct solo_dev *solo_dev = video_drvdata(file); unsigned long req_events = poll_requested_events(wait); unsigned res = v4l2_ctrl_poll(file, wait); if (!(req_events & (POLLIN | POLLRDNORM))) return res; - return res | videobuf_poll_stream(file, &fh->vidq, wait); + return res | videobuf_poll_stream(file, &solo_dev->vidq, wait); } static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma) { - struct solo_filehandle *fh = file->private_data; - - return videobuf_mmap_mapper(&fh->vidq, vma); -} - -static int solo_v4l2_open(struct file *file) -{ struct solo_dev *solo_dev = video_drvdata(file); - struct solo_filehandle *fh; - int ret; - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (fh == NULL) - return -ENOMEM; - - v4l2_fh_init(&fh->fh, video_devdata(file)); - spin_lock_init(&fh->slock); - INIT_LIST_HEAD(&fh->vidq_active); - fh->solo_dev = solo_dev; - file->private_data = fh; - - ret = solo_start_thread(fh); - if (ret) { - kfree(fh); - return ret; - } - - videobuf_queue_dma_contig_init(&fh->vidq, &solo_video_qops, - &solo_dev->pdev->dev, &fh->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct videobuf_buffer), - fh, NULL); - v4l2_fh_add(&fh->fh); - return 0; + return videobuf_mmap_mapper(&solo_dev->vidq, vma); } static ssize_t solo_v4l2_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { - struct solo_filehandle *fh = file->private_data; + struct solo_dev *solo_dev = video_drvdata(file); - return videobuf_read_stream(&fh->vidq, data, count, ppos, 0, + return videobuf_read_stream(&solo_dev->vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); } static int solo_v4l2_release(struct file *file) { - struct solo_filehandle *fh = file->private_data; - - solo_stop_thread(fh); - - videobuf_stop(&fh->vidq); - videobuf_mmap_free(&fh->vidq); - - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - kfree(fh); + struct solo_dev *solo_dev = video_drvdata(file); - return 0; + solo_stop_thread(solo_dev); + videobuf_stop(&solo_dev->vidq); + videobuf_mmap_free(&solo_dev->vidq); + return v4l2_fh_release(file); } static int solo_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct solo_filehandle *fh = priv; - struct solo_dev *solo_dev = fh->solo_dev; + struct solo_dev *solo_dev = video_drvdata(file); strcpy(cap->driver, SOLO6X10_NAME); strcpy(cap->card, "Softlogic 6x10"); @@ -521,8 +466,7 @@ static int solo_enum_ext_input(struct solo_dev *solo_dev, static int solo_enum_input(struct file *file, void *priv, struct v4l2_input *input) { - struct solo_filehandle *fh = priv; - struct solo_dev *solo_dev = fh->solo_dev; + struct solo_dev *solo_dev = video_drvdata(file); if (input->index >= solo_dev->nr_chans) { int ret = solo_enum_ext_input(solo_dev, input); @@ -549,11 +493,11 @@ static int solo_enum_input(struct file *file, void *priv, static int solo_set_input(struct file *file, void *priv, unsigned int index) { - struct solo_filehandle *fh = priv; - int ret = solo_v4l2_set_ch(fh->solo_dev, index); + struct solo_dev *solo_dev = video_drvdata(file); + int ret = solo_v4l2_set_ch(solo_dev, index); if (!ret) { - while (erase_off(fh->solo_dev)) + while (erase_off(solo_dev)) /* Do nothing */; } @@ -562,9 +506,9 @@ static int solo_set_input(struct file *file, void *priv, unsigned int index) static int solo_get_input(struct file *file, void *priv, unsigned int *index) { - struct solo_filehandle *fh = priv; + struct solo_dev *solo_dev = video_drvdata(file); - *index = fh->solo_dev->cur_disp_ch; + *index = solo_dev->cur_disp_ch; return 0; } @@ -584,8 +528,7 @@ static int solo_enum_fmt_cap(struct file *file, void *priv, static int solo_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct solo_filehandle *fh = priv; - struct solo_dev *solo_dev = fh->solo_dev; + struct solo_dev *solo_dev = video_drvdata(file); struct v4l2_pix_format *pix = &f->fmt.pix; int image_size = solo_image_size(solo_dev); @@ -605,9 +548,9 @@ static int solo_try_fmt_cap(struct file *file, void *priv, static int solo_set_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct solo_filehandle *fh = priv; + struct solo_dev *solo_dev = video_drvdata(file); - if (videobuf_queue_is_busy(&fh->vidq)) + if (videobuf_queue_is_busy(&solo_dev->vidq)) return -EBUSY; /* For right now, if it doesn't match our running config, @@ -618,8 +561,7 @@ static int solo_set_fmt_cap(struct file *file, void *priv, static int solo_get_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct solo_filehandle *fh = priv; - struct solo_dev *solo_dev = fh->solo_dev; + struct solo_dev *solo_dev = video_drvdata(file); struct v4l2_pix_format *pix = &f->fmt.pix; pix->width = solo_dev->video_hsize; @@ -637,51 +579,56 @@ static int solo_get_fmt_cap(struct file *file, void *priv, static int solo_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *req) { - struct solo_filehandle *fh = priv; + struct solo_dev *solo_dev = video_drvdata(file); - return videobuf_reqbufs(&fh->vidq, req); + return videobuf_reqbufs(&solo_dev->vidq, req); } static int solo_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct solo_filehandle *fh = priv; + struct solo_dev *solo_dev = video_drvdata(file); - return videobuf_querybuf(&fh->vidq, buf); + return videobuf_querybuf(&solo_dev->vidq, buf); } static int solo_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct solo_filehandle *fh = priv; + struct solo_dev *solo_dev = video_drvdata(file); - return videobuf_qbuf(&fh->vidq, buf); + return videobuf_qbuf(&solo_dev->vidq, buf); } static int solo_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct solo_filehandle *fh = priv; + struct solo_dev *solo_dev = video_drvdata(file); - return videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK); + return videobuf_dqbuf(&solo_dev->vidq, buf, file->f_flags & O_NONBLOCK); } static int solo_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { - struct solo_filehandle *fh = priv; + struct solo_dev *solo_dev = video_drvdata(file); + int ret; if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - return videobuf_streamon(&fh->vidq); + ret = solo_start_thread(solo_dev); + if (ret) + return ret; + + return videobuf_streamon(&solo_dev->vidq); } static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { - struct solo_filehandle *fh = priv; + struct solo_dev *solo_dev = video_drvdata(file); if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - return videobuf_streamoff(&fh->vidq); + return videobuf_streamoff(&solo_dev->vidq); } static int solo_s_std(struct file *file, void *priv, v4l2_std_id i) @@ -720,7 +667,7 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl) static const struct v4l2_file_operations solo_v4l2_fops = { .owner = THIS_MODULE, - .open = solo_v4l2_open, + .open = v4l2_fh_open, .release = solo_v4l2_release, .read = solo_v4l2_read, .poll = solo_v4l2_poll, @@ -798,21 +745,17 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl; set_bit(V4L2_FL_USE_FH_PRIO, &solo_dev->vfd->flags); - ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr); - if (ret < 0) { - video_device_release(solo_dev->vfd); - solo_dev->vfd = NULL; - return ret; - } - video_set_drvdata(solo_dev->vfd, solo_dev); - snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)", - SOLO6X10_NAME, solo_dev->vfd->num); + spin_lock_init(&solo_dev->slock); + INIT_LIST_HEAD(&solo_dev->vidq_active); - dev_info(&solo_dev->pdev->dev, - "Display as /dev/video%d with %d inputs (%d extended)\n", - solo_dev->vfd->num, solo_dev->nr_chans, solo_dev->nr_ext); + videobuf_queue_dma_contig_init(&solo_dev->vidq, &solo_video_qops, + &solo_dev->pdev->dev, &solo_dev->slock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct videobuf_buffer), + solo_dev, NULL); /* Cycle all the channels and clear */ for (i = 0; i < solo_dev->nr_chans; i++) { @@ -826,6 +769,20 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) while (erase_off(solo_dev)) /* Do nothing */; + ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr); + if (ret < 0) { + video_device_release(solo_dev->vfd); + solo_dev->vfd = NULL; + return ret; + } + + snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)", + SOLO6X10_NAME, solo_dev->vfd->num); + + dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with " + "%d inputs (%d extended)\n", solo_dev->vfd->num, + solo_dev->nr_chans, solo_dev->nr_ext); + return 0; } -- cgit v0.10.2 From a7eb931d635cce7b831f745c903204fb79a4aba0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 18 Mar 2013 08:41:13 -0300 Subject: [media] solo6x10: move global fields in solo_enc_fh to solo_enc_dev All fields in solo_enc_fh do not belong there since they refer to global properties. After moving all these fields to solo_enc_dev the solo_dev_fh struct can be removed completely. Note that this also kills the 'listener' feature of this driver. This feature (where multiple filehandles can read the video) is illegal in the V4L2 API. Do this in userspace: it's much more efficient to copy memory than it is to DMA to every listener. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index 830359f..413ee10 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h @@ -135,6 +135,11 @@ struct solo_p2m_dev { #define OSD_TEXT_MAX 44 +enum solo_enc_types { + SOLO_ENC_TYPE_STD, + SOLO_ENC_TYPE_EXT, +}; + struct solo_enc_dev { struct solo_dev *solo_dev; /* V4L2 Items */ @@ -163,8 +168,16 @@ struct solo_enc_dev { unsigned char jpeg_header[1024]; int jpeg_len; - /* File handles that are listening for buffers */ - struct list_head listeners; + u32 fmt; + u8 enc_on; + enum solo_enc_types type; + struct videobuf_queue vidq; + struct list_head vidq_active; + int desc_count; + int desc_nelts; + struct solo_p2m_desc *desc_items; + dma_addr_t desc_dma; + spinlock_t av_lock; }; /* The SOLO6x10 PCI Device */ diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index 7cf3e7b..546a18b 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -41,27 +41,6 @@ #define MP4_QS 16 #define DMA_ALIGN 4096 -enum solo_enc_types { - SOLO_ENC_TYPE_STD, - SOLO_ENC_TYPE_EXT, -}; - -struct solo_enc_fh { - struct v4l2_fh fh; - struct solo_enc_dev *enc; - u32 fmt; - u8 enc_on; - enum solo_enc_types type; - struct videobuf_queue vidq; - struct list_head vidq_active; - int desc_count; - int desc_nelts; - struct solo_p2m_desc *desc_items; - dma_addr_t desc_dma; - spinlock_t av_lock; - struct list_head list; -}; - struct solo_videobuf { struct videobuf_buffer vb; unsigned int flags; @@ -286,16 +265,15 @@ static void solo_update_mode(struct solo_enc_dev *solo_enc) } /* MUST be called with solo_enc->enable_lock held */ -static int __solo_enc_on(struct solo_enc_fh *fh) +static int __solo_enc_on(struct solo_enc_dev *solo_enc) { - struct solo_enc_dev *solo_enc = fh->enc; u8 ch = solo_enc->ch; struct solo_dev *solo_dev = solo_enc->solo_dev; u8 interval; BUG_ON(!mutex_is_locked(&solo_enc->enable_lock)); - if (fh->enc_on) + if (solo_enc->enc_on) return 0; solo_update_mode(solo_enc); @@ -308,15 +286,14 @@ static int __solo_enc_on(struct solo_enc_fh *fh) solo_dev->enc_bw_remain -= solo_enc->bw_weight; } - fh->enc_on = 1; - list_add(&fh->list, &solo_enc->listeners); + solo_enc->enc_on = 1; - if (fh->type == SOLO_ENC_TYPE_EXT) + if (solo_enc->type == SOLO_ENC_TYPE_EXT) solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1); /* Reset the encoder if we are the first mpeg reader, else only reset * on the first mjpeg reader. */ - if (fh->fmt == V4L2_PIX_FMT_MPEG) { + if (solo_enc->fmt == V4L2_PIX_FMT_MPEG) { atomic_inc(&solo_enc->readers); if (atomic_inc_return(&solo_enc->mpeg_readers) > 1) return 0; @@ -352,32 +329,29 @@ static int __solo_enc_on(struct solo_enc_fh *fh) return 0; } -static int solo_enc_on(struct solo_enc_fh *fh) +static int solo_enc_on(struct solo_enc_dev *solo_enc) { - struct solo_enc_dev *solo_enc = fh->enc; int ret; mutex_lock(&solo_enc->enable_lock); - ret = __solo_enc_on(fh); + ret = __solo_enc_on(solo_enc); mutex_unlock(&solo_enc->enable_lock); return ret; } -static void __solo_enc_off(struct solo_enc_fh *fh) +static void __solo_enc_off(struct solo_enc_dev *solo_enc) { - struct solo_enc_dev *solo_enc = fh->enc; struct solo_dev *solo_dev = solo_enc->solo_dev; BUG_ON(!mutex_is_locked(&solo_enc->enable_lock)); - if (!fh->enc_on) + if (!solo_enc->enc_on) return; - list_del(&fh->list); - fh->enc_on = 0; + solo_enc->enc_on = 0; - if (fh->fmt == V4L2_PIX_FMT_MPEG) + if (solo_enc->fmt == V4L2_PIX_FMT_MPEG) atomic_dec(&solo_enc->mpeg_readers); if (atomic_dec_return(&solo_enc->readers) > 0) @@ -389,12 +363,10 @@ static void __solo_enc_off(struct solo_enc_fh *fh) solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0); } -static void solo_enc_off(struct solo_enc_fh *fh) +static void solo_enc_off(struct solo_enc_dev *solo_enc) { - struct solo_enc_dev *solo_enc = fh->enc; - mutex_lock(&solo_enc->enable_lock); - __solo_enc_off(fh); + __solo_enc_off(solo_enc); mutex_unlock(&solo_enc->enable_lock); } @@ -430,11 +402,11 @@ static int enc_get_mpeg_dma(struct solo_dev *solo_dev, dma_addr_t dma, /* Build a descriptor queue out of an SG list and send it to the P2M for * processing. */ -static int solo_send_desc(struct solo_enc_fh *fh, int skip, +static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip, struct videobuf_dmabuf *vbuf, int off, int size, unsigned int base, unsigned int base_size) { - struct solo_dev *solo_dev = fh->enc->solo_dev; + struct solo_dev *solo_dev = solo_enc->solo_dev; struct scatterlist *sg; int i; int ret; @@ -442,7 +414,7 @@ static int solo_send_desc(struct solo_enc_fh *fh, int skip, if (WARN_ON_ONCE(size > FRAME_BUF_SIZE)) return -EINVAL; - fh->desc_count = 1; + solo_enc->desc_count = 1; for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) { struct solo_p2m_desc *desc; @@ -450,7 +422,7 @@ static int solo_send_desc(struct solo_enc_fh *fh, int skip, int len; int left = base_size - off; - desc = &fh->desc_items[fh->desc_count++]; + desc = &solo_enc->desc_items[solo_enc->desc_count++]; dma = sg_dma_address(sg); len = sg_dma_len(sg); @@ -486,7 +458,7 @@ static int solo_send_desc(struct solo_enc_fh *fh, int skip, if (ret) return ret; - fh->desc_count--; + solo_enc->desc_count--; } size -= len; @@ -498,27 +470,26 @@ static int solo_send_desc(struct solo_enc_fh *fh, int skip, off -= base_size; /* Because we may use two descriptors per loop */ - if (fh->desc_count >= (fh->desc_nelts - 1)) { - ret = solo_p2m_dma_desc(solo_dev, fh->desc_items, - fh->desc_dma, - fh->desc_count - 1); + if (solo_enc->desc_count >= (solo_enc->desc_nelts - 1)) { + ret = solo_p2m_dma_desc(solo_dev, solo_enc->desc_items, + solo_enc->desc_dma, + solo_enc->desc_count - 1); if (ret) return ret; - fh->desc_count = 1; + solo_enc->desc_count = 1; } } - if (fh->desc_count <= 1) + if (solo_enc->desc_count <= 1) return 0; - return solo_p2m_dma_desc(solo_dev, fh->desc_items, fh->desc_dma, - fh->desc_count - 1); + return solo_p2m_dma_desc(solo_dev, solo_enc->desc_items, solo_enc->desc_dma, + solo_enc->desc_count - 1); } -static int solo_fill_jpeg(struct solo_enc_fh *fh, struct videobuf_buffer *vb, +static int solo_fill_jpeg(struct solo_enc_dev *solo_enc, struct videobuf_buffer *vb, struct videobuf_dmabuf *vbuf, struct vop_header *vh) { - struct solo_enc_dev *solo_enc = fh->enc; struct solo_dev *solo_dev = solo_enc->solo_dev; struct solo_videobuf *svb = (struct solo_videobuf *)vb; int frame_size; @@ -539,15 +510,14 @@ static int solo_fill_jpeg(struct solo_enc_fh *fh, struct videobuf_buffer *vb, frame_size = (vh->jpeg_size + solo_enc->jpeg_len + (DMA_ALIGN - 1)) & ~(DMA_ALIGN - 1); - return solo_send_desc(fh, solo_enc->jpeg_len, vbuf, vh->jpeg_off, + return solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf, vh->jpeg_off, frame_size, SOLO_JPEG_EXT_ADDR(solo_dev), SOLO_JPEG_EXT_SIZE(solo_dev)); } -static int solo_fill_mpeg(struct solo_enc_fh *fh, struct videobuf_buffer *vb, +static int solo_fill_mpeg(struct solo_enc_dev *solo_enc, struct videobuf_buffer *vb, struct videobuf_dmabuf *vbuf, struct vop_header *vh) { - struct solo_enc_dev *solo_enc = fh->enc; struct solo_dev *solo_dev = solo_enc->solo_dev; struct solo_videobuf *svb = (struct solo_videobuf *)vb; int frame_off, frame_size; @@ -580,16 +550,15 @@ static int solo_fill_mpeg(struct solo_enc_fh *fh, struct videobuf_buffer *vb, frame_size = (vh->mpeg_size + skip + (DMA_ALIGN - 1)) & ~(DMA_ALIGN - 1); - return solo_send_desc(fh, skip, vbuf, frame_off, frame_size, + return solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size, SOLO_MP4E_EXT_ADDR(solo_dev), SOLO_MP4E_EXT_SIZE(solo_dev)); } -static int solo_enc_fillbuf(struct solo_enc_fh *fh, +static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, struct videobuf_buffer *vb, struct solo_enc_buf *enc_buf) { - struct solo_enc_dev *solo_enc = fh->enc; struct solo_videobuf *svb = (struct solo_videobuf *)vb; struct videobuf_dmabuf *vbuf = NULL; struct vop_header *vh = enc_buf->vh; @@ -613,10 +582,10 @@ static int solo_enc_fillbuf(struct solo_enc_fh *fh, svb->flags |= V4L2_BUF_FLAG_MOTION_DETECTED; } - if (fh->fmt == V4L2_PIX_FMT_MPEG) - ret = solo_fill_mpeg(fh, vb, vbuf, vh); + if (solo_enc->fmt == V4L2_PIX_FMT_MPEG) + ret = solo_fill_mpeg(solo_enc, vb, vbuf, vh); else - ret = solo_fill_jpeg(fh, vb, vbuf, vh); + ret = solo_fill_jpeg(solo_enc, vb, vbuf, vh); vbuf_error: /* On error, we push this buffer back into the queue. The @@ -625,10 +594,10 @@ vbuf_error: if (ret) { unsigned long flags; - spin_lock_irqsave(&fh->av_lock, flags); - list_add(&vb->queue, &fh->vidq_active); + spin_lock_irqsave(&solo_enc->av_lock, flags); + list_add(&vb->queue, &solo_enc->vidq_active); vb->state = VIDEOBUF_QUEUED; - spin_unlock_irqrestore(&fh->av_lock, flags); + spin_unlock_irqrestore(&solo_enc->av_lock, flags); } else { vb->state = VIDEOBUF_DONE; vb->field_count++; @@ -644,34 +613,29 @@ vbuf_error: static void solo_enc_handle_one(struct solo_enc_dev *solo_enc, struct solo_enc_buf *enc_buf) { - struct solo_enc_fh *fh; + struct videobuf_buffer *vb; + unsigned long flags; mutex_lock(&solo_enc->enable_lock); - list_for_each_entry(fh, &solo_enc->listeners, list) { - struct videobuf_buffer *vb; - unsigned long flags; - - if (fh->type != enc_buf->type) - continue; - - - if (list_empty(&fh->vidq_active)) - continue; + if (solo_enc->type != enc_buf->type) + goto unlock; - spin_lock_irqsave(&fh->av_lock, flags); + if (list_empty(&solo_enc->vidq_active)) + goto unlock; - vb = list_first_entry(&fh->vidq_active, - struct videobuf_buffer, queue); + spin_lock_irqsave(&solo_enc->av_lock, flags); - list_del(&vb->queue); - vb->state = VIDEOBUF_ACTIVE; + vb = list_first_entry(&solo_enc->vidq_active, + struct videobuf_buffer, queue); - spin_unlock_irqrestore(&fh->av_lock, flags); + list_del(&vb->queue); + vb->state = VIDEOBUF_ACTIVE; - solo_enc_fillbuf(fh, vb, enc_buf); - } + spin_unlock_irqrestore(&solo_enc->av_lock, flags); + solo_enc_fillbuf(solo_enc, vb, enc_buf); +unlock: mutex_unlock(&solo_enc->enable_lock); } @@ -799,10 +763,10 @@ static int solo_enc_buf_prepare(struct videobuf_queue *vq, static void solo_enc_buf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) { - struct solo_enc_fh *fh = vq->priv_data; + struct solo_enc_dev *solo_enc = vq->priv_data; vb->state = VIDEOBUF_QUEUED; - list_add_tail(&vb->queue, &fh->vidq_active); + list_add_tail(&vb->queue, &solo_enc->vidq_active); } static void solo_enc_buf_release(struct videobuf_queue *vq, @@ -824,20 +788,20 @@ static const struct videobuf_queue_ops solo_enc_video_qops = { static unsigned int solo_enc_poll(struct file *file, struct poll_table_struct *wait) { - struct solo_enc_fh *fh = file->private_data; + struct solo_enc_dev *solo_enc = video_drvdata(file); unsigned long req_events = poll_requested_events(wait); unsigned res = v4l2_ctrl_poll(file, wait); if (!(req_events & (POLLIN | POLLRDNORM))) return res; - return videobuf_poll_stream(file, &fh->vidq, wait); + return videobuf_poll_stream(file, &solo_enc->vidq, wait); } static int solo_enc_mmap(struct file *file, struct vm_area_struct *vma) { - struct solo_enc_fh *fh = file->private_data; + struct solo_enc_dev *solo_enc = video_drvdata(file); - return videobuf_mmap_mapper(&fh->vidq, vma); + return videobuf_mmap_mapper(&solo_enc->vidq, vma); } static int solo_ring_start(struct solo_dev *solo_dev) @@ -875,91 +839,50 @@ static int solo_enc_open(struct file *file) { struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_dev *solo_dev = solo_enc->solo_dev; - struct solo_enc_fh *fh; - int ret; + int ret = v4l2_fh_open(file); - ret = solo_ring_start(solo_dev); if (ret) return ret; - - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (fh == NULL) { - solo_ring_stop(solo_dev); - return -ENOMEM; - } - - fh->desc_nelts = 32; - fh->desc_items = pci_alloc_consistent(solo_dev->pdev, - sizeof(struct solo_p2m_desc) * - fh->desc_nelts, &fh->desc_dma); - if (fh->desc_items == NULL) { - kfree(fh); - solo_ring_stop(solo_dev); - return -ENOMEM; + ret = solo_ring_start(solo_dev); + if (ret) { + v4l2_fh_release(file); + return ret; } - - v4l2_fh_init(&fh->fh, video_devdata(file)); - fh->enc = solo_enc; - spin_lock_init(&fh->av_lock); - file->private_data = fh; - INIT_LIST_HEAD(&fh->vidq_active); - fh->fmt = V4L2_PIX_FMT_MPEG; - fh->type = SOLO_ENC_TYPE_STD; - - videobuf_queue_sg_init(&fh->vidq, &solo_enc_video_qops, - &solo_dev->pdev->dev, - &fh->av_lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct solo_videobuf), - fh, NULL); - v4l2_fh_add(&fh->fh); return 0; } static ssize_t solo_enc_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { - struct solo_enc_fh *fh = file->private_data; + struct solo_enc_dev *solo_enc = video_drvdata(file); int ret; /* Make sure the encoder is on */ - ret = solo_enc_on(fh); + ret = solo_enc_on(solo_enc); if (ret) return ret; - return videobuf_read_stream(&fh->vidq, data, count, ppos, 0, + return videobuf_read_stream(&solo_enc->vidq, data, count, ppos, 0, file->f_flags & O_NONBLOCK); } static int solo_enc_release(struct file *file) { - struct solo_enc_fh *fh = file->private_data; - struct solo_dev *solo_dev = fh->enc->solo_dev; - - solo_enc_off(fh); - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - - videobuf_stop(&fh->vidq); - videobuf_mmap_free(&fh->vidq); - - pci_free_consistent(fh->enc->solo_dev->pdev, - sizeof(struct solo_p2m_desc) * - fh->desc_nelts, fh->desc_items, fh->desc_dma); - - kfree(fh); + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; + solo_enc_off(solo_enc); + videobuf_stop(&solo_enc->vidq); + videobuf_mmap_free(&solo_enc->vidq); solo_ring_stop(solo_dev); - return 0; + return v4l2_fh_release(file); } static int solo_enc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct solo_enc_fh *fh = priv; - struct solo_enc_dev *solo_enc = fh->enc; + struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_dev *solo_dev = solo_enc->solo_dev; strcpy(cap->driver, SOLO6X10_NAME); @@ -976,8 +899,7 @@ static int solo_enc_querycap(struct file *file, void *priv, static int solo_enc_enum_input(struct file *file, void *priv, struct v4l2_input *input) { - struct solo_enc_fh *fh = priv; - struct solo_enc_dev *solo_enc = fh->enc; + struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_dev *solo_dev = solo_enc->solo_dev; if (input->index) @@ -1039,8 +961,7 @@ static int solo_enc_enum_fmt_cap(struct file *file, void *priv, static int solo_enc_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct solo_enc_fh *fh = priv; - struct solo_enc_dev *solo_enc = fh->enc; + struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_dev *solo_dev = solo_enc->solo_dev; struct v4l2_pix_format *pix = &f->fmt.pix; @@ -1081,8 +1002,7 @@ static int solo_enc_try_fmt_cap(struct file *file, void *priv, static int solo_enc_set_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct solo_enc_fh *fh = priv; - struct solo_enc_dev *solo_enc = fh->enc; + struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_dev *solo_dev = solo_enc->solo_dev; struct v4l2_pix_format *pix = &f->fmt.pix; int ret; @@ -1110,10 +1030,10 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv, solo_enc->mode = SOLO_ENC_MODE_CIF; /* This does not change the encoder at all */ - fh->fmt = pix->pixelformat; + solo_enc->fmt = pix->pixelformat; if (pix->priv) - fh->type = SOLO_ENC_TYPE_EXT; + solo_enc->type = SOLO_ENC_TYPE_EXT; mutex_unlock(&solo_enc->enable_lock); @@ -1123,13 +1043,12 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv, static int solo_enc_get_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct solo_enc_fh *fh = priv; - struct solo_enc_dev *solo_enc = fh->enc; + struct solo_enc_dev *solo_enc = video_drvdata(file); struct v4l2_pix_format *pix = &f->fmt.pix; pix->width = solo_enc->width; pix->height = solo_enc->height; - pix->pixelformat = fh->fmt; + pix->pixelformat = solo_enc->fmt; pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE; pix->sizeimage = FRAME_BUF_SIZE; @@ -1142,45 +1061,45 @@ static int solo_enc_get_fmt_cap(struct file *file, void *priv, static int solo_enc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *req) { - struct solo_enc_fh *fh = priv; + struct solo_enc_dev *solo_enc = video_drvdata(file); - return videobuf_reqbufs(&fh->vidq, req); + return videobuf_reqbufs(&solo_enc->vidq, req); } static int solo_enc_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct solo_enc_fh *fh = priv; + struct solo_enc_dev *solo_enc = video_drvdata(file); - return videobuf_querybuf(&fh->vidq, buf); + return videobuf_querybuf(&solo_enc->vidq, buf); } static int solo_enc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct solo_enc_fh *fh = priv; + struct solo_enc_dev *solo_enc = video_drvdata(file); - return videobuf_qbuf(&fh->vidq, buf); + return videobuf_qbuf(&solo_enc->vidq, buf); } static int solo_enc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct solo_enc_fh *fh = priv; + struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_videobuf *svb; int ret; /* Make sure the encoder is on */ - ret = solo_enc_on(fh); + ret = solo_enc_on(solo_enc); if (ret) return ret; - ret = videobuf_dqbuf(&fh->vidq, buf, file->f_flags & O_NONBLOCK); + ret = videobuf_dqbuf(&solo_enc->vidq, buf, file->f_flags & O_NONBLOCK); if (ret) return ret; /* Copy over the flags */ - svb = (struct solo_videobuf *)fh->vidq.bufs[buf->index]; + svb = (struct solo_videobuf *)solo_enc->vidq.bufs[buf->index]; buf->flags |= svb->flags; return 0; @@ -1189,26 +1108,26 @@ static int solo_enc_dqbuf(struct file *file, void *priv, static int solo_enc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { - struct solo_enc_fh *fh = priv; + struct solo_enc_dev *solo_enc = video_drvdata(file); if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - return videobuf_streamon(&fh->vidq); + return videobuf_streamon(&solo_enc->vidq); } static int solo_enc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { - struct solo_enc_fh *fh = priv; + struct solo_enc_dev *solo_enc = video_drvdata(file); int ret; if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - ret = videobuf_streamoff(&fh->vidq); + ret = videobuf_streamoff(&solo_enc->vidq); if (!ret) - solo_enc_off(fh); + solo_enc_off(solo_enc); return ret; } @@ -1221,8 +1140,8 @@ static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id i) static int solo_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { - struct solo_enc_fh *fh = priv; - struct solo_dev *solo_dev = fh->enc->solo_dev; + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; if (fsize->pixel_format != V4L2_PIX_FMT_MPEG && fsize->pixel_format != V4L2_PIX_FMT_MJPEG) @@ -1249,8 +1168,8 @@ static int solo_enum_framesizes(struct file *file, void *priv, static int solo_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fintv) { - struct solo_enc_fh *fh = priv; - struct solo_dev *solo_dev = fh->enc->solo_dev; + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; if (fintv->pixel_format != V4L2_PIX_FMT_MPEG && fintv->pixel_format != V4L2_PIX_FMT_MJPEG) @@ -1280,8 +1199,7 @@ static int solo_enum_frameintervals(struct file *file, void *priv, static int solo_g_parm(struct file *file, void *priv, struct v4l2_streamparm *sp) { - struct solo_enc_fh *fh = priv; - struct solo_enc_dev *solo_enc = fh->enc; + struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_dev *solo_dev = solo_enc->solo_dev; struct v4l2_captureparm *cp = &sp->parm.capture; @@ -1298,8 +1216,7 @@ static int solo_g_parm(struct file *file, void *priv, static int solo_s_parm(struct file *file, void *priv, struct v4l2_streamparm *sp) { - struct solo_enc_fh *fh = priv; - struct solo_enc_dev *solo_enc = fh->enc; + struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_dev *solo_dev = solo_enc->solo_dev; struct v4l2_captureparm *cp = &sp->parm.capture; @@ -1512,45 +1429,17 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL); if (hdl->error) { ret = hdl->error; - v4l2_ctrl_handler_free(hdl); - kfree(solo_enc); - return ERR_PTR(ret); - } - - solo_enc->vfd = video_device_alloc(); - if (!solo_enc->vfd) { - v4l2_ctrl_handler_free(hdl); - kfree(solo_enc); - return ERR_PTR(-ENOMEM); + goto hdl_free; } solo_enc->solo_dev = solo_dev; solo_enc->ch = ch; - - *solo_enc->vfd = solo_enc_template; - solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev; - solo_enc->vfd->ctrl_handler = hdl; - set_bit(V4L2_FL_USE_FH_PRIO, &solo_enc->vfd->flags); - ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr); - if (ret < 0) { - video_device_release(solo_enc->vfd); - v4l2_ctrl_handler_free(hdl); - kfree(solo_enc); - return ERR_PTR(ret); - } - - video_set_drvdata(solo_enc->vfd, solo_enc); - - snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name), - "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num, - solo_enc->vfd->num); - - INIT_LIST_HEAD(&solo_enc->listeners); - mutex_init(&solo_enc->enable_lock); - spin_lock_init(&solo_enc->motion_lock); + spin_lock_init(&solo_enc->av_lock); + INIT_LIST_HEAD(&solo_enc->vidq_active); + solo_enc->fmt = V4L2_PIX_FMT_MPEG; + solo_enc->type = SOLO_ENC_TYPE_STD; atomic_set(&solo_enc->readers, 0); - atomic_set(&solo_enc->mpeg_readers, 0); solo_enc->qp = SOLO_DEFAULT_QP; solo_enc->gop = solo_dev->fps; @@ -1558,15 +1447,65 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, solo_enc->mode = SOLO_ENC_MODE_CIF; solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH; - mutex_lock(&solo_enc->enable_lock); + spin_lock(&solo_enc->av_lock); solo_update_mode(solo_enc); - mutex_unlock(&solo_enc->enable_lock); + spin_unlock(&solo_enc->av_lock); + + mutex_init(&solo_enc->enable_lock); + spin_lock_init(&solo_enc->motion_lock); + + atomic_set(&solo_enc->readers, 0); + atomic_set(&solo_enc->mpeg_readers, 0); /* Initialize this per encoder */ solo_enc->jpeg_len = sizeof(jpeg_header); memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len); + solo_enc->desc_nelts = 32; + solo_enc->desc_items = pci_alloc_consistent(solo_dev->pdev, + sizeof(struct solo_p2m_desc) * + solo_enc->desc_nelts, &solo_enc->desc_dma); + ret = -ENOMEM; + if (solo_enc->desc_items == NULL) + goto hdl_free; + + videobuf_queue_sg_init(&solo_enc->vidq, &solo_enc_video_qops, + &solo_dev->pdev->dev, + &solo_enc->av_lock, + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_FIELD_INTERLACED, + sizeof(struct solo_videobuf), + solo_enc, NULL); + + solo_enc->vfd = video_device_alloc(); + if (!solo_enc->vfd) + goto pci_free; + + *solo_enc->vfd = solo_enc_template; + solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev; + solo_enc->vfd->ctrl_handler = hdl; + set_bit(V4L2_FL_USE_FH_PRIO, &solo_enc->vfd->flags); + video_set_drvdata(solo_enc->vfd, solo_enc); + ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr); + if (ret < 0) + goto vdev_release; + + snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name), + "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num, + solo_enc->vfd->num); + return solo_enc; + +vdev_release: + video_device_release(solo_enc->vfd); +pci_free: + pci_free_consistent(solo_enc->solo_dev->pdev, + sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts, + solo_enc->desc_items, solo_enc->desc_dma); +hdl_free: + v4l2_ctrl_handler_free(hdl); + kfree(solo_enc); + return ERR_PTR(ret); } static void solo_enc_free(struct solo_enc_dev *solo_enc) @@ -1605,6 +1544,7 @@ int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr) solo_enc_free(solo_dev->v4l2_enc[i]); pci_free_consistent(solo_dev->pdev, solo_dev->vh_size, solo_dev->vh_buf, solo_dev->vh_dma); + solo_dev->vh_buf = NULL; return ret; } @@ -1627,6 +1567,7 @@ void solo_enc_v4l2_exit(struct solo_dev *solo_dev) for (i = 0; i < solo_dev->nr_chans; i++) solo_enc_free(solo_dev->v4l2_enc[i]); - pci_free_consistent(solo_dev->pdev, solo_dev->vh_size, + if (solo_dev->vh_buf) + pci_free_consistent(solo_dev->pdev, solo_dev->vh_size, solo_dev->vh_buf, solo_dev->vh_dma); } -- cgit v0.10.2 From 382c31a94330a96e5800358140840998671722bf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2013 12:04:14 -0300 Subject: [media] solo6x10: convert encoder nodes to vb2 As a consequence the ioctl op has been replaced by unlocked_ioctl. Since we are now using the core lock the locking scheme has been simplified as well. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/Kconfig b/drivers/staging/media/solo6x10/Kconfig index 63352de..f93b4ca 100644 --- a/drivers/staging/media/solo6x10/Kconfig +++ b/drivers/staging/media/solo6x10/Kconfig @@ -2,6 +2,7 @@ config SOLO6X10 tristate "Softlogic 6x10 MPEG codec cards" depends on PCI && VIDEO_DEV && SND && I2C select VIDEOBUF_DMA_SG + select VIDEOBUF2_DMA_SG select SND_PCM ---help--- This driver supports the Softlogic based MPEG-4 and h.264 codec diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index 413ee10..d18093f 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h @@ -40,6 +40,7 @@ #include #include #include +#include #include "registers.h" @@ -135,6 +136,11 @@ struct solo_p2m_dev { #define OSD_TEXT_MAX 44 +struct solo_vb2_buf { + struct vb2_buffer vb; + struct list_head list; +}; + enum solo_enc_types { SOLO_ENC_TYPE_STD, SOLO_ENC_TYPE_EXT, @@ -146,10 +152,8 @@ struct solo_enc_dev { struct v4l2_ctrl_handler hdl; struct video_device *vfd; /* General accounting */ - struct mutex enable_lock; + struct mutex lock; spinlock_t motion_lock; - atomic_t readers; - atomic_t mpeg_readers; u8 ch; u8 mode, gop, qp, interlaced, interval; u8 bw_weight; @@ -169,9 +173,8 @@ struct solo_enc_dev { int jpeg_len; u32 fmt; - u8 enc_on; enum solo_enc_types type; - struct videobuf_queue vidq; + struct vb2_queue vidq; struct list_head vidq_active; int desc_count; int desc_nelts; diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index 546a18b..d7d96ce 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include "solo6x10.h" #include "tw28.h" @@ -181,7 +181,6 @@ static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on) spin_unlock_irqrestore(&solo_enc->motion_lock, flags); } -/* MUST be called with solo_enc->enable_lock held */ static void solo_update_mode(struct solo_enc_dev *solo_enc) { struct solo_dev *solo_dev = solo_enc->solo_dev; @@ -264,43 +263,22 @@ static void solo_update_mode(struct solo_enc_dev *solo_enc) jpeg_dqt[solo_g_jpeg_qp(solo_dev, solo_enc->ch)], DQT_LEN); } -/* MUST be called with solo_enc->enable_lock held */ -static int __solo_enc_on(struct solo_enc_dev *solo_enc) +static int solo_enc_on(struct solo_enc_dev *solo_enc) { u8 ch = solo_enc->ch; struct solo_dev *solo_dev = solo_enc->solo_dev; u8 interval; - BUG_ON(!mutex_is_locked(&solo_enc->enable_lock)); - - if (solo_enc->enc_on) - return 0; - solo_update_mode(solo_enc); - /* Make sure to bw check on first reader */ - if (!atomic_read(&solo_enc->readers)) { - if (solo_enc->bw_weight > solo_dev->enc_bw_remain) - return -EBUSY; - else - solo_dev->enc_bw_remain -= solo_enc->bw_weight; - } - - solo_enc->enc_on = 1; + /* Make sure to do a bandwidth check */ + if (solo_enc->bw_weight > solo_dev->enc_bw_remain) + return -EBUSY; + solo_dev->enc_bw_remain -= solo_enc->bw_weight; if (solo_enc->type == SOLO_ENC_TYPE_EXT) solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1); - /* Reset the encoder if we are the first mpeg reader, else only reset - * on the first mjpeg reader. */ - if (solo_enc->fmt == V4L2_PIX_FMT_MPEG) { - atomic_inc(&solo_enc->readers); - if (atomic_inc_return(&solo_enc->mpeg_readers) > 1) - return 0; - } else if (atomic_inc_return(&solo_enc->readers) > 1) { - return 0; - } - /* Disable all encoding for this channel */ solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0); @@ -329,47 +307,16 @@ static int __solo_enc_on(struct solo_enc_dev *solo_enc) return 0; } -static int solo_enc_on(struct solo_enc_dev *solo_enc) -{ - int ret; - - mutex_lock(&solo_enc->enable_lock); - ret = __solo_enc_on(solo_enc); - mutex_unlock(&solo_enc->enable_lock); - - return ret; -} - -static void __solo_enc_off(struct solo_enc_dev *solo_enc) +static void solo_enc_off(struct solo_enc_dev *solo_enc) { struct solo_dev *solo_dev = solo_enc->solo_dev; - BUG_ON(!mutex_is_locked(&solo_enc->enable_lock)); - - if (!solo_enc->enc_on) - return; - - solo_enc->enc_on = 0; - - if (solo_enc->fmt == V4L2_PIX_FMT_MPEG) - atomic_dec(&solo_enc->mpeg_readers); - - if (atomic_dec_return(&solo_enc->readers) > 0) - return; - solo_dev->enc_bw_remain += solo_enc->bw_weight; solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0); solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0); } -static void solo_enc_off(struct solo_enc_dev *solo_enc) -{ - mutex_lock(&solo_enc->enable_lock); - __solo_enc_off(solo_enc); - mutex_unlock(&solo_enc->enable_lock); -} - static int enc_get_mpeg_dma(struct solo_dev *solo_dev, dma_addr_t dma, unsigned int off, unsigned int size) { @@ -403,7 +350,7 @@ static int enc_get_mpeg_dma(struct solo_dev *solo_dev, dma_addr_t dma, /* Build a descriptor queue out of an SG list and send it to the P2M for * processing. */ static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip, - struct videobuf_dmabuf *vbuf, int off, int size, + struct vb2_dma_sg_desc *vbuf, int off, int size, unsigned int base, unsigned int base_size) { struct solo_dev *solo_dev = solo_enc->solo_dev; @@ -416,7 +363,7 @@ static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip, solo_enc->desc_count = 1; - for_each_sg(vbuf->sglist, sg, vbuf->sglen, i) { + for_each_sg(vbuf->sglist, sg, vbuf->num_pages, i) { struct solo_p2m_desc *desc; dma_addr_t dma; int len; @@ -487,61 +434,62 @@ static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip, solo_enc->desc_count - 1); } -static int solo_fill_jpeg(struct solo_enc_dev *solo_enc, struct videobuf_buffer *vb, - struct videobuf_dmabuf *vbuf, struct vop_header *vh) +static int solo_fill_jpeg(struct solo_enc_dev *solo_enc, + struct vb2_buffer *vb, struct vop_header *vh) { struct solo_dev *solo_dev = solo_enc->solo_dev; - struct solo_videobuf *svb = (struct solo_videobuf *)vb; + struct vb2_dma_sg_desc *vbuf = vb2_dma_sg_plane_desc(vb, 0); int frame_size; + int ret; - svb->flags |= V4L2_BUF_FLAG_KEYFRAME; + vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; - if (vb->bsize < (vh->jpeg_size + solo_enc->jpeg_len)) + if (vb2_plane_size(vb, 0) < vh->jpeg_size + solo_enc->jpeg_len) return -EIO; - vb->width = solo_enc->width; - vb->height = solo_enc->height; - vb->size = vh->jpeg_size + solo_enc->jpeg_len; - - sg_copy_from_buffer(vbuf->sglist, vbuf->sglen, - solo_enc->jpeg_header, - solo_enc->jpeg_len); + sg_copy_from_buffer(vbuf->sglist, vbuf->num_pages, + solo_enc->jpeg_header, + solo_enc->jpeg_len); frame_size = (vh->jpeg_size + solo_enc->jpeg_len + (DMA_ALIGN - 1)) & ~(DMA_ALIGN - 1); - - return solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf, vh->jpeg_off, - frame_size, SOLO_JPEG_EXT_ADDR(solo_dev), - SOLO_JPEG_EXT_SIZE(solo_dev)); + vb2_set_plane_payload(vb, 0, vh->jpeg_size + solo_enc->jpeg_len); + + dma_map_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages, + DMA_FROM_DEVICE); + ret = solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf, vh->jpeg_off, + frame_size, SOLO_JPEG_EXT_ADDR(solo_dev), + SOLO_JPEG_EXT_SIZE(solo_dev)); + dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages, + DMA_FROM_DEVICE); + return ret; } -static int solo_fill_mpeg(struct solo_enc_dev *solo_enc, struct videobuf_buffer *vb, - struct videobuf_dmabuf *vbuf, struct vop_header *vh) +static int solo_fill_mpeg(struct solo_enc_dev *solo_enc, + struct vb2_buffer *vb, struct vop_header *vh) { struct solo_dev *solo_dev = solo_enc->solo_dev; - struct solo_videobuf *svb = (struct solo_videobuf *)vb; + struct vb2_dma_sg_desc *vbuf = vb2_dma_sg_plane_desc(vb, 0); int frame_off, frame_size; int skip = 0; + int ret; - if (vb->bsize < vh->mpeg_size) + if (vb2_plane_size(vb, 0) < vh->mpeg_size) return -EIO; - vb->width = vh->hsize << 4; - vb->height = vh->vsize << 4; - vb->size = vh->mpeg_size; - /* If this is a key frame, add extra header */ if (!vh->vop_type) { - sg_copy_from_buffer(vbuf->sglist, vbuf->sglen, - solo_enc->vop, - solo_enc->vop_len); + sg_copy_from_buffer(vbuf->sglist, vbuf->num_pages, + solo_enc->vop, + solo_enc->vop_len); skip = solo_enc->vop_len; - vb->size += solo_enc->vop_len; - svb->flags |= V4L2_BUF_FLAG_KEYFRAME; + vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; + vb2_set_plane_payload(vb, 0, vh->mpeg_size + solo_enc->vop_len); } else { - svb->flags |= V4L2_BUF_FLAG_PFRAME; + vb->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; + vb2_set_plane_payload(vb, 0, vh->mpeg_size); } /* Now get the actual mpeg payload */ @@ -550,93 +498,67 @@ static int solo_fill_mpeg(struct solo_enc_dev *solo_enc, struct videobuf_buffer frame_size = (vh->mpeg_size + skip + (DMA_ALIGN - 1)) & ~(DMA_ALIGN - 1); - return solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size, - SOLO_MP4E_EXT_ADDR(solo_dev), - SOLO_MP4E_EXT_SIZE(solo_dev)); + dma_map_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages, + DMA_FROM_DEVICE); + ret = solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size, + SOLO_MP4E_EXT_ADDR(solo_dev), + SOLO_MP4E_EXT_SIZE(solo_dev)); + dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages, + DMA_FROM_DEVICE); + return ret; } static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, - struct videobuf_buffer *vb, - struct solo_enc_buf *enc_buf) + struct vb2_buffer *vb, struct solo_enc_buf *enc_buf) { - struct solo_videobuf *svb = (struct solo_videobuf *)vb; - struct videobuf_dmabuf *vbuf = NULL; struct vop_header *vh = enc_buf->vh; int ret; - vbuf = videobuf_to_dma(vb); - if (WARN_ON_ONCE(!vbuf)) { - ret = -EIO; - goto vbuf_error; - } - - /* Setup some common flags for both types */ - svb->flags = V4L2_BUF_FLAG_TIMECODE; - vb->ts.tv_sec = vh->sec; - vb->ts.tv_usec = vh->usec; - /* Check for motion flags */ if (solo_is_motion_on(solo_enc)) { - svb->flags |= V4L2_BUF_FLAG_MOTION_ON; + vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_ON; if (enc_buf->motion) - svb->flags |= V4L2_BUF_FLAG_MOTION_DETECTED; + vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_DETECTED; } if (solo_enc->fmt == V4L2_PIX_FMT_MPEG) - ret = solo_fill_mpeg(solo_enc, vb, vbuf, vh); + ret = solo_fill_mpeg(solo_enc, vb, vh); else - ret = solo_fill_jpeg(solo_enc, vb, vbuf, vh); - -vbuf_error: - /* On error, we push this buffer back into the queue. The - * videobuf-core doesn't handle error packets very well. Plus - * we recover nicely internally anyway. */ - if (ret) { - unsigned long flags; - - spin_lock_irqsave(&solo_enc->av_lock, flags); - list_add(&vb->queue, &solo_enc->vidq_active); - vb->state = VIDEOBUF_QUEUED; - spin_unlock_irqrestore(&solo_enc->av_lock, flags); - } else { - vb->state = VIDEOBUF_DONE; - vb->field_count++; - vb->width = solo_enc->width; - vb->height = solo_enc->height; + ret = solo_fill_jpeg(solo_enc, vb, vh); - wake_up(&vb->done); + if (!ret) { + vb->v4l2_buf.sequence++; + vb->v4l2_buf.timestamp.tv_sec = vh->sec; + vb->v4l2_buf.timestamp.tv_usec = vh->usec; } + vb2_buffer_done(vb, ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + return ret; } static void solo_enc_handle_one(struct solo_enc_dev *solo_enc, struct solo_enc_buf *enc_buf) { - struct videobuf_buffer *vb; + struct solo_vb2_buf *vb; unsigned long flags; - mutex_lock(&solo_enc->enable_lock); - + mutex_lock(&solo_enc->lock); if (solo_enc->type != enc_buf->type) goto unlock; - if (list_empty(&solo_enc->vidq_active)) - goto unlock; - spin_lock_irqsave(&solo_enc->av_lock, flags); - - vb = list_first_entry(&solo_enc->vidq_active, - struct videobuf_buffer, queue); - - list_del(&vb->queue); - vb->state = VIDEOBUF_ACTIVE; - + if (list_empty(&solo_enc->vidq_active)) { + spin_unlock_irqrestore(&solo_enc->av_lock, flags); + goto unlock; + } + vb = list_first_entry(&solo_enc->vidq_active, struct solo_vb2_buf, list); + list_del(&vb->list); spin_unlock_irqrestore(&solo_enc->av_lock, flags); - solo_enc_fillbuf(solo_enc, vb, enc_buf); + solo_enc_fillbuf(solo_enc, &vb->vb, enc_buf); unlock: - mutex_unlock(&solo_enc->enable_lock); + mutex_unlock(&solo_enc->lock); } void solo_enc_v4l2_isr(struct solo_dev *solo_dev) @@ -723,85 +645,29 @@ static int solo_ring_thread(void *data) return 0; } -static int solo_enc_buf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) -{ - *size = FRAME_BUF_SIZE; - - if (*count < MIN_VID_BUFFERS) - *count = MIN_VID_BUFFERS; - - return 0; -} - -static int solo_enc_buf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) +static int solo_enc_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - vb->size = FRAME_BUF_SIZE; - if (vb->baddr != 0 && vb->bsize < vb->size) - return -EINVAL; - - /* This property only change when queue is idle */ - vb->field = field; + sizes[0] = FRAME_BUF_SIZE; + *num_planes = 1; - if (vb->state == VIDEOBUF_NEEDS_INIT) { - int rc = videobuf_iolock(vq, vb, NULL); - if (rc < 0) { - struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - videobuf_dma_unmap(vq->dev, dma); - videobuf_dma_free(dma); - - return rc; - } - } - vb->state = VIDEOBUF_PREPARED; + if (*num_buffers < MIN_VID_BUFFERS) + *num_buffers = MIN_VID_BUFFERS; return 0; } -static void solo_enc_buf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void solo_enc_buf_queue(struct vb2_buffer *vb) { - struct solo_enc_dev *solo_enc = vq->priv_data; - - vb->state = VIDEOBUF_QUEUED; - list_add_tail(&vb->queue, &solo_enc->vidq_active); -} - -static void solo_enc_buf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct videobuf_dmabuf *dma = videobuf_to_dma(vb); - videobuf_dma_unmap(vq->dev, dma); - videobuf_dma_free(dma); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static const struct videobuf_queue_ops solo_enc_video_qops = { - .buf_setup = solo_enc_buf_setup, - .buf_prepare = solo_enc_buf_prepare, - .buf_queue = solo_enc_buf_queue, - .buf_release = solo_enc_buf_release, -}; + struct vb2_queue *vq = vb->vb2_queue; + struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vq); + struct solo_vb2_buf *solo_vb = + container_of(vb, struct solo_vb2_buf, vb); -static unsigned int solo_enc_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - unsigned long req_events = poll_requested_events(wait); - unsigned res = v4l2_ctrl_poll(file, wait); - - if (!(req_events & (POLLIN | POLLRDNORM))) - return res; - return videobuf_poll_stream(file, &solo_enc->vidq, wait); -} - -static int solo_enc_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - - return videobuf_mmap_mapper(&solo_enc->vidq, vma); + spin_lock(&solo_enc->av_lock); + list_add_tail(&solo_vb->list, &solo_enc->vidq_active); + spin_unlock(&solo_enc->av_lock); } static int solo_ring_start(struct solo_dev *solo_dev) @@ -835,50 +701,36 @@ static void solo_ring_stop(struct solo_dev *solo_dev) solo_irq_off(solo_dev, SOLO_IRQ_ENCODER); } -static int solo_enc_open(struct file *file) +static int solo_enc_start_streaming(struct vb2_queue *q, unsigned int count) { - struct solo_enc_dev *solo_enc = video_drvdata(file); - struct solo_dev *solo_dev = solo_enc->solo_dev; - int ret = v4l2_fh_open(file); - - if (ret) - return ret; - ret = solo_ring_start(solo_dev); - if (ret) { - v4l2_fh_release(file); - return ret; - } - return 0; -} - -static ssize_t solo_enc_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q); int ret; - /* Make sure the encoder is on */ ret = solo_enc_on(solo_enc); if (ret) return ret; - - return videobuf_read_stream(&solo_enc->vidq, data, count, ppos, 0, - file->f_flags & O_NONBLOCK); + return solo_ring_start(solo_enc->solo_dev); } -static int solo_enc_release(struct file *file) +static int solo_enc_stop_streaming(struct vb2_queue *q) { - struct solo_enc_dev *solo_enc = video_drvdata(file); - struct solo_dev *solo_dev = solo_enc->solo_dev; + struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q); solo_enc_off(solo_enc); - videobuf_stop(&solo_enc->vidq); - videobuf_mmap_free(&solo_enc->vidq); - solo_ring_stop(solo_dev); - - return v4l2_fh_release(file); + INIT_LIST_HEAD(&solo_enc->vidq_active); + solo_ring_stop(solo_enc->solo_dev); + return 0; } +static struct vb2_ops solo_enc_video_qops = { + .queue_setup = solo_enc_queue_setup, + .buf_queue = solo_enc_buf_queue, + .start_streaming = solo_enc_start_streaming, + .stop_streaming = solo_enc_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + static int solo_enc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -1007,23 +859,13 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv, struct v4l2_pix_format *pix = &f->fmt.pix; int ret; - mutex_lock(&solo_enc->enable_lock); + if (vb2_is_busy(&solo_enc->vidq)) + return -EBUSY; ret = solo_enc_try_fmt_cap(file, priv, f); if (ret) return ret; - /* We cannot change width/height in mid read */ - if (!ret && atomic_read(&solo_enc->readers) > 0) { - if (pix->width != solo_enc->width || - pix->height != solo_enc->height) - ret = -EBUSY; - } - if (ret) { - mutex_unlock(&solo_enc->enable_lock); - return ret; - } - if (pix->width == solo_dev->video_hsize) solo_enc->mode = SOLO_ENC_MODE_D1; else @@ -1034,9 +876,6 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv, if (pix->priv) solo_enc->type = SOLO_ENC_TYPE_EXT; - - mutex_unlock(&solo_enc->enable_lock); - return 0; } @@ -1058,80 +897,6 @@ static int solo_enc_get_fmt_cap(struct file *file, void *priv, return 0; } -static int solo_enc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - - return videobuf_reqbufs(&solo_enc->vidq, req); -} - -static int solo_enc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - - return videobuf_querybuf(&solo_enc->vidq, buf); -} - -static int solo_enc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - - return videobuf_qbuf(&solo_enc->vidq, buf); -} - -static int solo_enc_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - struct solo_videobuf *svb; - int ret; - - /* Make sure the encoder is on */ - ret = solo_enc_on(solo_enc); - if (ret) - return ret; - - ret = videobuf_dqbuf(&solo_enc->vidq, buf, file->f_flags & O_NONBLOCK); - if (ret) - return ret; - - /* Copy over the flags */ - svb = (struct solo_videobuf *)solo_enc->vidq.bufs[buf->index]; - buf->flags |= svb->flags; - - return 0; -} - -static int solo_enc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return videobuf_streamon(&solo_enc->vidq); -} - -static int solo_enc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - int ret; - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - ret = videobuf_streamoff(&solo_enc->vidq); - if (!ret) - solo_enc_off(solo_enc); - - return ret; -} - static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id i) { return 0; @@ -1220,12 +985,8 @@ static int solo_s_parm(struct file *file, void *priv, struct solo_dev *solo_dev = solo_enc->solo_dev; struct v4l2_captureparm *cp = &sp->parm.capture; - mutex_lock(&solo_enc->enable_lock); - - if (atomic_read(&solo_enc->mpeg_readers) > 0) { - mutex_unlock(&solo_enc->enable_lock); + if (vb2_is_streaming(&solo_enc->vidq)) return -EBUSY; - } if ((cp->timeperframe.numerator == 0) || (cp->timeperframe.denominator == 0)) { @@ -1246,9 +1007,6 @@ static int solo_s_parm(struct file *file, void *priv, cp->readbuffers = 2; solo_update_mode(solo_enc); - - mutex_unlock(&solo_enc->enable_lock); - return 0; } @@ -1297,10 +1055,8 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl) solo_motion_toggle(solo_enc, ctrl->val); return 0; case V4L2_CID_OSD_TEXT: - mutex_lock(&solo_enc->enable_lock); strcpy(solo_enc->osd_text, ctrl->string); err = solo_osd_print(solo_enc); - mutex_unlock(&solo_enc->enable_lock); return err; default: return -EINVAL; @@ -1311,12 +1067,12 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl) static const struct v4l2_file_operations solo_enc_fops = { .owner = THIS_MODULE, - .open = solo_enc_open, - .release = solo_enc_release, - .read = solo_enc_read, - .poll = solo_enc_poll, - .mmap = solo_enc_mmap, - .ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = { @@ -1332,12 +1088,12 @@ static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = { .vidioc_s_fmt_vid_cap = solo_enc_set_fmt_cap, .vidioc_g_fmt_vid_cap = solo_enc_get_fmt_cap, /* Streaming I/O */ - .vidioc_reqbufs = solo_enc_reqbufs, - .vidioc_querybuf = solo_enc_querybuf, - .vidioc_qbuf = solo_enc_qbuf, - .vidioc_dqbuf = solo_enc_dqbuf, - .vidioc_streamon = solo_enc_streamon, - .vidioc_streamoff = solo_enc_streamoff, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, /* Frame size and interval */ .vidioc_enum_framesizes = solo_enum_framesizes, .vidioc_enum_frameintervals = solo_enum_frameintervals, @@ -1434,29 +1190,36 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, solo_enc->solo_dev = solo_dev; solo_enc->ch = ch; + mutex_init(&solo_enc->lock); spin_lock_init(&solo_enc->av_lock); INIT_LIST_HEAD(&solo_enc->vidq_active); solo_enc->fmt = V4L2_PIX_FMT_MPEG; solo_enc->type = SOLO_ENC_TYPE_STD; - atomic_set(&solo_enc->readers, 0); - solo_enc->qp = SOLO_DEFAULT_QP; solo_enc->gop = solo_dev->fps; solo_enc->interval = 1; solo_enc->mode = SOLO_ENC_MODE_CIF; solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH; + solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; + solo_enc->vidq.ops = &solo_enc_video_qops; + solo_enc->vidq.mem_ops = &vb2_dma_sg_memops; + solo_enc->vidq.drv_priv = solo_enc; + solo_enc->vidq.gfp_flags = __GFP_DMA32; + solo_enc->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf); + solo_enc->vidq.lock = &solo_enc->lock; + ret = vb2_queue_init(&solo_enc->vidq); + if (ret) + goto hdl_free; spin_lock(&solo_enc->av_lock); solo_update_mode(solo_enc); spin_unlock(&solo_enc->av_lock); - mutex_init(&solo_enc->enable_lock); spin_lock_init(&solo_enc->motion_lock); - atomic_set(&solo_enc->readers, 0); - atomic_set(&solo_enc->mpeg_readers, 0); - /* Initialize this per encoder */ solo_enc->jpeg_len = sizeof(jpeg_header); memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len); @@ -1469,14 +1232,6 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, if (solo_enc->desc_items == NULL) goto hdl_free; - videobuf_queue_sg_init(&solo_enc->vidq, &solo_enc_video_qops, - &solo_dev->pdev->dev, - &solo_enc->av_lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct solo_videobuf), - solo_enc, NULL); - solo_enc->vfd = video_device_alloc(); if (!solo_enc->vfd) goto pci_free; @@ -1484,6 +1239,8 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, *solo_enc->vfd = solo_enc_template; solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev; solo_enc->vfd->ctrl_handler = hdl; + solo_enc->vfd->queue = &solo_enc->vidq; + solo_enc->vfd->lock = &solo_enc->lock; set_bit(V4L2_FL_USE_FH_PRIO, &solo_enc->vfd->flags); video_set_drvdata(solo_enc->vfd, solo_enc); ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr); -- cgit v0.10.2 From a4056c2fb4c4646267e23dcf6d72f0e28f2e0891 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2013 12:11:17 -0300 Subject: [media] solo6x10: convert the display node to vb2 As a consequence the ioctl op has been replaced by unlocked_ioctl. Since we are now using the core lock the locking scheme has been simplified as well. The main reason for converting this driver to vb2 was that the locking scheme in v4l2.c was hopeless. It was easier to just convert the driver then to try and salvage a threading and videobuf nightmare. The videobuf2 framework is far, far superior compared to the old videobuf. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/Kconfig b/drivers/staging/media/solo6x10/Kconfig index f93b4ca..ec32776 100644 --- a/drivers/staging/media/solo6x10/Kconfig +++ b/drivers/staging/media/solo6x10/Kconfig @@ -1,8 +1,8 @@ config SOLO6X10 tristate "Softlogic 6x10 MPEG codec cards" depends on PCI && VIDEO_DEV && SND && I2C - select VIDEOBUF_DMA_SG select VIDEOBUF2_DMA_SG + select VIDEOBUF2_DMA_CONTIG select SND_PCM ---help--- This driver supports the Softlogic based MPEG-4 and h.264 codec diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index d18093f..5181662 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h @@ -39,7 +39,6 @@ #include #include #include -#include #include #include "registers.h" @@ -259,8 +258,6 @@ struct solo_dev { /* Ring thread */ struct task_struct *ring_thread; wait_queue_head_t ring_thread_wait; - atomic_t enc_users; - atomic_t disp_users; /* VOP_HEADER handling */ void *vh_buf; @@ -268,8 +265,10 @@ struct solo_dev { int vh_size; /* Buffer handling */ - struct videobuf_queue vidq; + struct vb2_queue vidq; + struct vb2_alloc_ctx *alloc_ctx; struct task_struct *kthread; + struct mutex lock; spinlock_t slock; int old_write; struct list_head vidq_active; diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index d7d96ce..4dda6ec 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -41,11 +41,6 @@ #define MP4_QS 16 #define DMA_ALIGN 4096 -struct solo_videobuf { - struct videobuf_buffer vb; - unsigned int flags; -}; - /* 6010 M4V */ static unsigned char vop_6010_ntsc_d1[] = { 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, @@ -672,9 +667,6 @@ static void solo_enc_buf_queue(struct vb2_buffer *vb) static int solo_ring_start(struct solo_dev *solo_dev) { - if (atomic_inc_return(&solo_dev->enc_users) > 1) - return 0; - solo_dev->ring_thread = kthread_run(solo_ring_thread, solo_dev, SOLO6X10_NAME "_ring"); if (IS_ERR(solo_dev->ring_thread)) { @@ -690,9 +682,6 @@ static int solo_ring_start(struct solo_dev *solo_dev) static void solo_ring_stop(struct solo_dev *solo_dev) { - if (atomic_dec_return(&solo_dev->enc_users) > 0) - return; - if (solo_dev->ring_thread) { kthread_stop(solo_dev->ring_thread); solo_dev->ring_thread = NULL; @@ -1279,7 +1268,6 @@ int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr) { int i; - atomic_set(&solo_dev->enc_users, 0); init_waitqueue_head(&solo_dev->ring_thread_wait); solo_dev->vh_size = sizeof(struct vop_header); diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index 13b7640..d38a8fe 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include "solo6x10.h" #include "tw28.h" @@ -192,19 +192,19 @@ static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch) } static void solo_fillbuf(struct solo_dev *solo_dev, - struct videobuf_buffer *vb) + struct vb2_buffer *vb) { dma_addr_t vbuf; unsigned int fdma_addr; int error = -1; int i; - vbuf = videobuf_to_dma_contig(vb); + vbuf = vb2_dma_contig_plane_dma_addr(vb, 0); if (!vbuf) goto finish_buf; if (erase_off(solo_dev)) { - void *p = videobuf_queue_to_vaddr(&solo_dev->vidq, vb); + void *p = vb2_plane_vaddr(vb, 0); int image_size = solo_image_size(solo_dev); for (i = 0; i < image_size; i += 2) { ((u8 *)p)[i] = 0x80; @@ -221,19 +221,19 @@ static void solo_fillbuf(struct solo_dev *solo_dev, } finish_buf: - if (error) { - vb->state = VIDEOBUF_ERROR; - } else { - vb->state = VIDEOBUF_DONE; - vb->field_count++; + if (!error) { + vb2_set_plane_payload(vb, 0, + solo_vlines(solo_dev) * solo_bytesperline(solo_dev)); + vb->v4l2_buf.sequence++; + v4l2_get_timestamp(&vb->v4l2_buf.timestamp); } - wake_up(&vb->done); + vb2_buffer_done(vb, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); } static void solo_thread_try(struct solo_dev *solo_dev) { - struct videobuf_buffer *vb; + struct solo_vb2_buf *vb; /* Only "break" from this loop if slock is held, otherwise * just return. */ @@ -250,19 +250,15 @@ static void solo_thread_try(struct solo_dev *solo_dev) if (list_empty(&solo_dev->vidq_active)) break; - vb = list_first_entry(&solo_dev->vidq_active, struct videobuf_buffer, - queue); - - if (!waitqueue_active(&vb->done)) - break; + vb = list_first_entry(&solo_dev->vidq_active, struct solo_vb2_buf, + list); solo_dev->old_write = cur_write; - list_del(&vb->queue); - vb->state = VIDEOBUF_ACTIVE; + list_del(&vb->list); spin_unlock(&solo_dev->slock); - solo_fillbuf(solo_dev, vb); + solo_fillbuf(solo_dev, &vb->vb); } assert_spin_locked(&solo_dev->slock); @@ -294,15 +290,14 @@ static int solo_start_thread(struct solo_dev *solo_dev) { int ret = 0; - if (atomic_inc_return(&solo_dev->disp_users) == 1) - solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN); - solo_dev->kthread = kthread_run(solo_thread, solo_dev, SOLO6X10_NAME "_disp"); if (IS_ERR(solo_dev->kthread)) { ret = PTR_ERR(solo_dev->kthread); solo_dev->kthread = NULL; + return ret; } + solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN); return ret; } @@ -312,116 +307,65 @@ static void solo_stop_thread(struct solo_dev *solo_dev) if (!solo_dev->kthread) return; + solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN); kthread_stop(solo_dev->kthread); solo_dev->kthread = NULL; - - if (atomic_dec_return(&solo_dev->disp_users) == 0) - solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN); } -static int solo_buf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) +static int solo_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct solo_dev *solo_dev = vq->priv_data; + struct solo_dev *solo_dev = vb2_get_drv_priv(q); - *size = solo_image_size(solo_dev); + sizes[0] = solo_image_size(solo_dev); + alloc_ctxs[0] = solo_dev->alloc_ctx; + *num_planes = 1; - if (*count < MIN_VID_BUFFERS) - *count = MIN_VID_BUFFERS; + if (*num_buffers < MIN_VID_BUFFERS) + *num_buffers = MIN_VID_BUFFERS; return 0; } -static int solo_buf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, enum v4l2_field field) +static int solo_start_streaming(struct vb2_queue *q, unsigned int count) { - struct solo_dev *solo_dev = vq->priv_data; + struct solo_dev *solo_dev = vb2_get_drv_priv(q); - vb->size = solo_image_size(solo_dev); - if (vb->baddr != 0 && vb->bsize < vb->size) - return -EINVAL; + return solo_start_thread(solo_dev); +} - /* XXX: These properties only change when queue is idle */ - vb->width = solo_dev->video_hsize; - vb->height = solo_vlines(solo_dev); - vb->bytesperline = solo_bytesperline(solo_dev); - vb->field = field; - - if (vb->state == VIDEOBUF_NEEDS_INIT) { - int rc = videobuf_iolock(vq, vb, NULL); - if (rc < 0) { - videobuf_dma_contig_free(vq, vb); - vb->state = VIDEOBUF_NEEDS_INIT; - return rc; - } - } - vb->state = VIDEOBUF_PREPARED; +static int solo_stop_streaming(struct vb2_queue *q) +{ + struct solo_dev *solo_dev = vb2_get_drv_priv(q); + solo_stop_thread(solo_dev); + INIT_LIST_HEAD(&solo_dev->vidq_active); return 0; } -static void solo_buf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void solo_buf_queue(struct vb2_buffer *vb) { - struct solo_dev *solo_dev = vq->priv_data; + struct vb2_queue *vq = vb->vb2_queue; + struct solo_dev *solo_dev = vb2_get_drv_priv(vq); + struct solo_vb2_buf *solo_vb = + container_of(vb, struct solo_vb2_buf, vb); - vb->state = VIDEOBUF_QUEUED; - list_add_tail(&vb->queue, &solo_dev->vidq_active); + spin_lock(&solo_dev->slock); + list_add_tail(&solo_vb->list, &solo_dev->vidq_active); + spin_unlock(&solo_dev->slock); wake_up_interruptible(&solo_dev->disp_thread_wait); } -static void solo_buf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - videobuf_dma_contig_free(vq, vb); - vb->state = VIDEOBUF_NEEDS_INIT; -} - -static const struct videobuf_queue_ops solo_video_qops = { - .buf_setup = solo_buf_setup, - .buf_prepare = solo_buf_prepare, +static const struct vb2_ops solo_video_qops = { + .queue_setup = solo_queue_setup, .buf_queue = solo_buf_queue, - .buf_release = solo_buf_release, + .start_streaming = solo_start_streaming, + .stop_streaming = solo_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; -static unsigned int solo_v4l2_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct solo_dev *solo_dev = video_drvdata(file); - unsigned long req_events = poll_requested_events(wait); - unsigned res = v4l2_ctrl_poll(file, wait); - - if (!(req_events & (POLLIN | POLLRDNORM))) - return res; - return res | videobuf_poll_stream(file, &solo_dev->vidq, wait); -} - -static int solo_v4l2_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct solo_dev *solo_dev = video_drvdata(file); - - return videobuf_mmap_mapper(&solo_dev->vidq, vma); -} - -static ssize_t solo_v4l2_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct solo_dev *solo_dev = video_drvdata(file); - - return videobuf_read_stream(&solo_dev->vidq, data, count, ppos, 0, - file->f_flags & O_NONBLOCK); -} - -static int solo_v4l2_release(struct file *file) -{ - struct solo_dev *solo_dev = video_drvdata(file); - - solo_stop_thread(solo_dev); - videobuf_stop(&solo_dev->vidq); - videobuf_mmap_free(&solo_dev->vidq); - return v4l2_fh_release(file); -} - static int solo_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { @@ -550,7 +494,7 @@ static int solo_set_fmt_cap(struct file *file, void *priv, { struct solo_dev *solo_dev = video_drvdata(file); - if (videobuf_queue_is_busy(&solo_dev->vidq)) + if (vb2_is_busy(&solo_dev->vidq)) return -EBUSY; /* For right now, if it doesn't match our running config, @@ -576,61 +520,6 @@ static int solo_get_fmt_cap(struct file *file, void *priv, return 0; } -static int solo_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req) -{ - struct solo_dev *solo_dev = video_drvdata(file); - - return videobuf_reqbufs(&solo_dev->vidq, req); -} - -static int solo_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct solo_dev *solo_dev = video_drvdata(file); - - return videobuf_querybuf(&solo_dev->vidq, buf); -} - -static int solo_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct solo_dev *solo_dev = video_drvdata(file); - - return videobuf_qbuf(&solo_dev->vidq, buf); -} - -static int solo_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct solo_dev *solo_dev = video_drvdata(file); - - return videobuf_dqbuf(&solo_dev->vidq, buf, file->f_flags & O_NONBLOCK); -} - -static int solo_streamon(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct solo_dev *solo_dev = video_drvdata(file); - int ret; - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - ret = solo_start_thread(solo_dev); - if (ret) - return ret; - - return videobuf_streamon(&solo_dev->vidq); -} - -static int solo_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct solo_dev *solo_dev = video_drvdata(file); - - if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return videobuf_streamoff(&solo_dev->vidq); -} - static int solo_s_std(struct file *file, void *priv, v4l2_std_id i) { return 0; @@ -668,11 +557,11 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl) static const struct v4l2_file_operations solo_v4l2_fops = { .owner = THIS_MODULE, .open = v4l2_fh_open, - .release = solo_v4l2_release, - .read = solo_v4l2_read, - .poll = solo_v4l2_poll, - .mmap = solo_v4l2_mmap, - .ioctl = video_ioctl2, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = { @@ -688,12 +577,12 @@ static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = { .vidioc_s_fmt_vid_cap = solo_set_fmt_cap, .vidioc_g_fmt_vid_cap = solo_get_fmt_cap, /* Streaming I/O */ - .vidioc_reqbufs = solo_reqbufs, - .vidioc_querybuf = solo_querybuf, - .vidioc_qbuf = solo_qbuf, - .vidioc_dqbuf = solo_dqbuf, - .vidioc_streamon = solo_streamon, - .vidioc_streamoff = solo_streamoff, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, /* Logging and events */ .vidioc_log_status = v4l2_ctrl_log_status, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, @@ -729,8 +618,10 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) int ret; int i; - atomic_set(&solo_dev->disp_users, 0); init_waitqueue_head(&solo_dev->disp_thread_wait); + spin_lock_init(&solo_dev->slock); + mutex_init(&solo_dev->lock); + INIT_LIST_HEAD(&solo_dev->vidq_active); solo_dev->vfd = video_device_alloc(); if (!solo_dev->vfd) @@ -738,24 +629,37 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) *solo_dev->vfd = solo_v4l2_template; solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev; + solo_dev->vfd->queue = &solo_dev->vidq; + solo_dev->vfd->lock = &solo_dev->lock; v4l2_ctrl_handler_init(&solo_dev->disp_hdl, 1); v4l2_ctrl_new_custom(&solo_dev->disp_hdl, &solo_motion_trace_ctrl, NULL); - if (solo_dev->disp_hdl.error) - return solo_dev->disp_hdl.error; + if (solo_dev->disp_hdl.error) { + ret = solo_dev->disp_hdl.error; + goto fail; + } solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl; set_bit(V4L2_FL_USE_FH_PRIO, &solo_dev->vfd->flags); video_set_drvdata(solo_dev->vfd, solo_dev); - spin_lock_init(&solo_dev->slock); - INIT_LIST_HEAD(&solo_dev->vidq_active); - - videobuf_queue_dma_contig_init(&solo_dev->vidq, &solo_video_qops, - &solo_dev->pdev->dev, &solo_dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct videobuf_buffer), - solo_dev, NULL); + solo_dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + solo_dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; + solo_dev->vidq.ops = &solo_video_qops; + solo_dev->vidq.mem_ops = &vb2_dma_contig_memops; + solo_dev->vidq.drv_priv = solo_dev; + solo_dev->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + solo_dev->vidq.gfp_flags = __GFP_DMA32; + solo_dev->vidq.buf_struct_size = sizeof(struct solo_vb2_buf); + solo_dev->vidq.lock = &solo_dev->lock; + ret = vb2_queue_init(&solo_dev->vidq); + if (ret < 0) + goto fail; + + solo_dev->alloc_ctx = vb2_dma_contig_init_ctx(&solo_dev->pdev->dev); + if (IS_ERR(solo_dev->alloc_ctx)) { + dev_err(&solo_dev->pdev->dev, "Can't allocate buffer context"); + return PTR_ERR(solo_dev->alloc_ctx); + } /* Cycle all the channels and clear */ for (i = 0; i < solo_dev->nr_chans; i++) { @@ -770,11 +674,8 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) /* Do nothing */; ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr); - if (ret < 0) { - video_device_release(solo_dev->vfd); - solo_dev->vfd = NULL; - return ret; - } + if (ret < 0) + goto fail; snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)", SOLO6X10_NAME, solo_dev->vfd->num); @@ -784,6 +685,13 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) solo_dev->nr_chans, solo_dev->nr_ext); return 0; + +fail: + video_device_release(solo_dev->vfd); + vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx); + v4l2_ctrl_handler_free(&solo_dev->disp_hdl); + solo_dev->vfd = NULL; + return ret; } void solo_v4l2_exit(struct solo_dev *solo_dev) @@ -792,6 +700,7 @@ void solo_v4l2_exit(struct solo_dev *solo_dev) return; video_unregister_device(solo_dev->vfd); + vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx); v4l2_ctrl_handler_free(&solo_dev->disp_hdl); solo_dev->vfd = NULL; } -- cgit v0.10.2 From ff82ad223d386aa588948931dac5d61f4dae3cfb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2013 12:09:35 -0300 Subject: [media] solo6x10: fix 'BUG: key ffff88081a2a9b58 not in .data!' Caused by a missing sysfs_attr_init(). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/core.c b/drivers/staging/media/solo6x10/core.c index 05ecd48..3cea08d 100644 --- a/drivers/staging/media/solo6x10/core.c +++ b/drivers/staging/media/solo6x10/core.c @@ -481,6 +481,7 @@ static int solo_sysfs_init(struct solo_dev *solo_dev) } } + sysfs_attr_init(&sdram_attr->attr); sdram_attr->attr.name = "sdram"; sdram_attr->attr.mode = 0440; sdram_attr->read = sdram_show; -- cgit v0.10.2 From f43afb1e21ff31243e120401ff34f017d0818998 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 18 Mar 2013 08:21:33 -0300 Subject: [media] solo6x10: add call to pci_dma_mapping_error Check the result of the dma mapping. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/p2m.c b/drivers/staging/media/solo6x10/p2m.c index b3a9339..a77c8d9 100644 --- a/drivers/staging/media/solo6x10/p2m.c +++ b/drivers/staging/media/solo6x10/p2m.c @@ -52,6 +52,8 @@ int solo_p2m_dma(struct solo_dev *solo_dev, int wr, dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size, wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(solo_dev->pdev, dma_addr)) + return -ENOMEM; ret = solo_p2m_dma_t(solo_dev, wr, dma_addr, ext_addr, size, repeat, ext_size); -- cgit v0.10.2 From 4c211ed7e56bac729eab6552a2b8e85756f1cffd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2013 12:53:17 -0300 Subject: [media] solo6x10: drop video_type and add proper s_std support Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/core.c b/drivers/staging/media/solo6x10/core.c index 3cea08d..779d4b4 100644 --- a/drivers/staging/media/solo6x10/core.c +++ b/drivers/staging/media/solo6x10/core.c @@ -232,24 +232,6 @@ static ssize_t eeprom_show(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t video_type_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - return -EPERM; -} - -static ssize_t video_type_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct solo_dev *solo_dev = - container_of(dev, struct solo_dev, dev); - - return sprintf(buf, "%s", solo_dev->video_type == - SOLO_VO_FMT_TYPE_NTSC ? "NTSC" : "PAL"); -} - static ssize_t p2m_timeouts_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -436,7 +418,6 @@ static ssize_t sdram_show(struct file *file, struct kobject *kobj, static const struct device_attribute solo_dev_attrs[] = { __ATTR(eeprom, 0640, eeprom_show, eeprom_store), - __ATTR(video_type, 0644, video_type_show, video_type_store), __ATTR(p2m_timeout, 0644, p2m_timeout_show, p2m_timeout_store), __ATTR_RO(p2m_timeouts), __ATTR_RO(sdram_size), diff --git a/drivers/staging/media/solo6x10/disp.c b/drivers/staging/media/solo6x10/disp.c index ddd85e7..3dcaad9 100644 --- a/drivers/staging/media/solo6x10/disp.c +++ b/drivers/staging/media/solo6x10/disp.c @@ -39,10 +39,6 @@ #define SOLO_MOT_FLAG_SIZE 1024 #define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 16) -static unsigned video_type; -module_param(video_type, uint, 0644); -MODULE_PARM_DESC(video_type, "video_type (0 = NTSC/Default, 1 = PAL)"); - static void solo_vin_config(struct solo_dev *solo_dev) { solo_dev->vin_hstart = 8; @@ -273,12 +269,10 @@ int solo_disp_init(struct solo_dev *solo_dev) int i; solo_dev->video_hsize = 704; - if (video_type == 0) { - solo_dev->video_type = SOLO_VO_FMT_TYPE_NTSC; + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { solo_dev->video_vsize = 240; solo_dev->fps = 30; } else { - solo_dev->video_type = SOLO_VO_FMT_TYPE_PAL; solo_dev->video_vsize = 288; solo_dev->fps = 25; } diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index 5181662..6c00f07 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h @@ -320,7 +320,7 @@ static inline void solo_irq_off(struct solo_dev *dev, u32 mask) solo_reg_write(dev, SOLO_IRQ_MASK, dev->irq_mask); } -/* Init/exit routeines for subsystems */ +/* Init/exit routines for subsystems */ int solo_disp_init(struct solo_dev *solo_dev); void solo_disp_exit(struct solo_dev *solo_dev); @@ -373,6 +373,10 @@ int solo_p2m_dma_desc(struct solo_dev *solo_dev, struct solo_p2m_desc *desc, dma_addr_t desc_dma, int desc_cnt); +/* Global s_std ioctl */ +int solo_set_video_type(struct solo_dev *solo_dev, bool type); +void solo_update_mode(struct solo_enc_dev *solo_enc); + /* Set the threshold for motion detection */ int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val); int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, u16 val, diff --git a/drivers/staging/media/solo6x10/tw28.c b/drivers/staging/media/solo6x10/tw28.c index 69baf82..6c77af8 100644 --- a/drivers/staging/media/solo6x10/tw28.c +++ b/drivers/staging/media/solo6x10/tw28.c @@ -576,6 +576,8 @@ int solo_tw28_init(struct solo_dev *solo_dev) int i; u8 value; + solo_dev->tw28_cnt = 0; + /* Detect techwell chip type(s) */ for (i = 0; i < solo_dev->nr_chans / 4; i++) { value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index 4dda6ec..225b634 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -176,7 +176,7 @@ static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on) spin_unlock_irqrestore(&solo_enc->motion_lock, flags); } -static void solo_update_mode(struct solo_enc_dev *solo_enc) +void solo_update_mode(struct solo_enc_dev *solo_enc) { struct solo_dev *solo_dev = solo_enc->solo_dev; int vop_len; @@ -749,11 +749,7 @@ static int solo_enc_enum_input(struct file *file, void *priv, snprintf(input->name, sizeof(input->name), "Encoder %d", solo_enc->ch + 1); input->type = V4L2_INPUT_TYPE_CAMERA; - - if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) - input->std = V4L2_STD_NTSC_M; - else - input->std = V4L2_STD_PAL_B; + input->std = solo_enc->vfd->tvnorms; if (!tw28_get_video_status(solo_dev, solo_enc->ch)) input->status = V4L2_IN_ST_NO_SIGNAL; @@ -886,11 +882,25 @@ static int solo_enc_get_fmt_cap(struct file *file, void *priv, return 0; } -static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id i) +static int solo_enc_g_std(struct file *file, void *priv, v4l2_std_id *i) { + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; + + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) + *i = V4L2_STD_NTSC_M; + else + *i = V4L2_STD_PAL; return 0; } +static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id std) +{ + struct solo_enc_dev *solo_enc = video_drvdata(file); + + return solo_set_video_type(solo_enc->solo_dev, std & V4L2_STD_PAL); +} + static int solo_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { @@ -938,14 +948,14 @@ static int solo_enum_frameintervals(struct file *file, void *priv, fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE; + fintv->stepwise.min.numerator = 1; fintv->stepwise.min.denominator = solo_dev->fps; - fintv->stepwise.min.numerator = 15; + fintv->stepwise.max.numerator = 15; fintv->stepwise.max.denominator = solo_dev->fps; - fintv->stepwise.max.numerator = 1; fintv->stepwise.step.numerator = 1; - fintv->stepwise.step.denominator = 1; + fintv->stepwise.step.denominator = solo_dev->fps; return 0; } @@ -1067,6 +1077,7 @@ static const struct v4l2_file_operations solo_enc_fops = { static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = { .vidioc_querycap = solo_enc_querycap, .vidioc_s_std = solo_enc_s_std, + .vidioc_g_std = solo_enc_g_std, /* Input callbacks */ .vidioc_enum_input = solo_enc_enum_input, .vidioc_s_input = solo_enc_set_input, @@ -1101,9 +1112,7 @@ static const struct video_device solo_enc_template = { .ioctl_ops = &solo_enc_ioctl_ops, .minor = -1, .release = video_device_release, - - .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_B, - .current_norm = V4L2_STD_NTSC_M, + .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, }; static const struct v4l2_ctrl_ops solo_ctrl_ops = { @@ -1203,9 +1212,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, ret = vb2_queue_init(&solo_enc->vidq); if (ret) goto hdl_free; - spin_lock(&solo_enc->av_lock); solo_update_mode(solo_enc); - spin_unlock(&solo_enc->av_lock); spin_lock_init(&solo_enc->motion_lock); diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index d38a8fe..b5643ab 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c @@ -426,12 +426,7 @@ static int solo_enum_input(struct file *file, void *priv, } input->type = V4L2_INPUT_TYPE_CAMERA; - - if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) - input->std = V4L2_STD_NTSC_M; - else - input->std = V4L2_STD_PAL_B; - + input->std = solo_dev->vfd->tvnorms; return 0; } @@ -520,11 +515,44 @@ static int solo_get_fmt_cap(struct file *file, void *priv, return 0; } -static int solo_s_std(struct file *file, void *priv, v4l2_std_id i) +static int solo_g_std(struct file *file, void *priv, v4l2_std_id *i) { + struct solo_dev *solo_dev = video_drvdata(file); + + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) + *i = V4L2_STD_NTSC_M; + else + *i = V4L2_STD_PAL; return 0; } +int solo_set_video_type(struct solo_dev *solo_dev, bool type) +{ + int i; + + /* Make sure all video nodes are idle */ + if (vb2_is_busy(&solo_dev->vidq)) + return -EBUSY; + for (i = 0; i < solo_dev->nr_chans; i++) + if (vb2_is_busy(&solo_dev->v4l2_enc[i]->vidq)) + return -EBUSY; + solo_dev->video_type = type; + /* Reconfigure for the new standard */ + solo_disp_init(solo_dev); + solo_enc_init(solo_dev); + solo_tw28_init(solo_dev); + for (i = 0; i < solo_dev->nr_chans; i++) + solo_update_mode(solo_dev->v4l2_enc[i]); + return solo_v4l2_set_ch(solo_dev, solo_dev->cur_disp_ch); +} + +static int solo_s_std(struct file *file, void *priv, v4l2_std_id std) +{ + struct solo_dev *solo_dev = video_drvdata(file); + + return solo_set_video_type(solo_dev, std & V4L2_STD_PAL); +} + static int solo_s_ctrl(struct v4l2_ctrl *ctrl) { struct solo_dev *solo_dev = @@ -567,6 +595,7 @@ static const struct v4l2_file_operations solo_v4l2_fops = { static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = { .vidioc_querycap = solo_querycap, .vidioc_s_std = solo_s_std, + .vidioc_g_std = solo_g_std, /* Input callbacks */ .vidioc_enum_input = solo_enum_input, .vidioc_s_input = solo_set_input, @@ -595,9 +624,7 @@ static struct video_device solo_v4l2_template = { .ioctl_ops = &solo_v4l2_ioctl_ops, .minor = -1, .release = video_device_release, - - .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_B, - .current_norm = V4L2_STD_NTSC_M, + .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, }; static const struct v4l2_ctrl_ops solo_ctrl_ops = { -- cgit v0.10.2 From 4718892f0f8998685ed7980cb723a165030ae50d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2013 11:16:56 -0300 Subject: [media] solo6x10: also stop DMA if the SOLO_PCI_ERR_P2M_DESC is raised Otherwise the computer will hang. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/p2m.c b/drivers/staging/media/solo6x10/p2m.c index a77c8d9..3335941 100644 --- a/drivers/staging/media/solo6x10/p2m.c +++ b/drivers/staging/media/solo6x10/p2m.c @@ -198,7 +198,7 @@ void solo_p2m_error_isr(struct solo_dev *solo_dev) struct solo_p2m_dev *p2m_dev; int i; - if (!(err & SOLO_PCI_ERR_P2M)) + if (!(err & (SOLO_PCI_ERR_P2M | SOLO_PCI_ERR_P2M_DESC))) return; for (i = 0; i < SOLO_NR_P2M; i++) { -- cgit v0.10.2 From 225642853a1f2536757b775f76d925b78622ae28 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2013 11:17:12 -0300 Subject: [media] solo6x10: small big-endian fix Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/disp.c b/drivers/staging/media/solo6x10/disp.c index 3dcaad9..7007006 100644 --- a/drivers/staging/media/solo6x10/disp.c +++ b/drivers/staging/media/solo6x10/disp.c @@ -181,7 +181,7 @@ static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off, int ret = 0; for (i = 0; i < sizeof(buf) >> 1; i++) - buf[i] = val; + buf[i] = cpu_to_le16(val); for (i = 0; i < reg_size; i += sizeof(buf)) ret |= solo_p2m_dma(solo_dev, 1, buf, -- cgit v0.10.2 From 9a8bfe9fe958beef9cfb9a6f7b0922cc51deb65c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2013 12:53:59 -0300 Subject: [media] solo6x10: use V4L2_PIX_FMT_MPEG4, not _FMT_MPEG FMT_MPEG is for multiplexed streams, not elementary streams. The same is true for the V4L2_CID_MPEG_VIDEO_ENCODING control. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index 225b634..f804c93 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -516,7 +516,7 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_DETECTED; } - if (solo_enc->fmt == V4L2_PIX_FMT_MPEG) + if (solo_enc->fmt == V4L2_PIX_FMT_MPEG4) ret = solo_fill_mpeg(solo_enc, vb, vh); else ret = solo_fill_jpeg(solo_enc, vb, vh); @@ -779,7 +779,7 @@ static int solo_enc_enum_fmt_cap(struct file *file, void *priv, { switch (f->index) { case 0: - f->pixelformat = V4L2_PIX_FMT_MPEG; + f->pixelformat = V4L2_PIX_FMT_MPEG4; strcpy(f->description, "MPEG-4 AVC"); break; case 1: @@ -802,7 +802,7 @@ static int solo_enc_try_fmt_cap(struct file *file, void *priv, struct solo_dev *solo_dev = solo_enc->solo_dev; struct v4l2_pix_format *pix = &f->fmt.pix; - if (pix->pixelformat != V4L2_PIX_FMT_MPEG && + if (pix->pixelformat != V4L2_PIX_FMT_MPEG4 && pix->pixelformat != V4L2_PIX_FMT_MJPEG) return -EINVAL; @@ -907,7 +907,7 @@ static int solo_enum_framesizes(struct file *file, void *priv, struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_dev *solo_dev = solo_enc->solo_dev; - if (fsize->pixel_format != V4L2_PIX_FMT_MPEG && + if (fsize->pixel_format != V4L2_PIX_FMT_MPEG4 && fsize->pixel_format != V4L2_PIX_FMT_MJPEG) return -EINVAL; @@ -935,7 +935,7 @@ static int solo_enum_frameintervals(struct file *file, void *priv, struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_dev *solo_dev = solo_enc->solo_dev; - if (fintv->pixel_format != V4L2_PIX_FMT_MPEG && + if (fintv->pixel_format != V4L2_PIX_FMT_MPEG4 && fintv->pixel_format != V4L2_PIX_FMT_MJPEG) return -EINVAL; if (fintv->index) @@ -1024,8 +1024,6 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_SHARPNESS: return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch, ctrl->val); - case V4L2_CID_MPEG_VIDEO_ENCODING: - return 0; case V4L2_CID_MPEG_VIDEO_GOP_SIZE: solo_enc->gop = ctrl->val; return 0; @@ -1172,10 +1170,6 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, if (tw28_has_sharpness(solo_dev, ch)) v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, V4L2_CID_SHARPNESS, 0, 15, 1, 0); - v4l2_ctrl_new_std_menu(hdl, &solo_ctrl_ops, - V4L2_CID_MPEG_VIDEO_ENCODING, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 3, - V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC); v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps); v4l2_ctrl_new_custom(hdl, &solo_motion_threshold_ctrl, NULL); @@ -1191,7 +1185,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, mutex_init(&solo_enc->lock); spin_lock_init(&solo_enc->av_lock); INIT_LIST_HEAD(&solo_enc->vidq_active); - solo_enc->fmt = V4L2_PIX_FMT_MPEG; + solo_enc->fmt = V4L2_PIX_FMT_MPEG4; solo_enc->type = SOLO_ENC_TYPE_STD; solo_enc->qp = SOLO_DEFAULT_QP; -- cgit v0.10.2 From 15513c12e3c5f5e7c683865b3e019cf90babab8f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2013 13:16:49 -0300 Subject: [media] solo6x10: fix sequence handling Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index 6c00f07..94ac294 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h @@ -173,6 +173,7 @@ struct solo_enc_dev { u32 fmt; enum solo_enc_types type; + u32 sequence; struct vb2_queue vidq; struct list_head vidq_active; int desc_count; @@ -267,6 +268,7 @@ struct solo_dev { /* Buffer handling */ struct vb2_queue vidq; struct vb2_alloc_ctx *alloc_ctx; + u32 sequence; struct task_struct *kthread; struct mutex lock; spinlock_t slock; diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index f804c93..4fbfb35 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -269,6 +269,7 @@ static int solo_enc_on(struct solo_enc_dev *solo_enc) /* Make sure to do a bandwidth check */ if (solo_enc->bw_weight > solo_dev->enc_bw_remain) return -EBUSY; + solo_enc->sequence = 0; solo_dev->enc_bw_remain -= solo_enc->bw_weight; if (solo_enc->type == SOLO_ENC_TYPE_EXT) @@ -522,7 +523,7 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, ret = solo_fill_jpeg(solo_enc, vb, vh); if (!ret) { - vb->v4l2_buf.sequence++; + vb->v4l2_buf.sequence = solo_enc->sequence++; vb->v4l2_buf.timestamp.tv_sec = vh->sec; vb->v4l2_buf.timestamp.tv_usec = vh->usec; } diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index b5643ab..02749a3 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c @@ -224,7 +224,7 @@ finish_buf: if (!error) { vb2_set_plane_payload(vb, 0, solo_vlines(solo_dev) * solo_bytesperline(solo_dev)); - vb->v4l2_buf.sequence++; + vb->v4l2_buf.sequence = solo_dev->sequence++; v4l2_get_timestamp(&vb->v4l2_buf.timestamp); } @@ -332,6 +332,7 @@ static int solo_start_streaming(struct vb2_queue *q, unsigned int count) { struct solo_dev *solo_dev = vb2_get_drv_priv(q); + solo_dev->sequence = 0; return solo_start_thread(solo_dev); } -- cgit v0.10.2 From 69996873478d75381d14abbc9e768cc38d82e94b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2013 16:35:28 -0300 Subject: [media] solo6x10: disable the 'priv' abuse Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index 4fbfb35..0efb623 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -860,8 +860,16 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv, /* This does not change the encoder at all */ solo_enc->fmt = pix->pixelformat; + /* + * More information is needed about these 'extended' types. As far + * as I can tell these are basically additional video streams with + * different MPEG encoding attributes that can run in parallel with + * the main stream. If so, then this should be implemented as a + * second video node. Abusing priv like this is certainly not the + * right approach. if (pix->priv) solo_enc->type = SOLO_ENC_TYPE_EXT; + */ return 0; } -- cgit v0.10.2 From f5df0b7ff57732f938373f49e89ca219d4717836 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 18 Mar 2013 08:43:14 -0300 Subject: [media] solo6x10: clean up motion detection handling An earlier patch temporarily disabled regional motion detection. This patch adds it back: the 'Motion Detection Enable' control is now a 'Motion Detection Mode'. And to set/get the regional thresholds two new ioctls were added to get/set those thresholds. The BUF_FLAG constants were also updated to prevent clashing with existing buffer flags. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/disp.c b/drivers/staging/media/solo6x10/disp.c index 7007006..78070c8 100644 --- a/drivers/staging/media/solo6x10/disp.c +++ b/drivers/staging/media/solo6x10/disp.c @@ -201,31 +201,22 @@ int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val) val, SOLO_MOT_THRESH_SIZE); } -int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, u16 val, - u16 block) +int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, + const struct solo_motion_thresholds *thresholds) { - u16 buf[64]; - u32 addr; - int re; - - addr = SOLO_MOTION_EXT_ADDR(solo_dev) + - SOLO_MOT_FLAG_AREA + - (SOLO_MOT_THRESH_SIZE * 2 * ch) + - (block * 2); - - /* Read and write only on a 128-byte boundary; 4-byte writes with - solo_p2m_dma silently failed. Bluecherry bug #908. */ - re = solo_p2m_dma(solo_dev, 0, &buf, addr & ~0x7f, sizeof(buf), 0, 0); - if (re) - return re; - - buf[(addr & 0x7f) / 2] = val; - - re = solo_p2m_dma(solo_dev, 1, &buf, addr & ~0x7f, sizeof(buf), 0, 0); - if (re) - return re; + u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2; + u16 buf[SOLO_MOTION_SZ]; + int x, y; + int ret = 0; - return 0; + for (y = 0; y < SOLO_MOTION_SZ; y++) { + for (x = 0; x < SOLO_MOTION_SZ; x++) + buf[x] = cpu_to_le16(thresholds->thresholds[y][x]); + ret |= solo_p2m_dma(solo_dev, 1, buf, + SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * sizeof(buf), + sizeof(buf), 0, 0); + } + return ret; } /* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index 94ac294..da7611e 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h @@ -98,16 +98,30 @@ #define SOLO_DEFAULT_QP 3 #ifndef V4L2_BUF_FLAG_MOTION_ON -#define V4L2_BUF_FLAG_MOTION_ON 0x0400 -#define V4L2_BUF_FLAG_MOTION_DETECTED 0x0800 +#define V4L2_BUF_FLAG_MOTION_ON 0x10000 +#define V4L2_BUF_FLAG_MOTION_DETECTED 0x20000 #endif #define SOLO_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) -#define V4L2_CID_MOTION_ENABLE (SOLO_CID_CUSTOM_BASE+0) +#define V4L2_CID_MOTION_MODE (SOLO_CID_CUSTOM_BASE+0) #define V4L2_CID_MOTION_THRESHOLD (SOLO_CID_CUSTOM_BASE+1) #define V4L2_CID_MOTION_TRACE (SOLO_CID_CUSTOM_BASE+2) #define V4L2_CID_OSD_TEXT (SOLO_CID_CUSTOM_BASE+3) +/* + * Motion thresholds are in a table of 64x64 samples, with + * each sample representing 16x16 pixels of the source. In + * effect, 44x30 samples are used for NTSC, and 44x36 for PAL. + * The 5th sample on the 10th row is (10*64)+5 = 645. + */ +#define SOLO_MOTION_SZ (64) +struct solo_motion_thresholds { + __u16 thresholds[SOLO_MOTION_SZ][SOLO_MOTION_SZ]; +}; + +#define SOLO_IOC_G_MOTION_THRESHOLDS _IOR('V', BASE_VIDIOC_PRIVATE+0, struct solo_motion_thresholds) +#define SOLO_IOC_S_MOTION_THRESHOLDS _IOW('V', BASE_VIDIOC_PRIVATE+1, struct solo_motion_thresholds) + enum SOLO_I2C_STATE { IIC_STATE_IDLE, IIC_STATE_START, @@ -157,6 +171,9 @@ struct solo_enc_dev { u8 mode, gop, qp, interlaced, interval; u8 bw_weight; u16 motion_thresh; + struct solo_motion_thresholds motion_thresholds; + bool motion_global; + bool motion_enabled; u16 width; u16 height; @@ -381,8 +398,8 @@ void solo_update_mode(struct solo_enc_dev *solo_enc); /* Set the threshold for motion detection */ int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val); -int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, u16 val, - u16 block); +int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, + const struct solo_motion_thresholds *thresholds); #define SOLO_DEF_MOT_THRESH 0x0300 /* Write text on OSD */ diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index 0efb623..b1fa78b 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -511,6 +511,8 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, int ret; /* Check for motion flags */ + vb->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_MOTION_ON | + V4L2_BUF_FLAG_MOTION_DETECTED); if (solo_is_motion_on(solo_enc)) { vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_ON; if (enc_buf->motion) @@ -1018,6 +1020,31 @@ static int solo_s_parm(struct file *file, void *priv, return 0; } +static long solo_enc_default(struct file *file, void *fh, + bool valid_prio, int cmd, void *arg) +{ + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; + struct solo_motion_thresholds *thresholds = arg; + + switch (cmd) { + case SOLO_IOC_G_MOTION_THRESHOLDS: + *thresholds = solo_enc->motion_thresholds; + return 0; + + case SOLO_IOC_S_MOTION_THRESHOLDS: + if (!valid_prio) + return -EBUSY; + solo_enc->motion_thresholds = *thresholds; + if (solo_enc->motion_enabled && !solo_enc->motion_global) + return solo_set_motion_block(solo_dev, solo_enc->ch, + &solo_enc->motion_thresholds); + return 0; + default: + return -ENOTTY; + } +} + static int solo_s_ctrl(struct v4l2_ctrl *ctrl) { struct solo_enc_dev *solo_enc = @@ -1036,28 +1063,22 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_GOP_SIZE: solo_enc->gop = ctrl->val; return 0; - case V4L2_CID_MOTION_THRESHOLD: { - u16 block = (ctrl->val >> 16) & 0xffff; - u16 value = ctrl->val & 0xffff; - - /* Motion thresholds are in a table of 64x64 samples, with - * each sample representing 16x16 pixels of the source. In - * effect, 44x30 samples are used for NTSC, and 44x36 for PAL. - * The 5th sample on the 10th row is (10*64)+5 = 645. - * - * Block is 0 to set the threshold globally, or any positive - * number under 2049 to set block-1 individually. */ - /* Currently we limit support to block 0 only. A later patch - * will add a new ioctl to set all other blocks. */ - if (block == 0) { - solo_enc->motion_thresh = value; - return solo_set_motion_threshold(solo_dev, - solo_enc->ch, value); + case V4L2_CID_MOTION_THRESHOLD: + solo_enc->motion_thresh = ctrl->val; + if (!solo_enc->motion_global || !solo_enc->motion_enabled) + return 0; + return solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->val); + case V4L2_CID_MOTION_MODE: + solo_enc->motion_global = ctrl->val == 1; + solo_enc->motion_enabled = ctrl->val > 0; + if (ctrl->val) { + if (solo_enc->motion_global) + solo_set_motion_threshold(solo_dev, solo_enc->ch, + solo_enc->motion_thresh); + else + solo_set_motion_block(solo_dev, solo_enc->ch, + &solo_enc->motion_thresholds); } - return solo_set_motion_block(solo_dev, solo_enc->ch, - value, block - 1); - } - case V4L2_CID_MOTION_ENABLE: solo_motion_toggle(solo_enc, ctrl->val); return 0; case V4L2_CID_OSD_TEXT: @@ -1111,6 +1132,7 @@ static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = { .vidioc_log_status = v4l2_ctrl_log_status, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_default = solo_enc_default, }; static const struct video_device solo_enc_template = { @@ -1137,13 +1159,20 @@ static const struct v4l2_ctrl_config solo_motion_threshold_ctrl = { .flags = V4L2_CTRL_FLAG_SLIDER, }; +static const char * const solo_motion_mode_menu[] = { + "Disabled", + "Global Threshold", + "Regional Threshold", + NULL +}; + static const struct v4l2_ctrl_config solo_motion_enable_ctrl = { .ops = &solo_ctrl_ops, - .id = V4L2_CID_MOTION_ENABLE, - .name = "Motion Detection Enable", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, + .id = V4L2_CID_MOTION_MODE, + .name = "Motion Detection Mode", + .type = V4L2_CTRL_TYPE_MENU, + .qmenu = solo_motion_mode_menu, + .max = 2, }; static const struct v4l2_ctrl_config solo_osd_text_ctrl = { @@ -1161,6 +1190,7 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, struct solo_enc_dev *solo_enc; struct v4l2_ctrl_handler *hdl; int ret; + int x, y; solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL); if (!solo_enc) @@ -1201,7 +1231,12 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, solo_enc->gop = solo_dev->fps; solo_enc->interval = 1; solo_enc->mode = SOLO_ENC_MODE_CIF; + solo_enc->motion_global = true; solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH; + for (y = 0; y < SOLO_MOTION_SZ; y++) + for (x = 0; x < SOLO_MOTION_SZ; x++) + solo_enc->motion_thresholds.thresholds[y][x] = + SOLO_DEF_MOT_THRESH; solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; -- cgit v0.10.2 From dad7fab933622ee67774a9219d5c18040d97a5e5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Mar 2013 05:42:46 -0300 Subject: [media] solo6x10: rename headers Prefix the headers with 'solo6x10-'. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/core.c b/drivers/staging/media/solo6x10/core.c index 779d4b4..3675020 100644 --- a/drivers/staging/media/solo6x10/core.c +++ b/drivers/staging/media/solo6x10/core.c @@ -33,7 +33,7 @@ #include #include "solo6x10.h" -#include "tw28.h" +#include "solo6x10-tw28.h" MODULE_DESCRIPTION("Softlogic 6x10 MPEG4/H.264/G.723 CODEC V4L2/ALSA Driver"); MODULE_AUTHOR("Bluecherry "); diff --git a/drivers/staging/media/solo6x10/g723.c b/drivers/staging/media/solo6x10/g723.c index 183222e..1db18c7 100644 --- a/drivers/staging/media/solo6x10/g723.c +++ b/drivers/staging/media/solo6x10/g723.c @@ -36,7 +36,7 @@ #include #include "solo6x10.h" -#include "tw28.h" +#include "solo6x10-tw28.h" #define G723_FDMA_PAGES 32 #define G723_PERIOD_BYTES 48 diff --git a/drivers/staging/media/solo6x10/offsets.h b/drivers/staging/media/solo6x10/offsets.h deleted file mode 100644 index f005dca..0000000 --- a/drivers/staging/media/solo6x10/offsets.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2010-2013 Bluecherry, LLC - * - * Original author: - * Ben Collins - * - * Additional work by: - * John Brooks - * - * 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. - */ - -#ifndef __SOLO6X10_OFFSETS_H -#define __SOLO6X10_OFFSETS_H - -#define SOLO_DISP_EXT_ADDR 0x00000000 -#define SOLO_DISP_EXT_SIZE 0x00480000 - -#define SOLO_EOSD_EXT_ADDR \ - (SOLO_DISP_EXT_ADDR + SOLO_DISP_EXT_SIZE) -#define SOLO_EOSD_EXT_SIZE(__solo) \ - (__solo->type == SOLO_DEV_6010 ? 0x10000 : 0x20000) -#define SOLO_EOSD_EXT_SIZE_MAX 0x20000 -#define SOLO_EOSD_EXT_AREA(__solo) \ - (SOLO_EOSD_EXT_SIZE(__solo) * 32) - -#define SOLO_MOTION_EXT_ADDR(__solo) \ - (SOLO_EOSD_EXT_ADDR + SOLO_EOSD_EXT_AREA(__solo)) -#define SOLO_MOTION_EXT_SIZE 0x00080000 - -#define SOLO_G723_EXT_ADDR(__solo) \ - (SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE) -#define SOLO_G723_EXT_SIZE 0x00010000 - -#define SOLO_CAP_EXT_ADDR(__solo) \ - (SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE) - -/* 18 is the maximum number of pages required for PAL@D1, the largest frame - * possible */ -#define SOLO_CAP_PAGE_SIZE (18 << 16) - -/* Always allow the encoder enough for 16 channels, even if we have less. The - * exception is if we have card with only 32Megs of memory. */ -#define SOLO_CAP_EXT_SIZE(__solo) \ - ((((__solo->sdram_size <= (32 << 20)) ? 4 : 16) + 1) \ - * SOLO_CAP_PAGE_SIZE) - -#define SOLO_EREF_EXT_ADDR(__solo) \ - (SOLO_CAP_EXT_ADDR(__solo) + SOLO_CAP_EXT_SIZE(__solo)) -#define SOLO_EREF_EXT_SIZE 0x00140000 -#define SOLO_EREF_EXT_AREA(__solo) \ - (SOLO_EREF_EXT_SIZE * __solo->nr_chans * 2) - -#define __SOLO_JPEG_MIN_SIZE(__solo) (__solo->nr_chans * 0x00080000) - -#define SOLO_MP4E_EXT_ADDR(__solo) \ - (SOLO_EREF_EXT_ADDR(__solo) + SOLO_EREF_EXT_AREA(__solo)) -#define SOLO_MP4E_EXT_SIZE(__solo) \ - max((__solo->nr_chans * 0x00080000), \ - min(((__solo->sdram_size - SOLO_MP4E_EXT_ADDR(__solo)) - \ - __SOLO_JPEG_MIN_SIZE(__solo)), 0x00ff0000)) - -#define __SOLO_JPEG_MIN_SIZE(__solo) (__solo->nr_chans * 0x00080000) -#define SOLO_JPEG_EXT_ADDR(__solo) \ - (SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo)) -#define SOLO_JPEG_EXT_SIZE(__solo) \ - max(__SOLO_JPEG_MIN_SIZE(__solo), \ - min((__solo->sdram_size - SOLO_JPEG_EXT_ADDR(__solo)), 0x00ff0000)) - -#define SOLO_SDRAM_END(__solo) \ - (SOLO_JPEG_EXT_ADDR(__solo) + SOLO_JPEG_EXT_SIZE(__solo)) - -#endif /* __SOLO6X10_OFFSETS_H */ diff --git a/drivers/staging/media/solo6x10/registers.h b/drivers/staging/media/solo6x10/registers.h deleted file mode 100644 index 5e5c7e6..0000000 --- a/drivers/staging/media/solo6x10/registers.h +++ /dev/null @@ -1,639 +0,0 @@ -/* - * Copyright (C) 2010-2013 Bluecherry, LLC - * - * Original author: - * Ben Collins - * - * Additional work by: - * John Brooks - * - * 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. - */ - -#ifndef __SOLO6X10_REGISTERS_H -#define __SOLO6X10_REGISTERS_H - -#include "offsets.h" - -/* Global 6010 system configuration */ -#define SOLO_SYS_CFG 0x0000 -#define SOLO_SYS_CFG_FOUT_EN 0x00000001 -#define SOLO_SYS_CFG_PLL_BYPASS 0x00000002 -#define SOLO_SYS_CFG_PLL_PWDN 0x00000004 -#define SOLO_SYS_CFG_OUTDIV(__n) (((__n) & 0x003) << 3) -#define SOLO_SYS_CFG_FEEDBACKDIV(__n) (((__n) & 0x1ff) << 5) -#define SOLO_SYS_CFG_INPUTDIV(__n) (((__n) & 0x01f) << 14) -#define SOLO_SYS_CFG_CLOCK_DIV 0x00080000 -#define SOLO_SYS_CFG_NCLK_DELAY(__n) (((__n) & 0x003) << 24) -#define SOLO_SYS_CFG_PCLK_DELAY(__n) (((__n) & 0x00f) << 26) -#define SOLO_SYS_CFG_SDRAM64BIT 0x40000000 -#define SOLO_SYS_CFG_RESET 0x80000000 - -#define SOLO_DMA_CTRL 0x0004 -#define SOLO_DMA_CTRL_REFRESH_CYCLE(n) ((n)<<8) -/* 0=16/32MB, 1=32/64MB, 2=64/128MB, 3=128/256MB */ -#define SOLO_DMA_CTRL_SDRAM_SIZE(n) ((n)<<6) -#define SOLO_DMA_CTRL_SDRAM_CLK_INVERT (1<<5) -#define SOLO_DMA_CTRL_STROBE_SELECT (1<<4) -#define SOLO_DMA_CTRL_READ_DATA_SELECT (1<<3) -#define SOLO_DMA_CTRL_READ_CLK_SELECT (1<<2) -#define SOLO_DMA_CTRL_LATENCY(n) ((n)<<0) - -/* Some things we set in this are undocumented. Why Softlogic?!?! */ -#define SOLO_DMA_CTRL1 0x0008 - -#define SOLO_SYS_VCLK 0x000C -#define SOLO_VCLK_INVERT (1<<22) -/* 0=sys_clk/4, 1=sys_clk/2, 2=clk_in/2 of system input */ -#define SOLO_VCLK_SELECT(n) ((n)<<20) -#define SOLO_VCLK_VIN1415_DELAY(n) ((n)<<14) -#define SOLO_VCLK_VIN1213_DELAY(n) ((n)<<12) -#define SOLO_VCLK_VIN1011_DELAY(n) ((n)<<10) -#define SOLO_VCLK_VIN0809_DELAY(n) ((n)<<8) -#define SOLO_VCLK_VIN0607_DELAY(n) ((n)<<6) -#define SOLO_VCLK_VIN0405_DELAY(n) ((n)<<4) -#define SOLO_VCLK_VIN0203_DELAY(n) ((n)<<2) -#define SOLO_VCLK_VIN0001_DELAY(n) ((n)<<0) - -#define SOLO_IRQ_STAT 0x0010 -#define SOLO_IRQ_MASK 0x0014 -#define SOLO_IRQ_P2M(n) (1<<((n)+17)) -#define SOLO_IRQ_GPIO (1<<16) -#define SOLO_IRQ_VIDEO_LOSS (1<<15) -#define SOLO_IRQ_VIDEO_IN (1<<14) -#define SOLO_IRQ_MOTION (1<<13) -#define SOLO_IRQ_ATA_CMD (1<<12) -#define SOLO_IRQ_ATA_DIR (1<<11) -#define SOLO_IRQ_PCI_ERR (1<<10) -#define SOLO_IRQ_PS2_1 (1<<9) -#define SOLO_IRQ_PS2_0 (1<<8) -#define SOLO_IRQ_SPI (1<<7) -#define SOLO_IRQ_IIC (1<<6) -#define SOLO_IRQ_UART(n) (1<<((n) + 4)) -#define SOLO_IRQ_G723 (1<<3) -#define SOLO_IRQ_DECODER (1<<1) -#define SOLO_IRQ_ENCODER (1<<0) - -#define SOLO_CHIP_OPTION 0x001C -#define SOLO_CHIP_ID_MASK 0x00000007 - -#define SOLO_PLL_CONFIG 0x0020 /* 6110 Only */ - -#define SOLO_EEPROM_CTRL 0x0060 -#define SOLO_EEPROM_ACCESS_EN (1<<7) -#define SOLO_EEPROM_CS (1<<3) -#define SOLO_EEPROM_CLK (1<<2) -#define SOLO_EEPROM_DO (1<<1) -#define SOLO_EEPROM_DI (1<<0) -#define SOLO_EEPROM_ENABLE (SOLO_EEPROM_ACCESS_EN | SOLO_EEPROM_CS) - -#define SOLO_PCI_ERR 0x0070 -#define SOLO_PCI_ERR_FATAL 0x00000001 -#define SOLO_PCI_ERR_PARITY 0x00000002 -#define SOLO_PCI_ERR_TARGET 0x00000004 -#define SOLO_PCI_ERR_TIMEOUT 0x00000008 -#define SOLO_PCI_ERR_P2M 0x00000010 -#define SOLO_PCI_ERR_ATA 0x00000020 -#define SOLO_PCI_ERR_P2M_DESC 0x00000040 -#define SOLO_PCI_ERR_FSM0(__s) (((__s) >> 16) & 0x0f) -#define SOLO_PCI_ERR_FSM1(__s) (((__s) >> 20) & 0x0f) -#define SOLO_PCI_ERR_FSM2(__s) (((__s) >> 24) & 0x1f) - -#define SOLO_P2M_BASE 0x0080 - -#define SOLO_P2M_CONFIG(n) (0x0080 + ((n)*0x20)) -#define SOLO_P2M_DMA_INTERVAL(n) ((n)<<6)/* N*32 clocks */ -#define SOLO_P2M_CSC_BYTE_REORDER (1<<5) /* BGR -> RGB */ -/* 0:r=[14:10] g=[9:5] b=[4:0], 1:r=[15:11] g=[10:5] b=[4:0] */ -#define SOLO_P2M_CSC_16BIT_565 (1<<4) -#define SOLO_P2M_UV_SWAP (1<<3) -#define SOLO_P2M_PCI_MASTER_MODE (1<<2) -#define SOLO_P2M_DESC_INTR_OPT (1<<1) /* 1:Empty, 0:Each */ -#define SOLO_P2M_DESC_MODE (1<<0) - -#define SOLO_P2M_DES_ADR(n) (0x0084 + ((n)*0x20)) - -#define SOLO_P2M_DESC_ID(n) (0x0088 + ((n)*0x20)) -#define SOLO_P2M_UPDATE_ID(n) ((n)<<0) - -#define SOLO_P2M_STATUS(n) (0x008C + ((n)*0x20)) -#define SOLO_P2M_COMMAND_DONE (1<<8) -#define SOLO_P2M_CURRENT_ID(stat) (0xff & (stat)) - -#define SOLO_P2M_CONTROL(n) (0x0090 + ((n)*0x20)) -#define SOLO_P2M_PCI_INC(n) ((n)<<20) -#define SOLO_P2M_REPEAT(n) ((n)<<10) -/* 0:512, 1:256, 2:128, 3:64, 4:32, 5:128(2page) */ -#define SOLO_P2M_BURST_SIZE(n) ((n)<<7) -#define SOLO_P2M_BURST_512 0 -#define SOLO_P2M_BURST_256 1 -#define SOLO_P2M_BURST_128 2 -#define SOLO_P2M_BURST_64 3 -#define SOLO_P2M_BURST_32 4 -#define SOLO_P2M_CSC_16BIT (1<<6) /* 0:24bit, 1:16bit */ -/* 0:Y[0]<-0(OFF), 1:Y[0]<-1(ON), 2:Y[0]<-G[0], 3:Y[0]<-Bit[15] */ -#define SOLO_P2M_ALPHA_MODE(n) ((n)<<4) -#define SOLO_P2M_CSC_ON (1<<3) -#define SOLO_P2M_INTERRUPT_REQ (1<<2) -#define SOLO_P2M_WRITE (1<<1) -#define SOLO_P2M_TRANS_ON (1<<0) - -#define SOLO_P2M_EXT_CFG(n) (0x0094 + ((n)*0x20)) -#define SOLO_P2M_EXT_INC(n) ((n)<<20) -#define SOLO_P2M_COPY_SIZE(n) ((n)<<0) - -#define SOLO_P2M_TAR_ADR(n) (0x0098 + ((n)*0x20)) - -#define SOLO_P2M_EXT_ADR(n) (0x009C + ((n)*0x20)) - -#define SOLO_P2M_BUFFER(i) (0x2000 + ((i)*4)) - -#define SOLO_VI_CH_SWITCH_0 0x0100 -#define SOLO_VI_CH_SWITCH_1 0x0104 -#define SOLO_VI_CH_SWITCH_2 0x0108 - -#define SOLO_VI_CH_ENA 0x010C -#define SOLO_VI_CH_FORMAT 0x0110 -#define SOLO_VI_FD_SEL_MASK(n) ((n)<<16) -#define SOLO_VI_PROG_MASK(n) ((n)<<0) - -#define SOLO_VI_FMT_CFG 0x0114 -#define SOLO_VI_FMT_CHECK_VCOUNT (1<<31) -#define SOLO_VI_FMT_CHECK_HCOUNT (1<<30) -#define SOLO_VI_FMT_TEST_SIGNAL (1<<28) - -#define SOLO_VI_PAGE_SW 0x0118 -#define SOLO_FI_INV_DISP_LIVE(n) ((n)<<8) -#define SOLO_FI_INV_DISP_OUT(n) ((n)<<7) -#define SOLO_DISP_SYNC_FI(n) ((n)<<6) -#define SOLO_PIP_PAGE_ADD(n) ((n)<<3) -#define SOLO_NORMAL_PAGE_ADD(n) ((n)<<0) - -#define SOLO_VI_ACT_I_P 0x011C -#define SOLO_VI_ACT_I_S 0x0120 -#define SOLO_VI_ACT_P 0x0124 -#define SOLO_VI_FI_INVERT (1<<31) -#define SOLO_VI_H_START(n) ((n)<<21) -#define SOLO_VI_V_START(n) ((n)<<11) -#define SOLO_VI_V_STOP(n) ((n)<<0) - -#define SOLO_VI_STATUS0 0x0128 -#define SOLO_VI_STATUS0_PAGE(__n) ((__n) & 0x07) -#define SOLO_VI_STATUS1 0x012C - -/* XXX: Might be better off in kernel level disp.h */ -#define DISP_PAGE(stat) ((stat) & 0x07) - -#define SOLO_VI_PB_CONFIG 0x0130 -#define SOLO_VI_PB_USER_MODE (1<<1) -#define SOLO_VI_PB_PAL (1<<0) -#define SOLO_VI_PB_RANGE_HV 0x0134 -#define SOLO_VI_PB_HSIZE(h) ((h)<<12) -#define SOLO_VI_PB_VSIZE(v) ((v)<<0) -#define SOLO_VI_PB_ACT_H 0x0138 -#define SOLO_VI_PB_HSTART(n) ((n)<<12) -#define SOLO_VI_PB_HSTOP(n) ((n)<<0) -#define SOLO_VI_PB_ACT_V 0x013C -#define SOLO_VI_PB_VSTART(n) ((n)<<12) -#define SOLO_VI_PB_VSTOP(n) ((n)<<0) - -#define SOLO_VI_MOSAIC(ch) (0x0140 + ((ch)*4)) -#define SOLO_VI_MOSAIC_SX(x) ((x)<<24) -#define SOLO_VI_MOSAIC_EX(x) ((x)<<16) -#define SOLO_VI_MOSAIC_SY(x) ((x)<<8) -#define SOLO_VI_MOSAIC_EY(x) ((x)<<0) - -#define SOLO_VI_WIN_CTRL0(ch) (0x0180 + ((ch)*4)) -#define SOLO_VI_WIN_CTRL1(ch) (0x01C0 + ((ch)*4)) - -#define SOLO_VI_WIN_CHANNEL(n) ((n)<<28) - -#define SOLO_VI_WIN_PIP(n) ((n)<<27) -#define SOLO_VI_WIN_SCALE(n) ((n)<<24) - -#define SOLO_VI_WIN_SX(x) ((x)<<12) -#define SOLO_VI_WIN_EX(x) ((x)<<0) - -#define SOLO_VI_WIN_SY(x) ((x)<<12) -#define SOLO_VI_WIN_EY(x) ((x)<<0) - -#define SOLO_VI_WIN_ON(ch) (0x0200 + ((ch)*4)) - -#define SOLO_VI_WIN_SW 0x0240 -#define SOLO_VI_WIN_LIVE_AUTO_MUTE 0x0244 - -#define SOLO_VI_MOT_ADR 0x0260 -#define SOLO_VI_MOTION_EN(mask) ((mask)<<16) -#define SOLO_VI_MOT_CTRL 0x0264 -#define SOLO_VI_MOTION_FRAME_COUNT(n) ((n)<<24) -#define SOLO_VI_MOTION_SAMPLE_LENGTH(n) ((n)<<16) -#define SOLO_VI_MOTION_INTR_START_STOP (1<<15) -#define SOLO_VI_MOTION_FREEZE_DATA (1<<14) -#define SOLO_VI_MOTION_SAMPLE_COUNT(n) ((n)<<0) -#define SOLO_VI_MOT_CLEAR 0x0268 -#define SOLO_VI_MOT_STATUS 0x026C -#define SOLO_VI_MOTION_CNT(n) ((n)<<0) -#define SOLO_VI_MOTION_BORDER 0x0270 -#define SOLO_VI_MOTION_BAR 0x0274 -#define SOLO_VI_MOTION_Y_SET (1<<29) -#define SOLO_VI_MOTION_Y_ADD (1<<28) -#define SOLO_VI_MOTION_CB_SET (1<<27) -#define SOLO_VI_MOTION_CB_ADD (1<<26) -#define SOLO_VI_MOTION_CR_SET (1<<25) -#define SOLO_VI_MOTION_CR_ADD (1<<24) -#define SOLO_VI_MOTION_Y_VALUE(v) ((v)<<16) -#define SOLO_VI_MOTION_CB_VALUE(v) ((v)<<8) -#define SOLO_VI_MOTION_CR_VALUE(v) ((v)<<0) - -#define SOLO_VO_FMT_ENC 0x0300 -#define SOLO_VO_SCAN_MODE_PROGRESSIVE (1<<31) -#define SOLO_VO_FMT_TYPE_PAL (1<<30) -#define SOLO_VO_FMT_TYPE_NTSC 0 -#define SOLO_VO_USER_SET (1<<29) - -#define SOLO_VO_FI_CHANGE (1<<20) -#define SOLO_VO_USER_COLOR_SET_VSYNC (1<<19) -#define SOLO_VO_USER_COLOR_SET_HSYNC (1<<18) -#define SOLO_VO_USER_COLOR_SET_NAH (1<<17) -#define SOLO_VO_USER_COLOR_SET_NAV (1<<16) -#define SOLO_VO_NA_COLOR_Y(Y) ((Y)<<8) -#define SOLO_VO_NA_COLOR_CB(CB) (((CB)/16)<<4) -#define SOLO_VO_NA_COLOR_CR(CR) (((CR)/16)<<0) - -#define SOLO_VO_ACT_H 0x0304 -#define SOLO_VO_H_BLANK(n) ((n)<<22) -#define SOLO_VO_H_START(n) ((n)<<11) -#define SOLO_VO_H_STOP(n) ((n)<<0) - -#define SOLO_VO_ACT_V 0x0308 -#define SOLO_VO_V_BLANK(n) ((n)<<22) -#define SOLO_VO_V_START(n) ((n)<<11) -#define SOLO_VO_V_STOP(n) ((n)<<0) - -#define SOLO_VO_RANGE_HV 0x030C -#define SOLO_VO_SYNC_INVERT (1<<24) -#define SOLO_VO_HSYNC_INVERT (1<<23) -#define SOLO_VO_VSYNC_INVERT (1<<22) -#define SOLO_VO_H_LEN(n) ((n)<<11) -#define SOLO_VO_V_LEN(n) ((n)<<0) - -#define SOLO_VO_DISP_CTRL 0x0310 -#define SOLO_VO_DISP_ON (1<<31) -#define SOLO_VO_DISP_ERASE_COUNT(n) ((n&0xf)<<24) -#define SOLO_VO_DISP_DOUBLE_SCAN (1<<22) -#define SOLO_VO_DISP_SINGLE_PAGE (1<<21) -#define SOLO_VO_DISP_BASE(n) (((n)>>16) & 0xffff) - -#define SOLO_VO_DISP_ERASE 0x0314 -#define SOLO_VO_DISP_ERASE_ON (1<<0) - -#define SOLO_VO_ZOOM_CTRL 0x0318 -#define SOLO_VO_ZOOM_VER_ON (1<<24) -#define SOLO_VO_ZOOM_HOR_ON (1<<23) -#define SOLO_VO_ZOOM_V_COMP (1<<22) -#define SOLO_VO_ZOOM_SX(h) (((h)/2)<<11) -#define SOLO_VO_ZOOM_SY(v) (((v)/2)<<0) - -#define SOLO_VO_FREEZE_CTRL 0x031C -#define SOLO_VO_FREEZE_ON (1<<1) -#define SOLO_VO_FREEZE_INTERPOLATION (1<<0) - -#define SOLO_VO_BKG_COLOR 0x0320 -#define SOLO_BG_Y(y) ((y)<<16) -#define SOLO_BG_U(u) ((u)<<8) -#define SOLO_BG_V(v) ((v)<<0) - -#define SOLO_VO_DEINTERLACE 0x0324 -#define SOLO_VO_DEINTERLACE_THRESHOLD(n) ((n)<<8) -#define SOLO_VO_DEINTERLACE_EDGE_VALUE(n) ((n)<<0) - -#define SOLO_VO_BORDER_LINE_COLOR 0x0330 -#define SOLO_VO_BORDER_FILL_COLOR 0x0334 -#define SOLO_VO_BORDER_LINE_MASK 0x0338 -#define SOLO_VO_BORDER_FILL_MASK 0x033c - -#define SOLO_VO_BORDER_X(n) (0x0340+((n)*4)) -#define SOLO_VO_BORDER_Y(n) (0x0354+((n)*4)) - -#define SOLO_VO_CELL_EXT_SET 0x0368 -#define SOLO_VO_CELL_EXT_START 0x036c -#define SOLO_VO_CELL_EXT_STOP 0x0370 - -#define SOLO_VO_CELL_EXT_SET2 0x0374 -#define SOLO_VO_CELL_EXT_START2 0x0378 -#define SOLO_VO_CELL_EXT_STOP2 0x037c - -#define SOLO_VO_RECTANGLE_CTRL(n) (0x0368+((n)*12)) -#define SOLO_VO_RECTANGLE_START(n) (0x036c+((n)*12)) -#define SOLO_VO_RECTANGLE_STOP(n) (0x0370+((n)*12)) - -#define SOLO_VO_CURSOR_POS (0x0380) -#define SOLO_VO_CURSOR_CLR (0x0384) -#define SOLO_VO_CURSOR_CLR2 (0x0388) -#define SOLO_VO_CURSOR_MASK(id) (0x0390+((id)*4)) - -#define SOLO_VO_EXPANSION(id) (0x0250+((id)*4)) - -#define SOLO_OSG_CONFIG 0x03E0 -#define SOLO_VO_OSG_ON (1<<31) -#define SOLO_VO_OSG_COLOR_MUTE (1<<28) -#define SOLO_VO_OSG_ALPHA_RATE(n) ((n)<<22) -#define SOLO_VO_OSG_ALPHA_BG_RATE(n) ((n)<<16) -#define SOLO_VO_OSG_BASE(offset) (((offset)>>16)&0xffff) - -#define SOLO_OSG_ERASE 0x03E4 -#define SOLO_OSG_ERASE_ON (0x80) -#define SOLO_OSG_ERASE_OFF (0x00) - -#define SOLO_VO_OSG_BLINK 0x03E8 -#define SOLO_VO_OSG_BLINK_ON (1<<1) -#define SOLO_VO_OSG_BLINK_INTREVAL18 (1<<0) - -#define SOLO_CAP_BASE 0x0400 -#define SOLO_CAP_MAX_PAGE(n) ((n)<<16) -#define SOLO_CAP_BASE_ADDR(n) ((n)<<0) -#define SOLO_CAP_BTW 0x0404 -#define SOLO_CAP_PROG_BANDWIDTH(n) ((n)<<8) -#define SOLO_CAP_MAX_BANDWIDTH(n) ((n)<<0) - -#define SOLO_DIM_SCALE1 0x0408 -#define SOLO_DIM_SCALE2 0x040C -#define SOLO_DIM_SCALE3 0x0410 -#define SOLO_DIM_SCALE4 0x0414 -#define SOLO_DIM_SCALE5 0x0418 -#define SOLO_DIM_V_MB_NUM_FRAME(n) ((n)<<16) -#define SOLO_DIM_V_MB_NUM_FIELD(n) ((n)<<8) -#define SOLO_DIM_H_MB_NUM(n) ((n)<<0) - -#define SOLO_DIM_PROG 0x041C -#define SOLO_CAP_STATUS 0x0420 - -#define SOLO_CAP_CH_SCALE(ch) (0x0440+((ch)*4)) -#define SOLO_CAP_CH_COMP_ENA_E(ch) (0x0480+((ch)*4)) -#define SOLO_CAP_CH_INTV(ch) (0x04C0+((ch)*4)) -#define SOLO_CAP_CH_INTV_E(ch) (0x0500+((ch)*4)) - - -#define SOLO_VE_CFG0 0x0610 -#define SOLO_VE_TWO_PAGE_MODE (1<<31) -#define SOLO_VE_INTR_CTRL(n) ((n)<<24) -#define SOLO_VE_BLOCK_SIZE(n) ((n)<<16) -#define SOLO_VE_BLOCK_BASE(n) ((n)<<0) - -#define SOLO_VE_CFG1 0x0614 -#define SOLO_VE_BYTE_ALIGN(n) ((n)<<24) -#define SOLO_VE_INSERT_INDEX (1<<18) -#define SOLO_VE_MOTION_MODE(n) ((n)<<16) -#define SOLO_VE_MOTION_BASE(n) ((n)<<0) -#define SOLO_VE_MPEG_SIZE_H(n) ((n)<<28) /* 6110 Only */ -#define SOLO_VE_JPEG_SIZE_H(n) ((n)<<20) /* 6110 Only */ -#define SOLO_VE_INSERT_INDEX_JPEG (1<<19) /* 6110 Only */ - -#define SOLO_VE_WMRK_POLY 0x061C -#define SOLO_VE_VMRK_INIT_KEY 0x0620 -#define SOLO_VE_WMRK_STRL 0x0624 -#define SOLO_VE_ENCRYP_POLY 0x0628 -#define SOLO_VE_ENCRYP_INIT 0x062C -#define SOLO_VE_ATTR 0x0630 -#define SOLO_VE_LITTLE_ENDIAN (1<<31) -#define SOLO_COMP_ATTR_RN (1<<30) -#define SOLO_COMP_ATTR_FCODE(n) ((n)<<27) -#define SOLO_COMP_TIME_INC(n) ((n)<<25) -#define SOLO_COMP_TIME_WIDTH(n) ((n)<<21) -#define SOLO_DCT_INTERVAL(n) ((n)<<16) -#define SOLO_VE_COMPT_MOT 0x0634 /* 6110 Only */ - -#define SOLO_VE_STATE(n) (0x0640+((n)*4)) - -#define SOLO_VE_JPEG_QP_TBL 0x0670 -#define SOLO_VE_JPEG_QP_CH_L 0x0674 -#define SOLO_VE_JPEG_QP_CH_H 0x0678 -#define SOLO_VE_JPEG_CFG 0x067C -#define SOLO_VE_JPEG_CTRL 0x0680 -#define SOLO_VE_CODE_ENCRYPT 0x0684 /* 6110 Only */ -#define SOLO_VE_JPEG_CFG1 0x0688 /* 6110 Only */ -#define SOLO_VE_WMRK_ENABLE 0x068C /* 6110 Only */ -#define SOLO_VE_OSD_CH 0x0690 -#define SOLO_VE_OSD_BASE 0x0694 -#define SOLO_VE_OSD_CLR 0x0698 -#define SOLO_VE_OSD_OPT 0x069C -#define SOLO_VE_OSD_V_DOUBLE (1<<16) /* 6110 Only */ -#define SOLO_VE_OSD_H_SHADOW (1<<15) -#define SOLO_VE_OSD_V_SHADOW (1<<14) -#define SOLO_VE_OSD_H_OFFSET(n) ((n & 0x7f)<<7) -#define SOLO_VE_OSD_V_OFFSET(n) (n & 0x7f) - -#define SOLO_VE_CH_INTL(ch) (0x0700+((ch)*4)) -#define SOLO_VE_CH_MOT(ch) (0x0740+((ch)*4)) -#define SOLO_VE_CH_QP(ch) (0x0780+((ch)*4)) -#define SOLO_VE_CH_QP_E(ch) (0x07C0+((ch)*4)) -#define SOLO_VE_CH_GOP(ch) (0x0800+((ch)*4)) -#define SOLO_VE_CH_GOP_E(ch) (0x0840+((ch)*4)) -#define SOLO_VE_CH_REF_BASE(ch) (0x0880+((ch)*4)) -#define SOLO_VE_CH_REF_BASE_E(ch) (0x08C0+((ch)*4)) - -#define SOLO_VE_MPEG4_QUE(n) (0x0A00+((n)*8)) -#define SOLO_VE_JPEG_QUE(n) (0x0A04+((n)*8)) - -#define SOLO_VD_CFG0 0x0900 -#define SOLO_VD_CFG_NO_WRITE_NO_WINDOW (1<<24) -#define SOLO_VD_CFG_BUSY_WIAT_CODE (1<<23) -#define SOLO_VD_CFG_BUSY_WIAT_REF (1<<22) -#define SOLO_VD_CFG_BUSY_WIAT_RES (1<<21) -#define SOLO_VD_CFG_BUSY_WIAT_MS (1<<20) -#define SOLO_VD_CFG_SINGLE_MODE (1<<18) -#define SOLO_VD_CFG_SCAL_MANUAL (1<<17) -#define SOLO_VD_CFG_USER_PAGE_CTRL (1<<16) -#define SOLO_VD_CFG_LITTLE_ENDIAN (1<<15) -#define SOLO_VD_CFG_START_FI (1<<14) -#define SOLO_VD_CFG_ERR_LOCK (1<<13) -#define SOLO_VD_CFG_ERR_INT_ENA (1<<12) -#define SOLO_VD_CFG_TIME_WIDTH(n) ((n)<<8) -#define SOLO_VD_CFG_DCT_INTERVAL(n) ((n)<<0) - -#define SOLO_VD_CFG1 0x0904 - -#define SOLO_VD_DEINTERLACE 0x0908 -#define SOLO_VD_DEINTERLACE_THRESHOLD(n) ((n)<<8) -#define SOLO_VD_DEINTERLACE_EDGE_VALUE(n) ((n)<<0) - -#define SOLO_VD_CODE_ADR 0x090C - -#define SOLO_VD_CTRL 0x0910 -#define SOLO_VD_OPER_ON (1<<31) -#define SOLO_VD_MAX_ITEM(n) ((n)<<0) - -#define SOLO_VD_STATUS0 0x0920 -#define SOLO_VD_STATUS0_INTR_ACK (1<<22) -#define SOLO_VD_STATUS0_INTR_EMPTY (1<<21) -#define SOLO_VD_STATUS0_INTR_ERR (1<<20) - -#define SOLO_VD_STATUS1 0x0924 - -#define SOLO_VD_IDX0 0x0930 -#define SOLO_VD_IDX_INTERLACE (1<<30) -#define SOLO_VD_IDX_CHANNEL(n) ((n)<<24) -#define SOLO_VD_IDX_SIZE(n) ((n)<<0) - -#define SOLO_VD_IDX1 0x0934 -#define SOLO_VD_IDX_SRC_SCALE(n) ((n)<<28) -#define SOLO_VD_IDX_WINDOW(n) ((n)<<24) -#define SOLO_VD_IDX_DEINTERLACE (1<<16) -#define SOLO_VD_IDX_H_BLOCK(n) ((n)<<8) -#define SOLO_VD_IDX_V_BLOCK(n) ((n)<<0) - -#define SOLO_VD_IDX2 0x0938 -#define SOLO_VD_IDX_REF_BASE_SIDE (1<<31) -#define SOLO_VD_IDX_REF_BASE(n) (((n)>>16)&0xffff) - -#define SOLO_VD_IDX3 0x093C -#define SOLO_VD_IDX_DISP_SCALE(n) ((n)<<28) -#define SOLO_VD_IDX_INTERLACE_WR (1<<27) -#define SOLO_VD_IDX_INTERPOL (1<<26) -#define SOLO_VD_IDX_HOR2X (1<<25) -#define SOLO_VD_IDX_OFFSET_X(n) ((n)<<12) -#define SOLO_VD_IDX_OFFSET_Y(n) ((n)<<0) - -#define SOLO_VD_IDX4 0x0940 -#define SOLO_VD_IDX_DEC_WR_PAGE(n) ((n)<<8) -#define SOLO_VD_IDX_DISP_RD_PAGE(n) ((n)<<0) - -#define SOLO_VD_WR_PAGE(n) (0x03F0 + ((n) * 4)) - - -#define SOLO_GPIO_CONFIG_0 0x0B00 -#define SOLO_GPIO_CONFIG_1 0x0B04 -#define SOLO_GPIO_DATA_OUT 0x0B08 -#define SOLO_GPIO_DATA_IN 0x0B0C -#define SOLO_GPIO_INT_ACK_STA 0x0B10 -#define SOLO_GPIO_INT_ENA 0x0B14 -#define SOLO_GPIO_INT_CFG_0 0x0B18 -#define SOLO_GPIO_INT_CFG_1 0x0B1C - - -#define SOLO_IIC_CFG 0x0B20 -#define SOLO_IIC_ENABLE (1<<8) -#define SOLO_IIC_PRESCALE(n) ((n)<<0) - -#define SOLO_IIC_CTRL 0x0B24 -#define SOLO_IIC_AUTO_CLEAR (1<<20) -#define SOLO_IIC_STATE_RX_ACK (1<<19) -#define SOLO_IIC_STATE_BUSY (1<<18) -#define SOLO_IIC_STATE_SIG_ERR (1<<17) -#define SOLO_IIC_STATE_TRNS (1<<16) -#define SOLO_IIC_CH_SET(n) ((n)<<5) -#define SOLO_IIC_ACK_EN (1<<4) -#define SOLO_IIC_START (1<<3) -#define SOLO_IIC_STOP (1<<2) -#define SOLO_IIC_READ (1<<1) -#define SOLO_IIC_WRITE (1<<0) - -#define SOLO_IIC_TXD 0x0B28 -#define SOLO_IIC_RXD 0x0B2C - -/* - * UART REGISTER - */ -#define SOLO_UART_CONTROL(n) (0x0BA0 + ((n)*0x20)) -#define SOLO_UART_CLK_DIV(n) ((n)<<24) -#define SOLO_MODEM_CTRL_EN (1<<20) -#define SOLO_PARITY_ERROR_DROP (1<<18) -#define SOLO_IRQ_ERR_EN (1<<17) -#define SOLO_IRQ_RX_EN (1<<16) -#define SOLO_IRQ_TX_EN (1<<15) -#define SOLO_RX_EN (1<<14) -#define SOLO_TX_EN (1<<13) -#define SOLO_UART_HALF_DUPLEX (1<<12) -#define SOLO_UART_LOOPBACK (1<<11) - -#define SOLO_BAUDRATE_230400 ((0<<9)|(0<<6)) -#define SOLO_BAUDRATE_115200 ((0<<9)|(1<<6)) -#define SOLO_BAUDRATE_57600 ((0<<9)|(2<<6)) -#define SOLO_BAUDRATE_38400 ((0<<9)|(3<<6)) -#define SOLO_BAUDRATE_19200 ((0<<9)|(4<<6)) -#define SOLO_BAUDRATE_9600 ((0<<9)|(5<<6)) -#define SOLO_BAUDRATE_4800 ((0<<9)|(6<<6)) -#define SOLO_BAUDRATE_2400 ((1<<9)|(6<<6)) -#define SOLO_BAUDRATE_1200 ((2<<9)|(6<<6)) -#define SOLO_BAUDRATE_300 ((3<<9)|(6<<6)) - -#define SOLO_UART_DATA_BIT_8 (3<<4) -#define SOLO_UART_DATA_BIT_7 (2<<4) -#define SOLO_UART_DATA_BIT_6 (1<<4) -#define SOLO_UART_DATA_BIT_5 (0<<4) - -#define SOLO_UART_STOP_BIT_1 (0<<2) -#define SOLO_UART_STOP_BIT_2 (1<<2) - -#define SOLO_UART_PARITY_NONE (0<<0) -#define SOLO_UART_PARITY_EVEN (2<<0) -#define SOLO_UART_PARITY_ODD (3<<0) - -#define SOLO_UART_STATUS(n) (0x0BA4 + ((n)*0x20)) -#define SOLO_UART_CTS (1<<15) -#define SOLO_UART_RX_BUSY (1<<14) -#define SOLO_UART_OVERRUN (1<<13) -#define SOLO_UART_FRAME_ERR (1<<12) -#define SOLO_UART_PARITY_ERR (1<<11) -#define SOLO_UART_TX_BUSY (1<<5) - -#define SOLO_UART_RX_BUFF_CNT(stat) (((stat)>>6) & 0x1f) -#define SOLO_UART_RX_BUFF_SIZE 8 -#define SOLO_UART_TX_BUFF_CNT(stat) (((stat)>>0) & 0x1f) -#define SOLO_UART_TX_BUFF_SIZE 8 - -#define SOLO_UART_TX_DATA(n) (0x0BA8 + ((n)*0x20)) -#define SOLO_UART_TX_DATA_PUSH (1<<8) -#define SOLO_UART_RX_DATA(n) (0x0BAC + ((n)*0x20)) -#define SOLO_UART_RX_DATA_POP (1<<8) - -#define SOLO_TIMER_CLOCK_NUM 0x0be0 -#define SOLO_TIMER_USEC 0x0be8 -#define SOLO_TIMER_SEC 0x0bec -#define SOLO_TIMER_USEC_LSB 0x0d20 /* 6110 Only */ - -#define SOLO_AUDIO_CONTROL 0x0D00 -#define SOLO_AUDIO_ENABLE (1<<31) -#define SOLO_AUDIO_MASTER_MODE (1<<30) -#define SOLO_AUDIO_I2S_MODE (1<<29) -#define SOLO_AUDIO_I2S_LR_SWAP (1<<27) -#define SOLO_AUDIO_I2S_8BIT (1<<26) -#define SOLO_AUDIO_I2S_MULTI(n) ((n)<<24) -#define SOLO_AUDIO_MIX_9TO0 (1<<23) -#define SOLO_AUDIO_DEC_9TO0_VOL(n) ((n)<<20) -#define SOLO_AUDIO_MIX_19TO10 (1<<19) -#define SOLO_AUDIO_DEC_19TO10_VOL(n) ((n)<<16) -#define SOLO_AUDIO_MODE(n) ((n)<<0) -#define SOLO_AUDIO_SAMPLE 0x0D04 -#define SOLO_AUDIO_EE_MODE_ON (1<<30) -#define SOLO_AUDIO_EE_ENC_CH(ch) ((ch)<<25) -#define SOLO_AUDIO_BITRATE(n) ((n)<<16) -#define SOLO_AUDIO_CLK_DIV(n) ((n)<<0) -#define SOLO_AUDIO_FDMA_INTR 0x0D08 -#define SOLO_AUDIO_FDMA_INTERVAL(n) ((n)<<19) -#define SOLO_AUDIO_INTR_ORDER(n) ((n)<<16) -#define SOLO_AUDIO_FDMA_BASE(n) ((n)<<0) -#define SOLO_AUDIO_EVOL_0 0x0D0C -#define SOLO_AUDIO_EVOL_1 0x0D10 -#define SOLO_AUDIO_EVOL(ch, value) ((value)<<((ch)%10)) -#define SOLO_AUDIO_STA 0x0D14 - -/* - * Watchdog configuration - */ -#define SOLO_WATCHDOG 0x0be4 -#define SOLO_WATCHDOG_SET(status, sec) (status << 8 | (sec & 0xff)) - -#endif /* __SOLO6X10_REGISTERS_H */ diff --git a/drivers/staging/media/solo6x10/solo6x10-offsets.h b/drivers/staging/media/solo6x10/solo6x10-offsets.h new file mode 100644 index 0000000..f005dca --- /dev/null +++ b/drivers/staging/media/solo6x10/solo6x10-offsets.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +#ifndef __SOLO6X10_OFFSETS_H +#define __SOLO6X10_OFFSETS_H + +#define SOLO_DISP_EXT_ADDR 0x00000000 +#define SOLO_DISP_EXT_SIZE 0x00480000 + +#define SOLO_EOSD_EXT_ADDR \ + (SOLO_DISP_EXT_ADDR + SOLO_DISP_EXT_SIZE) +#define SOLO_EOSD_EXT_SIZE(__solo) \ + (__solo->type == SOLO_DEV_6010 ? 0x10000 : 0x20000) +#define SOLO_EOSD_EXT_SIZE_MAX 0x20000 +#define SOLO_EOSD_EXT_AREA(__solo) \ + (SOLO_EOSD_EXT_SIZE(__solo) * 32) + +#define SOLO_MOTION_EXT_ADDR(__solo) \ + (SOLO_EOSD_EXT_ADDR + SOLO_EOSD_EXT_AREA(__solo)) +#define SOLO_MOTION_EXT_SIZE 0x00080000 + +#define SOLO_G723_EXT_ADDR(__solo) \ + (SOLO_MOTION_EXT_ADDR(__solo) + SOLO_MOTION_EXT_SIZE) +#define SOLO_G723_EXT_SIZE 0x00010000 + +#define SOLO_CAP_EXT_ADDR(__solo) \ + (SOLO_G723_EXT_ADDR(__solo) + SOLO_G723_EXT_SIZE) + +/* 18 is the maximum number of pages required for PAL@D1, the largest frame + * possible */ +#define SOLO_CAP_PAGE_SIZE (18 << 16) + +/* Always allow the encoder enough for 16 channels, even if we have less. The + * exception is if we have card with only 32Megs of memory. */ +#define SOLO_CAP_EXT_SIZE(__solo) \ + ((((__solo->sdram_size <= (32 << 20)) ? 4 : 16) + 1) \ + * SOLO_CAP_PAGE_SIZE) + +#define SOLO_EREF_EXT_ADDR(__solo) \ + (SOLO_CAP_EXT_ADDR(__solo) + SOLO_CAP_EXT_SIZE(__solo)) +#define SOLO_EREF_EXT_SIZE 0x00140000 +#define SOLO_EREF_EXT_AREA(__solo) \ + (SOLO_EREF_EXT_SIZE * __solo->nr_chans * 2) + +#define __SOLO_JPEG_MIN_SIZE(__solo) (__solo->nr_chans * 0x00080000) + +#define SOLO_MP4E_EXT_ADDR(__solo) \ + (SOLO_EREF_EXT_ADDR(__solo) + SOLO_EREF_EXT_AREA(__solo)) +#define SOLO_MP4E_EXT_SIZE(__solo) \ + max((__solo->nr_chans * 0x00080000), \ + min(((__solo->sdram_size - SOLO_MP4E_EXT_ADDR(__solo)) - \ + __SOLO_JPEG_MIN_SIZE(__solo)), 0x00ff0000)) + +#define __SOLO_JPEG_MIN_SIZE(__solo) (__solo->nr_chans * 0x00080000) +#define SOLO_JPEG_EXT_ADDR(__solo) \ + (SOLO_MP4E_EXT_ADDR(__solo) + SOLO_MP4E_EXT_SIZE(__solo)) +#define SOLO_JPEG_EXT_SIZE(__solo) \ + max(__SOLO_JPEG_MIN_SIZE(__solo), \ + min((__solo->sdram_size - SOLO_JPEG_EXT_ADDR(__solo)), 0x00ff0000)) + +#define SOLO_SDRAM_END(__solo) \ + (SOLO_JPEG_EXT_ADDR(__solo) + SOLO_JPEG_EXT_SIZE(__solo)) + +#endif /* __SOLO6X10_OFFSETS_H */ diff --git a/drivers/staging/media/solo6x10/solo6x10-regs.h b/drivers/staging/media/solo6x10/solo6x10-regs.h new file mode 100644 index 0000000..428f6c9 --- /dev/null +++ b/drivers/staging/media/solo6x10/solo6x10-regs.h @@ -0,0 +1,639 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +#ifndef __SOLO6X10_REGISTERS_H +#define __SOLO6X10_REGISTERS_H + +#include "solo6x10-offsets.h" + +/* Global 6010 system configuration */ +#define SOLO_SYS_CFG 0x0000 +#define SOLO_SYS_CFG_FOUT_EN 0x00000001 +#define SOLO_SYS_CFG_PLL_BYPASS 0x00000002 +#define SOLO_SYS_CFG_PLL_PWDN 0x00000004 +#define SOLO_SYS_CFG_OUTDIV(__n) (((__n) & 0x003) << 3) +#define SOLO_SYS_CFG_FEEDBACKDIV(__n) (((__n) & 0x1ff) << 5) +#define SOLO_SYS_CFG_INPUTDIV(__n) (((__n) & 0x01f) << 14) +#define SOLO_SYS_CFG_CLOCK_DIV 0x00080000 +#define SOLO_SYS_CFG_NCLK_DELAY(__n) (((__n) & 0x003) << 24) +#define SOLO_SYS_CFG_PCLK_DELAY(__n) (((__n) & 0x00f) << 26) +#define SOLO_SYS_CFG_SDRAM64BIT 0x40000000 +#define SOLO_SYS_CFG_RESET 0x80000000 + +#define SOLO_DMA_CTRL 0x0004 +#define SOLO_DMA_CTRL_REFRESH_CYCLE(n) ((n)<<8) +/* 0=16/32MB, 1=32/64MB, 2=64/128MB, 3=128/256MB */ +#define SOLO_DMA_CTRL_SDRAM_SIZE(n) ((n)<<6) +#define SOLO_DMA_CTRL_SDRAM_CLK_INVERT (1<<5) +#define SOLO_DMA_CTRL_STROBE_SELECT (1<<4) +#define SOLO_DMA_CTRL_READ_DATA_SELECT (1<<3) +#define SOLO_DMA_CTRL_READ_CLK_SELECT (1<<2) +#define SOLO_DMA_CTRL_LATENCY(n) ((n)<<0) + +/* Some things we set in this are undocumented. Why Softlogic?!?! */ +#define SOLO_DMA_CTRL1 0x0008 + +#define SOLO_SYS_VCLK 0x000C +#define SOLO_VCLK_INVERT (1<<22) +/* 0=sys_clk/4, 1=sys_clk/2, 2=clk_in/2 of system input */ +#define SOLO_VCLK_SELECT(n) ((n)<<20) +#define SOLO_VCLK_VIN1415_DELAY(n) ((n)<<14) +#define SOLO_VCLK_VIN1213_DELAY(n) ((n)<<12) +#define SOLO_VCLK_VIN1011_DELAY(n) ((n)<<10) +#define SOLO_VCLK_VIN0809_DELAY(n) ((n)<<8) +#define SOLO_VCLK_VIN0607_DELAY(n) ((n)<<6) +#define SOLO_VCLK_VIN0405_DELAY(n) ((n)<<4) +#define SOLO_VCLK_VIN0203_DELAY(n) ((n)<<2) +#define SOLO_VCLK_VIN0001_DELAY(n) ((n)<<0) + +#define SOLO_IRQ_STAT 0x0010 +#define SOLO_IRQ_MASK 0x0014 +#define SOLO_IRQ_P2M(n) (1<<((n)+17)) +#define SOLO_IRQ_GPIO (1<<16) +#define SOLO_IRQ_VIDEO_LOSS (1<<15) +#define SOLO_IRQ_VIDEO_IN (1<<14) +#define SOLO_IRQ_MOTION (1<<13) +#define SOLO_IRQ_ATA_CMD (1<<12) +#define SOLO_IRQ_ATA_DIR (1<<11) +#define SOLO_IRQ_PCI_ERR (1<<10) +#define SOLO_IRQ_PS2_1 (1<<9) +#define SOLO_IRQ_PS2_0 (1<<8) +#define SOLO_IRQ_SPI (1<<7) +#define SOLO_IRQ_IIC (1<<6) +#define SOLO_IRQ_UART(n) (1<<((n) + 4)) +#define SOLO_IRQ_G723 (1<<3) +#define SOLO_IRQ_DECODER (1<<1) +#define SOLO_IRQ_ENCODER (1<<0) + +#define SOLO_CHIP_OPTION 0x001C +#define SOLO_CHIP_ID_MASK 0x00000007 + +#define SOLO_PLL_CONFIG 0x0020 /* 6110 Only */ + +#define SOLO_EEPROM_CTRL 0x0060 +#define SOLO_EEPROM_ACCESS_EN (1<<7) +#define SOLO_EEPROM_CS (1<<3) +#define SOLO_EEPROM_CLK (1<<2) +#define SOLO_EEPROM_DO (1<<1) +#define SOLO_EEPROM_DI (1<<0) +#define SOLO_EEPROM_ENABLE (SOLO_EEPROM_ACCESS_EN | SOLO_EEPROM_CS) + +#define SOLO_PCI_ERR 0x0070 +#define SOLO_PCI_ERR_FATAL 0x00000001 +#define SOLO_PCI_ERR_PARITY 0x00000002 +#define SOLO_PCI_ERR_TARGET 0x00000004 +#define SOLO_PCI_ERR_TIMEOUT 0x00000008 +#define SOLO_PCI_ERR_P2M 0x00000010 +#define SOLO_PCI_ERR_ATA 0x00000020 +#define SOLO_PCI_ERR_P2M_DESC 0x00000040 +#define SOLO_PCI_ERR_FSM0(__s) (((__s) >> 16) & 0x0f) +#define SOLO_PCI_ERR_FSM1(__s) (((__s) >> 20) & 0x0f) +#define SOLO_PCI_ERR_FSM2(__s) (((__s) >> 24) & 0x1f) + +#define SOLO_P2M_BASE 0x0080 + +#define SOLO_P2M_CONFIG(n) (0x0080 + ((n)*0x20)) +#define SOLO_P2M_DMA_INTERVAL(n) ((n)<<6)/* N*32 clocks */ +#define SOLO_P2M_CSC_BYTE_REORDER (1<<5) /* BGR -> RGB */ +/* 0:r=[14:10] g=[9:5] b=[4:0], 1:r=[15:11] g=[10:5] b=[4:0] */ +#define SOLO_P2M_CSC_16BIT_565 (1<<4) +#define SOLO_P2M_UV_SWAP (1<<3) +#define SOLO_P2M_PCI_MASTER_MODE (1<<2) +#define SOLO_P2M_DESC_INTR_OPT (1<<1) /* 1:Empty, 0:Each */ +#define SOLO_P2M_DESC_MODE (1<<0) + +#define SOLO_P2M_DES_ADR(n) (0x0084 + ((n)*0x20)) + +#define SOLO_P2M_DESC_ID(n) (0x0088 + ((n)*0x20)) +#define SOLO_P2M_UPDATE_ID(n) ((n)<<0) + +#define SOLO_P2M_STATUS(n) (0x008C + ((n)*0x20)) +#define SOLO_P2M_COMMAND_DONE (1<<8) +#define SOLO_P2M_CURRENT_ID(stat) (0xff & (stat)) + +#define SOLO_P2M_CONTROL(n) (0x0090 + ((n)*0x20)) +#define SOLO_P2M_PCI_INC(n) ((n)<<20) +#define SOLO_P2M_REPEAT(n) ((n)<<10) +/* 0:512, 1:256, 2:128, 3:64, 4:32, 5:128(2page) */ +#define SOLO_P2M_BURST_SIZE(n) ((n)<<7) +#define SOLO_P2M_BURST_512 0 +#define SOLO_P2M_BURST_256 1 +#define SOLO_P2M_BURST_128 2 +#define SOLO_P2M_BURST_64 3 +#define SOLO_P2M_BURST_32 4 +#define SOLO_P2M_CSC_16BIT (1<<6) /* 0:24bit, 1:16bit */ +/* 0:Y[0]<-0(OFF), 1:Y[0]<-1(ON), 2:Y[0]<-G[0], 3:Y[0]<-Bit[15] */ +#define SOLO_P2M_ALPHA_MODE(n) ((n)<<4) +#define SOLO_P2M_CSC_ON (1<<3) +#define SOLO_P2M_INTERRUPT_REQ (1<<2) +#define SOLO_P2M_WRITE (1<<1) +#define SOLO_P2M_TRANS_ON (1<<0) + +#define SOLO_P2M_EXT_CFG(n) (0x0094 + ((n)*0x20)) +#define SOLO_P2M_EXT_INC(n) ((n)<<20) +#define SOLO_P2M_COPY_SIZE(n) ((n)<<0) + +#define SOLO_P2M_TAR_ADR(n) (0x0098 + ((n)*0x20)) + +#define SOLO_P2M_EXT_ADR(n) (0x009C + ((n)*0x20)) + +#define SOLO_P2M_BUFFER(i) (0x2000 + ((i)*4)) + +#define SOLO_VI_CH_SWITCH_0 0x0100 +#define SOLO_VI_CH_SWITCH_1 0x0104 +#define SOLO_VI_CH_SWITCH_2 0x0108 + +#define SOLO_VI_CH_ENA 0x010C +#define SOLO_VI_CH_FORMAT 0x0110 +#define SOLO_VI_FD_SEL_MASK(n) ((n)<<16) +#define SOLO_VI_PROG_MASK(n) ((n)<<0) + +#define SOLO_VI_FMT_CFG 0x0114 +#define SOLO_VI_FMT_CHECK_VCOUNT (1<<31) +#define SOLO_VI_FMT_CHECK_HCOUNT (1<<30) +#define SOLO_VI_FMT_TEST_SIGNAL (1<<28) + +#define SOLO_VI_PAGE_SW 0x0118 +#define SOLO_FI_INV_DISP_LIVE(n) ((n)<<8) +#define SOLO_FI_INV_DISP_OUT(n) ((n)<<7) +#define SOLO_DISP_SYNC_FI(n) ((n)<<6) +#define SOLO_PIP_PAGE_ADD(n) ((n)<<3) +#define SOLO_NORMAL_PAGE_ADD(n) ((n)<<0) + +#define SOLO_VI_ACT_I_P 0x011C +#define SOLO_VI_ACT_I_S 0x0120 +#define SOLO_VI_ACT_P 0x0124 +#define SOLO_VI_FI_INVERT (1<<31) +#define SOLO_VI_H_START(n) ((n)<<21) +#define SOLO_VI_V_START(n) ((n)<<11) +#define SOLO_VI_V_STOP(n) ((n)<<0) + +#define SOLO_VI_STATUS0 0x0128 +#define SOLO_VI_STATUS0_PAGE(__n) ((__n) & 0x07) +#define SOLO_VI_STATUS1 0x012C + +/* XXX: Might be better off in kernel level disp.h */ +#define DISP_PAGE(stat) ((stat) & 0x07) + +#define SOLO_VI_PB_CONFIG 0x0130 +#define SOLO_VI_PB_USER_MODE (1<<1) +#define SOLO_VI_PB_PAL (1<<0) +#define SOLO_VI_PB_RANGE_HV 0x0134 +#define SOLO_VI_PB_HSIZE(h) ((h)<<12) +#define SOLO_VI_PB_VSIZE(v) ((v)<<0) +#define SOLO_VI_PB_ACT_H 0x0138 +#define SOLO_VI_PB_HSTART(n) ((n)<<12) +#define SOLO_VI_PB_HSTOP(n) ((n)<<0) +#define SOLO_VI_PB_ACT_V 0x013C +#define SOLO_VI_PB_VSTART(n) ((n)<<12) +#define SOLO_VI_PB_VSTOP(n) ((n)<<0) + +#define SOLO_VI_MOSAIC(ch) (0x0140 + ((ch)*4)) +#define SOLO_VI_MOSAIC_SX(x) ((x)<<24) +#define SOLO_VI_MOSAIC_EX(x) ((x)<<16) +#define SOLO_VI_MOSAIC_SY(x) ((x)<<8) +#define SOLO_VI_MOSAIC_EY(x) ((x)<<0) + +#define SOLO_VI_WIN_CTRL0(ch) (0x0180 + ((ch)*4)) +#define SOLO_VI_WIN_CTRL1(ch) (0x01C0 + ((ch)*4)) + +#define SOLO_VI_WIN_CHANNEL(n) ((n)<<28) + +#define SOLO_VI_WIN_PIP(n) ((n)<<27) +#define SOLO_VI_WIN_SCALE(n) ((n)<<24) + +#define SOLO_VI_WIN_SX(x) ((x)<<12) +#define SOLO_VI_WIN_EX(x) ((x)<<0) + +#define SOLO_VI_WIN_SY(x) ((x)<<12) +#define SOLO_VI_WIN_EY(x) ((x)<<0) + +#define SOLO_VI_WIN_ON(ch) (0x0200 + ((ch)*4)) + +#define SOLO_VI_WIN_SW 0x0240 +#define SOLO_VI_WIN_LIVE_AUTO_MUTE 0x0244 + +#define SOLO_VI_MOT_ADR 0x0260 +#define SOLO_VI_MOTION_EN(mask) ((mask)<<16) +#define SOLO_VI_MOT_CTRL 0x0264 +#define SOLO_VI_MOTION_FRAME_COUNT(n) ((n)<<24) +#define SOLO_VI_MOTION_SAMPLE_LENGTH(n) ((n)<<16) +#define SOLO_VI_MOTION_INTR_START_STOP (1<<15) +#define SOLO_VI_MOTION_FREEZE_DATA (1<<14) +#define SOLO_VI_MOTION_SAMPLE_COUNT(n) ((n)<<0) +#define SOLO_VI_MOT_CLEAR 0x0268 +#define SOLO_VI_MOT_STATUS 0x026C +#define SOLO_VI_MOTION_CNT(n) ((n)<<0) +#define SOLO_VI_MOTION_BORDER 0x0270 +#define SOLO_VI_MOTION_BAR 0x0274 +#define SOLO_VI_MOTION_Y_SET (1<<29) +#define SOLO_VI_MOTION_Y_ADD (1<<28) +#define SOLO_VI_MOTION_CB_SET (1<<27) +#define SOLO_VI_MOTION_CB_ADD (1<<26) +#define SOLO_VI_MOTION_CR_SET (1<<25) +#define SOLO_VI_MOTION_CR_ADD (1<<24) +#define SOLO_VI_MOTION_Y_VALUE(v) ((v)<<16) +#define SOLO_VI_MOTION_CB_VALUE(v) ((v)<<8) +#define SOLO_VI_MOTION_CR_VALUE(v) ((v)<<0) + +#define SOLO_VO_FMT_ENC 0x0300 +#define SOLO_VO_SCAN_MODE_PROGRESSIVE (1<<31) +#define SOLO_VO_FMT_TYPE_PAL (1<<30) +#define SOLO_VO_FMT_TYPE_NTSC 0 +#define SOLO_VO_USER_SET (1<<29) + +#define SOLO_VO_FI_CHANGE (1<<20) +#define SOLO_VO_USER_COLOR_SET_VSYNC (1<<19) +#define SOLO_VO_USER_COLOR_SET_HSYNC (1<<18) +#define SOLO_VO_USER_COLOR_SET_NAH (1<<17) +#define SOLO_VO_USER_COLOR_SET_NAV (1<<16) +#define SOLO_VO_NA_COLOR_Y(Y) ((Y)<<8) +#define SOLO_VO_NA_COLOR_CB(CB) (((CB)/16)<<4) +#define SOLO_VO_NA_COLOR_CR(CR) (((CR)/16)<<0) + +#define SOLO_VO_ACT_H 0x0304 +#define SOLO_VO_H_BLANK(n) ((n)<<22) +#define SOLO_VO_H_START(n) ((n)<<11) +#define SOLO_VO_H_STOP(n) ((n)<<0) + +#define SOLO_VO_ACT_V 0x0308 +#define SOLO_VO_V_BLANK(n) ((n)<<22) +#define SOLO_VO_V_START(n) ((n)<<11) +#define SOLO_VO_V_STOP(n) ((n)<<0) + +#define SOLO_VO_RANGE_HV 0x030C +#define SOLO_VO_SYNC_INVERT (1<<24) +#define SOLO_VO_HSYNC_INVERT (1<<23) +#define SOLO_VO_VSYNC_INVERT (1<<22) +#define SOLO_VO_H_LEN(n) ((n)<<11) +#define SOLO_VO_V_LEN(n) ((n)<<0) + +#define SOLO_VO_DISP_CTRL 0x0310 +#define SOLO_VO_DISP_ON (1<<31) +#define SOLO_VO_DISP_ERASE_COUNT(n) ((n&0xf)<<24) +#define SOLO_VO_DISP_DOUBLE_SCAN (1<<22) +#define SOLO_VO_DISP_SINGLE_PAGE (1<<21) +#define SOLO_VO_DISP_BASE(n) (((n)>>16) & 0xffff) + +#define SOLO_VO_DISP_ERASE 0x0314 +#define SOLO_VO_DISP_ERASE_ON (1<<0) + +#define SOLO_VO_ZOOM_CTRL 0x0318 +#define SOLO_VO_ZOOM_VER_ON (1<<24) +#define SOLO_VO_ZOOM_HOR_ON (1<<23) +#define SOLO_VO_ZOOM_V_COMP (1<<22) +#define SOLO_VO_ZOOM_SX(h) (((h)/2)<<11) +#define SOLO_VO_ZOOM_SY(v) (((v)/2)<<0) + +#define SOLO_VO_FREEZE_CTRL 0x031C +#define SOLO_VO_FREEZE_ON (1<<1) +#define SOLO_VO_FREEZE_INTERPOLATION (1<<0) + +#define SOLO_VO_BKG_COLOR 0x0320 +#define SOLO_BG_Y(y) ((y)<<16) +#define SOLO_BG_U(u) ((u)<<8) +#define SOLO_BG_V(v) ((v)<<0) + +#define SOLO_VO_DEINTERLACE 0x0324 +#define SOLO_VO_DEINTERLACE_THRESHOLD(n) ((n)<<8) +#define SOLO_VO_DEINTERLACE_EDGE_VALUE(n) ((n)<<0) + +#define SOLO_VO_BORDER_LINE_COLOR 0x0330 +#define SOLO_VO_BORDER_FILL_COLOR 0x0334 +#define SOLO_VO_BORDER_LINE_MASK 0x0338 +#define SOLO_VO_BORDER_FILL_MASK 0x033c + +#define SOLO_VO_BORDER_X(n) (0x0340+((n)*4)) +#define SOLO_VO_BORDER_Y(n) (0x0354+((n)*4)) + +#define SOLO_VO_CELL_EXT_SET 0x0368 +#define SOLO_VO_CELL_EXT_START 0x036c +#define SOLO_VO_CELL_EXT_STOP 0x0370 + +#define SOLO_VO_CELL_EXT_SET2 0x0374 +#define SOLO_VO_CELL_EXT_START2 0x0378 +#define SOLO_VO_CELL_EXT_STOP2 0x037c + +#define SOLO_VO_RECTANGLE_CTRL(n) (0x0368+((n)*12)) +#define SOLO_VO_RECTANGLE_START(n) (0x036c+((n)*12)) +#define SOLO_VO_RECTANGLE_STOP(n) (0x0370+((n)*12)) + +#define SOLO_VO_CURSOR_POS (0x0380) +#define SOLO_VO_CURSOR_CLR (0x0384) +#define SOLO_VO_CURSOR_CLR2 (0x0388) +#define SOLO_VO_CURSOR_MASK(id) (0x0390+((id)*4)) + +#define SOLO_VO_EXPANSION(id) (0x0250+((id)*4)) + +#define SOLO_OSG_CONFIG 0x03E0 +#define SOLO_VO_OSG_ON (1<<31) +#define SOLO_VO_OSG_COLOR_MUTE (1<<28) +#define SOLO_VO_OSG_ALPHA_RATE(n) ((n)<<22) +#define SOLO_VO_OSG_ALPHA_BG_RATE(n) ((n)<<16) +#define SOLO_VO_OSG_BASE(offset) (((offset)>>16)&0xffff) + +#define SOLO_OSG_ERASE 0x03E4 +#define SOLO_OSG_ERASE_ON (0x80) +#define SOLO_OSG_ERASE_OFF (0x00) + +#define SOLO_VO_OSG_BLINK 0x03E8 +#define SOLO_VO_OSG_BLINK_ON (1<<1) +#define SOLO_VO_OSG_BLINK_INTREVAL18 (1<<0) + +#define SOLO_CAP_BASE 0x0400 +#define SOLO_CAP_MAX_PAGE(n) ((n)<<16) +#define SOLO_CAP_BASE_ADDR(n) ((n)<<0) +#define SOLO_CAP_BTW 0x0404 +#define SOLO_CAP_PROG_BANDWIDTH(n) ((n)<<8) +#define SOLO_CAP_MAX_BANDWIDTH(n) ((n)<<0) + +#define SOLO_DIM_SCALE1 0x0408 +#define SOLO_DIM_SCALE2 0x040C +#define SOLO_DIM_SCALE3 0x0410 +#define SOLO_DIM_SCALE4 0x0414 +#define SOLO_DIM_SCALE5 0x0418 +#define SOLO_DIM_V_MB_NUM_FRAME(n) ((n)<<16) +#define SOLO_DIM_V_MB_NUM_FIELD(n) ((n)<<8) +#define SOLO_DIM_H_MB_NUM(n) ((n)<<0) + +#define SOLO_DIM_PROG 0x041C +#define SOLO_CAP_STATUS 0x0420 + +#define SOLO_CAP_CH_SCALE(ch) (0x0440+((ch)*4)) +#define SOLO_CAP_CH_COMP_ENA_E(ch) (0x0480+((ch)*4)) +#define SOLO_CAP_CH_INTV(ch) (0x04C0+((ch)*4)) +#define SOLO_CAP_CH_INTV_E(ch) (0x0500+((ch)*4)) + + +#define SOLO_VE_CFG0 0x0610 +#define SOLO_VE_TWO_PAGE_MODE (1<<31) +#define SOLO_VE_INTR_CTRL(n) ((n)<<24) +#define SOLO_VE_BLOCK_SIZE(n) ((n)<<16) +#define SOLO_VE_BLOCK_BASE(n) ((n)<<0) + +#define SOLO_VE_CFG1 0x0614 +#define SOLO_VE_BYTE_ALIGN(n) ((n)<<24) +#define SOLO_VE_INSERT_INDEX (1<<18) +#define SOLO_VE_MOTION_MODE(n) ((n)<<16) +#define SOLO_VE_MOTION_BASE(n) ((n)<<0) +#define SOLO_VE_MPEG_SIZE_H(n) ((n)<<28) /* 6110 Only */ +#define SOLO_VE_JPEG_SIZE_H(n) ((n)<<20) /* 6110 Only */ +#define SOLO_VE_INSERT_INDEX_JPEG (1<<19) /* 6110 Only */ + +#define SOLO_VE_WMRK_POLY 0x061C +#define SOLO_VE_VMRK_INIT_KEY 0x0620 +#define SOLO_VE_WMRK_STRL 0x0624 +#define SOLO_VE_ENCRYP_POLY 0x0628 +#define SOLO_VE_ENCRYP_INIT 0x062C +#define SOLO_VE_ATTR 0x0630 +#define SOLO_VE_LITTLE_ENDIAN (1<<31) +#define SOLO_COMP_ATTR_RN (1<<30) +#define SOLO_COMP_ATTR_FCODE(n) ((n)<<27) +#define SOLO_COMP_TIME_INC(n) ((n)<<25) +#define SOLO_COMP_TIME_WIDTH(n) ((n)<<21) +#define SOLO_DCT_INTERVAL(n) ((n)<<16) +#define SOLO_VE_COMPT_MOT 0x0634 /* 6110 Only */ + +#define SOLO_VE_STATE(n) (0x0640+((n)*4)) + +#define SOLO_VE_JPEG_QP_TBL 0x0670 +#define SOLO_VE_JPEG_QP_CH_L 0x0674 +#define SOLO_VE_JPEG_QP_CH_H 0x0678 +#define SOLO_VE_JPEG_CFG 0x067C +#define SOLO_VE_JPEG_CTRL 0x0680 +#define SOLO_VE_CODE_ENCRYPT 0x0684 /* 6110 Only */ +#define SOLO_VE_JPEG_CFG1 0x0688 /* 6110 Only */ +#define SOLO_VE_WMRK_ENABLE 0x068C /* 6110 Only */ +#define SOLO_VE_OSD_CH 0x0690 +#define SOLO_VE_OSD_BASE 0x0694 +#define SOLO_VE_OSD_CLR 0x0698 +#define SOLO_VE_OSD_OPT 0x069C +#define SOLO_VE_OSD_V_DOUBLE (1<<16) /* 6110 Only */ +#define SOLO_VE_OSD_H_SHADOW (1<<15) +#define SOLO_VE_OSD_V_SHADOW (1<<14) +#define SOLO_VE_OSD_H_OFFSET(n) ((n & 0x7f)<<7) +#define SOLO_VE_OSD_V_OFFSET(n) (n & 0x7f) + +#define SOLO_VE_CH_INTL(ch) (0x0700+((ch)*4)) +#define SOLO_VE_CH_MOT(ch) (0x0740+((ch)*4)) +#define SOLO_VE_CH_QP(ch) (0x0780+((ch)*4)) +#define SOLO_VE_CH_QP_E(ch) (0x07C0+((ch)*4)) +#define SOLO_VE_CH_GOP(ch) (0x0800+((ch)*4)) +#define SOLO_VE_CH_GOP_E(ch) (0x0840+((ch)*4)) +#define SOLO_VE_CH_REF_BASE(ch) (0x0880+((ch)*4)) +#define SOLO_VE_CH_REF_BASE_E(ch) (0x08C0+((ch)*4)) + +#define SOLO_VE_MPEG4_QUE(n) (0x0A00+((n)*8)) +#define SOLO_VE_JPEG_QUE(n) (0x0A04+((n)*8)) + +#define SOLO_VD_CFG0 0x0900 +#define SOLO_VD_CFG_NO_WRITE_NO_WINDOW (1<<24) +#define SOLO_VD_CFG_BUSY_WIAT_CODE (1<<23) +#define SOLO_VD_CFG_BUSY_WIAT_REF (1<<22) +#define SOLO_VD_CFG_BUSY_WIAT_RES (1<<21) +#define SOLO_VD_CFG_BUSY_WIAT_MS (1<<20) +#define SOLO_VD_CFG_SINGLE_MODE (1<<18) +#define SOLO_VD_CFG_SCAL_MANUAL (1<<17) +#define SOLO_VD_CFG_USER_PAGE_CTRL (1<<16) +#define SOLO_VD_CFG_LITTLE_ENDIAN (1<<15) +#define SOLO_VD_CFG_START_FI (1<<14) +#define SOLO_VD_CFG_ERR_LOCK (1<<13) +#define SOLO_VD_CFG_ERR_INT_ENA (1<<12) +#define SOLO_VD_CFG_TIME_WIDTH(n) ((n)<<8) +#define SOLO_VD_CFG_DCT_INTERVAL(n) ((n)<<0) + +#define SOLO_VD_CFG1 0x0904 + +#define SOLO_VD_DEINTERLACE 0x0908 +#define SOLO_VD_DEINTERLACE_THRESHOLD(n) ((n)<<8) +#define SOLO_VD_DEINTERLACE_EDGE_VALUE(n) ((n)<<0) + +#define SOLO_VD_CODE_ADR 0x090C + +#define SOLO_VD_CTRL 0x0910 +#define SOLO_VD_OPER_ON (1<<31) +#define SOLO_VD_MAX_ITEM(n) ((n)<<0) + +#define SOLO_VD_STATUS0 0x0920 +#define SOLO_VD_STATUS0_INTR_ACK (1<<22) +#define SOLO_VD_STATUS0_INTR_EMPTY (1<<21) +#define SOLO_VD_STATUS0_INTR_ERR (1<<20) + +#define SOLO_VD_STATUS1 0x0924 + +#define SOLO_VD_IDX0 0x0930 +#define SOLO_VD_IDX_INTERLACE (1<<30) +#define SOLO_VD_IDX_CHANNEL(n) ((n)<<24) +#define SOLO_VD_IDX_SIZE(n) ((n)<<0) + +#define SOLO_VD_IDX1 0x0934 +#define SOLO_VD_IDX_SRC_SCALE(n) ((n)<<28) +#define SOLO_VD_IDX_WINDOW(n) ((n)<<24) +#define SOLO_VD_IDX_DEINTERLACE (1<<16) +#define SOLO_VD_IDX_H_BLOCK(n) ((n)<<8) +#define SOLO_VD_IDX_V_BLOCK(n) ((n)<<0) + +#define SOLO_VD_IDX2 0x0938 +#define SOLO_VD_IDX_REF_BASE_SIDE (1<<31) +#define SOLO_VD_IDX_REF_BASE(n) (((n)>>16)&0xffff) + +#define SOLO_VD_IDX3 0x093C +#define SOLO_VD_IDX_DISP_SCALE(n) ((n)<<28) +#define SOLO_VD_IDX_INTERLACE_WR (1<<27) +#define SOLO_VD_IDX_INTERPOL (1<<26) +#define SOLO_VD_IDX_HOR2X (1<<25) +#define SOLO_VD_IDX_OFFSET_X(n) ((n)<<12) +#define SOLO_VD_IDX_OFFSET_Y(n) ((n)<<0) + +#define SOLO_VD_IDX4 0x0940 +#define SOLO_VD_IDX_DEC_WR_PAGE(n) ((n)<<8) +#define SOLO_VD_IDX_DISP_RD_PAGE(n) ((n)<<0) + +#define SOLO_VD_WR_PAGE(n) (0x03F0 + ((n) * 4)) + + +#define SOLO_GPIO_CONFIG_0 0x0B00 +#define SOLO_GPIO_CONFIG_1 0x0B04 +#define SOLO_GPIO_DATA_OUT 0x0B08 +#define SOLO_GPIO_DATA_IN 0x0B0C +#define SOLO_GPIO_INT_ACK_STA 0x0B10 +#define SOLO_GPIO_INT_ENA 0x0B14 +#define SOLO_GPIO_INT_CFG_0 0x0B18 +#define SOLO_GPIO_INT_CFG_1 0x0B1C + + +#define SOLO_IIC_CFG 0x0B20 +#define SOLO_IIC_ENABLE (1<<8) +#define SOLO_IIC_PRESCALE(n) ((n)<<0) + +#define SOLO_IIC_CTRL 0x0B24 +#define SOLO_IIC_AUTO_CLEAR (1<<20) +#define SOLO_IIC_STATE_RX_ACK (1<<19) +#define SOLO_IIC_STATE_BUSY (1<<18) +#define SOLO_IIC_STATE_SIG_ERR (1<<17) +#define SOLO_IIC_STATE_TRNS (1<<16) +#define SOLO_IIC_CH_SET(n) ((n)<<5) +#define SOLO_IIC_ACK_EN (1<<4) +#define SOLO_IIC_START (1<<3) +#define SOLO_IIC_STOP (1<<2) +#define SOLO_IIC_READ (1<<1) +#define SOLO_IIC_WRITE (1<<0) + +#define SOLO_IIC_TXD 0x0B28 +#define SOLO_IIC_RXD 0x0B2C + +/* + * UART REGISTER + */ +#define SOLO_UART_CONTROL(n) (0x0BA0 + ((n)*0x20)) +#define SOLO_UART_CLK_DIV(n) ((n)<<24) +#define SOLO_MODEM_CTRL_EN (1<<20) +#define SOLO_PARITY_ERROR_DROP (1<<18) +#define SOLO_IRQ_ERR_EN (1<<17) +#define SOLO_IRQ_RX_EN (1<<16) +#define SOLO_IRQ_TX_EN (1<<15) +#define SOLO_RX_EN (1<<14) +#define SOLO_TX_EN (1<<13) +#define SOLO_UART_HALF_DUPLEX (1<<12) +#define SOLO_UART_LOOPBACK (1<<11) + +#define SOLO_BAUDRATE_230400 ((0<<9)|(0<<6)) +#define SOLO_BAUDRATE_115200 ((0<<9)|(1<<6)) +#define SOLO_BAUDRATE_57600 ((0<<9)|(2<<6)) +#define SOLO_BAUDRATE_38400 ((0<<9)|(3<<6)) +#define SOLO_BAUDRATE_19200 ((0<<9)|(4<<6)) +#define SOLO_BAUDRATE_9600 ((0<<9)|(5<<6)) +#define SOLO_BAUDRATE_4800 ((0<<9)|(6<<6)) +#define SOLO_BAUDRATE_2400 ((1<<9)|(6<<6)) +#define SOLO_BAUDRATE_1200 ((2<<9)|(6<<6)) +#define SOLO_BAUDRATE_300 ((3<<9)|(6<<6)) + +#define SOLO_UART_DATA_BIT_8 (3<<4) +#define SOLO_UART_DATA_BIT_7 (2<<4) +#define SOLO_UART_DATA_BIT_6 (1<<4) +#define SOLO_UART_DATA_BIT_5 (0<<4) + +#define SOLO_UART_STOP_BIT_1 (0<<2) +#define SOLO_UART_STOP_BIT_2 (1<<2) + +#define SOLO_UART_PARITY_NONE (0<<0) +#define SOLO_UART_PARITY_EVEN (2<<0) +#define SOLO_UART_PARITY_ODD (3<<0) + +#define SOLO_UART_STATUS(n) (0x0BA4 + ((n)*0x20)) +#define SOLO_UART_CTS (1<<15) +#define SOLO_UART_RX_BUSY (1<<14) +#define SOLO_UART_OVERRUN (1<<13) +#define SOLO_UART_FRAME_ERR (1<<12) +#define SOLO_UART_PARITY_ERR (1<<11) +#define SOLO_UART_TX_BUSY (1<<5) + +#define SOLO_UART_RX_BUFF_CNT(stat) (((stat)>>6) & 0x1f) +#define SOLO_UART_RX_BUFF_SIZE 8 +#define SOLO_UART_TX_BUFF_CNT(stat) (((stat)>>0) & 0x1f) +#define SOLO_UART_TX_BUFF_SIZE 8 + +#define SOLO_UART_TX_DATA(n) (0x0BA8 + ((n)*0x20)) +#define SOLO_UART_TX_DATA_PUSH (1<<8) +#define SOLO_UART_RX_DATA(n) (0x0BAC + ((n)*0x20)) +#define SOLO_UART_RX_DATA_POP (1<<8) + +#define SOLO_TIMER_CLOCK_NUM 0x0be0 +#define SOLO_TIMER_USEC 0x0be8 +#define SOLO_TIMER_SEC 0x0bec +#define SOLO_TIMER_USEC_LSB 0x0d20 /* 6110 Only */ + +#define SOLO_AUDIO_CONTROL 0x0D00 +#define SOLO_AUDIO_ENABLE (1<<31) +#define SOLO_AUDIO_MASTER_MODE (1<<30) +#define SOLO_AUDIO_I2S_MODE (1<<29) +#define SOLO_AUDIO_I2S_LR_SWAP (1<<27) +#define SOLO_AUDIO_I2S_8BIT (1<<26) +#define SOLO_AUDIO_I2S_MULTI(n) ((n)<<24) +#define SOLO_AUDIO_MIX_9TO0 (1<<23) +#define SOLO_AUDIO_DEC_9TO0_VOL(n) ((n)<<20) +#define SOLO_AUDIO_MIX_19TO10 (1<<19) +#define SOLO_AUDIO_DEC_19TO10_VOL(n) ((n)<<16) +#define SOLO_AUDIO_MODE(n) ((n)<<0) +#define SOLO_AUDIO_SAMPLE 0x0D04 +#define SOLO_AUDIO_EE_MODE_ON (1<<30) +#define SOLO_AUDIO_EE_ENC_CH(ch) ((ch)<<25) +#define SOLO_AUDIO_BITRATE(n) ((n)<<16) +#define SOLO_AUDIO_CLK_DIV(n) ((n)<<0) +#define SOLO_AUDIO_FDMA_INTR 0x0D08 +#define SOLO_AUDIO_FDMA_INTERVAL(n) ((n)<<19) +#define SOLO_AUDIO_INTR_ORDER(n) ((n)<<16) +#define SOLO_AUDIO_FDMA_BASE(n) ((n)<<0) +#define SOLO_AUDIO_EVOL_0 0x0D0C +#define SOLO_AUDIO_EVOL_1 0x0D10 +#define SOLO_AUDIO_EVOL(ch, value) ((value)<<((ch)%10)) +#define SOLO_AUDIO_STA 0x0D14 + +/* + * Watchdog configuration + */ +#define SOLO_WATCHDOG 0x0be4 +#define SOLO_WATCHDOG_SET(status, sec) (status << 8 | (sec & 0xff)) + +#endif /* __SOLO6X10_REGISTERS_H */ diff --git a/drivers/staging/media/solo6x10/solo6x10-tw28.h b/drivers/staging/media/solo6x10/solo6x10-tw28.h new file mode 100644 index 0000000..1a02c87 --- /dev/null +++ b/drivers/staging/media/solo6x10/solo6x10-tw28.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +#ifndef __SOLO6X10_TW28_H +#define __SOLO6X10_TW28_H + +#include "solo6x10.h" + +#define TW_NUM_CHIP 4 +#define TW_BASE_ADDR 0x28 +#define TW_CHIP_OFFSET_ADDR(n) (TW_BASE_ADDR + (n)) + +/* tw2815 */ +#define TW_AV_STAT_ADDR 0x5a +#define TW_HUE_ADDR(n) (0x07 | ((n) << 4)) +#define TW_SATURATION_ADDR(n) (0x08 | ((n) << 4)) +#define TW_CONTRAST_ADDR(n) (0x09 | ((n) << 4)) +#define TW_BRIGHTNESS_ADDR(n) (0x0a | ((n) << 4)) +#define TW_AUDIO_OUTPUT_VOL_ADDR 0x70 +#define TW_AUDIO_INPUT_GAIN_ADDR(n) (0x60 + ((n > 1) ? 1 : 0)) + +/* tw286x */ +#define TW286x_AV_STAT_ADDR 0xfd +#define TW286x_HUE_ADDR(n) (0x06 | ((n) << 4)) +#define TW286x_SATURATIONU_ADDR(n) (0x04 | ((n) << 4)) +#define TW286x_SATURATIONV_ADDR(n) (0x05 | ((n) << 4)) +#define TW286x_CONTRAST_ADDR(n) (0x02 | ((n) << 4)) +#define TW286x_BRIGHTNESS_ADDR(n) (0x01 | ((n) << 4)) +#define TW286x_SHARPNESS(n) (0x03 | ((n) << 4)) +#define TW286x_AUDIO_OUTPUT_VOL_ADDR 0xdf +#define TW286x_AUDIO_INPUT_GAIN_ADDR(n) (0xD0 + ((n > 1) ? 1 : 0)) + +int solo_tw28_init(struct solo_dev *solo_dev); + +int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val); +int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val); +bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch); + +u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch); +void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val); +int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch); + +#if 0 +unsigned int tw2815_get_audio_status(struct SOLO *solo); +void tw2815_Set_AudioOutVol(struct SOLO *solo, unsigned int u_val); +#endif + +#endif /* __SOLO6X10_TW28_H */ diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index da7611e..3526d6b 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h @@ -41,7 +41,7 @@ #include #include -#include "registers.h" +#include "solo6x10-regs.h" #ifndef PCI_VENDOR_ID_SOFTLOGIC #define PCI_VENDOR_ID_SOFTLOGIC 0x9413 diff --git a/drivers/staging/media/solo6x10/tw28.c b/drivers/staging/media/solo6x10/tw28.c index 6c77af8..ad00e2b 100644 --- a/drivers/staging/media/solo6x10/tw28.c +++ b/drivers/staging/media/solo6x10/tw28.c @@ -26,7 +26,7 @@ #include #include "solo6x10.h" -#include "tw28.h" +#include "solo6x10-tw28.h" #define DEFAULT_HDELAY_NTSC (32 - 8) #define DEFAULT_HACTIVE_NTSC (720 + 16) diff --git a/drivers/staging/media/solo6x10/tw28.h b/drivers/staging/media/solo6x10/tw28.h deleted file mode 100644 index 1a02c87..0000000 --- a/drivers/staging/media/solo6x10/tw28.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2010-2013 Bluecherry, LLC - * - * Original author: - * Ben Collins - * - * Additional work by: - * John Brooks - * - * 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. - */ - -#ifndef __SOLO6X10_TW28_H -#define __SOLO6X10_TW28_H - -#include "solo6x10.h" - -#define TW_NUM_CHIP 4 -#define TW_BASE_ADDR 0x28 -#define TW_CHIP_OFFSET_ADDR(n) (TW_BASE_ADDR + (n)) - -/* tw2815 */ -#define TW_AV_STAT_ADDR 0x5a -#define TW_HUE_ADDR(n) (0x07 | ((n) << 4)) -#define TW_SATURATION_ADDR(n) (0x08 | ((n) << 4)) -#define TW_CONTRAST_ADDR(n) (0x09 | ((n) << 4)) -#define TW_BRIGHTNESS_ADDR(n) (0x0a | ((n) << 4)) -#define TW_AUDIO_OUTPUT_VOL_ADDR 0x70 -#define TW_AUDIO_INPUT_GAIN_ADDR(n) (0x60 + ((n > 1) ? 1 : 0)) - -/* tw286x */ -#define TW286x_AV_STAT_ADDR 0xfd -#define TW286x_HUE_ADDR(n) (0x06 | ((n) << 4)) -#define TW286x_SATURATIONU_ADDR(n) (0x04 | ((n) << 4)) -#define TW286x_SATURATIONV_ADDR(n) (0x05 | ((n) << 4)) -#define TW286x_CONTRAST_ADDR(n) (0x02 | ((n) << 4)) -#define TW286x_BRIGHTNESS_ADDR(n) (0x01 | ((n) << 4)) -#define TW286x_SHARPNESS(n) (0x03 | ((n) << 4)) -#define TW286x_AUDIO_OUTPUT_VOL_ADDR 0xdf -#define TW286x_AUDIO_INPUT_GAIN_ADDR(n) (0xD0 + ((n > 1) ? 1 : 0)) - -int solo_tw28_init(struct solo_dev *solo_dev); - -int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val); -int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 *val); -bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch); - -u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch); -void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val); -int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch); - -#if 0 -unsigned int tw2815_get_audio_status(struct SOLO *solo); -void tw2815_Set_AudioOutVol(struct SOLO *solo, unsigned int u_val); -#endif - -#endif /* __SOLO6X10_TW28_H */ diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c index b1fa78b..39a8fb2 100644 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ b/drivers/staging/media/solo6x10/v4l2-enc.c @@ -33,7 +33,7 @@ #include #include "solo6x10.h" -#include "tw28.h" +#include "solo6x10-tw28.h" #include "solo6x10-jpeg.h" #define MIN_VID_BUFFERS 2 diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c index 02749a3..7b26de3 100644 --- a/drivers/staging/media/solo6x10/v4l2.c +++ b/drivers/staging/media/solo6x10/v4l2.c @@ -33,7 +33,7 @@ #include #include "solo6x10.h" -#include "tw28.h" +#include "solo6x10-tw28.h" /* Image size is two fields, SOLO_HW_BPL is one horizontal line in hardware */ #define SOLO_HW_BPL 2048 -- cgit v0.10.2 From 7bce33daeaca26a3ea3f6099fdfe4e11ea46cac6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Mar 2013 05:47:48 -0300 Subject: [media] solo6x10: prefix sources with 'solo6x10-' Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/Makefile b/drivers/staging/media/solo6x10/Makefile index 9bbde29..7aae118 100644 --- a/drivers/staging/media/solo6x10/Makefile +++ b/drivers/staging/media/solo6x10/Makefile @@ -1,3 +1,5 @@ -solo6x10-y := core.o i2c.o p2m.o v4l2.o tw28.o gpio.o disp.o enc.o v4l2-enc.o g723.o eeprom.o +solo6x10-y := solo6x10-core.o solo6x10-i2c.o solo6x10-p2m.o solo6x10-v4l2.o \ + solo6x10-tw28.o solo6x10-gpio.o solo6x10-disp.o solo6x10-enc.o \ + solo6x10-v4l2-enc.o solo6x10-g723.o solo6x10-eeprom.o obj-$(CONFIG_SOLO6X10) += solo6x10.o diff --git a/drivers/staging/media/solo6x10/core.c b/drivers/staging/media/solo6x10/core.c deleted file mode 100644 index 3675020..0000000 --- a/drivers/staging/media/solo6x10/core.c +++ /dev/null @@ -1,709 +0,0 @@ -/* - * Copyright (C) 2010-2013 Bluecherry, LLC - * - * Original author: - * Ben Collins - * - * Additional work by: - * John Brooks - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "solo6x10.h" -#include "solo6x10-tw28.h" - -MODULE_DESCRIPTION("Softlogic 6x10 MPEG4/H.264/G.723 CODEC V4L2/ALSA Driver"); -MODULE_AUTHOR("Bluecherry "); -MODULE_VERSION(SOLO6X10_VERSION); -MODULE_LICENSE("GPL"); - -unsigned video_nr = -1; -module_param(video_nr, uint, 0644); -MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)"); - -static int full_eeprom; /* default is only top 64B */ -module_param(full_eeprom, uint, 0644); -MODULE_PARM_DESC(full_eeprom, "Allow access to full 128B EEPROM (dangerous)"); - - -static void solo_set_time(struct solo_dev *solo_dev) -{ - struct timespec ts; - - ktime_get_ts(&ts); - - solo_reg_write(solo_dev, SOLO_TIMER_SEC, ts.tv_sec); - solo_reg_write(solo_dev, SOLO_TIMER_USEC, ts.tv_nsec / NSEC_PER_USEC); -} - -static void solo_timer_sync(struct solo_dev *solo_dev) -{ - u32 sec, usec; - struct timespec ts; - long diff; - - if (solo_dev->type != SOLO_DEV_6110) - return; - - if (++solo_dev->time_sync < 60) - return; - - solo_dev->time_sync = 0; - - sec = solo_reg_read(solo_dev, SOLO_TIMER_SEC); - usec = solo_reg_read(solo_dev, SOLO_TIMER_USEC); - - ktime_get_ts(&ts); - - diff = (long)ts.tv_sec - (long)sec; - diff = (diff * 1000000) - + ((long)(ts.tv_nsec / NSEC_PER_USEC) - (long)usec); - - if (diff > 1000 || diff < -1000) { - solo_set_time(solo_dev); - } else if (diff) { - long usec_lsb = solo_dev->usec_lsb; - - usec_lsb -= diff / 4; - if (usec_lsb < 0) - usec_lsb = 0; - else if (usec_lsb > 255) - usec_lsb = 255; - - solo_dev->usec_lsb = usec_lsb; - solo_reg_write(solo_dev, SOLO_TIMER_USEC_LSB, - solo_dev->usec_lsb); - } -} - -static irqreturn_t solo_isr(int irq, void *data) -{ - struct solo_dev *solo_dev = data; - u32 status; - int i; - - status = solo_reg_read(solo_dev, SOLO_IRQ_STAT); - if (!status) - return IRQ_NONE; - - if (status & ~solo_dev->irq_mask) { - solo_reg_write(solo_dev, SOLO_IRQ_STAT, - status & ~solo_dev->irq_mask); - status &= solo_dev->irq_mask; - } - - if (status & SOLO_IRQ_PCI_ERR) - solo_p2m_error_isr(solo_dev); - - for (i = 0; i < SOLO_NR_P2M; i++) - if (status & SOLO_IRQ_P2M(i)) - solo_p2m_isr(solo_dev, i); - - if (status & SOLO_IRQ_IIC) - solo_i2c_isr(solo_dev); - - if (status & SOLO_IRQ_VIDEO_IN) { - solo_video_in_isr(solo_dev); - solo_timer_sync(solo_dev); - } - - if (status & SOLO_IRQ_ENCODER) - solo_enc_v4l2_isr(solo_dev); - - if (status & SOLO_IRQ_G723) - solo_g723_isr(solo_dev); - - /* Clear all interrupts handled */ - solo_reg_write(solo_dev, SOLO_IRQ_STAT, status); - - return IRQ_HANDLED; -} - -static void free_solo_dev(struct solo_dev *solo_dev) -{ - struct pci_dev *pdev; - - if (!solo_dev) - return; - - if (solo_dev->dev.parent) - device_unregister(&solo_dev->dev); - - pdev = solo_dev->pdev; - - /* If we never initialized the PCI device, then nothing else - * below here needs cleanup */ - if (!pdev) { - kfree(solo_dev); - return; - } - - if (solo_dev->reg_base) { - /* Bring down the sub-devices first */ - solo_g723_exit(solo_dev); - solo_enc_v4l2_exit(solo_dev); - solo_enc_exit(solo_dev); - solo_v4l2_exit(solo_dev); - solo_disp_exit(solo_dev); - solo_gpio_exit(solo_dev); - solo_p2m_exit(solo_dev); - solo_i2c_exit(solo_dev); - - /* Now cleanup the PCI device */ - solo_irq_off(solo_dev, ~0); - pci_iounmap(pdev, solo_dev->reg_base); - if (pdev->irq) - free_irq(pdev->irq, solo_dev); - } - - pci_release_regions(pdev); - pci_disable_device(pdev); - v4l2_device_unregister(&solo_dev->v4l2_dev); - pci_set_drvdata(pdev, NULL); - - kfree(solo_dev); -} - -static ssize_t eeprom_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct solo_dev *solo_dev = - container_of(dev, struct solo_dev, dev); - unsigned short *p = (unsigned short *)buf; - int i; - - if (count & 0x1) - dev_warn(dev, "EEPROM Write not aligned (truncating)\n"); - - if (!full_eeprom && count > 64) { - dev_warn(dev, "EEPROM Write truncated to 64 bytes\n"); - count = 64; - } else if (full_eeprom && count > 128) { - dev_warn(dev, "EEPROM Write truncated to 128 bytes\n"); - count = 128; - } - - solo_eeprom_ewen(solo_dev, 1); - - for (i = full_eeprom ? 0 : 32; i < min((int)(full_eeprom ? 64 : 32), - (int)(count / 2)); i++) - solo_eeprom_write(solo_dev, i, cpu_to_be16(p[i])); - - solo_eeprom_ewen(solo_dev, 0); - - return count; -} - -static ssize_t eeprom_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct solo_dev *solo_dev = - container_of(dev, struct solo_dev, dev); - unsigned short *p = (unsigned short *)buf; - int count = (full_eeprom ? 128 : 64); - int i; - - for (i = (full_eeprom ? 0 : 32); i < (count / 2); i++) - p[i] = be16_to_cpu(solo_eeprom_read(solo_dev, i)); - - return count; -} - -static ssize_t p2m_timeouts_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct solo_dev *solo_dev = - container_of(dev, struct solo_dev, dev); - - return sprintf(buf, "%d\n", solo_dev->p2m_timeouts); -} - -static ssize_t sdram_size_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct solo_dev *solo_dev = - container_of(dev, struct solo_dev, dev); - - return sprintf(buf, "%dMegs\n", solo_dev->sdram_size >> 20); -} - -static ssize_t tw28xx_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct solo_dev *solo_dev = - container_of(dev, struct solo_dev, dev); - - return sprintf(buf, "tw2815[%d] tw2864[%d] tw2865[%d]\n", - hweight32(solo_dev->tw2815), - hweight32(solo_dev->tw2864), - hweight32(solo_dev->tw2865)); -} - -static ssize_t input_map_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct solo_dev *solo_dev = - container_of(dev, struct solo_dev, dev); - unsigned int val; - char *out = buf; - - val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_0); - out += sprintf(out, "Channel 0 => Input %d\n", val & 0x1f); - out += sprintf(out, "Channel 1 => Input %d\n", (val >> 5) & 0x1f); - out += sprintf(out, "Channel 2 => Input %d\n", (val >> 10) & 0x1f); - out += sprintf(out, "Channel 3 => Input %d\n", (val >> 15) & 0x1f); - out += sprintf(out, "Channel 4 => Input %d\n", (val >> 20) & 0x1f); - out += sprintf(out, "Channel 5 => Input %d\n", (val >> 25) & 0x1f); - - val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_1); - out += sprintf(out, "Channel 6 => Input %d\n", val & 0x1f); - out += sprintf(out, "Channel 7 => Input %d\n", (val >> 5) & 0x1f); - out += sprintf(out, "Channel 8 => Input %d\n", (val >> 10) & 0x1f); - out += sprintf(out, "Channel 9 => Input %d\n", (val >> 15) & 0x1f); - out += sprintf(out, "Channel 10 => Input %d\n", (val >> 20) & 0x1f); - out += sprintf(out, "Channel 11 => Input %d\n", (val >> 25) & 0x1f); - - val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_2); - out += sprintf(out, "Channel 12 => Input %d\n", val & 0x1f); - out += sprintf(out, "Channel 13 => Input %d\n", (val >> 5) & 0x1f); - out += sprintf(out, "Channel 14 => Input %d\n", (val >> 10) & 0x1f); - out += sprintf(out, "Channel 15 => Input %d\n", (val >> 15) & 0x1f); - out += sprintf(out, "Spot Output => Input %d\n", (val >> 20) & 0x1f); - - return out - buf; -} - -static ssize_t p2m_timeout_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct solo_dev *solo_dev = - container_of(dev, struct solo_dev, dev); - unsigned long ms; - - int ret = kstrtoul(buf, 10, &ms); - if (ret < 0 || ms > 200) - return -EINVAL; - solo_dev->p2m_jiffies = msecs_to_jiffies(ms); - - return count; -} - -static ssize_t p2m_timeout_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct solo_dev *solo_dev = - container_of(dev, struct solo_dev, dev); - - return sprintf(buf, "%ums\n", jiffies_to_msecs(solo_dev->p2m_jiffies)); -} - -static ssize_t intervals_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct solo_dev *solo_dev = - container_of(dev, struct solo_dev, dev); - char *out = buf; - int fps = solo_dev->fps; - int i; - - for (i = 0; i < solo_dev->nr_chans; i++) { - out += sprintf(out, "Channel %d: %d/%d (0x%08x)\n", - i, solo_dev->v4l2_enc[i]->interval, fps, - solo_reg_read(solo_dev, SOLO_CAP_CH_INTV(i))); - } - - return out - buf; -} - -static ssize_t sdram_offsets_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct solo_dev *solo_dev = - container_of(dev, struct solo_dev, dev); - char *out = buf; - - out += sprintf(out, "DISP: 0x%08x @ 0x%08x\n", - SOLO_DISP_EXT_ADDR, - SOLO_DISP_EXT_SIZE); - - out += sprintf(out, "EOSD: 0x%08x @ 0x%08x (0x%08x * %d)\n", - SOLO_EOSD_EXT_ADDR, - SOLO_EOSD_EXT_AREA(solo_dev), - SOLO_EOSD_EXT_SIZE(solo_dev), - SOLO_EOSD_EXT_AREA(solo_dev) / - SOLO_EOSD_EXT_SIZE(solo_dev)); - - out += sprintf(out, "MOTI: 0x%08x @ 0x%08x\n", - SOLO_MOTION_EXT_ADDR(solo_dev), - SOLO_MOTION_EXT_SIZE); - - out += sprintf(out, "G723: 0x%08x @ 0x%08x\n", - SOLO_G723_EXT_ADDR(solo_dev), - SOLO_G723_EXT_SIZE); - - out += sprintf(out, "CAPT: 0x%08x @ 0x%08x (0x%08x * %d)\n", - SOLO_CAP_EXT_ADDR(solo_dev), - SOLO_CAP_EXT_SIZE(solo_dev), - SOLO_CAP_PAGE_SIZE, - SOLO_CAP_EXT_SIZE(solo_dev) / SOLO_CAP_PAGE_SIZE); - - out += sprintf(out, "EREF: 0x%08x @ 0x%08x (0x%08x * %d)\n", - SOLO_EREF_EXT_ADDR(solo_dev), - SOLO_EREF_EXT_AREA(solo_dev), - SOLO_EREF_EXT_SIZE, - SOLO_EREF_EXT_AREA(solo_dev) / SOLO_EREF_EXT_SIZE); - - out += sprintf(out, "MPEG: 0x%08x @ 0x%08x\n", - SOLO_MP4E_EXT_ADDR(solo_dev), - SOLO_MP4E_EXT_SIZE(solo_dev)); - - out += sprintf(out, "JPEG: 0x%08x @ 0x%08x\n", - SOLO_JPEG_EXT_ADDR(solo_dev), - SOLO_JPEG_EXT_SIZE(solo_dev)); - - return out - buf; -} - -static ssize_t sdram_show(struct file *file, struct kobject *kobj, - struct bin_attribute *a, char *buf, - loff_t off, size_t count) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct solo_dev *solo_dev = - container_of(dev, struct solo_dev, dev); - const int size = solo_dev->sdram_size; - - if (off >= size) - return 0; - - if (off + count > size) - count = size - off; - - if (solo_p2m_dma(solo_dev, 0, buf, off, count, 0, 0)) - return -EIO; - - return count; -} - -static const struct device_attribute solo_dev_attrs[] = { - __ATTR(eeprom, 0640, eeprom_show, eeprom_store), - __ATTR(p2m_timeout, 0644, p2m_timeout_show, p2m_timeout_store), - __ATTR_RO(p2m_timeouts), - __ATTR_RO(sdram_size), - __ATTR_RO(tw28xx), - __ATTR_RO(input_map), - __ATTR_RO(intervals), - __ATTR_RO(sdram_offsets), -}; - -static void solo_device_release(struct device *dev) -{ - /* Do nothing */ -} - -static int solo_sysfs_init(struct solo_dev *solo_dev) -{ - struct bin_attribute *sdram_attr = &solo_dev->sdram_attr; - struct device *dev = &solo_dev->dev; - const char *driver; - int i; - - if (solo_dev->type == SOLO_DEV_6110) - driver = "solo6110"; - else - driver = "solo6010"; - - dev->release = solo_device_release; - dev->parent = &solo_dev->pdev->dev; - set_dev_node(dev, dev_to_node(&solo_dev->pdev->dev)); - dev_set_name(dev, "%s-%d-%d", driver, solo_dev->vfd->num, - solo_dev->nr_chans); - - if (device_register(dev)) { - dev->parent = NULL; - return -ENOMEM; - } - - for (i = 0; i < ARRAY_SIZE(solo_dev_attrs); i++) { - if (device_create_file(dev, &solo_dev_attrs[i])) { - device_unregister(dev); - return -ENOMEM; - } - } - - sysfs_attr_init(&sdram_attr->attr); - sdram_attr->attr.name = "sdram"; - sdram_attr->attr.mode = 0440; - sdram_attr->read = sdram_show; - sdram_attr->size = solo_dev->sdram_size; - - if (device_create_bin_file(dev, sdram_attr)) { - device_unregister(dev); - return -ENOMEM; - } - - return 0; -} - -static int solo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct solo_dev *solo_dev; - int ret; - u8 chip_id; - - solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL); - if (solo_dev == NULL) - return -ENOMEM; - - if (id->driver_data == SOLO_DEV_6010) - dev_info(&pdev->dev, "Probing Softlogic 6010\n"); - else - dev_info(&pdev->dev, "Probing Softlogic 6110\n"); - - solo_dev->type = id->driver_data; - solo_dev->pdev = pdev; - spin_lock_init(&solo_dev->reg_io_lock); - ret = v4l2_device_register(&pdev->dev, &solo_dev->v4l2_dev); - if (ret) - goto fail_probe; - - /* Only for during init */ - solo_dev->p2m_jiffies = msecs_to_jiffies(100); - - ret = pci_enable_device(pdev); - if (ret) - goto fail_probe; - - pci_set_master(pdev); - - /* RETRY/TRDY Timeout disabled */ - pci_write_config_byte(pdev, 0x40, 0x00); - pci_write_config_byte(pdev, 0x41, 0x00); - - ret = pci_request_regions(pdev, SOLO6X10_NAME); - if (ret) - goto fail_probe; - - solo_dev->reg_base = pci_ioremap_bar(pdev, 0); - if (solo_dev->reg_base == NULL) { - ret = -ENOMEM; - goto fail_probe; - } - - chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) & - SOLO_CHIP_ID_MASK; - switch (chip_id) { - case 7: - solo_dev->nr_chans = 16; - solo_dev->nr_ext = 5; - break; - case 6: - solo_dev->nr_chans = 8; - solo_dev->nr_ext = 2; - break; - default: - dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, assuming 4 ch\n", - chip_id); - case 5: - solo_dev->nr_chans = 4; - solo_dev->nr_ext = 1; - } - - /* Disable all interrupts to start */ - solo_irq_off(solo_dev, ~0); - - /* Initial global settings */ - if (solo_dev->type == SOLO_DEV_6010) { - solo_dev->clock_mhz = 108; - solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT - | SOLO_SYS_CFG_INPUTDIV(25) - | SOLO_SYS_CFG_FEEDBACKDIV(solo_dev->clock_mhz * 2 - 2) - | SOLO_SYS_CFG_OUTDIV(3); - solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config); - } else { - u32 divq, divf; - - solo_dev->clock_mhz = 135; - - if (solo_dev->clock_mhz < 125) { - divq = 3; - divf = (solo_dev->clock_mhz * 4) / 3 - 1; - } else { - divq = 2; - divf = (solo_dev->clock_mhz * 2) / 3 - 1; - } - - solo_reg_write(solo_dev, SOLO_PLL_CONFIG, - (1 << 20) | /* PLL_RANGE */ - (8 << 15) | /* PLL_DIVR */ - (divq << 12) | - (divf << 4) | - (1 << 1) /* PLL_FSEN */); - - solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT; - } - - solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config); - solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, - solo_dev->clock_mhz - 1); - - /* PLL locking time of 1ms */ - mdelay(1); - - ret = request_irq(pdev->irq, solo_isr, IRQF_SHARED, SOLO6X10_NAME, - solo_dev); - if (ret) - goto fail_probe; - - /* Handle this from the start */ - solo_irq_on(solo_dev, SOLO_IRQ_PCI_ERR); - - ret = solo_i2c_init(solo_dev); - if (ret) - goto fail_probe; - - /* Setup the DMA engine */ - solo_reg_write(solo_dev, SOLO_DMA_CTRL, - SOLO_DMA_CTRL_REFRESH_CYCLE(1) | - SOLO_DMA_CTRL_SDRAM_SIZE(2) | - SOLO_DMA_CTRL_SDRAM_CLK_INVERT | - SOLO_DMA_CTRL_READ_CLK_SELECT | - SOLO_DMA_CTRL_LATENCY(1)); - - /* Undocumented crap */ - solo_reg_write(solo_dev, SOLO_DMA_CTRL1, - solo_dev->type == SOLO_DEV_6010 ? 0x100 : 0x300); - - if (solo_dev->type != SOLO_DEV_6010) { - solo_dev->usec_lsb = 0x3f; - solo_set_time(solo_dev); - } - - /* Disable watchdog */ - solo_reg_write(solo_dev, SOLO_WATCHDOG, 0); - - /* Initialize sub components */ - - ret = solo_p2m_init(solo_dev); - if (ret) - goto fail_probe; - - ret = solo_disp_init(solo_dev); - if (ret) - goto fail_probe; - - ret = solo_gpio_init(solo_dev); - if (ret) - goto fail_probe; - - ret = solo_tw28_init(solo_dev); - if (ret) - goto fail_probe; - - ret = solo_v4l2_init(solo_dev, video_nr); - if (ret) - goto fail_probe; - - ret = solo_enc_init(solo_dev); - if (ret) - goto fail_probe; - - ret = solo_enc_v4l2_init(solo_dev, video_nr); - if (ret) - goto fail_probe; - - ret = solo_g723_init(solo_dev); - if (ret) - goto fail_probe; - - ret = solo_sysfs_init(solo_dev); - if (ret) - goto fail_probe; - - /* Now that init is over, set this lower */ - solo_dev->p2m_jiffies = msecs_to_jiffies(20); - - return 0; - -fail_probe: - free_solo_dev(solo_dev); - return ret; -} - -static void solo_pci_remove(struct pci_dev *pdev) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); - struct solo_dev *solo_dev = container_of(v4l2_dev, struct solo_dev, v4l2_dev); - - free_solo_dev(solo_dev); -} - -static DEFINE_PCI_DEVICE_TABLE(solo_id_table) = { - /* 6010 based cards */ - { PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010), - .driver_data = SOLO_DEV_6010 }, - { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4), - .driver_data = SOLO_DEV_6010 }, - { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9), - .driver_data = SOLO_DEV_6010 }, - { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16), - .driver_data = SOLO_DEV_6010 }, - { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4), - .driver_data = SOLO_DEV_6010 }, - { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9), - .driver_data = SOLO_DEV_6010 }, - { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16), - .driver_data = SOLO_DEV_6010 }, - /* 6110 based cards */ - { PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6110), - .driver_data = SOLO_DEV_6110 }, - { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4), - .driver_data = SOLO_DEV_6110 }, - { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8), - .driver_data = SOLO_DEV_6110 }, - { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16), - .driver_data = SOLO_DEV_6110 }, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, solo_id_table); - -static struct pci_driver solo_pci_driver = { - .name = SOLO6X10_NAME, - .id_table = solo_id_table, - .probe = solo_pci_probe, - .remove = solo_pci_remove, -}; - -module_pci_driver(solo_pci_driver); diff --git a/drivers/staging/media/solo6x10/disp.c b/drivers/staging/media/solo6x10/disp.c deleted file mode 100644 index 78070c8..0000000 --- a/drivers/staging/media/solo6x10/disp.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (C) 2010-2013 Bluecherry, LLC - * - * Original author: - * Ben Collins - * - * Additional work by: - * John Brooks - * - * 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. - */ - -#include -#include -#include -#include - -#include "solo6x10.h" - -#define SOLO_VCLK_DELAY 3 -#define SOLO_PROGRESSIVE_VSIZE 1024 - -#define SOLO_MOT_THRESH_W 64 -#define SOLO_MOT_THRESH_H 64 -#define SOLO_MOT_THRESH_SIZE 8192 -#define SOLO_MOT_THRESH_REAL (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H) -#define SOLO_MOT_FLAG_SIZE 1024 -#define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 16) - -static void solo_vin_config(struct solo_dev *solo_dev) -{ - solo_dev->vin_hstart = 8; - solo_dev->vin_vstart = 2; - - solo_reg_write(solo_dev, SOLO_SYS_VCLK, - SOLO_VCLK_SELECT(2) | - SOLO_VCLK_VIN1415_DELAY(SOLO_VCLK_DELAY) | - SOLO_VCLK_VIN1213_DELAY(SOLO_VCLK_DELAY) | - SOLO_VCLK_VIN1011_DELAY(SOLO_VCLK_DELAY) | - SOLO_VCLK_VIN0809_DELAY(SOLO_VCLK_DELAY) | - SOLO_VCLK_VIN0607_DELAY(SOLO_VCLK_DELAY) | - SOLO_VCLK_VIN0405_DELAY(SOLO_VCLK_DELAY) | - SOLO_VCLK_VIN0203_DELAY(SOLO_VCLK_DELAY) | - SOLO_VCLK_VIN0001_DELAY(SOLO_VCLK_DELAY)); - - solo_reg_write(solo_dev, SOLO_VI_ACT_I_P, - SOLO_VI_H_START(solo_dev->vin_hstart) | - SOLO_VI_V_START(solo_dev->vin_vstart) | - SOLO_VI_V_STOP(solo_dev->vin_vstart + - solo_dev->video_vsize)); - - solo_reg_write(solo_dev, SOLO_VI_ACT_I_S, - SOLO_VI_H_START(solo_dev->vout_hstart) | - SOLO_VI_V_START(solo_dev->vout_vstart) | - SOLO_VI_V_STOP(solo_dev->vout_vstart + - solo_dev->video_vsize)); - - solo_reg_write(solo_dev, SOLO_VI_ACT_P, - SOLO_VI_H_START(0) | - SOLO_VI_V_START(1) | - SOLO_VI_V_STOP(SOLO_PROGRESSIVE_VSIZE)); - - solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT, - SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0)); - - /* On 6110, initialize mozaic darkness stength */ - if (solo_dev->type == SOLO_DEV_6010) - solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0); - else - solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 16 << 22); - - solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2); - - if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { - solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG, - SOLO_VI_PB_USER_MODE); - solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV, - SOLO_VI_PB_HSIZE(858) | SOLO_VI_PB_VSIZE(246)); - solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V, - SOLO_VI_PB_VSTART(4) | - SOLO_VI_PB_VSTOP(4 + 240)); - } else { - solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG, - SOLO_VI_PB_USER_MODE | SOLO_VI_PB_PAL); - solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV, - SOLO_VI_PB_HSIZE(864) | SOLO_VI_PB_VSIZE(294)); - solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V, - SOLO_VI_PB_VSTART(4) | - SOLO_VI_PB_VSTOP(4 + 288)); - } - solo_reg_write(solo_dev, SOLO_VI_PB_ACT_H, SOLO_VI_PB_HSTART(16) | - SOLO_VI_PB_HSTOP(16 + 720)); -} - -static void solo_vout_config_cursor(struct solo_dev *dev) -{ - int i; - - /* Load (blank) cursor bitmap mask (2bpp) */ - for (i = 0; i < 20; i++) - solo_reg_write(dev, SOLO_VO_CURSOR_MASK(i), 0); - - solo_reg_write(dev, SOLO_VO_CURSOR_POS, 0); - - solo_reg_write(dev, SOLO_VO_CURSOR_CLR, - (0x80 << 24) | (0x80 << 16) | (0x10 << 8) | 0x80); - solo_reg_write(dev, SOLO_VO_CURSOR_CLR2, (0xe0 << 8) | 0x80); -} - -static void solo_vout_config(struct solo_dev *solo_dev) -{ - solo_dev->vout_hstart = 6; - solo_dev->vout_vstart = 8; - - solo_reg_write(solo_dev, SOLO_VO_FMT_ENC, - solo_dev->video_type | - SOLO_VO_USER_COLOR_SET_NAV | - SOLO_VO_USER_COLOR_SET_NAH | - SOLO_VO_NA_COLOR_Y(0) | - SOLO_VO_NA_COLOR_CB(0) | - SOLO_VO_NA_COLOR_CR(0)); - - solo_reg_write(solo_dev, SOLO_VO_ACT_H, - SOLO_VO_H_START(solo_dev->vout_hstart) | - SOLO_VO_H_STOP(solo_dev->vout_hstart + - solo_dev->video_hsize)); - - solo_reg_write(solo_dev, SOLO_VO_ACT_V, - SOLO_VO_V_START(solo_dev->vout_vstart) | - SOLO_VO_V_STOP(solo_dev->vout_vstart + - solo_dev->video_vsize)); - - solo_reg_write(solo_dev, SOLO_VO_RANGE_HV, - SOLO_VO_H_LEN(solo_dev->video_hsize) | - SOLO_VO_V_LEN(solo_dev->video_vsize)); - - /* Border & background colors */ - solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR, - (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88); - solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR, - (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f); - solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR, - (16 << 24) | (128 << 16) | (16 << 8) | 128); - - solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); - - solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 0); - - solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0); - solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0); - - solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON | - SOLO_VO_DISP_ERASE_COUNT(8) | - SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR)); - - - solo_vout_config_cursor(solo_dev); - - /* Enable channels we support */ - solo_reg_write(solo_dev, SOLO_VI_CH_ENA, - (1 << solo_dev->nr_chans) - 1); -} - -static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off, - u16 val, int reg_size) -{ - u16 buf[64]; - int i; - int ret = 0; - - for (i = 0; i < sizeof(buf) >> 1; i++) - buf[i] = cpu_to_le16(val); - - for (i = 0; i < reg_size; i += sizeof(buf)) - ret |= solo_p2m_dma(solo_dev, 1, buf, - SOLO_MOTION_EXT_ADDR(solo_dev) + off + i, - sizeof(buf), 0, 0); - - return ret; -} - -int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val) -{ - if (ch > solo_dev->nr_chans) - return -EINVAL; - - return solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + - (ch * SOLO_MOT_THRESH_SIZE * 2), - val, SOLO_MOT_THRESH_SIZE); -} - -int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, - const struct solo_motion_thresholds *thresholds) -{ - u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2; - u16 buf[SOLO_MOTION_SZ]; - int x, y; - int ret = 0; - - for (y = 0; y < SOLO_MOTION_SZ; y++) { - for (x = 0; x < SOLO_MOTION_SZ; x++) - buf[x] = cpu_to_le16(thresholds->thresholds[y][x]); - ret |= solo_p2m_dma(solo_dev, 1, buf, - SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * sizeof(buf), - sizeof(buf), 0, 0); - } - return ret; -} - -/* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k - * threshold and working table for each channel. Atleast that's what the - * spec says. However, this code (taken from rdk) has some mystery 8k - * block right after the flag area, before the first thresh table. */ -static void solo_motion_config(struct solo_dev *solo_dev) -{ - int i; - - for (i = 0; i < solo_dev->nr_chans; i++) { - /* Clear motion flag area */ - solo_dma_vin_region(solo_dev, i * SOLO_MOT_FLAG_SIZE, 0x0000, - SOLO_MOT_FLAG_SIZE); - - /* Clear working cache table */ - solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + - (i * SOLO_MOT_THRESH_SIZE * 2) + - SOLO_MOT_THRESH_SIZE, 0x0000, - SOLO_MOT_THRESH_SIZE); - - /* Set default threshold table */ - solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH); - } - - /* Default motion settings */ - solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) | - (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16)); - solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL, - SOLO_VI_MOTION_FRAME_COUNT(3) | - SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16) - /* | SOLO_VI_MOTION_INTR_START_STOP */ - | SOLO_VI_MOTION_SAMPLE_COUNT(10)); - - solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0); - solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); -} - -int solo_disp_init(struct solo_dev *solo_dev) -{ - int i; - - solo_dev->video_hsize = 704; - if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { - solo_dev->video_vsize = 240; - solo_dev->fps = 30; - } else { - solo_dev->video_vsize = 288; - solo_dev->fps = 25; - } - - solo_vin_config(solo_dev); - solo_motion_config(solo_dev); - solo_vout_config(solo_dev); - - for (i = 0; i < solo_dev->nr_chans; i++) - solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1); - - return 0; -} - -void solo_disp_exit(struct solo_dev *solo_dev) -{ - int i; - - solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0); - solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0); - solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0); - - for (i = 0; i < solo_dev->nr_chans; i++) { - solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(i), 0); - solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(i), 0); - solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 0); - } - - /* Set default border */ - for (i = 0; i < 5; i++) - solo_reg_write(solo_dev, SOLO_VO_BORDER_X(i), 0); - - for (i = 0; i < 5; i++) - solo_reg_write(solo_dev, SOLO_VO_BORDER_Y(i), 0); - - solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_MASK, 0); - solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_MASK, 0); - - solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0); - solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0); - solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0); - - solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0); - solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0); - solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0); -} diff --git a/drivers/staging/media/solo6x10/eeprom.c b/drivers/staging/media/solo6x10/eeprom.c deleted file mode 100644 index 9d1c9bb..0000000 --- a/drivers/staging/media/solo6x10/eeprom.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2010-2013 Bluecherry, LLC - * - * Original author: - * Ben Collins - * - * Additional work by: - * John Brooks - * - * 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. - */ - -#include -#include - -#include "solo6x10.h" - -/* Control */ -#define EE_SHIFT_CLK 0x04 -#define EE_CS 0x08 -#define EE_DATA_WRITE 0x02 -#define EE_DATA_READ 0x01 -#define EE_ENB (0x80 | EE_CS) - -#define eeprom_delay() udelay(100) -#if 0 -#define eeprom_delay() solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) -#define eeprom_delay() ({ \ - int i, ret; \ - udelay(100); \ - for (i = ret = 0; i < 1000 && !ret; i++) \ - ret = solo_eeprom_reg_read(solo_dev); \ -}) -#endif -#define ADDR_LEN 6 - -/* Commands */ -#define EE_EWEN_CMD 4 -#define EE_EWDS_CMD 4 -#define EE_WRITE_CMD 5 -#define EE_READ_CMD 6 -#define EE_ERASE_CMD 7 - -static unsigned int solo_eeprom_reg_read(struct solo_dev *solo_dev) -{ - return solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) & EE_DATA_READ; -} - -static void solo_eeprom_reg_write(struct solo_dev *solo_dev, u32 data) -{ - solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data); - eeprom_delay(); -} - -static void solo_eeprom_cmd(struct solo_dev *solo_dev, int cmd) -{ - int i; - - solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ACCESS_EN); - solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); - - for (i = 4 + ADDR_LEN; i >= 0; i--) { - int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0; - - solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | dataval); - solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | - EE_SHIFT_CLK | dataval); - } - - solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); -} - -unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en) -{ - int ewen_cmd = (w_en ? 0x3f : 0) | (EE_EWEN_CMD << ADDR_LEN); - unsigned int retval = 0; - int i; - - solo_eeprom_cmd(solo_dev, ewen_cmd); - - for (i = 0; i < 16; i++) { - solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | - EE_SHIFT_CLK); - retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); - solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); - retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); - } - - solo_eeprom_reg_write(solo_dev, ~EE_CS); - retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); - - return retval; -} - -unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc) -{ - int read_cmd = loc | (EE_READ_CMD << ADDR_LEN); - unsigned short retval = 0; - int i; - - solo_eeprom_cmd(solo_dev, read_cmd); - - for (i = 0; i < 16; i++) { - solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | - EE_SHIFT_CLK); - retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); - solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); - } - - solo_eeprom_reg_write(solo_dev, ~EE_CS); - - return retval; -} - -int solo_eeprom_write(struct solo_dev *solo_dev, int loc, - unsigned short data) -{ - int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN); - unsigned int retval; - int i; - - solo_eeprom_cmd(solo_dev, write_cmd); - - for (i = 15; i >= 0; i--) { - unsigned int dataval = (data >> i) & 1; - - solo_eeprom_reg_write(solo_dev, EE_ENB); - solo_eeprom_reg_write(solo_dev, - EE_ENB | (dataval << 1) | EE_SHIFT_CLK); - } - - solo_eeprom_reg_write(solo_dev, EE_ENB); - solo_eeprom_reg_write(solo_dev, ~EE_CS); - solo_eeprom_reg_write(solo_dev, EE_ENB); - - for (i = retval = 0; i < 10000 && !retval; i++) - retval = solo_eeprom_reg_read(solo_dev); - - solo_eeprom_reg_write(solo_dev, ~EE_CS); - - return !retval; -} diff --git a/drivers/staging/media/solo6x10/enc.c b/drivers/staging/media/solo6x10/enc.c deleted file mode 100644 index 94d5735..0000000 --- a/drivers/staging/media/solo6x10/enc.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (C) 2010-2013 Bluecherry, LLC - * - * Original author: - * Ben Collins - * - * Additional work by: - * John Brooks - * - * 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. - */ - -#include -#include -#include -#include - -#include "solo6x10.h" - -#define VI_PROG_HSIZE (1280 - 16) -#define VI_PROG_VSIZE (1024 - 16) - -#define IRQ_LEVEL 2 - -static void solo_capture_config(struct solo_dev *solo_dev) -{ - unsigned long height; - unsigned long width; - void *buf; - int i; - - solo_reg_write(solo_dev, SOLO_CAP_BASE, - SOLO_CAP_MAX_PAGE((SOLO_CAP_EXT_SIZE(solo_dev) - - SOLO_CAP_PAGE_SIZE) >> 16) - | SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16)); - - /* XXX: Undocumented bits at b17 and b24 */ - if (solo_dev->type == SOLO_DEV_6110) { - /* NOTE: Ref driver has (62 << 24) here as well, but it causes - * wacked out frame timing on 4-port 6110. */ - solo_reg_write(solo_dev, SOLO_CAP_BTW, - (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | - SOLO_CAP_MAX_BANDWIDTH(36)); - } else { - solo_reg_write(solo_dev, SOLO_CAP_BTW, - (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | - SOLO_CAP_MAX_BANDWIDTH(32)); - } - - /* Set scale 1, 9 dimension */ - width = solo_dev->video_hsize; - height = solo_dev->video_vsize; - solo_reg_write(solo_dev, SOLO_DIM_SCALE1, - SOLO_DIM_H_MB_NUM(width / 16) | - SOLO_DIM_V_MB_NUM_FRAME(height / 8) | - SOLO_DIM_V_MB_NUM_FIELD(height / 16)); - - /* Set scale 2, 10 dimension */ - width = solo_dev->video_hsize / 2; - height = solo_dev->video_vsize; - solo_reg_write(solo_dev, SOLO_DIM_SCALE2, - SOLO_DIM_H_MB_NUM(width / 16) | - SOLO_DIM_V_MB_NUM_FRAME(height / 8) | - SOLO_DIM_V_MB_NUM_FIELD(height / 16)); - - /* Set scale 3, 11 dimension */ - width = solo_dev->video_hsize / 2; - height = solo_dev->video_vsize / 2; - solo_reg_write(solo_dev, SOLO_DIM_SCALE3, - SOLO_DIM_H_MB_NUM(width / 16) | - SOLO_DIM_V_MB_NUM_FRAME(height / 8) | - SOLO_DIM_V_MB_NUM_FIELD(height / 16)); - - /* Set scale 4, 12 dimension */ - width = solo_dev->video_hsize / 3; - height = solo_dev->video_vsize / 3; - solo_reg_write(solo_dev, SOLO_DIM_SCALE4, - SOLO_DIM_H_MB_NUM(width / 16) | - SOLO_DIM_V_MB_NUM_FRAME(height / 8) | - SOLO_DIM_V_MB_NUM_FIELD(height / 16)); - - /* Set scale 5, 13 dimension */ - width = solo_dev->video_hsize / 4; - height = solo_dev->video_vsize / 2; - solo_reg_write(solo_dev, SOLO_DIM_SCALE5, - SOLO_DIM_H_MB_NUM(width / 16) | - SOLO_DIM_V_MB_NUM_FRAME(height / 8) | - SOLO_DIM_V_MB_NUM_FIELD(height / 16)); - - /* Progressive */ - width = VI_PROG_HSIZE; - height = VI_PROG_VSIZE; - solo_reg_write(solo_dev, SOLO_DIM_PROG, - SOLO_DIM_H_MB_NUM(width / 16) | - SOLO_DIM_V_MB_NUM_FRAME(height / 16) | - SOLO_DIM_V_MB_NUM_FIELD(height / 16)); - - /* Clear OSD */ - solo_reg_write(solo_dev, SOLO_VE_OSD_CH, 0); - solo_reg_write(solo_dev, SOLO_VE_OSD_BASE, SOLO_EOSD_EXT_ADDR >> 16); - solo_reg_write(solo_dev, SOLO_VE_OSD_CLR, - 0xF0 << 16 | 0x80 << 8 | 0x80); - - if (solo_dev->type == SOLO_DEV_6010) - solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, - SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW); - else - solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, SOLO_VE_OSD_V_DOUBLE - | SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW); - - /* Clear OSG buffer */ - buf = kzalloc(SOLO_EOSD_EXT_SIZE(solo_dev), GFP_KERNEL); - if (!buf) - return; - - for (i = 0; i < solo_dev->nr_chans; i++) { - solo_p2m_dma(solo_dev, 1, buf, - SOLO_EOSD_EXT_ADDR + - (SOLO_EOSD_EXT_SIZE(solo_dev) * i), - SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0); - } - kfree(buf); -} - -/* Should be called with enable_lock held */ -int solo_osd_print(struct solo_enc_dev *solo_enc) -{ - struct solo_dev *solo_dev = solo_enc->solo_dev; - unsigned char *str = solo_enc->osd_text; - u8 *buf = solo_enc->osd_buf; - u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH); - const struct font_desc *vga = find_font("VGA8x16"); - const unsigned char *vga_data; - int len; - int i, j; - - if (WARN_ON_ONCE(!vga)) - return -ENODEV; - - len = strlen(str); - - if (len == 0) { - /* Disable OSD on this channel */ - reg &= ~(1 << solo_enc->ch); - solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); - return 0; - } - - memset(buf, 0, SOLO_EOSD_EXT_SIZE_MAX); - vga_data = (const unsigned char *)vga->data; - - for (i = 0; i < len; i++) { - unsigned char c = str[i]; - - for (j = 0; j < 16; j++) { - buf[(j * 2) + (i % 2) + (i / 2 * 32)] = - bitrev8(vga_data[(c * 16) + j]); - } - } - - solo_p2m_dma(solo_dev, 1, buf, - SOLO_EOSD_EXT_ADDR + - (solo_enc->ch * SOLO_EOSD_EXT_SIZE(solo_dev)), - SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0); - - /* Enable OSD on this channel */ - reg |= (1 << solo_enc->ch); - solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); - - return 0; -} - -/** - * Set channel Quality Profile (0-3). - */ -void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch, - unsigned int qp) -{ - unsigned long flags; - unsigned int idx, reg; - - if ((ch > 31) || (qp > 3)) - return; - - if (solo_dev->type == SOLO_DEV_6010) - return; - - if (ch < 16) { - idx = 0; - reg = SOLO_VE_JPEG_QP_CH_L; - } else { - ch -= 16; - idx = 1; - reg = SOLO_VE_JPEG_QP_CH_H; - } - ch *= 2; - - spin_lock_irqsave(&solo_dev->jpeg_qp_lock, flags); - - solo_dev->jpeg_qp[idx] &= ~(3 << ch); - solo_dev->jpeg_qp[idx] |= (qp & 3) << ch; - - solo_reg_write(solo_dev, reg, solo_dev->jpeg_qp[idx]); - - spin_unlock_irqrestore(&solo_dev->jpeg_qp_lock, flags); -} - -int solo_g_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch) -{ - int idx; - - if (solo_dev->type == SOLO_DEV_6010) - return 2; - - if (WARN_ON_ONCE(ch > 31)) - return 2; - - if (ch < 16) { - idx = 0; - } else { - ch -= 16; - idx = 1; - } - ch *= 2; - - return (solo_dev->jpeg_qp[idx] >> ch) & 3; -} - -#define SOLO_QP_INIT 0xaaaaaaaa - -static void solo_jpeg_config(struct solo_dev *solo_dev) -{ - if (solo_dev->type == SOLO_DEV_6010) { - solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, - (2 << 24) | (2 << 16) | (2 << 8) | 2); - } else { - solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, - (4 << 24) | (3 << 16) | (2 << 8) | 1); - } - - spin_lock_init(&solo_dev->jpeg_qp_lock); - - /* Initialize Quality Profile for all channels */ - solo_dev->jpeg_qp[0] = solo_dev->jpeg_qp[1] = SOLO_QP_INIT; - solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, SOLO_QP_INIT); - solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, SOLO_QP_INIT); - - solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG, - (SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) | - ((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff)); - solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff); - if (solo_dev->type == SOLO_DEV_6110) { - solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG1, - (0 << 16) | (30 << 8) | 60); - } -} - -static void solo_mp4e_config(struct solo_dev *solo_dev) -{ - int i; - u32 cfg; - - solo_reg_write(solo_dev, SOLO_VE_CFG0, - SOLO_VE_INTR_CTRL(IRQ_LEVEL) | - SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) | - SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16)); - - - cfg = SOLO_VE_BYTE_ALIGN(2) | SOLO_VE_INSERT_INDEX - | SOLO_VE_MOTION_MODE(0); - if (solo_dev->type != SOLO_DEV_6010) { - cfg |= SOLO_VE_MPEG_SIZE_H( - (SOLO_MP4E_EXT_SIZE(solo_dev) >> 24) & 0x0f); - cfg |= SOLO_VE_JPEG_SIZE_H( - (SOLO_JPEG_EXT_SIZE(solo_dev) >> 24) & 0x0f); - } - solo_reg_write(solo_dev, SOLO_VE_CFG1, cfg); - - solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0); - solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0); - solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0); - if (solo_dev->type == SOLO_DEV_6110) - solo_reg_write(solo_dev, SOLO_VE_WMRK_ENABLE, 0); - solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0); - solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0); - - solo_reg_write(solo_dev, SOLO_VE_ATTR, - SOLO_VE_LITTLE_ENDIAN | - SOLO_COMP_ATTR_FCODE(1) | - SOLO_COMP_TIME_INC(0) | - SOLO_COMP_TIME_WIDTH(15) | - SOLO_DCT_INTERVAL(solo_dev->type == SOLO_DEV_6010 ? 9 : 10)); - - for (i = 0; i < solo_dev->nr_chans; i++) { - solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i), - (SOLO_EREF_EXT_ADDR(solo_dev) + - (i * SOLO_EREF_EXT_SIZE)) >> 16); - solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE_E(i), - (SOLO_EREF_EXT_ADDR(solo_dev) + - ((i + 16) * SOLO_EREF_EXT_SIZE)) >> 16); - } - - if (solo_dev->type == SOLO_DEV_6110) { - solo_reg_write(solo_dev, SOLO_VE_COMPT_MOT, 0x00040008); - } else { - for (i = 0; i < solo_dev->nr_chans; i++) - solo_reg_write(solo_dev, SOLO_VE_CH_MOT(i), 0x100); - } -} - -int solo_enc_init(struct solo_dev *solo_dev) -{ - int i; - - solo_capture_config(solo_dev); - solo_mp4e_config(solo_dev); - solo_jpeg_config(solo_dev); - - for (i = 0; i < solo_dev->nr_chans; i++) { - solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); - solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); - } - - return 0; -} - -void solo_enc_exit(struct solo_dev *solo_dev) -{ - int i; - - for (i = 0; i < solo_dev->nr_chans; i++) { - solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); - solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); - } -} diff --git a/drivers/staging/media/solo6x10/g723.c b/drivers/staging/media/solo6x10/g723.c deleted file mode 100644 index 1db18c7..0000000 --- a/drivers/staging/media/solo6x10/g723.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (C) 2010-2013 Bluecherry, LLC - * - * Original author: - * Ben Collins - * - * Additional work by: - * John Brooks - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "solo6x10.h" -#include "solo6x10-tw28.h" - -#define G723_FDMA_PAGES 32 -#define G723_PERIOD_BYTES 48 -#define G723_PERIOD_BLOCK 1024 -#define G723_FRAMES_PER_PAGE 48 - -/* Sets up channels 16-19 for decoding and 0-15 for encoding */ -#define OUTMODE_MASK 0x300 - -#define SAMPLERATE 8000 -#define BITRATE 25 - -/* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page - * is broken down to 20 * 48 byte regions (one for each channel possible) - * with the rest of the page being dummy data. */ -#define G723_MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX) -#define G723_INTR_ORDER 4 /* 0 - 4 */ -#define PERIODS_MIN (1 << G723_INTR_ORDER) -#define PERIODS_MAX G723_FDMA_PAGES - -struct solo_snd_pcm { - int on; - spinlock_t lock; - struct solo_dev *solo_dev; - unsigned char *g723_buf; - dma_addr_t g723_dma; -}; - -static void solo_g723_config(struct solo_dev *solo_dev) -{ - int clk_div; - - clk_div = (solo_dev->clock_mhz * 1000000) - / (SAMPLERATE * (BITRATE * 2) * 2); - - solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE, - SOLO_AUDIO_BITRATE(BITRATE) - | SOLO_AUDIO_CLK_DIV(clk_div)); - - solo_reg_write(solo_dev, SOLO_AUDIO_FDMA_INTR, - SOLO_AUDIO_FDMA_INTERVAL(1) - | SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER) - | SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16)); - - solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, - SOLO_AUDIO_ENABLE - | SOLO_AUDIO_I2S_MODE - | SOLO_AUDIO_I2S_MULTI(3) - | SOLO_AUDIO_MODE(OUTMODE_MASK)); -} - -void solo_g723_isr(struct solo_dev *solo_dev) -{ - struct snd_pcm_str *pstr = - &solo_dev->snd_pcm->streams[SNDRV_PCM_STREAM_CAPTURE]; - struct snd_pcm_substream *ss; - struct solo_snd_pcm *solo_pcm; - - for (ss = pstr->substream; ss != NULL; ss = ss->next) { - if (snd_pcm_substream_chip(ss) == NULL) - continue; - - /* This means open() hasn't been called on this one */ - if (snd_pcm_substream_chip(ss) == solo_dev) - continue; - - /* Haven't triggered a start yet */ - solo_pcm = snd_pcm_substream_chip(ss); - if (!solo_pcm->on) - continue; - - snd_pcm_period_elapsed(ss); - } -} - -static int snd_solo_hw_params(struct snd_pcm_substream *ss, - struct snd_pcm_hw_params *hw_params) -{ - return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params)); -} - -static int snd_solo_hw_free(struct snd_pcm_substream *ss) -{ - return snd_pcm_lib_free_pages(ss); -} - -static const struct snd_pcm_hardware snd_solo_pcm_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), - .formats = SNDRV_PCM_FMTBIT_U8, - .rates = SNDRV_PCM_RATE_8000, - .rate_min = SAMPLERATE, - .rate_max = SAMPLERATE, - .channels_min = 1, - .channels_max = 1, - .buffer_bytes_max = G723_MAX_BUFFER, - .period_bytes_min = G723_PERIOD_BYTES, - .period_bytes_max = G723_PERIOD_BYTES, - .periods_min = PERIODS_MIN, - .periods_max = PERIODS_MAX, -}; - -static int snd_solo_pcm_open(struct snd_pcm_substream *ss) -{ - struct solo_dev *solo_dev = snd_pcm_substream_chip(ss); - struct solo_snd_pcm *solo_pcm; - - solo_pcm = kzalloc(sizeof(*solo_pcm), GFP_KERNEL); - if (solo_pcm == NULL) - goto oom; - - solo_pcm->g723_buf = pci_alloc_consistent(solo_dev->pdev, - G723_PERIOD_BYTES, - &solo_pcm->g723_dma); - if (solo_pcm->g723_buf == NULL) - goto oom; - - spin_lock_init(&solo_pcm->lock); - solo_pcm->solo_dev = solo_dev; - ss->runtime->hw = snd_solo_pcm_hw; - - snd_pcm_substream_chip(ss) = solo_pcm; - - return 0; - -oom: - kfree(solo_pcm); - return -ENOMEM; -} - -static int snd_solo_pcm_close(struct snd_pcm_substream *ss) -{ - struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); - - snd_pcm_substream_chip(ss) = solo_pcm->solo_dev; - pci_free_consistent(solo_pcm->solo_dev->pdev, G723_PERIOD_BYTES, - solo_pcm->g723_buf, solo_pcm->g723_dma); - kfree(solo_pcm); - - return 0; -} - -static int snd_solo_pcm_trigger(struct snd_pcm_substream *ss, int cmd) -{ - struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); - struct solo_dev *solo_dev = solo_pcm->solo_dev; - int ret = 0; - - spin_lock(&solo_pcm->lock); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - if (solo_pcm->on == 0) { - /* If this is the first user, switch on interrupts */ - if (atomic_inc_return(&solo_dev->snd_users) == 1) - solo_irq_on(solo_dev, SOLO_IRQ_G723); - solo_pcm->on = 1; - } - break; - case SNDRV_PCM_TRIGGER_STOP: - if (solo_pcm->on) { - /* If this was our last user, switch them off */ - if (atomic_dec_return(&solo_dev->snd_users) == 0) - solo_irq_off(solo_dev, SOLO_IRQ_G723); - solo_pcm->on = 0; - } - break; - default: - ret = -EINVAL; - } - - spin_unlock(&solo_pcm->lock); - - return ret; -} - -static int snd_solo_pcm_prepare(struct snd_pcm_substream *ss) -{ - return 0; -} - -static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss) -{ - struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); - struct solo_dev *solo_dev = solo_pcm->solo_dev; - snd_pcm_uframes_t idx = solo_reg_read(solo_dev, SOLO_AUDIO_STA) & 0x1f; - - return idx * G723_FRAMES_PER_PAGE; -} - -static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel, - snd_pcm_uframes_t pos, void __user *dst, - snd_pcm_uframes_t count) -{ - struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); - struct solo_dev *solo_dev = solo_pcm->solo_dev; - int err, i; - - for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) { - int page = (pos / G723_FRAMES_PER_PAGE) + i; - - err = solo_p2m_dma_t(solo_dev, 0, solo_pcm->g723_dma, - SOLO_G723_EXT_ADDR(solo_dev) + - (page * G723_PERIOD_BLOCK) + - (ss->number * G723_PERIOD_BYTES), - G723_PERIOD_BYTES, 0, 0); - if (err) - return err; - - err = copy_to_user(dst + (i * G723_PERIOD_BYTES), - solo_pcm->g723_buf, G723_PERIOD_BYTES); - - if (err) - return -EFAULT; - } - - return 0; -} - -static struct snd_pcm_ops snd_solo_pcm_ops = { - .open = snd_solo_pcm_open, - .close = snd_solo_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_solo_hw_params, - .hw_free = snd_solo_hw_free, - .prepare = snd_solo_pcm_prepare, - .trigger = snd_solo_pcm_trigger, - .pointer = snd_solo_pcm_pointer, - .copy = snd_solo_pcm_copy, -}; - -static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *info) -{ - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = 1; - info->value.integer.min = 0; - info->value.integer.max = 15; - info->value.integer.step = 1; - - return 0; -} - -static int snd_solo_capture_volume_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol); - u8 ch = value->id.numid - 1; - - value->value.integer.value[0] = tw28_get_audio_gain(solo_dev, ch); - - return 0; -} - -static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) -{ - struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol); - u8 ch = value->id.numid - 1; - u8 old_val; - - old_val = tw28_get_audio_gain(solo_dev, ch); - if (old_val == value->value.integer.value[0]) - return 0; - - tw28_set_audio_gain(solo_dev, ch, value->value.integer.value[0]); - - return 1; -} - -static struct snd_kcontrol_new snd_solo_capture_volume = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Volume", - .info = snd_solo_capture_volume_info, - .get = snd_solo_capture_volume_get, - .put = snd_solo_capture_volume_put, -}; - -static int solo_snd_pcm_init(struct solo_dev *solo_dev) -{ - struct snd_card *card = solo_dev->snd_card; - struct snd_pcm *pcm; - struct snd_pcm_substream *ss; - int ret; - int i; - - ret = snd_pcm_new(card, card->driver, 0, 0, solo_dev->nr_chans, - &pcm); - if (ret < 0) - return ret; - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, - &snd_solo_pcm_ops); - - snd_pcm_chip(pcm) = solo_dev; - pcm->info_flags = 0; - strcpy(pcm->name, card->shortname); - - for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; - ss; ss = ss->next, i++) - sprintf(ss->name, "Camera #%d Audio", i); - - ret = snd_pcm_lib_preallocate_pages_for_all(pcm, - SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - G723_MAX_BUFFER, G723_MAX_BUFFER); - if (ret < 0) - return ret; - - solo_dev->snd_pcm = pcm; - - return 0; -} - -int solo_g723_init(struct solo_dev *solo_dev) -{ - static struct snd_device_ops ops = { NULL }; - struct snd_card *card; - struct snd_kcontrol_new kctl; - char name[32]; - int ret; - - atomic_set(&solo_dev->snd_users, 0); - - /* Allows for easier mapping between video and audio */ - sprintf(name, "Softlogic%d", solo_dev->vfd->num); - - ret = snd_card_create(SNDRV_DEFAULT_IDX1, name, THIS_MODULE, 0, - &solo_dev->snd_card); - if (ret < 0) - return ret; - - card = solo_dev->snd_card; - - strcpy(card->driver, SOLO6X10_NAME); - strcpy(card->shortname, "SOLO-6x10 Audio"); - sprintf(card->longname, "%s on %s IRQ %d", card->shortname, - pci_name(solo_dev->pdev), solo_dev->pdev->irq); - snd_card_set_dev(card, &solo_dev->pdev->dev); - - ret = snd_device_new(card, SNDRV_DEV_LOWLEVEL, solo_dev, &ops); - if (ret < 0) - goto snd_error; - - /* Mixer controls */ - strcpy(card->mixername, "SOLO-6x10"); - kctl = snd_solo_capture_volume; - kctl.count = solo_dev->nr_chans; - - ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev)); - if (ret < 0) - return ret; - - ret = solo_snd_pcm_init(solo_dev); - if (ret < 0) - goto snd_error; - - ret = snd_card_register(card); - if (ret < 0) - goto snd_error; - - solo_g723_config(solo_dev); - - dev_info(&solo_dev->pdev->dev, "Alsa sound card as %s\n", name); - - return 0; - -snd_error: - snd_card_free(card); - return ret; -} - -void solo_g723_exit(struct solo_dev *solo_dev) -{ - if (!solo_dev->snd_card) - return; - - solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, 0); - solo_irq_off(solo_dev, SOLO_IRQ_G723); - - snd_card_free(solo_dev->snd_card); - solo_dev->snd_card = NULL; -} diff --git a/drivers/staging/media/solo6x10/gpio.c b/drivers/staging/media/solo6x10/gpio.c deleted file mode 100644 index 73276dc..0000000 --- a/drivers/staging/media/solo6x10/gpio.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2010-2013 Bluecherry, LLC - * - * Original author: - * Ben Collins - * - * Additional work by: - * John Brooks - * - * 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. - */ - -#include -#include -#include -#include - -#include "solo6x10.h" - -static void solo_gpio_mode(struct solo_dev *solo_dev, - unsigned int port_mask, unsigned int mode) -{ - int port; - unsigned int ret; - - ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0); - - /* To set gpio */ - for (port = 0; port < 16; port++) { - if (!((1 << port) & port_mask)) - continue; - - ret &= (~(3 << (port << 1))); - ret |= ((mode & 3) << (port << 1)); - } - - solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_0, ret); - - /* To set extended gpio - sensor */ - ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1); - - for (port = 0; port < 16; port++) { - if (!((1 << (port + 16)) & port_mask)) - continue; - - if (!mode) - ret &= ~(1 << port); - else - ret |= 1 << port; - } - - solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret); -} - -static void solo_gpio_set(struct solo_dev *solo_dev, unsigned int value) -{ - solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT, - solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) | value); -} - -static void solo_gpio_clear(struct solo_dev *solo_dev, unsigned int value) -{ - solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT, - solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) & ~value); -} - -static void solo_gpio_config(struct solo_dev *solo_dev) -{ - /* Video reset */ - solo_gpio_mode(solo_dev, 0x30, 1); - solo_gpio_clear(solo_dev, 0x30); - udelay(100); - solo_gpio_set(solo_dev, 0x30); - udelay(100); - - /* Warning: Don't touch the next line unless you're sure of what - * you're doing: first four gpio [0-3] are used for video. */ - solo_gpio_mode(solo_dev, 0x0f, 2); - - /* We use bit 8-15 of SOLO_GPIO_CONFIG_0 for relay purposes */ - solo_gpio_mode(solo_dev, 0xff00, 1); - - /* Initially set relay status to 0 */ - solo_gpio_clear(solo_dev, 0xff00); -} - -int solo_gpio_init(struct solo_dev *solo_dev) -{ - solo_gpio_config(solo_dev); - return 0; -} - -void solo_gpio_exit(struct solo_dev *solo_dev) -{ - solo_gpio_clear(solo_dev, 0x30); - solo_gpio_config(solo_dev); -} diff --git a/drivers/staging/media/solo6x10/i2c.c b/drivers/staging/media/solo6x10/i2c.c deleted file mode 100644 index 01aa417..0000000 --- a/drivers/staging/media/solo6x10/i2c.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright (C) 2010-2013 Bluecherry, LLC - * - * Original author: - * Ben Collins - * - * Additional work by: - * John Brooks - * - * 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. - */ - -/* XXX: The SOLO6x10 i2c does not have separate interrupts for each i2c - * channel. The bus can only handle one i2c event at a time. The below handles - * this all wrong. We should be using the status registers to see if the bus - * is in use, and have a global lock to check the status register. Also, - * the bulk of the work should be handled out-of-interrupt. The ugly loops - * that occur during interrupt scare me. The ISR should merely signal - * thread context, ACK the interrupt, and move on. -- BenC */ - -#include - -#include "solo6x10.h" - -u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off) -{ - struct i2c_msg msgs[2]; - u8 data; - - msgs[0].flags = 0; - msgs[0].addr = addr; - msgs[0].len = 1; - msgs[0].buf = &off; - - msgs[1].flags = I2C_M_RD; - msgs[1].addr = addr; - msgs[1].len = 1; - msgs[1].buf = &data; - - i2c_transfer(&solo_dev->i2c_adap[id], msgs, 2); - - return data; -} - -void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr, - u8 off, u8 data) -{ - struct i2c_msg msgs; - u8 buf[2]; - - buf[0] = off; - buf[1] = data; - msgs.flags = 0; - msgs.addr = addr; - msgs.len = 2; - msgs.buf = buf; - - i2c_transfer(&solo_dev->i2c_adap[id], &msgs, 1); -} - -static void solo_i2c_flush(struct solo_dev *solo_dev, int wr) -{ - u32 ctrl; - - ctrl = SOLO_IIC_CH_SET(solo_dev->i2c_id); - - if (solo_dev->i2c_state == IIC_STATE_START) - ctrl |= SOLO_IIC_START; - - if (wr) { - ctrl |= SOLO_IIC_WRITE; - } else { - ctrl |= SOLO_IIC_READ; - if (!(solo_dev->i2c_msg->flags & I2C_M_NO_RD_ACK)) - ctrl |= SOLO_IIC_ACK_EN; - } - - if (solo_dev->i2c_msg_ptr == solo_dev->i2c_msg->len) - ctrl |= SOLO_IIC_STOP; - - solo_reg_write(solo_dev, SOLO_IIC_CTRL, ctrl); -} - -static void solo_i2c_start(struct solo_dev *solo_dev) -{ - u32 addr = solo_dev->i2c_msg->addr << 1; - - if (solo_dev->i2c_msg->flags & I2C_M_RD) - addr |= 1; - - solo_dev->i2c_state = IIC_STATE_START; - solo_reg_write(solo_dev, SOLO_IIC_TXD, addr); - solo_i2c_flush(solo_dev, 1); -} - -static void solo_i2c_stop(struct solo_dev *solo_dev) -{ - solo_irq_off(solo_dev, SOLO_IRQ_IIC); - solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0); - solo_dev->i2c_state = IIC_STATE_STOP; - wake_up(&solo_dev->i2c_wait); -} - -static int solo_i2c_handle_read(struct solo_dev *solo_dev) -{ -prepare_read: - if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) { - solo_i2c_flush(solo_dev, 0); - return 0; - } - - solo_dev->i2c_msg_ptr = 0; - solo_dev->i2c_msg++; - solo_dev->i2c_msg_num--; - - if (solo_dev->i2c_msg_num == 0) { - solo_i2c_stop(solo_dev); - return 0; - } - - if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) { - solo_i2c_start(solo_dev); - } else { - if (solo_dev->i2c_msg->flags & I2C_M_RD) - goto prepare_read; - else - solo_i2c_stop(solo_dev); - } - - return 0; -} - -static int solo_i2c_handle_write(struct solo_dev *solo_dev) -{ -retry_write: - if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) { - solo_reg_write(solo_dev, SOLO_IIC_TXD, - solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr]); - solo_dev->i2c_msg_ptr++; - solo_i2c_flush(solo_dev, 1); - return 0; - } - - solo_dev->i2c_msg_ptr = 0; - solo_dev->i2c_msg++; - solo_dev->i2c_msg_num--; - - if (solo_dev->i2c_msg_num == 0) { - solo_i2c_stop(solo_dev); - return 0; - } - - if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) { - solo_i2c_start(solo_dev); - } else { - if (solo_dev->i2c_msg->flags & I2C_M_RD) - solo_i2c_stop(solo_dev); - else - goto retry_write; - } - - return 0; -} - -int solo_i2c_isr(struct solo_dev *solo_dev) -{ - u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL); - int ret = -EINVAL; - - - if (CHK_FLAGS(status, SOLO_IIC_STATE_TRNS | SOLO_IIC_STATE_SIG_ERR) - || solo_dev->i2c_id < 0) { - solo_i2c_stop(solo_dev); - return -ENXIO; - } - - switch (solo_dev->i2c_state) { - case IIC_STATE_START: - if (solo_dev->i2c_msg->flags & I2C_M_RD) { - solo_dev->i2c_state = IIC_STATE_READ; - ret = solo_i2c_handle_read(solo_dev); - break; - } - - solo_dev->i2c_state = IIC_STATE_WRITE; - case IIC_STATE_WRITE: - ret = solo_i2c_handle_write(solo_dev); - break; - - case IIC_STATE_READ: - solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr] = - solo_reg_read(solo_dev, SOLO_IIC_RXD); - solo_dev->i2c_msg_ptr++; - - ret = solo_i2c_handle_read(solo_dev); - break; - - default: - solo_i2c_stop(solo_dev); - } - - return ret; -} - -static int solo_i2c_master_xfer(struct i2c_adapter *adap, - struct i2c_msg msgs[], int num) -{ - struct solo_dev *solo_dev = adap->algo_data; - unsigned long timeout; - int ret; - int i; - DEFINE_WAIT(wait); - - for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { - if (&solo_dev->i2c_adap[i] == adap) - break; - } - - if (i == SOLO_I2C_ADAPTERS) - return num; /* XXX Right return value for failure? */ - - mutex_lock(&solo_dev->i2c_mutex); - solo_dev->i2c_id = i; - solo_dev->i2c_msg = msgs; - solo_dev->i2c_msg_num = num; - solo_dev->i2c_msg_ptr = 0; - - solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0); - solo_irq_on(solo_dev, SOLO_IRQ_IIC); - solo_i2c_start(solo_dev); - - timeout = HZ / 2; - - for (;;) { - prepare_to_wait(&solo_dev->i2c_wait, &wait, - TASK_INTERRUPTIBLE); - - if (solo_dev->i2c_state == IIC_STATE_STOP) - break; - - timeout = schedule_timeout(timeout); - if (!timeout) - break; - - if (signal_pending(current)) - break; - } - - finish_wait(&solo_dev->i2c_wait, &wait); - ret = num - solo_dev->i2c_msg_num; - solo_dev->i2c_state = IIC_STATE_IDLE; - solo_dev->i2c_id = -1; - - mutex_unlock(&solo_dev->i2c_mutex); - - return ret; -} - -static u32 solo_i2c_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C; -} - -static const struct i2c_algorithm solo_i2c_algo = { - .master_xfer = solo_i2c_master_xfer, - .functionality = solo_i2c_functionality, -}; - -int solo_i2c_init(struct solo_dev *solo_dev) -{ - int i; - int ret; - - solo_reg_write(solo_dev, SOLO_IIC_CFG, - SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE); - - solo_dev->i2c_id = -1; - solo_dev->i2c_state = IIC_STATE_IDLE; - init_waitqueue_head(&solo_dev->i2c_wait); - mutex_init(&solo_dev->i2c_mutex); - - for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { - struct i2c_adapter *adap = &solo_dev->i2c_adap[i]; - - snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d", - SOLO6X10_NAME, i); - adap->algo = &solo_i2c_algo; - adap->algo_data = solo_dev; - adap->retries = 1; - adap->dev.parent = &solo_dev->pdev->dev; - - ret = i2c_add_adapter(adap); - if (ret) { - adap->algo_data = NULL; - break; - } - } - - if (ret) { - for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { - if (!solo_dev->i2c_adap[i].algo_data) - break; - i2c_del_adapter(&solo_dev->i2c_adap[i]); - solo_dev->i2c_adap[i].algo_data = NULL; - } - return ret; - } - - return 0; -} - -void solo_i2c_exit(struct solo_dev *solo_dev) -{ - int i; - - for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { - if (!solo_dev->i2c_adap[i].algo_data) - continue; - i2c_del_adapter(&solo_dev->i2c_adap[i]); - solo_dev->i2c_adap[i].algo_data = NULL; - } -} diff --git a/drivers/staging/media/solo6x10/p2m.c b/drivers/staging/media/solo6x10/p2m.c deleted file mode 100644 index 3335941..0000000 --- a/drivers/staging/media/solo6x10/p2m.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright (C) 2010-2013 Bluecherry, LLC - * - * Original author: - * Ben Collins - * - * Additional work by: - * John Brooks - * - * 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. - */ - -#include -#include -#include - -#include "solo6x10.h" - -static int multi_p2m; -module_param(multi_p2m, uint, 0644); -MODULE_PARM_DESC(multi_p2m, - "Use multiple P2M DMA channels (default: no, 6010-only)"); - -static int desc_mode; -module_param(desc_mode, uint, 0644); -MODULE_PARM_DESC(desc_mode, - "Allow use of descriptor mode DMA (default: no, 6010-only)"); - -int solo_p2m_dma(struct solo_dev *solo_dev, int wr, - void *sys_addr, u32 ext_addr, u32 size, - int repeat, u32 ext_size) -{ - dma_addr_t dma_addr; - int ret; - - if (WARN_ON_ONCE((unsigned long)sys_addr & 0x03)) - return -EINVAL; - if (WARN_ON_ONCE(!size)) - return -EINVAL; - - dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size, - wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(solo_dev->pdev, dma_addr)) - return -ENOMEM; - - ret = solo_p2m_dma_t(solo_dev, wr, dma_addr, ext_addr, size, - repeat, ext_size); - - pci_unmap_single(solo_dev->pdev, dma_addr, size, - wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - - return ret; -} - -/* Mutex must be held for p2m_id before calling this!! */ -int solo_p2m_dma_desc(struct solo_dev *solo_dev, - struct solo_p2m_desc *desc, dma_addr_t desc_dma, - int desc_cnt) -{ - struct solo_p2m_dev *p2m_dev; - unsigned int timeout; - unsigned int config = 0; - int ret = 0; - int p2m_id = 0; - - /* Get next ID. According to Softlogic, 6110 has problems on !=0 P2M */ - if (solo_dev->type != SOLO_DEV_6110 && multi_p2m) { - p2m_id = atomic_inc_return(&solo_dev->p2m_count) % SOLO_NR_P2M; - if (p2m_id < 0) - p2m_id = -p2m_id; - } - - p2m_dev = &solo_dev->p2m_dev[p2m_id]; - - if (mutex_lock_interruptible(&p2m_dev->mutex)) - return -EINTR; - - INIT_COMPLETION(p2m_dev->completion); - p2m_dev->error = 0; - - if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && desc_mode) { - /* For 6010 with more than one desc, we can do a one-shot */ - p2m_dev->desc_count = p2m_dev->desc_idx = 0; - config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(p2m_id)); - - solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(p2m_id), desc_dma); - solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(p2m_id), desc_cnt); - solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config | - SOLO_P2M_DESC_MODE); - } else { - /* For single descriptors and 6110, we need to run each desc */ - p2m_dev->desc_count = desc_cnt; - p2m_dev->desc_idx = 1; - p2m_dev->descs = desc; - - solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(p2m_id), - desc[1].dma_addr); - solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(p2m_id), - desc[1].ext_addr); - solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(p2m_id), - desc[1].cfg); - solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), - desc[1].ctrl); - } - - timeout = wait_for_completion_timeout(&p2m_dev->completion, - solo_dev->p2m_jiffies); - - if (WARN_ON_ONCE(p2m_dev->error)) - ret = -EIO; - else if (timeout == 0) { - solo_dev->p2m_timeouts++; - ret = -EAGAIN; - } - - solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), 0); - - /* Don't write here for the no_desc_mode case, because config is 0. - * We can't test no_desc_mode again, it might race. */ - if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && config) - solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config); - - mutex_unlock(&p2m_dev->mutex); - - return ret; -} - -void solo_p2m_fill_desc(struct solo_p2m_desc *desc, int wr, - dma_addr_t dma_addr, u32 ext_addr, u32 size, - int repeat, u32 ext_size) -{ - WARN_ON_ONCE(dma_addr & 0x03); - WARN_ON_ONCE(!size); - - desc->cfg = SOLO_P2M_COPY_SIZE(size >> 2); - desc->ctrl = SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) | - (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON; - - if (repeat) { - desc->cfg |= SOLO_P2M_EXT_INC(ext_size >> 2); - desc->ctrl |= SOLO_P2M_PCI_INC(size >> 2) | - SOLO_P2M_REPEAT(repeat); - } - - desc->dma_addr = dma_addr; - desc->ext_addr = ext_addr; -} - -int solo_p2m_dma_t(struct solo_dev *solo_dev, int wr, - dma_addr_t dma_addr, u32 ext_addr, u32 size, - int repeat, u32 ext_size) -{ - struct solo_p2m_desc desc[2]; - - solo_p2m_fill_desc(&desc[1], wr, dma_addr, ext_addr, size, repeat, - ext_size); - - /* No need for desc_dma since we know it is a single-shot */ - return solo_p2m_dma_desc(solo_dev, desc, 0, 1); -} - -void solo_p2m_isr(struct solo_dev *solo_dev, int id) -{ - struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id]; - struct solo_p2m_desc *desc; - - if (p2m_dev->desc_count <= p2m_dev->desc_idx) { - complete(&p2m_dev->completion); - return; - } - - /* Setup next descriptor */ - p2m_dev->desc_idx++; - desc = &p2m_dev->descs[p2m_dev->desc_idx]; - - solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0); - solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), desc->dma_addr); - solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), desc->ext_addr); - solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id), desc->cfg); - solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), desc->ctrl); -} - -void solo_p2m_error_isr(struct solo_dev *solo_dev) -{ - unsigned int err = solo_reg_read(solo_dev, SOLO_PCI_ERR); - struct solo_p2m_dev *p2m_dev; - int i; - - if (!(err & (SOLO_PCI_ERR_P2M | SOLO_PCI_ERR_P2M_DESC))) - return; - - for (i = 0; i < SOLO_NR_P2M; i++) { - p2m_dev = &solo_dev->p2m_dev[i]; - p2m_dev->error = 1; - solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0); - complete(&p2m_dev->completion); - } -} - -void solo_p2m_exit(struct solo_dev *solo_dev) -{ - int i; - - for (i = 0; i < SOLO_NR_P2M; i++) - solo_irq_off(solo_dev, SOLO_IRQ_P2M(i)); -} - -static int solo_p2m_test(struct solo_dev *solo_dev, int base, int size) -{ - u32 *wr_buf; - u32 *rd_buf; - int i; - int ret = -EIO; - int order = get_order(size); - - wr_buf = (u32 *)__get_free_pages(GFP_KERNEL, order); - if (wr_buf == NULL) - return -1; - - rd_buf = (u32 *)__get_free_pages(GFP_KERNEL, order); - if (rd_buf == NULL) { - free_pages((unsigned long)wr_buf, order); - return -1; - } - - for (i = 0; i < (size >> 3); i++) - *(wr_buf + i) = (i << 16) | (i + 1); - - for (i = (size >> 3); i < (size >> 2); i++) - *(wr_buf + i) = ~((i << 16) | (i + 1)); - - memset(rd_buf, 0x55, size); - - if (solo_p2m_dma(solo_dev, 1, wr_buf, base, size, 0, 0)) - goto test_fail; - - if (solo_p2m_dma(solo_dev, 0, rd_buf, base, size, 0, 0)) - goto test_fail; - - for (i = 0; i < (size >> 2); i++) { - if (*(wr_buf + i) != *(rd_buf + i)) - goto test_fail; - } - - ret = 0; - -test_fail: - free_pages((unsigned long)wr_buf, order); - free_pages((unsigned long)rd_buf, order); - - return ret; -} - -int solo_p2m_init(struct solo_dev *solo_dev) -{ - struct solo_p2m_dev *p2m_dev; - int i; - - for (i = 0; i < SOLO_NR_P2M; i++) { - p2m_dev = &solo_dev->p2m_dev[i]; - - mutex_init(&p2m_dev->mutex); - init_completion(&p2m_dev->completion); - - solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0); - solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i), - SOLO_P2M_CSC_16BIT_565 | - SOLO_P2M_DESC_INTR_OPT | - SOLO_P2M_DMA_INTERVAL(0) | - SOLO_P2M_PCI_MASTER_MODE); - solo_irq_on(solo_dev, SOLO_IRQ_P2M(i)); - } - - /* Find correct SDRAM size */ - for (solo_dev->sdram_size = 0, i = 2; i >= 0; i--) { - solo_reg_write(solo_dev, SOLO_DMA_CTRL, - SOLO_DMA_CTRL_REFRESH_CYCLE(1) | - SOLO_DMA_CTRL_SDRAM_SIZE(i) | - SOLO_DMA_CTRL_SDRAM_CLK_INVERT | - SOLO_DMA_CTRL_READ_CLK_SELECT | - SOLO_DMA_CTRL_LATENCY(1)); - - solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config | - SOLO_SYS_CFG_RESET); - solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config); - - switch (i) { - case 2: - if (solo_p2m_test(solo_dev, 0x07ff0000, 0x00010000) || - solo_p2m_test(solo_dev, 0x05ff0000, 0x00010000)) - continue; - break; - - case 1: - if (solo_p2m_test(solo_dev, 0x03ff0000, 0x00010000)) - continue; - break; - - default: - if (solo_p2m_test(solo_dev, 0x01ff0000, 0x00010000)) - continue; - } - - solo_dev->sdram_size = (32 << 20) << i; - break; - } - - if (!solo_dev->sdram_size) { - dev_err(&solo_dev->pdev->dev, "Error detecting SDRAM size\n"); - return -EIO; - } - - if (SOLO_SDRAM_END(solo_dev) > solo_dev->sdram_size) { - dev_err(&solo_dev->pdev->dev, - "SDRAM is not large enough (%u < %u)\n", - solo_dev->sdram_size, SOLO_SDRAM_END(solo_dev)); - return -EIO; - } - - return 0; -} diff --git a/drivers/staging/media/solo6x10/solo6x10-core.c b/drivers/staging/media/solo6x10/solo6x10-core.c new file mode 100644 index 0000000..3675020 --- /dev/null +++ b/drivers/staging/media/solo6x10/solo6x10-core.c @@ -0,0 +1,709 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "solo6x10.h" +#include "solo6x10-tw28.h" + +MODULE_DESCRIPTION("Softlogic 6x10 MPEG4/H.264/G.723 CODEC V4L2/ALSA Driver"); +MODULE_AUTHOR("Bluecherry "); +MODULE_VERSION(SOLO6X10_VERSION); +MODULE_LICENSE("GPL"); + +unsigned video_nr = -1; +module_param(video_nr, uint, 0644); +MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect (default)"); + +static int full_eeprom; /* default is only top 64B */ +module_param(full_eeprom, uint, 0644); +MODULE_PARM_DESC(full_eeprom, "Allow access to full 128B EEPROM (dangerous)"); + + +static void solo_set_time(struct solo_dev *solo_dev) +{ + struct timespec ts; + + ktime_get_ts(&ts); + + solo_reg_write(solo_dev, SOLO_TIMER_SEC, ts.tv_sec); + solo_reg_write(solo_dev, SOLO_TIMER_USEC, ts.tv_nsec / NSEC_PER_USEC); +} + +static void solo_timer_sync(struct solo_dev *solo_dev) +{ + u32 sec, usec; + struct timespec ts; + long diff; + + if (solo_dev->type != SOLO_DEV_6110) + return; + + if (++solo_dev->time_sync < 60) + return; + + solo_dev->time_sync = 0; + + sec = solo_reg_read(solo_dev, SOLO_TIMER_SEC); + usec = solo_reg_read(solo_dev, SOLO_TIMER_USEC); + + ktime_get_ts(&ts); + + diff = (long)ts.tv_sec - (long)sec; + diff = (diff * 1000000) + + ((long)(ts.tv_nsec / NSEC_PER_USEC) - (long)usec); + + if (diff > 1000 || diff < -1000) { + solo_set_time(solo_dev); + } else if (diff) { + long usec_lsb = solo_dev->usec_lsb; + + usec_lsb -= diff / 4; + if (usec_lsb < 0) + usec_lsb = 0; + else if (usec_lsb > 255) + usec_lsb = 255; + + solo_dev->usec_lsb = usec_lsb; + solo_reg_write(solo_dev, SOLO_TIMER_USEC_LSB, + solo_dev->usec_lsb); + } +} + +static irqreturn_t solo_isr(int irq, void *data) +{ + struct solo_dev *solo_dev = data; + u32 status; + int i; + + status = solo_reg_read(solo_dev, SOLO_IRQ_STAT); + if (!status) + return IRQ_NONE; + + if (status & ~solo_dev->irq_mask) { + solo_reg_write(solo_dev, SOLO_IRQ_STAT, + status & ~solo_dev->irq_mask); + status &= solo_dev->irq_mask; + } + + if (status & SOLO_IRQ_PCI_ERR) + solo_p2m_error_isr(solo_dev); + + for (i = 0; i < SOLO_NR_P2M; i++) + if (status & SOLO_IRQ_P2M(i)) + solo_p2m_isr(solo_dev, i); + + if (status & SOLO_IRQ_IIC) + solo_i2c_isr(solo_dev); + + if (status & SOLO_IRQ_VIDEO_IN) { + solo_video_in_isr(solo_dev); + solo_timer_sync(solo_dev); + } + + if (status & SOLO_IRQ_ENCODER) + solo_enc_v4l2_isr(solo_dev); + + if (status & SOLO_IRQ_G723) + solo_g723_isr(solo_dev); + + /* Clear all interrupts handled */ + solo_reg_write(solo_dev, SOLO_IRQ_STAT, status); + + return IRQ_HANDLED; +} + +static void free_solo_dev(struct solo_dev *solo_dev) +{ + struct pci_dev *pdev; + + if (!solo_dev) + return; + + if (solo_dev->dev.parent) + device_unregister(&solo_dev->dev); + + pdev = solo_dev->pdev; + + /* If we never initialized the PCI device, then nothing else + * below here needs cleanup */ + if (!pdev) { + kfree(solo_dev); + return; + } + + if (solo_dev->reg_base) { + /* Bring down the sub-devices first */ + solo_g723_exit(solo_dev); + solo_enc_v4l2_exit(solo_dev); + solo_enc_exit(solo_dev); + solo_v4l2_exit(solo_dev); + solo_disp_exit(solo_dev); + solo_gpio_exit(solo_dev); + solo_p2m_exit(solo_dev); + solo_i2c_exit(solo_dev); + + /* Now cleanup the PCI device */ + solo_irq_off(solo_dev, ~0); + pci_iounmap(pdev, solo_dev->reg_base); + if (pdev->irq) + free_irq(pdev->irq, solo_dev); + } + + pci_release_regions(pdev); + pci_disable_device(pdev); + v4l2_device_unregister(&solo_dev->v4l2_dev); + pci_set_drvdata(pdev, NULL); + + kfree(solo_dev); +} + +static ssize_t eeprom_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + unsigned short *p = (unsigned short *)buf; + int i; + + if (count & 0x1) + dev_warn(dev, "EEPROM Write not aligned (truncating)\n"); + + if (!full_eeprom && count > 64) { + dev_warn(dev, "EEPROM Write truncated to 64 bytes\n"); + count = 64; + } else if (full_eeprom && count > 128) { + dev_warn(dev, "EEPROM Write truncated to 128 bytes\n"); + count = 128; + } + + solo_eeprom_ewen(solo_dev, 1); + + for (i = full_eeprom ? 0 : 32; i < min((int)(full_eeprom ? 64 : 32), + (int)(count / 2)); i++) + solo_eeprom_write(solo_dev, i, cpu_to_be16(p[i])); + + solo_eeprom_ewen(solo_dev, 0); + + return count; +} + +static ssize_t eeprom_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + unsigned short *p = (unsigned short *)buf; + int count = (full_eeprom ? 128 : 64); + int i; + + for (i = (full_eeprom ? 0 : 32); i < (count / 2); i++) + p[i] = be16_to_cpu(solo_eeprom_read(solo_dev, i)); + + return count; +} + +static ssize_t p2m_timeouts_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + + return sprintf(buf, "%d\n", solo_dev->p2m_timeouts); +} + +static ssize_t sdram_size_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + + return sprintf(buf, "%dMegs\n", solo_dev->sdram_size >> 20); +} + +static ssize_t tw28xx_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + + return sprintf(buf, "tw2815[%d] tw2864[%d] tw2865[%d]\n", + hweight32(solo_dev->tw2815), + hweight32(solo_dev->tw2864), + hweight32(solo_dev->tw2865)); +} + +static ssize_t input_map_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + unsigned int val; + char *out = buf; + + val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_0); + out += sprintf(out, "Channel 0 => Input %d\n", val & 0x1f); + out += sprintf(out, "Channel 1 => Input %d\n", (val >> 5) & 0x1f); + out += sprintf(out, "Channel 2 => Input %d\n", (val >> 10) & 0x1f); + out += sprintf(out, "Channel 3 => Input %d\n", (val >> 15) & 0x1f); + out += sprintf(out, "Channel 4 => Input %d\n", (val >> 20) & 0x1f); + out += sprintf(out, "Channel 5 => Input %d\n", (val >> 25) & 0x1f); + + val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_1); + out += sprintf(out, "Channel 6 => Input %d\n", val & 0x1f); + out += sprintf(out, "Channel 7 => Input %d\n", (val >> 5) & 0x1f); + out += sprintf(out, "Channel 8 => Input %d\n", (val >> 10) & 0x1f); + out += sprintf(out, "Channel 9 => Input %d\n", (val >> 15) & 0x1f); + out += sprintf(out, "Channel 10 => Input %d\n", (val >> 20) & 0x1f); + out += sprintf(out, "Channel 11 => Input %d\n", (val >> 25) & 0x1f); + + val = solo_reg_read(solo_dev, SOLO_VI_CH_SWITCH_2); + out += sprintf(out, "Channel 12 => Input %d\n", val & 0x1f); + out += sprintf(out, "Channel 13 => Input %d\n", (val >> 5) & 0x1f); + out += sprintf(out, "Channel 14 => Input %d\n", (val >> 10) & 0x1f); + out += sprintf(out, "Channel 15 => Input %d\n", (val >> 15) & 0x1f); + out += sprintf(out, "Spot Output => Input %d\n", (val >> 20) & 0x1f); + + return out - buf; +} + +static ssize_t p2m_timeout_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + unsigned long ms; + + int ret = kstrtoul(buf, 10, &ms); + if (ret < 0 || ms > 200) + return -EINVAL; + solo_dev->p2m_jiffies = msecs_to_jiffies(ms); + + return count; +} + +static ssize_t p2m_timeout_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + + return sprintf(buf, "%ums\n", jiffies_to_msecs(solo_dev->p2m_jiffies)); +} + +static ssize_t intervals_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + char *out = buf; + int fps = solo_dev->fps; + int i; + + for (i = 0; i < solo_dev->nr_chans; i++) { + out += sprintf(out, "Channel %d: %d/%d (0x%08x)\n", + i, solo_dev->v4l2_enc[i]->interval, fps, + solo_reg_read(solo_dev, SOLO_CAP_CH_INTV(i))); + } + + return out - buf; +} + +static ssize_t sdram_offsets_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + char *out = buf; + + out += sprintf(out, "DISP: 0x%08x @ 0x%08x\n", + SOLO_DISP_EXT_ADDR, + SOLO_DISP_EXT_SIZE); + + out += sprintf(out, "EOSD: 0x%08x @ 0x%08x (0x%08x * %d)\n", + SOLO_EOSD_EXT_ADDR, + SOLO_EOSD_EXT_AREA(solo_dev), + SOLO_EOSD_EXT_SIZE(solo_dev), + SOLO_EOSD_EXT_AREA(solo_dev) / + SOLO_EOSD_EXT_SIZE(solo_dev)); + + out += sprintf(out, "MOTI: 0x%08x @ 0x%08x\n", + SOLO_MOTION_EXT_ADDR(solo_dev), + SOLO_MOTION_EXT_SIZE); + + out += sprintf(out, "G723: 0x%08x @ 0x%08x\n", + SOLO_G723_EXT_ADDR(solo_dev), + SOLO_G723_EXT_SIZE); + + out += sprintf(out, "CAPT: 0x%08x @ 0x%08x (0x%08x * %d)\n", + SOLO_CAP_EXT_ADDR(solo_dev), + SOLO_CAP_EXT_SIZE(solo_dev), + SOLO_CAP_PAGE_SIZE, + SOLO_CAP_EXT_SIZE(solo_dev) / SOLO_CAP_PAGE_SIZE); + + out += sprintf(out, "EREF: 0x%08x @ 0x%08x (0x%08x * %d)\n", + SOLO_EREF_EXT_ADDR(solo_dev), + SOLO_EREF_EXT_AREA(solo_dev), + SOLO_EREF_EXT_SIZE, + SOLO_EREF_EXT_AREA(solo_dev) / SOLO_EREF_EXT_SIZE); + + out += sprintf(out, "MPEG: 0x%08x @ 0x%08x\n", + SOLO_MP4E_EXT_ADDR(solo_dev), + SOLO_MP4E_EXT_SIZE(solo_dev)); + + out += sprintf(out, "JPEG: 0x%08x @ 0x%08x\n", + SOLO_JPEG_EXT_ADDR(solo_dev), + SOLO_JPEG_EXT_SIZE(solo_dev)); + + return out - buf; +} + +static ssize_t sdram_show(struct file *file, struct kobject *kobj, + struct bin_attribute *a, char *buf, + loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct solo_dev *solo_dev = + container_of(dev, struct solo_dev, dev); + const int size = solo_dev->sdram_size; + + if (off >= size) + return 0; + + if (off + count > size) + count = size - off; + + if (solo_p2m_dma(solo_dev, 0, buf, off, count, 0, 0)) + return -EIO; + + return count; +} + +static const struct device_attribute solo_dev_attrs[] = { + __ATTR(eeprom, 0640, eeprom_show, eeprom_store), + __ATTR(p2m_timeout, 0644, p2m_timeout_show, p2m_timeout_store), + __ATTR_RO(p2m_timeouts), + __ATTR_RO(sdram_size), + __ATTR_RO(tw28xx), + __ATTR_RO(input_map), + __ATTR_RO(intervals), + __ATTR_RO(sdram_offsets), +}; + +static void solo_device_release(struct device *dev) +{ + /* Do nothing */ +} + +static int solo_sysfs_init(struct solo_dev *solo_dev) +{ + struct bin_attribute *sdram_attr = &solo_dev->sdram_attr; + struct device *dev = &solo_dev->dev; + const char *driver; + int i; + + if (solo_dev->type == SOLO_DEV_6110) + driver = "solo6110"; + else + driver = "solo6010"; + + dev->release = solo_device_release; + dev->parent = &solo_dev->pdev->dev; + set_dev_node(dev, dev_to_node(&solo_dev->pdev->dev)); + dev_set_name(dev, "%s-%d-%d", driver, solo_dev->vfd->num, + solo_dev->nr_chans); + + if (device_register(dev)) { + dev->parent = NULL; + return -ENOMEM; + } + + for (i = 0; i < ARRAY_SIZE(solo_dev_attrs); i++) { + if (device_create_file(dev, &solo_dev_attrs[i])) { + device_unregister(dev); + return -ENOMEM; + } + } + + sysfs_attr_init(&sdram_attr->attr); + sdram_attr->attr.name = "sdram"; + sdram_attr->attr.mode = 0440; + sdram_attr->read = sdram_show; + sdram_attr->size = solo_dev->sdram_size; + + if (device_create_bin_file(dev, sdram_attr)) { + device_unregister(dev); + return -ENOMEM; + } + + return 0; +} + +static int solo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct solo_dev *solo_dev; + int ret; + u8 chip_id; + + solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL); + if (solo_dev == NULL) + return -ENOMEM; + + if (id->driver_data == SOLO_DEV_6010) + dev_info(&pdev->dev, "Probing Softlogic 6010\n"); + else + dev_info(&pdev->dev, "Probing Softlogic 6110\n"); + + solo_dev->type = id->driver_data; + solo_dev->pdev = pdev; + spin_lock_init(&solo_dev->reg_io_lock); + ret = v4l2_device_register(&pdev->dev, &solo_dev->v4l2_dev); + if (ret) + goto fail_probe; + + /* Only for during init */ + solo_dev->p2m_jiffies = msecs_to_jiffies(100); + + ret = pci_enable_device(pdev); + if (ret) + goto fail_probe; + + pci_set_master(pdev); + + /* RETRY/TRDY Timeout disabled */ + pci_write_config_byte(pdev, 0x40, 0x00); + pci_write_config_byte(pdev, 0x41, 0x00); + + ret = pci_request_regions(pdev, SOLO6X10_NAME); + if (ret) + goto fail_probe; + + solo_dev->reg_base = pci_ioremap_bar(pdev, 0); + if (solo_dev->reg_base == NULL) { + ret = -ENOMEM; + goto fail_probe; + } + + chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) & + SOLO_CHIP_ID_MASK; + switch (chip_id) { + case 7: + solo_dev->nr_chans = 16; + solo_dev->nr_ext = 5; + break; + case 6: + solo_dev->nr_chans = 8; + solo_dev->nr_ext = 2; + break; + default: + dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, assuming 4 ch\n", + chip_id); + case 5: + solo_dev->nr_chans = 4; + solo_dev->nr_ext = 1; + } + + /* Disable all interrupts to start */ + solo_irq_off(solo_dev, ~0); + + /* Initial global settings */ + if (solo_dev->type == SOLO_DEV_6010) { + solo_dev->clock_mhz = 108; + solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT + | SOLO_SYS_CFG_INPUTDIV(25) + | SOLO_SYS_CFG_FEEDBACKDIV(solo_dev->clock_mhz * 2 - 2) + | SOLO_SYS_CFG_OUTDIV(3); + solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config); + } else { + u32 divq, divf; + + solo_dev->clock_mhz = 135; + + if (solo_dev->clock_mhz < 125) { + divq = 3; + divf = (solo_dev->clock_mhz * 4) / 3 - 1; + } else { + divq = 2; + divf = (solo_dev->clock_mhz * 2) / 3 - 1; + } + + solo_reg_write(solo_dev, SOLO_PLL_CONFIG, + (1 << 20) | /* PLL_RANGE */ + (8 << 15) | /* PLL_DIVR */ + (divq << 12) | + (divf << 4) | + (1 << 1) /* PLL_FSEN */); + + solo_dev->sys_config = SOLO_SYS_CFG_SDRAM64BIT; + } + + solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config); + solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, + solo_dev->clock_mhz - 1); + + /* PLL locking time of 1ms */ + mdelay(1); + + ret = request_irq(pdev->irq, solo_isr, IRQF_SHARED, SOLO6X10_NAME, + solo_dev); + if (ret) + goto fail_probe; + + /* Handle this from the start */ + solo_irq_on(solo_dev, SOLO_IRQ_PCI_ERR); + + ret = solo_i2c_init(solo_dev); + if (ret) + goto fail_probe; + + /* Setup the DMA engine */ + solo_reg_write(solo_dev, SOLO_DMA_CTRL, + SOLO_DMA_CTRL_REFRESH_CYCLE(1) | + SOLO_DMA_CTRL_SDRAM_SIZE(2) | + SOLO_DMA_CTRL_SDRAM_CLK_INVERT | + SOLO_DMA_CTRL_READ_CLK_SELECT | + SOLO_DMA_CTRL_LATENCY(1)); + + /* Undocumented crap */ + solo_reg_write(solo_dev, SOLO_DMA_CTRL1, + solo_dev->type == SOLO_DEV_6010 ? 0x100 : 0x300); + + if (solo_dev->type != SOLO_DEV_6010) { + solo_dev->usec_lsb = 0x3f; + solo_set_time(solo_dev); + } + + /* Disable watchdog */ + solo_reg_write(solo_dev, SOLO_WATCHDOG, 0); + + /* Initialize sub components */ + + ret = solo_p2m_init(solo_dev); + if (ret) + goto fail_probe; + + ret = solo_disp_init(solo_dev); + if (ret) + goto fail_probe; + + ret = solo_gpio_init(solo_dev); + if (ret) + goto fail_probe; + + ret = solo_tw28_init(solo_dev); + if (ret) + goto fail_probe; + + ret = solo_v4l2_init(solo_dev, video_nr); + if (ret) + goto fail_probe; + + ret = solo_enc_init(solo_dev); + if (ret) + goto fail_probe; + + ret = solo_enc_v4l2_init(solo_dev, video_nr); + if (ret) + goto fail_probe; + + ret = solo_g723_init(solo_dev); + if (ret) + goto fail_probe; + + ret = solo_sysfs_init(solo_dev); + if (ret) + goto fail_probe; + + /* Now that init is over, set this lower */ + solo_dev->p2m_jiffies = msecs_to_jiffies(20); + + return 0; + +fail_probe: + free_solo_dev(solo_dev); + return ret; +} + +static void solo_pci_remove(struct pci_dev *pdev) +{ + struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); + struct solo_dev *solo_dev = container_of(v4l2_dev, struct solo_dev, v4l2_dev); + + free_solo_dev(solo_dev); +} + +static DEFINE_PCI_DEVICE_TABLE(solo_id_table) = { + /* 6010 based cards */ + { PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010), + .driver_data = SOLO_DEV_6010 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4), + .driver_data = SOLO_DEV_6010 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9), + .driver_data = SOLO_DEV_6010 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16), + .driver_data = SOLO_DEV_6010 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_4), + .driver_data = SOLO_DEV_6010 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_9), + .driver_data = SOLO_DEV_6010 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_SOLO_16), + .driver_data = SOLO_DEV_6010 }, + /* 6110 based cards */ + { PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6110), + .driver_data = SOLO_DEV_6110 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_4), + .driver_data = SOLO_DEV_6110 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_8), + .driver_data = SOLO_DEV_6110 }, + { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16), + .driver_data = SOLO_DEV_6110 }, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, solo_id_table); + +static struct pci_driver solo_pci_driver = { + .name = SOLO6X10_NAME, + .id_table = solo_id_table, + .probe = solo_pci_probe, + .remove = solo_pci_remove, +}; + +module_pci_driver(solo_pci_driver); diff --git a/drivers/staging/media/solo6x10/solo6x10-disp.c b/drivers/staging/media/solo6x10/solo6x10-disp.c new file mode 100644 index 0000000..78070c8 --- /dev/null +++ b/drivers/staging/media/solo6x10/solo6x10-disp.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +#include +#include +#include +#include + +#include "solo6x10.h" + +#define SOLO_VCLK_DELAY 3 +#define SOLO_PROGRESSIVE_VSIZE 1024 + +#define SOLO_MOT_THRESH_W 64 +#define SOLO_MOT_THRESH_H 64 +#define SOLO_MOT_THRESH_SIZE 8192 +#define SOLO_MOT_THRESH_REAL (SOLO_MOT_THRESH_W * SOLO_MOT_THRESH_H) +#define SOLO_MOT_FLAG_SIZE 1024 +#define SOLO_MOT_FLAG_AREA (SOLO_MOT_FLAG_SIZE * 16) + +static void solo_vin_config(struct solo_dev *solo_dev) +{ + solo_dev->vin_hstart = 8; + solo_dev->vin_vstart = 2; + + solo_reg_write(solo_dev, SOLO_SYS_VCLK, + SOLO_VCLK_SELECT(2) | + SOLO_VCLK_VIN1415_DELAY(SOLO_VCLK_DELAY) | + SOLO_VCLK_VIN1213_DELAY(SOLO_VCLK_DELAY) | + SOLO_VCLK_VIN1011_DELAY(SOLO_VCLK_DELAY) | + SOLO_VCLK_VIN0809_DELAY(SOLO_VCLK_DELAY) | + SOLO_VCLK_VIN0607_DELAY(SOLO_VCLK_DELAY) | + SOLO_VCLK_VIN0405_DELAY(SOLO_VCLK_DELAY) | + SOLO_VCLK_VIN0203_DELAY(SOLO_VCLK_DELAY) | + SOLO_VCLK_VIN0001_DELAY(SOLO_VCLK_DELAY)); + + solo_reg_write(solo_dev, SOLO_VI_ACT_I_P, + SOLO_VI_H_START(solo_dev->vin_hstart) | + SOLO_VI_V_START(solo_dev->vin_vstart) | + SOLO_VI_V_STOP(solo_dev->vin_vstart + + solo_dev->video_vsize)); + + solo_reg_write(solo_dev, SOLO_VI_ACT_I_S, + SOLO_VI_H_START(solo_dev->vout_hstart) | + SOLO_VI_V_START(solo_dev->vout_vstart) | + SOLO_VI_V_STOP(solo_dev->vout_vstart + + solo_dev->video_vsize)); + + solo_reg_write(solo_dev, SOLO_VI_ACT_P, + SOLO_VI_H_START(0) | + SOLO_VI_V_START(1) | + SOLO_VI_V_STOP(SOLO_PROGRESSIVE_VSIZE)); + + solo_reg_write(solo_dev, SOLO_VI_CH_FORMAT, + SOLO_VI_FD_SEL_MASK(0) | SOLO_VI_PROG_MASK(0)); + + /* On 6110, initialize mozaic darkness stength */ + if (solo_dev->type == SOLO_DEV_6010) + solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 0); + else + solo_reg_write(solo_dev, SOLO_VI_FMT_CFG, 16 << 22); + + solo_reg_write(solo_dev, SOLO_VI_PAGE_SW, 2); + + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { + solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG, + SOLO_VI_PB_USER_MODE); + solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV, + SOLO_VI_PB_HSIZE(858) | SOLO_VI_PB_VSIZE(246)); + solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V, + SOLO_VI_PB_VSTART(4) | + SOLO_VI_PB_VSTOP(4 + 240)); + } else { + solo_reg_write(solo_dev, SOLO_VI_PB_CONFIG, + SOLO_VI_PB_USER_MODE | SOLO_VI_PB_PAL); + solo_reg_write(solo_dev, SOLO_VI_PB_RANGE_HV, + SOLO_VI_PB_HSIZE(864) | SOLO_VI_PB_VSIZE(294)); + solo_reg_write(solo_dev, SOLO_VI_PB_ACT_V, + SOLO_VI_PB_VSTART(4) | + SOLO_VI_PB_VSTOP(4 + 288)); + } + solo_reg_write(solo_dev, SOLO_VI_PB_ACT_H, SOLO_VI_PB_HSTART(16) | + SOLO_VI_PB_HSTOP(16 + 720)); +} + +static void solo_vout_config_cursor(struct solo_dev *dev) +{ + int i; + + /* Load (blank) cursor bitmap mask (2bpp) */ + for (i = 0; i < 20; i++) + solo_reg_write(dev, SOLO_VO_CURSOR_MASK(i), 0); + + solo_reg_write(dev, SOLO_VO_CURSOR_POS, 0); + + solo_reg_write(dev, SOLO_VO_CURSOR_CLR, + (0x80 << 24) | (0x80 << 16) | (0x10 << 8) | 0x80); + solo_reg_write(dev, SOLO_VO_CURSOR_CLR2, (0xe0 << 8) | 0x80); +} + +static void solo_vout_config(struct solo_dev *solo_dev) +{ + solo_dev->vout_hstart = 6; + solo_dev->vout_vstart = 8; + + solo_reg_write(solo_dev, SOLO_VO_FMT_ENC, + solo_dev->video_type | + SOLO_VO_USER_COLOR_SET_NAV | + SOLO_VO_USER_COLOR_SET_NAH | + SOLO_VO_NA_COLOR_Y(0) | + SOLO_VO_NA_COLOR_CB(0) | + SOLO_VO_NA_COLOR_CR(0)); + + solo_reg_write(solo_dev, SOLO_VO_ACT_H, + SOLO_VO_H_START(solo_dev->vout_hstart) | + SOLO_VO_H_STOP(solo_dev->vout_hstart + + solo_dev->video_hsize)); + + solo_reg_write(solo_dev, SOLO_VO_ACT_V, + SOLO_VO_V_START(solo_dev->vout_vstart) | + SOLO_VO_V_STOP(solo_dev->vout_vstart + + solo_dev->video_vsize)); + + solo_reg_write(solo_dev, SOLO_VO_RANGE_HV, + SOLO_VO_H_LEN(solo_dev->video_hsize) | + SOLO_VO_V_LEN(solo_dev->video_vsize)); + + /* Border & background colors */ + solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_COLOR, + (0xa0 << 24) | (0x88 << 16) | (0xa0 << 8) | 0x88); + solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_COLOR, + (0x10 << 24) | (0x8f << 16) | (0x10 << 8) | 0x8f); + solo_reg_write(solo_dev, SOLO_VO_BKG_COLOR, + (16 << 24) | (128 << 16) | (16 << 8) | 128); + + solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); + + solo_reg_write(solo_dev, SOLO_VI_WIN_SW, 0); + + solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0); + solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0); + + solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, SOLO_VO_DISP_ON | + SOLO_VO_DISP_ERASE_COUNT(8) | + SOLO_VO_DISP_BASE(SOLO_DISP_EXT_ADDR)); + + + solo_vout_config_cursor(solo_dev); + + /* Enable channels we support */ + solo_reg_write(solo_dev, SOLO_VI_CH_ENA, + (1 << solo_dev->nr_chans) - 1); +} + +static int solo_dma_vin_region(struct solo_dev *solo_dev, u32 off, + u16 val, int reg_size) +{ + u16 buf[64]; + int i; + int ret = 0; + + for (i = 0; i < sizeof(buf) >> 1; i++) + buf[i] = cpu_to_le16(val); + + for (i = 0; i < reg_size; i += sizeof(buf)) + ret |= solo_p2m_dma(solo_dev, 1, buf, + SOLO_MOTION_EXT_ADDR(solo_dev) + off + i, + sizeof(buf), 0, 0); + + return ret; +} + +int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val) +{ + if (ch > solo_dev->nr_chans) + return -EINVAL; + + return solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + + (ch * SOLO_MOT_THRESH_SIZE * 2), + val, SOLO_MOT_THRESH_SIZE); +} + +int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, + const struct solo_motion_thresholds *thresholds) +{ + u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2; + u16 buf[SOLO_MOTION_SZ]; + int x, y; + int ret = 0; + + for (y = 0; y < SOLO_MOTION_SZ; y++) { + for (x = 0; x < SOLO_MOTION_SZ; x++) + buf[x] = cpu_to_le16(thresholds->thresholds[y][x]); + ret |= solo_p2m_dma(solo_dev, 1, buf, + SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * sizeof(buf), + sizeof(buf), 0, 0); + } + return ret; +} + +/* First 8k is motion flag (512 bytes * 16). Following that is an 8k+8k + * threshold and working table for each channel. Atleast that's what the + * spec says. However, this code (taken from rdk) has some mystery 8k + * block right after the flag area, before the first thresh table. */ +static void solo_motion_config(struct solo_dev *solo_dev) +{ + int i; + + for (i = 0; i < solo_dev->nr_chans; i++) { + /* Clear motion flag area */ + solo_dma_vin_region(solo_dev, i * SOLO_MOT_FLAG_SIZE, 0x0000, + SOLO_MOT_FLAG_SIZE); + + /* Clear working cache table */ + solo_dma_vin_region(solo_dev, SOLO_MOT_FLAG_AREA + + (i * SOLO_MOT_THRESH_SIZE * 2) + + SOLO_MOT_THRESH_SIZE, 0x0000, + SOLO_MOT_THRESH_SIZE); + + /* Set default threshold table */ + solo_set_motion_threshold(solo_dev, i, SOLO_DEF_MOT_THRESH); + } + + /* Default motion settings */ + solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, SOLO_VI_MOTION_EN(0) | + (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16)); + solo_reg_write(solo_dev, SOLO_VI_MOT_CTRL, + SOLO_VI_MOTION_FRAME_COUNT(3) | + SOLO_VI_MOTION_SAMPLE_LENGTH(solo_dev->video_hsize / 16) + /* | SOLO_VI_MOTION_INTR_START_STOP */ + | SOLO_VI_MOTION_SAMPLE_COUNT(10)); + + solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0); + solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); +} + +int solo_disp_init(struct solo_dev *solo_dev) +{ + int i; + + solo_dev->video_hsize = 704; + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { + solo_dev->video_vsize = 240; + solo_dev->fps = 30; + } else { + solo_dev->video_vsize = 288; + solo_dev->fps = 25; + } + + solo_vin_config(solo_dev); + solo_motion_config(solo_dev); + solo_vout_config(solo_dev); + + for (i = 0; i < solo_dev->nr_chans; i++) + solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 1); + + return 0; +} + +void solo_disp_exit(struct solo_dev *solo_dev) +{ + int i; + + solo_reg_write(solo_dev, SOLO_VO_DISP_CTRL, 0); + solo_reg_write(solo_dev, SOLO_VO_ZOOM_CTRL, 0); + solo_reg_write(solo_dev, SOLO_VO_FREEZE_CTRL, 0); + + for (i = 0; i < solo_dev->nr_chans; i++) { + solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(i), 0); + solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(i), 0); + solo_reg_write(solo_dev, SOLO_VI_WIN_ON(i), 0); + } + + /* Set default border */ + for (i = 0; i < 5; i++) + solo_reg_write(solo_dev, SOLO_VO_BORDER_X(i), 0); + + for (i = 0; i < 5; i++) + solo_reg_write(solo_dev, SOLO_VO_BORDER_Y(i), 0); + + solo_reg_write(solo_dev, SOLO_VO_BORDER_LINE_MASK, 0); + solo_reg_write(solo_dev, SOLO_VO_BORDER_FILL_MASK, 0); + + solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(0), 0); + solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(0), 0); + solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(0), 0); + + solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_CTRL(1), 0); + solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_START(1), 0); + solo_reg_write(solo_dev, SOLO_VO_RECTANGLE_STOP(1), 0); +} diff --git a/drivers/staging/media/solo6x10/solo6x10-eeprom.c b/drivers/staging/media/solo6x10/solo6x10-eeprom.c new file mode 100644 index 0000000..9d1c9bb --- /dev/null +++ b/drivers/staging/media/solo6x10/solo6x10-eeprom.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +#include +#include + +#include "solo6x10.h" + +/* Control */ +#define EE_SHIFT_CLK 0x04 +#define EE_CS 0x08 +#define EE_DATA_WRITE 0x02 +#define EE_DATA_READ 0x01 +#define EE_ENB (0x80 | EE_CS) + +#define eeprom_delay() udelay(100) +#if 0 +#define eeprom_delay() solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) +#define eeprom_delay() ({ \ + int i, ret; \ + udelay(100); \ + for (i = ret = 0; i < 1000 && !ret; i++) \ + ret = solo_eeprom_reg_read(solo_dev); \ +}) +#endif +#define ADDR_LEN 6 + +/* Commands */ +#define EE_EWEN_CMD 4 +#define EE_EWDS_CMD 4 +#define EE_WRITE_CMD 5 +#define EE_READ_CMD 6 +#define EE_ERASE_CMD 7 + +static unsigned int solo_eeprom_reg_read(struct solo_dev *solo_dev) +{ + return solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) & EE_DATA_READ; +} + +static void solo_eeprom_reg_write(struct solo_dev *solo_dev, u32 data) +{ + solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data); + eeprom_delay(); +} + +static void solo_eeprom_cmd(struct solo_dev *solo_dev, int cmd) +{ + int i; + + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ACCESS_EN); + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); + + for (i = 4 + ADDR_LEN; i >= 0; i--) { + int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0; + + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | dataval); + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | + EE_SHIFT_CLK | dataval); + } + + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); +} + +unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en) +{ + int ewen_cmd = (w_en ? 0x3f : 0) | (EE_EWEN_CMD << ADDR_LEN); + unsigned int retval = 0; + int i; + + solo_eeprom_cmd(solo_dev, ewen_cmd); + + for (i = 0; i < 16; i++) { + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | + EE_SHIFT_CLK); + retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); + retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); + } + + solo_eeprom_reg_write(solo_dev, ~EE_CS); + retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); + + return retval; +} + +unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc) +{ + int read_cmd = loc | (EE_READ_CMD << ADDR_LEN); + unsigned short retval = 0; + int i; + + solo_eeprom_cmd(solo_dev, read_cmd); + + for (i = 0; i < 16; i++) { + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | + EE_SHIFT_CLK); + retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); + solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); + } + + solo_eeprom_reg_write(solo_dev, ~EE_CS); + + return retval; +} + +int solo_eeprom_write(struct solo_dev *solo_dev, int loc, + unsigned short data) +{ + int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN); + unsigned int retval; + int i; + + solo_eeprom_cmd(solo_dev, write_cmd); + + for (i = 15; i >= 0; i--) { + unsigned int dataval = (data >> i) & 1; + + solo_eeprom_reg_write(solo_dev, EE_ENB); + solo_eeprom_reg_write(solo_dev, + EE_ENB | (dataval << 1) | EE_SHIFT_CLK); + } + + solo_eeprom_reg_write(solo_dev, EE_ENB); + solo_eeprom_reg_write(solo_dev, ~EE_CS); + solo_eeprom_reg_write(solo_dev, EE_ENB); + + for (i = retval = 0; i < 10000 && !retval; i++) + retval = solo_eeprom_reg_read(solo_dev); + + solo_eeprom_reg_write(solo_dev, ~EE_CS); + + return !retval; +} diff --git a/drivers/staging/media/solo6x10/solo6x10-enc.c b/drivers/staging/media/solo6x10/solo6x10-enc.c new file mode 100644 index 0000000..94d5735 --- /dev/null +++ b/drivers/staging/media/solo6x10/solo6x10-enc.c @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +#include +#include +#include +#include + +#include "solo6x10.h" + +#define VI_PROG_HSIZE (1280 - 16) +#define VI_PROG_VSIZE (1024 - 16) + +#define IRQ_LEVEL 2 + +static void solo_capture_config(struct solo_dev *solo_dev) +{ + unsigned long height; + unsigned long width; + void *buf; + int i; + + solo_reg_write(solo_dev, SOLO_CAP_BASE, + SOLO_CAP_MAX_PAGE((SOLO_CAP_EXT_SIZE(solo_dev) + - SOLO_CAP_PAGE_SIZE) >> 16) + | SOLO_CAP_BASE_ADDR(SOLO_CAP_EXT_ADDR(solo_dev) >> 16)); + + /* XXX: Undocumented bits at b17 and b24 */ + if (solo_dev->type == SOLO_DEV_6110) { + /* NOTE: Ref driver has (62 << 24) here as well, but it causes + * wacked out frame timing on 4-port 6110. */ + solo_reg_write(solo_dev, SOLO_CAP_BTW, + (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | + SOLO_CAP_MAX_BANDWIDTH(36)); + } else { + solo_reg_write(solo_dev, SOLO_CAP_BTW, + (1 << 17) | SOLO_CAP_PROG_BANDWIDTH(2) | + SOLO_CAP_MAX_BANDWIDTH(32)); + } + + /* Set scale 1, 9 dimension */ + width = solo_dev->video_hsize; + height = solo_dev->video_vsize; + solo_reg_write(solo_dev, SOLO_DIM_SCALE1, + SOLO_DIM_H_MB_NUM(width / 16) | + SOLO_DIM_V_MB_NUM_FRAME(height / 8) | + SOLO_DIM_V_MB_NUM_FIELD(height / 16)); + + /* Set scale 2, 10 dimension */ + width = solo_dev->video_hsize / 2; + height = solo_dev->video_vsize; + solo_reg_write(solo_dev, SOLO_DIM_SCALE2, + SOLO_DIM_H_MB_NUM(width / 16) | + SOLO_DIM_V_MB_NUM_FRAME(height / 8) | + SOLO_DIM_V_MB_NUM_FIELD(height / 16)); + + /* Set scale 3, 11 dimension */ + width = solo_dev->video_hsize / 2; + height = solo_dev->video_vsize / 2; + solo_reg_write(solo_dev, SOLO_DIM_SCALE3, + SOLO_DIM_H_MB_NUM(width / 16) | + SOLO_DIM_V_MB_NUM_FRAME(height / 8) | + SOLO_DIM_V_MB_NUM_FIELD(height / 16)); + + /* Set scale 4, 12 dimension */ + width = solo_dev->video_hsize / 3; + height = solo_dev->video_vsize / 3; + solo_reg_write(solo_dev, SOLO_DIM_SCALE4, + SOLO_DIM_H_MB_NUM(width / 16) | + SOLO_DIM_V_MB_NUM_FRAME(height / 8) | + SOLO_DIM_V_MB_NUM_FIELD(height / 16)); + + /* Set scale 5, 13 dimension */ + width = solo_dev->video_hsize / 4; + height = solo_dev->video_vsize / 2; + solo_reg_write(solo_dev, SOLO_DIM_SCALE5, + SOLO_DIM_H_MB_NUM(width / 16) | + SOLO_DIM_V_MB_NUM_FRAME(height / 8) | + SOLO_DIM_V_MB_NUM_FIELD(height / 16)); + + /* Progressive */ + width = VI_PROG_HSIZE; + height = VI_PROG_VSIZE; + solo_reg_write(solo_dev, SOLO_DIM_PROG, + SOLO_DIM_H_MB_NUM(width / 16) | + SOLO_DIM_V_MB_NUM_FRAME(height / 16) | + SOLO_DIM_V_MB_NUM_FIELD(height / 16)); + + /* Clear OSD */ + solo_reg_write(solo_dev, SOLO_VE_OSD_CH, 0); + solo_reg_write(solo_dev, SOLO_VE_OSD_BASE, SOLO_EOSD_EXT_ADDR >> 16); + solo_reg_write(solo_dev, SOLO_VE_OSD_CLR, + 0xF0 << 16 | 0x80 << 8 | 0x80); + + if (solo_dev->type == SOLO_DEV_6010) + solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, + SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW); + else + solo_reg_write(solo_dev, SOLO_VE_OSD_OPT, SOLO_VE_OSD_V_DOUBLE + | SOLO_VE_OSD_H_SHADOW | SOLO_VE_OSD_V_SHADOW); + + /* Clear OSG buffer */ + buf = kzalloc(SOLO_EOSD_EXT_SIZE(solo_dev), GFP_KERNEL); + if (!buf) + return; + + for (i = 0; i < solo_dev->nr_chans; i++) { + solo_p2m_dma(solo_dev, 1, buf, + SOLO_EOSD_EXT_ADDR + + (SOLO_EOSD_EXT_SIZE(solo_dev) * i), + SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0); + } + kfree(buf); +} + +/* Should be called with enable_lock held */ +int solo_osd_print(struct solo_enc_dev *solo_enc) +{ + struct solo_dev *solo_dev = solo_enc->solo_dev; + unsigned char *str = solo_enc->osd_text; + u8 *buf = solo_enc->osd_buf; + u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH); + const struct font_desc *vga = find_font("VGA8x16"); + const unsigned char *vga_data; + int len; + int i, j; + + if (WARN_ON_ONCE(!vga)) + return -ENODEV; + + len = strlen(str); + + if (len == 0) { + /* Disable OSD on this channel */ + reg &= ~(1 << solo_enc->ch); + solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); + return 0; + } + + memset(buf, 0, SOLO_EOSD_EXT_SIZE_MAX); + vga_data = (const unsigned char *)vga->data; + + for (i = 0; i < len; i++) { + unsigned char c = str[i]; + + for (j = 0; j < 16; j++) { + buf[(j * 2) + (i % 2) + (i / 2 * 32)] = + bitrev8(vga_data[(c * 16) + j]); + } + } + + solo_p2m_dma(solo_dev, 1, buf, + SOLO_EOSD_EXT_ADDR + + (solo_enc->ch * SOLO_EOSD_EXT_SIZE(solo_dev)), + SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0); + + /* Enable OSD on this channel */ + reg |= (1 << solo_enc->ch); + solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg); + + return 0; +} + +/** + * Set channel Quality Profile (0-3). + */ +void solo_s_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch, + unsigned int qp) +{ + unsigned long flags; + unsigned int idx, reg; + + if ((ch > 31) || (qp > 3)) + return; + + if (solo_dev->type == SOLO_DEV_6010) + return; + + if (ch < 16) { + idx = 0; + reg = SOLO_VE_JPEG_QP_CH_L; + } else { + ch -= 16; + idx = 1; + reg = SOLO_VE_JPEG_QP_CH_H; + } + ch *= 2; + + spin_lock_irqsave(&solo_dev->jpeg_qp_lock, flags); + + solo_dev->jpeg_qp[idx] &= ~(3 << ch); + solo_dev->jpeg_qp[idx] |= (qp & 3) << ch; + + solo_reg_write(solo_dev, reg, solo_dev->jpeg_qp[idx]); + + spin_unlock_irqrestore(&solo_dev->jpeg_qp_lock, flags); +} + +int solo_g_jpeg_qp(struct solo_dev *solo_dev, unsigned int ch) +{ + int idx; + + if (solo_dev->type == SOLO_DEV_6010) + return 2; + + if (WARN_ON_ONCE(ch > 31)) + return 2; + + if (ch < 16) { + idx = 0; + } else { + ch -= 16; + idx = 1; + } + ch *= 2; + + return (solo_dev->jpeg_qp[idx] >> ch) & 3; +} + +#define SOLO_QP_INIT 0xaaaaaaaa + +static void solo_jpeg_config(struct solo_dev *solo_dev) +{ + if (solo_dev->type == SOLO_DEV_6010) { + solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, + (2 << 24) | (2 << 16) | (2 << 8) | 2); + } else { + solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_TBL, + (4 << 24) | (3 << 16) | (2 << 8) | 1); + } + + spin_lock_init(&solo_dev->jpeg_qp_lock); + + /* Initialize Quality Profile for all channels */ + solo_dev->jpeg_qp[0] = solo_dev->jpeg_qp[1] = SOLO_QP_INIT; + solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_L, SOLO_QP_INIT); + solo_reg_write(solo_dev, SOLO_VE_JPEG_QP_CH_H, SOLO_QP_INIT); + + solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG, + (SOLO_JPEG_EXT_SIZE(solo_dev) & 0xffff0000) | + ((SOLO_JPEG_EXT_ADDR(solo_dev) >> 16) & 0x0000ffff)); + solo_reg_write(solo_dev, SOLO_VE_JPEG_CTRL, 0xffffffff); + if (solo_dev->type == SOLO_DEV_6110) { + solo_reg_write(solo_dev, SOLO_VE_JPEG_CFG1, + (0 << 16) | (30 << 8) | 60); + } +} + +static void solo_mp4e_config(struct solo_dev *solo_dev) +{ + int i; + u32 cfg; + + solo_reg_write(solo_dev, SOLO_VE_CFG0, + SOLO_VE_INTR_CTRL(IRQ_LEVEL) | + SOLO_VE_BLOCK_SIZE(SOLO_MP4E_EXT_SIZE(solo_dev) >> 16) | + SOLO_VE_BLOCK_BASE(SOLO_MP4E_EXT_ADDR(solo_dev) >> 16)); + + + cfg = SOLO_VE_BYTE_ALIGN(2) | SOLO_VE_INSERT_INDEX + | SOLO_VE_MOTION_MODE(0); + if (solo_dev->type != SOLO_DEV_6010) { + cfg |= SOLO_VE_MPEG_SIZE_H( + (SOLO_MP4E_EXT_SIZE(solo_dev) >> 24) & 0x0f); + cfg |= SOLO_VE_JPEG_SIZE_H( + (SOLO_JPEG_EXT_SIZE(solo_dev) >> 24) & 0x0f); + } + solo_reg_write(solo_dev, SOLO_VE_CFG1, cfg); + + solo_reg_write(solo_dev, SOLO_VE_WMRK_POLY, 0); + solo_reg_write(solo_dev, SOLO_VE_VMRK_INIT_KEY, 0); + solo_reg_write(solo_dev, SOLO_VE_WMRK_STRL, 0); + if (solo_dev->type == SOLO_DEV_6110) + solo_reg_write(solo_dev, SOLO_VE_WMRK_ENABLE, 0); + solo_reg_write(solo_dev, SOLO_VE_ENCRYP_POLY, 0); + solo_reg_write(solo_dev, SOLO_VE_ENCRYP_INIT, 0); + + solo_reg_write(solo_dev, SOLO_VE_ATTR, + SOLO_VE_LITTLE_ENDIAN | + SOLO_COMP_ATTR_FCODE(1) | + SOLO_COMP_TIME_INC(0) | + SOLO_COMP_TIME_WIDTH(15) | + SOLO_DCT_INTERVAL(solo_dev->type == SOLO_DEV_6010 ? 9 : 10)); + + for (i = 0; i < solo_dev->nr_chans; i++) { + solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE(i), + (SOLO_EREF_EXT_ADDR(solo_dev) + + (i * SOLO_EREF_EXT_SIZE)) >> 16); + solo_reg_write(solo_dev, SOLO_VE_CH_REF_BASE_E(i), + (SOLO_EREF_EXT_ADDR(solo_dev) + + ((i + 16) * SOLO_EREF_EXT_SIZE)) >> 16); + } + + if (solo_dev->type == SOLO_DEV_6110) { + solo_reg_write(solo_dev, SOLO_VE_COMPT_MOT, 0x00040008); + } else { + for (i = 0; i < solo_dev->nr_chans; i++) + solo_reg_write(solo_dev, SOLO_VE_CH_MOT(i), 0x100); + } +} + +int solo_enc_init(struct solo_dev *solo_dev) +{ + int i; + + solo_capture_config(solo_dev); + solo_mp4e_config(solo_dev); + solo_jpeg_config(solo_dev); + + for (i = 0; i < solo_dev->nr_chans; i++) { + solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); + solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); + } + + return 0; +} + +void solo_enc_exit(struct solo_dev *solo_dev) +{ + int i; + + for (i = 0; i < solo_dev->nr_chans; i++) { + solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(i), 0); + solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(i), 0); + } +} diff --git a/drivers/staging/media/solo6x10/solo6x10-g723.c b/drivers/staging/media/solo6x10/solo6x10-g723.c new file mode 100644 index 0000000..1db18c7 --- /dev/null +++ b/drivers/staging/media/solo6x10/solo6x10-g723.c @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "solo6x10.h" +#include "solo6x10-tw28.h" + +#define G723_FDMA_PAGES 32 +#define G723_PERIOD_BYTES 48 +#define G723_PERIOD_BLOCK 1024 +#define G723_FRAMES_PER_PAGE 48 + +/* Sets up channels 16-19 for decoding and 0-15 for encoding */ +#define OUTMODE_MASK 0x300 + +#define SAMPLERATE 8000 +#define BITRATE 25 + +/* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page + * is broken down to 20 * 48 byte regions (one for each channel possible) + * with the rest of the page being dummy data. */ +#define G723_MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX) +#define G723_INTR_ORDER 4 /* 0 - 4 */ +#define PERIODS_MIN (1 << G723_INTR_ORDER) +#define PERIODS_MAX G723_FDMA_PAGES + +struct solo_snd_pcm { + int on; + spinlock_t lock; + struct solo_dev *solo_dev; + unsigned char *g723_buf; + dma_addr_t g723_dma; +}; + +static void solo_g723_config(struct solo_dev *solo_dev) +{ + int clk_div; + + clk_div = (solo_dev->clock_mhz * 1000000) + / (SAMPLERATE * (BITRATE * 2) * 2); + + solo_reg_write(solo_dev, SOLO_AUDIO_SAMPLE, + SOLO_AUDIO_BITRATE(BITRATE) + | SOLO_AUDIO_CLK_DIV(clk_div)); + + solo_reg_write(solo_dev, SOLO_AUDIO_FDMA_INTR, + SOLO_AUDIO_FDMA_INTERVAL(1) + | SOLO_AUDIO_INTR_ORDER(G723_INTR_ORDER) + | SOLO_AUDIO_FDMA_BASE(SOLO_G723_EXT_ADDR(solo_dev) >> 16)); + + solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, + SOLO_AUDIO_ENABLE + | SOLO_AUDIO_I2S_MODE + | SOLO_AUDIO_I2S_MULTI(3) + | SOLO_AUDIO_MODE(OUTMODE_MASK)); +} + +void solo_g723_isr(struct solo_dev *solo_dev) +{ + struct snd_pcm_str *pstr = + &solo_dev->snd_pcm->streams[SNDRV_PCM_STREAM_CAPTURE]; + struct snd_pcm_substream *ss; + struct solo_snd_pcm *solo_pcm; + + for (ss = pstr->substream; ss != NULL; ss = ss->next) { + if (snd_pcm_substream_chip(ss) == NULL) + continue; + + /* This means open() hasn't been called on this one */ + if (snd_pcm_substream_chip(ss) == solo_dev) + continue; + + /* Haven't triggered a start yet */ + solo_pcm = snd_pcm_substream_chip(ss); + if (!solo_pcm->on) + continue; + + snd_pcm_period_elapsed(ss); + } +} + +static int snd_solo_hw_params(struct snd_pcm_substream *ss, + struct snd_pcm_hw_params *hw_params) +{ + return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params)); +} + +static int snd_solo_hw_free(struct snd_pcm_substream *ss) +{ + return snd_pcm_lib_free_pages(ss); +} + +static const struct snd_pcm_hardware snd_solo_pcm_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_U8, + .rates = SNDRV_PCM_RATE_8000, + .rate_min = SAMPLERATE, + .rate_max = SAMPLERATE, + .channels_min = 1, + .channels_max = 1, + .buffer_bytes_max = G723_MAX_BUFFER, + .period_bytes_min = G723_PERIOD_BYTES, + .period_bytes_max = G723_PERIOD_BYTES, + .periods_min = PERIODS_MIN, + .periods_max = PERIODS_MAX, +}; + +static int snd_solo_pcm_open(struct snd_pcm_substream *ss) +{ + struct solo_dev *solo_dev = snd_pcm_substream_chip(ss); + struct solo_snd_pcm *solo_pcm; + + solo_pcm = kzalloc(sizeof(*solo_pcm), GFP_KERNEL); + if (solo_pcm == NULL) + goto oom; + + solo_pcm->g723_buf = pci_alloc_consistent(solo_dev->pdev, + G723_PERIOD_BYTES, + &solo_pcm->g723_dma); + if (solo_pcm->g723_buf == NULL) + goto oom; + + spin_lock_init(&solo_pcm->lock); + solo_pcm->solo_dev = solo_dev; + ss->runtime->hw = snd_solo_pcm_hw; + + snd_pcm_substream_chip(ss) = solo_pcm; + + return 0; + +oom: + kfree(solo_pcm); + return -ENOMEM; +} + +static int snd_solo_pcm_close(struct snd_pcm_substream *ss) +{ + struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); + + snd_pcm_substream_chip(ss) = solo_pcm->solo_dev; + pci_free_consistent(solo_pcm->solo_dev->pdev, G723_PERIOD_BYTES, + solo_pcm->g723_buf, solo_pcm->g723_dma); + kfree(solo_pcm); + + return 0; +} + +static int snd_solo_pcm_trigger(struct snd_pcm_substream *ss, int cmd) +{ + struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); + struct solo_dev *solo_dev = solo_pcm->solo_dev; + int ret = 0; + + spin_lock(&solo_pcm->lock); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (solo_pcm->on == 0) { + /* If this is the first user, switch on interrupts */ + if (atomic_inc_return(&solo_dev->snd_users) == 1) + solo_irq_on(solo_dev, SOLO_IRQ_G723); + solo_pcm->on = 1; + } + break; + case SNDRV_PCM_TRIGGER_STOP: + if (solo_pcm->on) { + /* If this was our last user, switch them off */ + if (atomic_dec_return(&solo_dev->snd_users) == 0) + solo_irq_off(solo_dev, SOLO_IRQ_G723); + solo_pcm->on = 0; + } + break; + default: + ret = -EINVAL; + } + + spin_unlock(&solo_pcm->lock); + + return ret; +} + +static int snd_solo_pcm_prepare(struct snd_pcm_substream *ss) +{ + return 0; +} + +static snd_pcm_uframes_t snd_solo_pcm_pointer(struct snd_pcm_substream *ss) +{ + struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); + struct solo_dev *solo_dev = solo_pcm->solo_dev; + snd_pcm_uframes_t idx = solo_reg_read(solo_dev, SOLO_AUDIO_STA) & 0x1f; + + return idx * G723_FRAMES_PER_PAGE; +} + +static int snd_solo_pcm_copy(struct snd_pcm_substream *ss, int channel, + snd_pcm_uframes_t pos, void __user *dst, + snd_pcm_uframes_t count) +{ + struct solo_snd_pcm *solo_pcm = snd_pcm_substream_chip(ss); + struct solo_dev *solo_dev = solo_pcm->solo_dev; + int err, i; + + for (i = 0; i < (count / G723_FRAMES_PER_PAGE); i++) { + int page = (pos / G723_FRAMES_PER_PAGE) + i; + + err = solo_p2m_dma_t(solo_dev, 0, solo_pcm->g723_dma, + SOLO_G723_EXT_ADDR(solo_dev) + + (page * G723_PERIOD_BLOCK) + + (ss->number * G723_PERIOD_BYTES), + G723_PERIOD_BYTES, 0, 0); + if (err) + return err; + + err = copy_to_user(dst + (i * G723_PERIOD_BYTES), + solo_pcm->g723_buf, G723_PERIOD_BYTES); + + if (err) + return -EFAULT; + } + + return 0; +} + +static struct snd_pcm_ops snd_solo_pcm_ops = { + .open = snd_solo_pcm_open, + .close = snd_solo_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_solo_hw_params, + .hw_free = snd_solo_hw_free, + .prepare = snd_solo_pcm_prepare, + .trigger = snd_solo_pcm_trigger, + .pointer = snd_solo_pcm_pointer, + .copy = snd_solo_pcm_copy, +}; + +static int snd_solo_capture_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 1; + info->value.integer.min = 0; + info->value.integer.max = 15; + info->value.integer.step = 1; + + return 0; +} + +static int snd_solo_capture_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol); + u8 ch = value->id.numid - 1; + + value->value.integer.value[0] = tw28_get_audio_gain(solo_dev, ch); + + return 0; +} + +static int snd_solo_capture_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct solo_dev *solo_dev = snd_kcontrol_chip(kcontrol); + u8 ch = value->id.numid - 1; + u8 old_val; + + old_val = tw28_get_audio_gain(solo_dev, ch); + if (old_val == value->value.integer.value[0]) + return 0; + + tw28_set_audio_gain(solo_dev, ch, value->value.integer.value[0]); + + return 1; +} + +static struct snd_kcontrol_new snd_solo_capture_volume = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Volume", + .info = snd_solo_capture_volume_info, + .get = snd_solo_capture_volume_get, + .put = snd_solo_capture_volume_put, +}; + +static int solo_snd_pcm_init(struct solo_dev *solo_dev) +{ + struct snd_card *card = solo_dev->snd_card; + struct snd_pcm *pcm; + struct snd_pcm_substream *ss; + int ret; + int i; + + ret = snd_pcm_new(card, card->driver, 0, 0, solo_dev->nr_chans, + &pcm); + if (ret < 0) + return ret; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_solo_pcm_ops); + + snd_pcm_chip(pcm) = solo_dev; + pcm->info_flags = 0; + strcpy(pcm->name, card->shortname); + + for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + ss; ss = ss->next, i++) + sprintf(ss->name, "Camera #%d Audio", i); + + ret = snd_pcm_lib_preallocate_pages_for_all(pcm, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + G723_MAX_BUFFER, G723_MAX_BUFFER); + if (ret < 0) + return ret; + + solo_dev->snd_pcm = pcm; + + return 0; +} + +int solo_g723_init(struct solo_dev *solo_dev) +{ + static struct snd_device_ops ops = { NULL }; + struct snd_card *card; + struct snd_kcontrol_new kctl; + char name[32]; + int ret; + + atomic_set(&solo_dev->snd_users, 0); + + /* Allows for easier mapping between video and audio */ + sprintf(name, "Softlogic%d", solo_dev->vfd->num); + + ret = snd_card_create(SNDRV_DEFAULT_IDX1, name, THIS_MODULE, 0, + &solo_dev->snd_card); + if (ret < 0) + return ret; + + card = solo_dev->snd_card; + + strcpy(card->driver, SOLO6X10_NAME); + strcpy(card->shortname, "SOLO-6x10 Audio"); + sprintf(card->longname, "%s on %s IRQ %d", card->shortname, + pci_name(solo_dev->pdev), solo_dev->pdev->irq); + snd_card_set_dev(card, &solo_dev->pdev->dev); + + ret = snd_device_new(card, SNDRV_DEV_LOWLEVEL, solo_dev, &ops); + if (ret < 0) + goto snd_error; + + /* Mixer controls */ + strcpy(card->mixername, "SOLO-6x10"); + kctl = snd_solo_capture_volume; + kctl.count = solo_dev->nr_chans; + + ret = snd_ctl_add(card, snd_ctl_new1(&kctl, solo_dev)); + if (ret < 0) + return ret; + + ret = solo_snd_pcm_init(solo_dev); + if (ret < 0) + goto snd_error; + + ret = snd_card_register(card); + if (ret < 0) + goto snd_error; + + solo_g723_config(solo_dev); + + dev_info(&solo_dev->pdev->dev, "Alsa sound card as %s\n", name); + + return 0; + +snd_error: + snd_card_free(card); + return ret; +} + +void solo_g723_exit(struct solo_dev *solo_dev) +{ + if (!solo_dev->snd_card) + return; + + solo_reg_write(solo_dev, SOLO_AUDIO_CONTROL, 0); + solo_irq_off(solo_dev, SOLO_IRQ_G723); + + snd_card_free(solo_dev->snd_card); + solo_dev->snd_card = NULL; +} diff --git a/drivers/staging/media/solo6x10/solo6x10-gpio.c b/drivers/staging/media/solo6x10/solo6x10-gpio.c new file mode 100644 index 0000000..73276dc --- /dev/null +++ b/drivers/staging/media/solo6x10/solo6x10-gpio.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +#include +#include +#include +#include + +#include "solo6x10.h" + +static void solo_gpio_mode(struct solo_dev *solo_dev, + unsigned int port_mask, unsigned int mode) +{ + int port; + unsigned int ret; + + ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_0); + + /* To set gpio */ + for (port = 0; port < 16; port++) { + if (!((1 << port) & port_mask)) + continue; + + ret &= (~(3 << (port << 1))); + ret |= ((mode & 3) << (port << 1)); + } + + solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_0, ret); + + /* To set extended gpio - sensor */ + ret = solo_reg_read(solo_dev, SOLO_GPIO_CONFIG_1); + + for (port = 0; port < 16; port++) { + if (!((1 << (port + 16)) & port_mask)) + continue; + + if (!mode) + ret &= ~(1 << port); + else + ret |= 1 << port; + } + + solo_reg_write(solo_dev, SOLO_GPIO_CONFIG_1, ret); +} + +static void solo_gpio_set(struct solo_dev *solo_dev, unsigned int value) +{ + solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT, + solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) | value); +} + +static void solo_gpio_clear(struct solo_dev *solo_dev, unsigned int value) +{ + solo_reg_write(solo_dev, SOLO_GPIO_DATA_OUT, + solo_reg_read(solo_dev, SOLO_GPIO_DATA_OUT) & ~value); +} + +static void solo_gpio_config(struct solo_dev *solo_dev) +{ + /* Video reset */ + solo_gpio_mode(solo_dev, 0x30, 1); + solo_gpio_clear(solo_dev, 0x30); + udelay(100); + solo_gpio_set(solo_dev, 0x30); + udelay(100); + + /* Warning: Don't touch the next line unless you're sure of what + * you're doing: first four gpio [0-3] are used for video. */ + solo_gpio_mode(solo_dev, 0x0f, 2); + + /* We use bit 8-15 of SOLO_GPIO_CONFIG_0 for relay purposes */ + solo_gpio_mode(solo_dev, 0xff00, 1); + + /* Initially set relay status to 0 */ + solo_gpio_clear(solo_dev, 0xff00); +} + +int solo_gpio_init(struct solo_dev *solo_dev) +{ + solo_gpio_config(solo_dev); + return 0; +} + +void solo_gpio_exit(struct solo_dev *solo_dev) +{ + solo_gpio_clear(solo_dev, 0x30); + solo_gpio_config(solo_dev); +} diff --git a/drivers/staging/media/solo6x10/solo6x10-i2c.c b/drivers/staging/media/solo6x10/solo6x10-i2c.c new file mode 100644 index 0000000..01aa417 --- /dev/null +++ b/drivers/staging/media/solo6x10/solo6x10-i2c.c @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +/* XXX: The SOLO6x10 i2c does not have separate interrupts for each i2c + * channel. The bus can only handle one i2c event at a time. The below handles + * this all wrong. We should be using the status registers to see if the bus + * is in use, and have a global lock to check the status register. Also, + * the bulk of the work should be handled out-of-interrupt. The ugly loops + * that occur during interrupt scare me. The ISR should merely signal + * thread context, ACK the interrupt, and move on. -- BenC */ + +#include + +#include "solo6x10.h" + +u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off) +{ + struct i2c_msg msgs[2]; + u8 data; + + msgs[0].flags = 0; + msgs[0].addr = addr; + msgs[0].len = 1; + msgs[0].buf = &off; + + msgs[1].flags = I2C_M_RD; + msgs[1].addr = addr; + msgs[1].len = 1; + msgs[1].buf = &data; + + i2c_transfer(&solo_dev->i2c_adap[id], msgs, 2); + + return data; +} + +void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr, + u8 off, u8 data) +{ + struct i2c_msg msgs; + u8 buf[2]; + + buf[0] = off; + buf[1] = data; + msgs.flags = 0; + msgs.addr = addr; + msgs.len = 2; + msgs.buf = buf; + + i2c_transfer(&solo_dev->i2c_adap[id], &msgs, 1); +} + +static void solo_i2c_flush(struct solo_dev *solo_dev, int wr) +{ + u32 ctrl; + + ctrl = SOLO_IIC_CH_SET(solo_dev->i2c_id); + + if (solo_dev->i2c_state == IIC_STATE_START) + ctrl |= SOLO_IIC_START; + + if (wr) { + ctrl |= SOLO_IIC_WRITE; + } else { + ctrl |= SOLO_IIC_READ; + if (!(solo_dev->i2c_msg->flags & I2C_M_NO_RD_ACK)) + ctrl |= SOLO_IIC_ACK_EN; + } + + if (solo_dev->i2c_msg_ptr == solo_dev->i2c_msg->len) + ctrl |= SOLO_IIC_STOP; + + solo_reg_write(solo_dev, SOLO_IIC_CTRL, ctrl); +} + +static void solo_i2c_start(struct solo_dev *solo_dev) +{ + u32 addr = solo_dev->i2c_msg->addr << 1; + + if (solo_dev->i2c_msg->flags & I2C_M_RD) + addr |= 1; + + solo_dev->i2c_state = IIC_STATE_START; + solo_reg_write(solo_dev, SOLO_IIC_TXD, addr); + solo_i2c_flush(solo_dev, 1); +} + +static void solo_i2c_stop(struct solo_dev *solo_dev) +{ + solo_irq_off(solo_dev, SOLO_IRQ_IIC); + solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0); + solo_dev->i2c_state = IIC_STATE_STOP; + wake_up(&solo_dev->i2c_wait); +} + +static int solo_i2c_handle_read(struct solo_dev *solo_dev) +{ +prepare_read: + if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) { + solo_i2c_flush(solo_dev, 0); + return 0; + } + + solo_dev->i2c_msg_ptr = 0; + solo_dev->i2c_msg++; + solo_dev->i2c_msg_num--; + + if (solo_dev->i2c_msg_num == 0) { + solo_i2c_stop(solo_dev); + return 0; + } + + if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) { + solo_i2c_start(solo_dev); + } else { + if (solo_dev->i2c_msg->flags & I2C_M_RD) + goto prepare_read; + else + solo_i2c_stop(solo_dev); + } + + return 0; +} + +static int solo_i2c_handle_write(struct solo_dev *solo_dev) +{ +retry_write: + if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) { + solo_reg_write(solo_dev, SOLO_IIC_TXD, + solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr]); + solo_dev->i2c_msg_ptr++; + solo_i2c_flush(solo_dev, 1); + return 0; + } + + solo_dev->i2c_msg_ptr = 0; + solo_dev->i2c_msg++; + solo_dev->i2c_msg_num--; + + if (solo_dev->i2c_msg_num == 0) { + solo_i2c_stop(solo_dev); + return 0; + } + + if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) { + solo_i2c_start(solo_dev); + } else { + if (solo_dev->i2c_msg->flags & I2C_M_RD) + solo_i2c_stop(solo_dev); + else + goto retry_write; + } + + return 0; +} + +int solo_i2c_isr(struct solo_dev *solo_dev) +{ + u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL); + int ret = -EINVAL; + + + if (CHK_FLAGS(status, SOLO_IIC_STATE_TRNS | SOLO_IIC_STATE_SIG_ERR) + || solo_dev->i2c_id < 0) { + solo_i2c_stop(solo_dev); + return -ENXIO; + } + + switch (solo_dev->i2c_state) { + case IIC_STATE_START: + if (solo_dev->i2c_msg->flags & I2C_M_RD) { + solo_dev->i2c_state = IIC_STATE_READ; + ret = solo_i2c_handle_read(solo_dev); + break; + } + + solo_dev->i2c_state = IIC_STATE_WRITE; + case IIC_STATE_WRITE: + ret = solo_i2c_handle_write(solo_dev); + break; + + case IIC_STATE_READ: + solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr] = + solo_reg_read(solo_dev, SOLO_IIC_RXD); + solo_dev->i2c_msg_ptr++; + + ret = solo_i2c_handle_read(solo_dev); + break; + + default: + solo_i2c_stop(solo_dev); + } + + return ret; +} + +static int solo_i2c_master_xfer(struct i2c_adapter *adap, + struct i2c_msg msgs[], int num) +{ + struct solo_dev *solo_dev = adap->algo_data; + unsigned long timeout; + int ret; + int i; + DEFINE_WAIT(wait); + + for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { + if (&solo_dev->i2c_adap[i] == adap) + break; + } + + if (i == SOLO_I2C_ADAPTERS) + return num; /* XXX Right return value for failure? */ + + mutex_lock(&solo_dev->i2c_mutex); + solo_dev->i2c_id = i; + solo_dev->i2c_msg = msgs; + solo_dev->i2c_msg_num = num; + solo_dev->i2c_msg_ptr = 0; + + solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0); + solo_irq_on(solo_dev, SOLO_IRQ_IIC); + solo_i2c_start(solo_dev); + + timeout = HZ / 2; + + for (;;) { + prepare_to_wait(&solo_dev->i2c_wait, &wait, + TASK_INTERRUPTIBLE); + + if (solo_dev->i2c_state == IIC_STATE_STOP) + break; + + timeout = schedule_timeout(timeout); + if (!timeout) + break; + + if (signal_pending(current)) + break; + } + + finish_wait(&solo_dev->i2c_wait, &wait); + ret = num - solo_dev->i2c_msg_num; + solo_dev->i2c_state = IIC_STATE_IDLE; + solo_dev->i2c_id = -1; + + mutex_unlock(&solo_dev->i2c_mutex); + + return ret; +} + +static u32 solo_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C; +} + +static const struct i2c_algorithm solo_i2c_algo = { + .master_xfer = solo_i2c_master_xfer, + .functionality = solo_i2c_functionality, +}; + +int solo_i2c_init(struct solo_dev *solo_dev) +{ + int i; + int ret; + + solo_reg_write(solo_dev, SOLO_IIC_CFG, + SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE); + + solo_dev->i2c_id = -1; + solo_dev->i2c_state = IIC_STATE_IDLE; + init_waitqueue_head(&solo_dev->i2c_wait); + mutex_init(&solo_dev->i2c_mutex); + + for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { + struct i2c_adapter *adap = &solo_dev->i2c_adap[i]; + + snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d", + SOLO6X10_NAME, i); + adap->algo = &solo_i2c_algo; + adap->algo_data = solo_dev; + adap->retries = 1; + adap->dev.parent = &solo_dev->pdev->dev; + + ret = i2c_add_adapter(adap); + if (ret) { + adap->algo_data = NULL; + break; + } + } + + if (ret) { + for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { + if (!solo_dev->i2c_adap[i].algo_data) + break; + i2c_del_adapter(&solo_dev->i2c_adap[i]); + solo_dev->i2c_adap[i].algo_data = NULL; + } + return ret; + } + + return 0; +} + +void solo_i2c_exit(struct solo_dev *solo_dev) +{ + int i; + + for (i = 0; i < SOLO_I2C_ADAPTERS; i++) { + if (!solo_dev->i2c_adap[i].algo_data) + continue; + i2c_del_adapter(&solo_dev->i2c_adap[i]); + solo_dev->i2c_adap[i].algo_data = NULL; + } +} diff --git a/drivers/staging/media/solo6x10/solo6x10-p2m.c b/drivers/staging/media/solo6x10/solo6x10-p2m.c new file mode 100644 index 0000000..3335941 --- /dev/null +++ b/drivers/staging/media/solo6x10/solo6x10-p2m.c @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +#include +#include +#include + +#include "solo6x10.h" + +static int multi_p2m; +module_param(multi_p2m, uint, 0644); +MODULE_PARM_DESC(multi_p2m, + "Use multiple P2M DMA channels (default: no, 6010-only)"); + +static int desc_mode; +module_param(desc_mode, uint, 0644); +MODULE_PARM_DESC(desc_mode, + "Allow use of descriptor mode DMA (default: no, 6010-only)"); + +int solo_p2m_dma(struct solo_dev *solo_dev, int wr, + void *sys_addr, u32 ext_addr, u32 size, + int repeat, u32 ext_size) +{ + dma_addr_t dma_addr; + int ret; + + if (WARN_ON_ONCE((unsigned long)sys_addr & 0x03)) + return -EINVAL; + if (WARN_ON_ONCE(!size)) + return -EINVAL; + + dma_addr = pci_map_single(solo_dev->pdev, sys_addr, size, + wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(solo_dev->pdev, dma_addr)) + return -ENOMEM; + + ret = solo_p2m_dma_t(solo_dev, wr, dma_addr, ext_addr, size, + repeat, ext_size); + + pci_unmap_single(solo_dev->pdev, dma_addr, size, + wr ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); + + return ret; +} + +/* Mutex must be held for p2m_id before calling this!! */ +int solo_p2m_dma_desc(struct solo_dev *solo_dev, + struct solo_p2m_desc *desc, dma_addr_t desc_dma, + int desc_cnt) +{ + struct solo_p2m_dev *p2m_dev; + unsigned int timeout; + unsigned int config = 0; + int ret = 0; + int p2m_id = 0; + + /* Get next ID. According to Softlogic, 6110 has problems on !=0 P2M */ + if (solo_dev->type != SOLO_DEV_6110 && multi_p2m) { + p2m_id = atomic_inc_return(&solo_dev->p2m_count) % SOLO_NR_P2M; + if (p2m_id < 0) + p2m_id = -p2m_id; + } + + p2m_dev = &solo_dev->p2m_dev[p2m_id]; + + if (mutex_lock_interruptible(&p2m_dev->mutex)) + return -EINTR; + + INIT_COMPLETION(p2m_dev->completion); + p2m_dev->error = 0; + + if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && desc_mode) { + /* For 6010 with more than one desc, we can do a one-shot */ + p2m_dev->desc_count = p2m_dev->desc_idx = 0; + config = solo_reg_read(solo_dev, SOLO_P2M_CONFIG(p2m_id)); + + solo_reg_write(solo_dev, SOLO_P2M_DES_ADR(p2m_id), desc_dma); + solo_reg_write(solo_dev, SOLO_P2M_DESC_ID(p2m_id), desc_cnt); + solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config | + SOLO_P2M_DESC_MODE); + } else { + /* For single descriptors and 6110, we need to run each desc */ + p2m_dev->desc_count = desc_cnt; + p2m_dev->desc_idx = 1; + p2m_dev->descs = desc; + + solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(p2m_id), + desc[1].dma_addr); + solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(p2m_id), + desc[1].ext_addr); + solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(p2m_id), + desc[1].cfg); + solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), + desc[1].ctrl); + } + + timeout = wait_for_completion_timeout(&p2m_dev->completion, + solo_dev->p2m_jiffies); + + if (WARN_ON_ONCE(p2m_dev->error)) + ret = -EIO; + else if (timeout == 0) { + solo_dev->p2m_timeouts++; + ret = -EAGAIN; + } + + solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), 0); + + /* Don't write here for the no_desc_mode case, because config is 0. + * We can't test no_desc_mode again, it might race. */ + if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && config) + solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config); + + mutex_unlock(&p2m_dev->mutex); + + return ret; +} + +void solo_p2m_fill_desc(struct solo_p2m_desc *desc, int wr, + dma_addr_t dma_addr, u32 ext_addr, u32 size, + int repeat, u32 ext_size) +{ + WARN_ON_ONCE(dma_addr & 0x03); + WARN_ON_ONCE(!size); + + desc->cfg = SOLO_P2M_COPY_SIZE(size >> 2); + desc->ctrl = SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) | + (wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON; + + if (repeat) { + desc->cfg |= SOLO_P2M_EXT_INC(ext_size >> 2); + desc->ctrl |= SOLO_P2M_PCI_INC(size >> 2) | + SOLO_P2M_REPEAT(repeat); + } + + desc->dma_addr = dma_addr; + desc->ext_addr = ext_addr; +} + +int solo_p2m_dma_t(struct solo_dev *solo_dev, int wr, + dma_addr_t dma_addr, u32 ext_addr, u32 size, + int repeat, u32 ext_size) +{ + struct solo_p2m_desc desc[2]; + + solo_p2m_fill_desc(&desc[1], wr, dma_addr, ext_addr, size, repeat, + ext_size); + + /* No need for desc_dma since we know it is a single-shot */ + return solo_p2m_dma_desc(solo_dev, desc, 0, 1); +} + +void solo_p2m_isr(struct solo_dev *solo_dev, int id) +{ + struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id]; + struct solo_p2m_desc *desc; + + if (p2m_dev->desc_count <= p2m_dev->desc_idx) { + complete(&p2m_dev->completion); + return; + } + + /* Setup next descriptor */ + p2m_dev->desc_idx++; + desc = &p2m_dev->descs[p2m_dev->desc_idx]; + + solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0); + solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), desc->dma_addr); + solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), desc->ext_addr); + solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id), desc->cfg); + solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), desc->ctrl); +} + +void solo_p2m_error_isr(struct solo_dev *solo_dev) +{ + unsigned int err = solo_reg_read(solo_dev, SOLO_PCI_ERR); + struct solo_p2m_dev *p2m_dev; + int i; + + if (!(err & (SOLO_PCI_ERR_P2M | SOLO_PCI_ERR_P2M_DESC))) + return; + + for (i = 0; i < SOLO_NR_P2M; i++) { + p2m_dev = &solo_dev->p2m_dev[i]; + p2m_dev->error = 1; + solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0); + complete(&p2m_dev->completion); + } +} + +void solo_p2m_exit(struct solo_dev *solo_dev) +{ + int i; + + for (i = 0; i < SOLO_NR_P2M; i++) + solo_irq_off(solo_dev, SOLO_IRQ_P2M(i)); +} + +static int solo_p2m_test(struct solo_dev *solo_dev, int base, int size) +{ + u32 *wr_buf; + u32 *rd_buf; + int i; + int ret = -EIO; + int order = get_order(size); + + wr_buf = (u32 *)__get_free_pages(GFP_KERNEL, order); + if (wr_buf == NULL) + return -1; + + rd_buf = (u32 *)__get_free_pages(GFP_KERNEL, order); + if (rd_buf == NULL) { + free_pages((unsigned long)wr_buf, order); + return -1; + } + + for (i = 0; i < (size >> 3); i++) + *(wr_buf + i) = (i << 16) | (i + 1); + + for (i = (size >> 3); i < (size >> 2); i++) + *(wr_buf + i) = ~((i << 16) | (i + 1)); + + memset(rd_buf, 0x55, size); + + if (solo_p2m_dma(solo_dev, 1, wr_buf, base, size, 0, 0)) + goto test_fail; + + if (solo_p2m_dma(solo_dev, 0, rd_buf, base, size, 0, 0)) + goto test_fail; + + for (i = 0; i < (size >> 2); i++) { + if (*(wr_buf + i) != *(rd_buf + i)) + goto test_fail; + } + + ret = 0; + +test_fail: + free_pages((unsigned long)wr_buf, order); + free_pages((unsigned long)rd_buf, order); + + return ret; +} + +int solo_p2m_init(struct solo_dev *solo_dev) +{ + struct solo_p2m_dev *p2m_dev; + int i; + + for (i = 0; i < SOLO_NR_P2M; i++) { + p2m_dev = &solo_dev->p2m_dev[i]; + + mutex_init(&p2m_dev->mutex); + init_completion(&p2m_dev->completion); + + solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0); + solo_reg_write(solo_dev, SOLO_P2M_CONFIG(i), + SOLO_P2M_CSC_16BIT_565 | + SOLO_P2M_DESC_INTR_OPT | + SOLO_P2M_DMA_INTERVAL(0) | + SOLO_P2M_PCI_MASTER_MODE); + solo_irq_on(solo_dev, SOLO_IRQ_P2M(i)); + } + + /* Find correct SDRAM size */ + for (solo_dev->sdram_size = 0, i = 2; i >= 0; i--) { + solo_reg_write(solo_dev, SOLO_DMA_CTRL, + SOLO_DMA_CTRL_REFRESH_CYCLE(1) | + SOLO_DMA_CTRL_SDRAM_SIZE(i) | + SOLO_DMA_CTRL_SDRAM_CLK_INVERT | + SOLO_DMA_CTRL_READ_CLK_SELECT | + SOLO_DMA_CTRL_LATENCY(1)); + + solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config | + SOLO_SYS_CFG_RESET); + solo_reg_write(solo_dev, SOLO_SYS_CFG, solo_dev->sys_config); + + switch (i) { + case 2: + if (solo_p2m_test(solo_dev, 0x07ff0000, 0x00010000) || + solo_p2m_test(solo_dev, 0x05ff0000, 0x00010000)) + continue; + break; + + case 1: + if (solo_p2m_test(solo_dev, 0x03ff0000, 0x00010000)) + continue; + break; + + default: + if (solo_p2m_test(solo_dev, 0x01ff0000, 0x00010000)) + continue; + } + + solo_dev->sdram_size = (32 << 20) << i; + break; + } + + if (!solo_dev->sdram_size) { + dev_err(&solo_dev->pdev->dev, "Error detecting SDRAM size\n"); + return -EIO; + } + + if (SOLO_SDRAM_END(solo_dev) > solo_dev->sdram_size) { + dev_err(&solo_dev->pdev->dev, + "SDRAM is not large enough (%u < %u)\n", + solo_dev->sdram_size, SOLO_SDRAM_END(solo_dev)); + return -EIO; + } + + return 0; +} diff --git a/drivers/staging/media/solo6x10/solo6x10-tw28.c b/drivers/staging/media/solo6x10/solo6x10-tw28.c new file mode 100644 index 0000000..ad00e2b --- /dev/null +++ b/drivers/staging/media/solo6x10/solo6x10-tw28.c @@ -0,0 +1,854 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +#include +#include + +#include "solo6x10.h" +#include "solo6x10-tw28.h" + +#define DEFAULT_HDELAY_NTSC (32 - 8) +#define DEFAULT_HACTIVE_NTSC (720 + 16) +#define DEFAULT_VDELAY_NTSC (7 - 2) +#define DEFAULT_VACTIVE_NTSC (240 + 4) + +#define DEFAULT_HDELAY_PAL (32 + 4) +#define DEFAULT_HACTIVE_PAL (864-DEFAULT_HDELAY_PAL) +#define DEFAULT_VDELAY_PAL (6) +#define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL) + + +static const u8 tbl_tw2864_ntsc_template[] = { + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ + 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ + 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */ + 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x30 */ + 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00, + 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ + 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00, + 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */ + 0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01, + 0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */ + 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44, + 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ + 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00, + 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */ + 0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81, + 0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ + 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, + 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */ + 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00, +}; + +static const u8 tbl_tw2864_pal_template[] = { + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */ + 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */ + 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */ + 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */ + 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00, + 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ + 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00, + 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */ + 0x00, 0x28, 0x44, 0x44, 0xa0, 0x90, 0x5a, 0x01, + 0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */ + 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44, + 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ + 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00, + 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */ + 0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81, + 0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ + 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, + 0x83, 0xb5, 0x09, 0x00, 0xa0, 0x00, 0x01, 0x20, /* 0xf0 */ + 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00, +}; + +static const u8 tbl_tw2865_ntsc_template[] = { + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ + 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ + 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */ + 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, /* 0x30 */ + 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, /* 0x40 */ + 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43, + 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */ + 0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80, + 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ + 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00, + 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */ + 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13, + 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, /* 0xa0 */ + 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44, + 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */ + 0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8, + 0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ + 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80, + 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */ + 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81, + 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ + 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, + 0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */ + 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0, +}; + +static const u8 tbl_tw2865_pal_template[] = { + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */ + 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */ + 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */ + 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, + 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */ + 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, + 0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, /* 0x40 */ + 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43, + 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */ + 0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80, + 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ + 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00, + 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */ + 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13, + 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, /* 0xa0 */ + 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44, + 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */ + 0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8, + 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ + 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80, + 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */ + 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81, + 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ + 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, + 0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, /* 0xf0 */ + 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0, +}; + +#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id))) + +static u8 tw_readbyte(struct solo_dev *solo_dev, int chip_id, u8 tw6x_off, + u8 tw_off) +{ + if (is_tw286x(solo_dev, chip_id)) + return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, + TW_CHIP_OFFSET_ADDR(chip_id), + tw6x_off); + else + return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, + TW_CHIP_OFFSET_ADDR(chip_id), + tw_off); +} + +static void tw_writebyte(struct solo_dev *solo_dev, int chip_id, + u8 tw6x_off, u8 tw_off, u8 val) +{ + if (is_tw286x(solo_dev, chip_id)) + solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, + TW_CHIP_OFFSET_ADDR(chip_id), + tw6x_off, val); + else + solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, + TW_CHIP_OFFSET_ADDR(chip_id), + tw_off, val); +} + +static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off, + u8 val) +{ + int i; + + for (i = 0; i < 5; i++) { + u8 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, addr, off); + if (rval == val) + return; + + solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, addr, off, val); + msleep_interruptible(1); + } + +/* printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n", */ +/* addr, off, val); */ +} + +static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr) +{ + u8 tbl_tw2865_common[256]; + int i; + + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) + memcpy(tbl_tw2865_common, tbl_tw2865_pal_template, + sizeof(tbl_tw2865_common)); + else + memcpy(tbl_tw2865_common, tbl_tw2865_ntsc_template, + sizeof(tbl_tw2865_common)); + + /* ALINK Mode */ + if (solo_dev->nr_chans == 4) { + tbl_tw2865_common[0xd2] = 0x01; + tbl_tw2865_common[0xcf] = 0x00; + } else if (solo_dev->nr_chans == 8) { + tbl_tw2865_common[0xd2] = 0x02; + if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) + tbl_tw2865_common[0xcf] = 0x80; + } else if (solo_dev->nr_chans == 16) { + tbl_tw2865_common[0xd2] = 0x03; + if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) + tbl_tw2865_common[0xcf] = 0x83; + else if (dev_addr == TW_CHIP_OFFSET_ADDR(2)) + tbl_tw2865_common[0xcf] = 0x83; + else if (dev_addr == TW_CHIP_OFFSET_ADDR(3)) + tbl_tw2865_common[0xcf] = 0x80; + } + + for (i = 0; i < 0xff; i++) { + /* Skip read only registers */ + switch (i) { + case 0xb8 ... 0xc1: + case 0xc4 ... 0xc7: + case 0xfd: + continue; + } + switch (i & ~0x30) { + case 0x00: + case 0x0c ... 0x0d: + continue; + } + + tw_write_and_verify(solo_dev, dev_addr, i, + tbl_tw2865_common[i]); + } + + return 0; +} + +static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr) +{ + u8 tbl_tw2864_common[256]; + int i; + + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) + memcpy(tbl_tw2864_common, tbl_tw2864_pal_template, + sizeof(tbl_tw2864_common)); + else + memcpy(tbl_tw2864_common, tbl_tw2864_ntsc_template, + sizeof(tbl_tw2864_common)); + + if (solo_dev->tw2865 == 0) { + /* IRQ Mode */ + if (solo_dev->nr_chans == 4) { + tbl_tw2864_common[0xd2] = 0x01; + tbl_tw2864_common[0xcf] = 0x00; + } else if (solo_dev->nr_chans == 8) { + tbl_tw2864_common[0xd2] = 0x02; + if (dev_addr == TW_CHIP_OFFSET_ADDR(0)) + tbl_tw2864_common[0xcf] = 0x43; + else if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) + tbl_tw2864_common[0xcf] = 0x40; + } else if (solo_dev->nr_chans == 16) { + tbl_tw2864_common[0xd2] = 0x03; + if (dev_addr == TW_CHIP_OFFSET_ADDR(0)) + tbl_tw2864_common[0xcf] = 0x43; + else if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) + tbl_tw2864_common[0xcf] = 0x43; + else if (dev_addr == TW_CHIP_OFFSET_ADDR(2)) + tbl_tw2864_common[0xcf] = 0x43; + else if (dev_addr == TW_CHIP_OFFSET_ADDR(3)) + tbl_tw2864_common[0xcf] = 0x40; + } + } else { + /* ALINK Mode. Assumes that the first tw28xx is a + * 2865 and these are in cascade. */ + for (i = 0; i <= 4; i++) + tbl_tw2864_common[0x08 | i << 4] = 0x12; + + if (solo_dev->nr_chans == 8) { + tbl_tw2864_common[0xd2] = 0x02; + if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) + tbl_tw2864_common[0xcf] = 0x80; + } else if (solo_dev->nr_chans == 16) { + tbl_tw2864_common[0xd2] = 0x03; + if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) + tbl_tw2864_common[0xcf] = 0x83; + else if (dev_addr == TW_CHIP_OFFSET_ADDR(2)) + tbl_tw2864_common[0xcf] = 0x83; + else if (dev_addr == TW_CHIP_OFFSET_ADDR(3)) + tbl_tw2864_common[0xcf] = 0x80; + } + } + + for (i = 0; i < 0xff; i++) { + /* Skip read only registers */ + switch (i) { + case 0xb8 ... 0xc1: + case 0xfd: + continue; + } + switch (i & ~0x30) { + case 0x00: + case 0x0c: + case 0x0d: + continue; + } + + tw_write_and_verify(solo_dev, dev_addr, i, + tbl_tw2864_common[i]); + } + + return 0; +} + +static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr) +{ + u8 tbl_ntsc_tw2815_common[] = { + 0x00, 0xc8, 0x20, 0xd0, 0x06, 0xf0, 0x08, 0x80, + 0x80, 0x80, 0x80, 0x02, 0x06, 0x00, 0x11, + }; + + u8 tbl_pal_tw2815_common[] = { + 0x00, 0x88, 0x20, 0xd0, 0x05, 0x20, 0x28, 0x80, + 0x80, 0x80, 0x80, 0x82, 0x06, 0x00, 0x11, + }; + + u8 tbl_tw2815_sfr[] = { + 0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, /* 0x00 */ + 0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00, + 0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, /* 0x10 */ + 0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00, + 0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, /* 0x20 */ + 0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88, + 0x88, 0x11, 0x00, 0x88, 0x88, 0x00, /* 0x30 */ + }; + u8 *tbl_tw2815_common; + int i; + int ch; + + tbl_ntsc_tw2815_common[0x06] = 0; + + /* Horizontal Delay Control */ + tbl_ntsc_tw2815_common[0x02] = DEFAULT_HDELAY_NTSC & 0xff; + tbl_ntsc_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_NTSC >> 8); + + /* Horizontal Active Control */ + tbl_ntsc_tw2815_common[0x03] = DEFAULT_HACTIVE_NTSC & 0xff; + tbl_ntsc_tw2815_common[0x06] |= + ((0x03 & (DEFAULT_HACTIVE_NTSC >> 8)) << 2); + + /* Vertical Delay Control */ + tbl_ntsc_tw2815_common[0x04] = DEFAULT_VDELAY_NTSC & 0xff; + tbl_ntsc_tw2815_common[0x06] |= + ((0x01 & (DEFAULT_VDELAY_NTSC >> 8)) << 4); + + /* Vertical Active Control */ + tbl_ntsc_tw2815_common[0x05] = DEFAULT_VACTIVE_NTSC & 0xff; + tbl_ntsc_tw2815_common[0x06] |= + ((0x01 & (DEFAULT_VACTIVE_NTSC >> 8)) << 5); + + tbl_pal_tw2815_common[0x06] = 0; + + /* Horizontal Delay Control */ + tbl_pal_tw2815_common[0x02] = DEFAULT_HDELAY_PAL & 0xff; + tbl_pal_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_PAL >> 8); + + /* Horizontal Active Control */ + tbl_pal_tw2815_common[0x03] = DEFAULT_HACTIVE_PAL & 0xff; + tbl_pal_tw2815_common[0x06] |= + ((0x03 & (DEFAULT_HACTIVE_PAL >> 8)) << 2); + + /* Vertical Delay Control */ + tbl_pal_tw2815_common[0x04] = DEFAULT_VDELAY_PAL & 0xff; + tbl_pal_tw2815_common[0x06] |= + ((0x01 & (DEFAULT_VDELAY_PAL >> 8)) << 4); + + /* Vertical Active Control */ + tbl_pal_tw2815_common[0x05] = DEFAULT_VACTIVE_PAL & 0xff; + tbl_pal_tw2815_common[0x06] |= + ((0x01 & (DEFAULT_VACTIVE_PAL >> 8)) << 5); + + tbl_tw2815_common = + (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) ? + tbl_ntsc_tw2815_common : tbl_pal_tw2815_common; + + /* Dual ITU-R BT.656 format */ + tbl_tw2815_common[0x0d] |= 0x04; + + /* Audio configuration */ + tbl_tw2815_sfr[0x62 - 0x40] &= ~(3 << 6); + + if (solo_dev->nr_chans == 4) { + tbl_tw2815_sfr[0x63 - 0x40] |= 1; + tbl_tw2815_sfr[0x62 - 0x40] |= 3 << 6; + } else if (solo_dev->nr_chans == 8) { + tbl_tw2815_sfr[0x63 - 0x40] |= 2; + if (dev_addr == TW_CHIP_OFFSET_ADDR(0)) + tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6; + else if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) + tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6; + } else if (solo_dev->nr_chans == 16) { + tbl_tw2815_sfr[0x63 - 0x40] |= 3; + if (dev_addr == TW_CHIP_OFFSET_ADDR(0)) + tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6; + else if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) + tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6; + else if (dev_addr == TW_CHIP_OFFSET_ADDR(2)) + tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6; + else if (dev_addr == TW_CHIP_OFFSET_ADDR(3)) + tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6; + } + + /* Output mode of R_ADATM pin (0 mixing, 1 record) */ + /* tbl_tw2815_sfr[0x63 - 0x40] |= 0 << 2; */ + + /* 8KHz, used to be 16KHz, but changed for remote client compat */ + tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 2; + tbl_tw2815_sfr[0x6c - 0x40] |= 0 << 2; + + /* Playback of right channel */ + tbl_tw2815_sfr[0x6c - 0x40] |= 1 << 5; + + /* Reserved value (XXX ??) */ + tbl_tw2815_sfr[0x5c - 0x40] |= 1 << 5; + + /* Analog output gain and mix ratio playback on full */ + tbl_tw2815_sfr[0x70 - 0x40] |= 0xff; + /* Select playback audio and mute all except */ + tbl_tw2815_sfr[0x71 - 0x40] |= 0x10; + tbl_tw2815_sfr[0x6d - 0x40] |= 0x0f; + + /* End of audio configuration */ + + for (ch = 0; ch < 4; ch++) { + tbl_tw2815_common[0x0d] &= ~3; + switch (ch) { + case 0: + tbl_tw2815_common[0x0d] |= 0x21; + break; + case 1: + tbl_tw2815_common[0x0d] |= 0x20; + break; + case 2: + tbl_tw2815_common[0x0d] |= 0x23; + break; + case 3: + tbl_tw2815_common[0x0d] |= 0x22; + break; + } + + for (i = 0; i < 0x0f; i++) { + if (i == 0x00) + continue; /* read-only */ + solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, + dev_addr, (ch * 0x10) + i, + tbl_tw2815_common[i]); + } + } + + for (i = 0x40; i < 0x76; i++) { + /* Skip read-only and nop registers */ + if (i == 0x40 || i == 0x59 || i == 0x5a || + i == 0x5d || i == 0x5e || i == 0x5f) + continue; + + solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, dev_addr, i, + tbl_tw2815_sfr[i - 0x40]); + } + + return 0; +} + +#define FIRST_ACTIVE_LINE 0x0008 +#define LAST_ACTIVE_LINE 0x0102 + +static void saa7128_setup(struct solo_dev *solo_dev) +{ + int i; + unsigned char regs[128] = { + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1C, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, + 0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f, 0x00, 0x00, + 0x1c, 0x33, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00, + 0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18, + 0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f, + 0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06, + 0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e, + 0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77, + 0x41, 0x88, 0x41, 0x12, 0xed, 0x10, 0x10, 0x00, + 0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x08, 0xff, 0x80, 0x00, 0xff, 0xff, + }; + + regs[0x7A] = FIRST_ACTIVE_LINE & 0xff; + regs[0x7B] = LAST_ACTIVE_LINE & 0xff; + regs[0x7C] = ((1 << 7) | + (((LAST_ACTIVE_LINE >> 8) & 1) << 6) | + (((FIRST_ACTIVE_LINE >> 8) & 1) << 4)); + + /* PAL: XXX: We could do a second set of regs to avoid this */ + if (solo_dev->video_type != SOLO_VO_FMT_TYPE_NTSC) { + regs[0x28] = 0xE1; + + regs[0x5A] = 0x0F; + regs[0x61] = 0x02; + regs[0x62] = 0x35; + regs[0x63] = 0xCB; + regs[0x64] = 0x8A; + regs[0x65] = 0x09; + regs[0x66] = 0x2A; + + regs[0x6C] = 0xf1; + regs[0x6E] = 0x20; + + regs[0x7A] = 0x06 + 12; + regs[0x7b] = 0x24 + 12; + regs[0x7c] |= 1 << 6; + } + + /* First 0x25 bytes are read-only? */ + for (i = 0x26; i < 128; i++) { + if (i == 0x60 || i == 0x7D) + continue; + solo_i2c_writebyte(solo_dev, SOLO_I2C_SAA, 0x46, i, regs[i]); + } + + return; +} + +int solo_tw28_init(struct solo_dev *solo_dev) +{ + int i; + u8 value; + + solo_dev->tw28_cnt = 0; + + /* Detect techwell chip type(s) */ + for (i = 0; i < solo_dev->nr_chans / 4; i++) { + value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, + TW_CHIP_OFFSET_ADDR(i), 0xFF); + + switch (value >> 3) { + case 0x18: + solo_dev->tw2865 |= 1 << i; + solo_dev->tw28_cnt++; + break; + case 0x0c: + solo_dev->tw2864 |= 1 << i; + solo_dev->tw28_cnt++; + break; + default: + value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, + TW_CHIP_OFFSET_ADDR(i), + 0x59); + if ((value >> 3) == 0x04) { + solo_dev->tw2815 |= 1 << i; + solo_dev->tw28_cnt++; + } + } + } + + if (solo_dev->tw28_cnt != (solo_dev->nr_chans >> 2)) { + dev_err(&solo_dev->pdev->dev, + "Could not initialize any techwell chips\n"); + return -EINVAL; + } + + saa7128_setup(solo_dev); + + for (i = 0; i < solo_dev->tw28_cnt; i++) { + if ((solo_dev->tw2865 & (1 << i))) + tw2865_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i)); + else if ((solo_dev->tw2864 & (1 << i))) + tw2864_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i)); + else + tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i)); + } + + return 0; +} + +/* + * We accessed the video status signal in the Techwell chip through + * iic/i2c because the video status reported by register REG_VI_STATUS1 + * (address 0x012C) of the SOLO6010 chip doesn't give the correct video + * status signal values. + */ +int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch) +{ + u8 val, chip_num; + + /* Get the right chip and on-chip channel */ + chip_num = ch / 4; + ch %= 4; + + val = tw_readbyte(solo_dev, chip_num, TW286x_AV_STAT_ADDR, + TW_AV_STAT_ADDR) & 0x0f; + + return val & (1 << ch) ? 1 : 0; +} + +#if 0 +/* Status of audio from up to 4 techwell chips are combined into 1 variable. + * See techwell datasheet for details. */ +u16 tw28_get_audio_status(struct solo_dev *solo_dev) +{ + u8 val; + u16 status = 0; + int i; + + for (i = 0; i < solo_dev->tw28_cnt; i++) { + val = (tw_readbyte(solo_dev, i, TW286x_AV_STAT_ADDR, + TW_AV_STAT_ADDR) & 0xf0) >> 4; + status |= val << (i * 4); + } + + return status; +} +#endif + +bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch) +{ + return is_tw286x(solo_dev, ch / 4); +} + +int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, + s32 val) +{ + char sval; + u8 chip_num; + + /* Get the right chip and on-chip channel */ + chip_num = ch / 4; + ch %= 4; + + if (val > 255 || val < 0) + return -ERANGE; + + switch (ctrl) { + case V4L2_CID_SHARPNESS: + /* Only 286x has sharpness */ + if (is_tw286x(solo_dev, chip_num)) { + u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, + TW_CHIP_OFFSET_ADDR(chip_num), + TW286x_SHARPNESS(chip_num)); + v &= 0xf0; + v |= val; + solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, + TW_CHIP_OFFSET_ADDR(chip_num), + TW286x_SHARPNESS(chip_num), v); + } else { + return -EINVAL; + } + break; + + case V4L2_CID_HUE: + if (is_tw286x(solo_dev, chip_num)) + sval = val - 128; + else + sval = (char)val; + tw_writebyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch), + TW_HUE_ADDR(ch), sval); + + break; + + case V4L2_CID_SATURATION: + /* 286x chips have a U and V component for saturation */ + if (is_tw286x(solo_dev, chip_num)) { + solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, + TW_CHIP_OFFSET_ADDR(chip_num), + TW286x_SATURATIONU_ADDR(ch), val); + } + tw_writebyte(solo_dev, chip_num, TW286x_SATURATIONV_ADDR(ch), + TW_SATURATION_ADDR(ch), val); + + break; + + case V4L2_CID_CONTRAST: + tw_writebyte(solo_dev, chip_num, TW286x_CONTRAST_ADDR(ch), + TW_CONTRAST_ADDR(ch), val); + break; + + case V4L2_CID_BRIGHTNESS: + if (is_tw286x(solo_dev, chip_num)) + sval = val - 128; + else + sval = (char)val; + tw_writebyte(solo_dev, chip_num, TW286x_BRIGHTNESS_ADDR(ch), + TW_BRIGHTNESS_ADDR(ch), sval); + + break; + default: + return -EINVAL; + } + + return 0; +} + +int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, + s32 *val) +{ + u8 rval, chip_num; + + /* Get the right chip and on-chip channel */ + chip_num = ch / 4; + ch %= 4; + + switch (ctrl) { + case V4L2_CID_SHARPNESS: + /* Only 286x has sharpness */ + if (is_tw286x(solo_dev, chip_num)) { + rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, + TW_CHIP_OFFSET_ADDR(chip_num), + TW286x_SHARPNESS(chip_num)); + *val = rval & 0x0f; + } else + *val = 0; + break; + case V4L2_CID_HUE: + rval = tw_readbyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch), + TW_HUE_ADDR(ch)); + if (is_tw286x(solo_dev, chip_num)) + *val = (s32)((char)rval) + 128; + else + *val = rval; + break; + case V4L2_CID_SATURATION: + *val = tw_readbyte(solo_dev, chip_num, + TW286x_SATURATIONU_ADDR(ch), + TW_SATURATION_ADDR(ch)); + break; + case V4L2_CID_CONTRAST: + *val = tw_readbyte(solo_dev, chip_num, + TW286x_CONTRAST_ADDR(ch), + TW_CONTRAST_ADDR(ch)); + break; + case V4L2_CID_BRIGHTNESS: + rval = tw_readbyte(solo_dev, chip_num, + TW286x_BRIGHTNESS_ADDR(ch), + TW_BRIGHTNESS_ADDR(ch)); + if (is_tw286x(solo_dev, chip_num)) + *val = (s32)((char)rval) + 128; + else + *val = rval; + break; + default: + return -EINVAL; + } + + return 0; +} + +#if 0 +/* + * For audio output volume, the output channel is only 1. In this case we + * don't need to offset TW_CHIP_OFFSET_ADDR. The TW_CHIP_OFFSET_ADDR used + * is the base address of the techwell chip. + */ +void tw2815_Set_AudioOutVol(struct solo_dev *solo_dev, unsigned int u_val) +{ + unsigned int val; + unsigned int chip_num; + + chip_num = (solo_dev->nr_chans - 1) / 4; + + val = tw_readbyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR, + TW_AUDIO_OUTPUT_VOL_ADDR); + + u_val = (val & 0x0f) | (u_val << 4); + + tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR, + TW_AUDIO_OUTPUT_VOL_ADDR, u_val); +} +#endif + +u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch) +{ + u8 val; + u8 chip_num; + + /* Get the right chip and on-chip channel */ + chip_num = ch / 4; + ch %= 4; + + val = tw_readbyte(solo_dev, chip_num, + TW286x_AUDIO_INPUT_GAIN_ADDR(ch), + TW_AUDIO_INPUT_GAIN_ADDR(ch)); + + return (ch % 2) ? (val >> 4) : (val & 0x0f); +} + +void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val) +{ + u8 old_val; + u8 chip_num; + + /* Get the right chip and on-chip channel */ + chip_num = ch / 4; + ch %= 4; + + old_val = tw_readbyte(solo_dev, chip_num, + TW286x_AUDIO_INPUT_GAIN_ADDR(ch), + TW_AUDIO_INPUT_GAIN_ADDR(ch)); + + val = (old_val & ((ch % 2) ? 0x0f : 0xf0)) | + ((ch % 2) ? (val << 4) : val); + + tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_INPUT_GAIN_ADDR(ch), + TW_AUDIO_INPUT_GAIN_ADDR(ch), val); +} diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c new file mode 100644 index 0000000..39a8fb2 --- /dev/null +++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c @@ -0,0 +1,1363 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "solo6x10.h" +#include "solo6x10-tw28.h" +#include "solo6x10-jpeg.h" + +#define MIN_VID_BUFFERS 2 +#define FRAME_BUF_SIZE (196 * 1024) +#define MP4_QS 16 +#define DMA_ALIGN 4096 + +/* 6010 M4V */ +static unsigned char vop_6010_ntsc_d1[] = { + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, + 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40, + 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, + 0x1f, 0x4c, 0x58, 0x10, 0xf0, 0x71, 0x18, 0x3f, +}; + +static unsigned char vop_6010_ntsc_cif[] = { + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, + 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40, + 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, + 0x1f, 0x4c, 0x2c, 0x10, 0x78, 0x51, 0x18, 0x3f, +}; + +static unsigned char vop_6010_pal_d1[] = { + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, + 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40, + 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, + 0x1f, 0x4c, 0x58, 0x11, 0x20, 0x71, 0x18, 0x3f, +}; + +static unsigned char vop_6010_pal_cif[] = { + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, + 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40, + 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, + 0x1f, 0x4c, 0x2c, 0x10, 0x90, 0x51, 0x18, 0x3f, +}; + +/* 6110 h.264 */ +static unsigned char vop_6110_ntsc_d1[] = { + 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, + 0x9a, 0x74, 0x05, 0x81, 0xec, 0x80, 0x00, 0x00, + 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, +}; + +static unsigned char vop_6110_ntsc_cif[] = { + 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, + 0x9a, 0x74, 0x0b, 0x0f, 0xc8, 0x00, 0x00, 0x00, + 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00, +}; + +static unsigned char vop_6110_pal_d1[] = { + 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, + 0x9a, 0x74, 0x05, 0x80, 0x93, 0x20, 0x00, 0x00, + 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, +}; + +static unsigned char vop_6110_pal_cif[] = { + 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, + 0x9a, 0x74, 0x0b, 0x04, 0xb2, 0x00, 0x00, 0x00, + 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00, +}; + +struct vop_header { + /* VE_STATUS0 */ + u32 mpeg_size:20, sad_motion_flag:1, video_motion_flag:1, vop_type:2, + channel:5, source_fl:1, interlace:1, progressive:1; + + /* VE_STATUS1 */ + u32 vsize:8, hsize:8, last_queue:4, nop0:8, scale:4; + + /* VE_STATUS2 */ + u32 mpeg_off; + + /* VE_STATUS3 */ + u32 jpeg_off; + + /* VE_STATUS4 */ + u32 jpeg_size:20, interval:10, nop1:2; + + /* VE_STATUS5/6 */ + u32 sec, usec; + + /* VE_STATUS7/8/9 */ + u32 nop2[3]; + + /* VE_STATUS10 */ + u32 mpeg_size_alt:20, nop3:12; + + u32 end_nops[5]; +} __packed; + +struct solo_enc_buf { + enum solo_enc_types type; + struct vop_header *vh; + int motion; +}; + +static int solo_is_motion_on(struct solo_enc_dev *solo_enc) +{ + struct solo_dev *solo_dev = solo_enc->solo_dev; + + return (solo_dev->motion_mask >> solo_enc->ch) & 1; +} + +static int solo_motion_detected(struct solo_enc_dev *solo_enc) +{ + struct solo_dev *solo_dev = solo_enc->solo_dev; + unsigned long flags; + u32 ch_mask = 1 << solo_enc->ch; + int ret = 0; + + spin_lock_irqsave(&solo_enc->motion_lock, flags); + if (solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS) & ch_mask) { + solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, ch_mask); + ret = 1; + } + spin_unlock_irqrestore(&solo_enc->motion_lock, flags); + + return ret; +} + +static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on) +{ + struct solo_dev *solo_dev = solo_enc->solo_dev; + u32 mask = 1 << solo_enc->ch; + unsigned long flags; + + spin_lock_irqsave(&solo_enc->motion_lock, flags); + + if (on) + solo_dev->motion_mask |= mask; + else + solo_dev->motion_mask &= ~mask; + + solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, mask); + + solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, + SOLO_VI_MOTION_EN(solo_dev->motion_mask) | + (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16)); + + spin_unlock_irqrestore(&solo_enc->motion_lock, flags); +} + +void solo_update_mode(struct solo_enc_dev *solo_enc) +{ + struct solo_dev *solo_dev = solo_enc->solo_dev; + int vop_len; + unsigned char *vop; + + solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0; + solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1); + + if (solo_enc->mode == SOLO_ENC_MODE_CIF) { + solo_enc->width = solo_dev->video_hsize >> 1; + solo_enc->height = solo_dev->video_vsize; + if (solo_dev->type == SOLO_DEV_6110) { + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { + vop = vop_6110_ntsc_cif; + vop_len = sizeof(vop_6110_ntsc_cif); + } else { + vop = vop_6110_pal_cif; + vop_len = sizeof(vop_6110_pal_cif); + } + } else { + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { + vop = vop_6010_ntsc_cif; + vop_len = sizeof(vop_6010_ntsc_cif); + } else { + vop = vop_6010_pal_cif; + vop_len = sizeof(vop_6010_pal_cif); + } + } + } else { + solo_enc->width = solo_dev->video_hsize; + solo_enc->height = solo_dev->video_vsize << 1; + solo_enc->bw_weight <<= 2; + if (solo_dev->type == SOLO_DEV_6110) { + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { + vop = vop_6110_ntsc_d1; + vop_len = sizeof(vop_6110_ntsc_d1); + } else { + vop = vop_6110_pal_d1; + vop_len = sizeof(vop_6110_pal_d1); + } + } else { + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { + vop = vop_6010_ntsc_d1; + vop_len = sizeof(vop_6010_ntsc_d1); + } else { + vop = vop_6010_pal_d1; + vop_len = sizeof(vop_6010_pal_d1); + } + } + } + + memcpy(solo_enc->vop, vop, vop_len); + + /* Some fixups for 6010/M4V */ + if (solo_dev->type == SOLO_DEV_6010) { + u16 fps = solo_dev->fps * 1000; + u16 interval = solo_enc->interval * 1000; + + vop = solo_enc->vop; + + /* Frame rate and interval */ + vop[22] = fps >> 4; + vop[23] = ((fps << 4) & 0xf0) | 0x0c + | ((interval >> 13) & 0x3); + vop[24] = (interval >> 5) & 0xff; + vop[25] = ((interval << 3) & 0xf8) | 0x04; + } + + solo_enc->vop_len = vop_len; + + /* Now handle the jpeg header */ + vop = solo_enc->jpeg_header; + vop[SOF0_START + 5] = 0xff & (solo_enc->height >> 8); + vop[SOF0_START + 6] = 0xff & solo_enc->height; + vop[SOF0_START + 7] = 0xff & (solo_enc->width >> 8); + vop[SOF0_START + 8] = 0xff & solo_enc->width; + + memcpy(vop + DQT_START, + jpeg_dqt[solo_g_jpeg_qp(solo_dev, solo_enc->ch)], DQT_LEN); +} + +static int solo_enc_on(struct solo_enc_dev *solo_enc) +{ + u8 ch = solo_enc->ch; + struct solo_dev *solo_dev = solo_enc->solo_dev; + u8 interval; + + solo_update_mode(solo_enc); + + /* Make sure to do a bandwidth check */ + if (solo_enc->bw_weight > solo_dev->enc_bw_remain) + return -EBUSY; + solo_enc->sequence = 0; + solo_dev->enc_bw_remain -= solo_enc->bw_weight; + + if (solo_enc->type == SOLO_ENC_TYPE_EXT) + solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1); + + /* Disable all encoding for this channel */ + solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0); + + /* Common for both std and ext encoding */ + solo_reg_write(solo_dev, SOLO_VE_CH_INTL(ch), + solo_enc->interlaced ? 1 : 0); + + if (solo_enc->interlaced) + interval = solo_enc->interval - 1; + else + interval = solo_enc->interval; + + /* Standard encoding only */ + solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), solo_enc->gop); + solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp); + solo_reg_write(solo_dev, SOLO_CAP_CH_INTV(ch), interval); + + /* Extended encoding only */ + solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(ch), solo_enc->gop); + solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp); + solo_reg_write(solo_dev, SOLO_CAP_CH_INTV_E(ch), interval); + + /* Enables the standard encoder */ + solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode); + + return 0; +} + +static void solo_enc_off(struct solo_enc_dev *solo_enc) +{ + struct solo_dev *solo_dev = solo_enc->solo_dev; + + solo_dev->enc_bw_remain += solo_enc->bw_weight; + + solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0); + solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0); +} + +static int enc_get_mpeg_dma(struct solo_dev *solo_dev, dma_addr_t dma, + unsigned int off, unsigned int size) +{ + int ret; + + if (off > SOLO_MP4E_EXT_SIZE(solo_dev)) + return -EINVAL; + + /* Single shot */ + if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) { + return solo_p2m_dma_t(solo_dev, 0, dma, + SOLO_MP4E_EXT_ADDR(solo_dev) + off, size, + 0, 0); + } + + /* Buffer wrap */ + ret = solo_p2m_dma_t(solo_dev, 0, dma, + SOLO_MP4E_EXT_ADDR(solo_dev) + off, + SOLO_MP4E_EXT_SIZE(solo_dev) - off, 0, 0); + + if (!ret) { + ret = solo_p2m_dma_t(solo_dev, 0, + dma + SOLO_MP4E_EXT_SIZE(solo_dev) - off, + SOLO_MP4E_EXT_ADDR(solo_dev), + size + off - SOLO_MP4E_EXT_SIZE(solo_dev), 0, 0); + } + + return ret; +} + +/* Build a descriptor queue out of an SG list and send it to the P2M for + * processing. */ +static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip, + struct vb2_dma_sg_desc *vbuf, int off, int size, + unsigned int base, unsigned int base_size) +{ + struct solo_dev *solo_dev = solo_enc->solo_dev; + struct scatterlist *sg; + int i; + int ret; + + if (WARN_ON_ONCE(size > FRAME_BUF_SIZE)) + return -EINVAL; + + solo_enc->desc_count = 1; + + for_each_sg(vbuf->sglist, sg, vbuf->num_pages, i) { + struct solo_p2m_desc *desc; + dma_addr_t dma; + int len; + int left = base_size - off; + + desc = &solo_enc->desc_items[solo_enc->desc_count++]; + dma = sg_dma_address(sg); + len = sg_dma_len(sg); + + /* We assume this is smaller than the scatter size */ + BUG_ON(skip >= len); + if (skip) { + len -= skip; + dma += skip; + size -= skip; + skip = 0; + } + + len = min(len, size); + + if (len <= left) { + /* Single descriptor */ + solo_p2m_fill_desc(desc, 0, dma, base + off, + len, 0, 0); + } else { + /* Buffer wrap */ + /* XXX: Do these as separate DMA requests, to avoid + timeout errors triggered by awkwardly sized + descriptors. See + + */ + ret = solo_p2m_dma_t(solo_dev, 0, dma, base + off, + left, 0, 0); + if (ret) + return ret; + + ret = solo_p2m_dma_t(solo_dev, 0, dma + left, base, + len - left, 0, 0); + if (ret) + return ret; + + solo_enc->desc_count--; + } + + size -= len; + if (size <= 0) + break; + + off += len; + if (off >= base_size) + off -= base_size; + + /* Because we may use two descriptors per loop */ + if (solo_enc->desc_count >= (solo_enc->desc_nelts - 1)) { + ret = solo_p2m_dma_desc(solo_dev, solo_enc->desc_items, + solo_enc->desc_dma, + solo_enc->desc_count - 1); + if (ret) + return ret; + solo_enc->desc_count = 1; + } + } + + if (solo_enc->desc_count <= 1) + return 0; + + return solo_p2m_dma_desc(solo_dev, solo_enc->desc_items, solo_enc->desc_dma, + solo_enc->desc_count - 1); +} + +static int solo_fill_jpeg(struct solo_enc_dev *solo_enc, + struct vb2_buffer *vb, struct vop_header *vh) +{ + struct solo_dev *solo_dev = solo_enc->solo_dev; + struct vb2_dma_sg_desc *vbuf = vb2_dma_sg_plane_desc(vb, 0); + int frame_size; + int ret; + + vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; + + if (vb2_plane_size(vb, 0) < vh->jpeg_size + solo_enc->jpeg_len) + return -EIO; + + sg_copy_from_buffer(vbuf->sglist, vbuf->num_pages, + solo_enc->jpeg_header, + solo_enc->jpeg_len); + + frame_size = (vh->jpeg_size + solo_enc->jpeg_len + (DMA_ALIGN - 1)) + & ~(DMA_ALIGN - 1); + vb2_set_plane_payload(vb, 0, vh->jpeg_size + solo_enc->jpeg_len); + + dma_map_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages, + DMA_FROM_DEVICE); + ret = solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf, vh->jpeg_off, + frame_size, SOLO_JPEG_EXT_ADDR(solo_dev), + SOLO_JPEG_EXT_SIZE(solo_dev)); + dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages, + DMA_FROM_DEVICE); + return ret; +} + +static int solo_fill_mpeg(struct solo_enc_dev *solo_enc, + struct vb2_buffer *vb, struct vop_header *vh) +{ + struct solo_dev *solo_dev = solo_enc->solo_dev; + struct vb2_dma_sg_desc *vbuf = vb2_dma_sg_plane_desc(vb, 0); + int frame_off, frame_size; + int skip = 0; + int ret; + + if (vb2_plane_size(vb, 0) < vh->mpeg_size) + return -EIO; + + /* If this is a key frame, add extra header */ + if (!vh->vop_type) { + sg_copy_from_buffer(vbuf->sglist, vbuf->num_pages, + solo_enc->vop, + solo_enc->vop_len); + + skip = solo_enc->vop_len; + + vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; + vb2_set_plane_payload(vb, 0, vh->mpeg_size + solo_enc->vop_len); + } else { + vb->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; + vb2_set_plane_payload(vb, 0, vh->mpeg_size); + } + + /* Now get the actual mpeg payload */ + frame_off = (vh->mpeg_off + sizeof(*vh)) + % SOLO_MP4E_EXT_SIZE(solo_dev); + frame_size = (vh->mpeg_size + skip + (DMA_ALIGN - 1)) + & ~(DMA_ALIGN - 1); + + dma_map_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages, + DMA_FROM_DEVICE); + ret = solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size, + SOLO_MP4E_EXT_ADDR(solo_dev), + SOLO_MP4E_EXT_SIZE(solo_dev)); + dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages, + DMA_FROM_DEVICE); + return ret; +} + +static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, + struct vb2_buffer *vb, struct solo_enc_buf *enc_buf) +{ + struct vop_header *vh = enc_buf->vh; + int ret; + + /* Check for motion flags */ + vb->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_MOTION_ON | + V4L2_BUF_FLAG_MOTION_DETECTED); + if (solo_is_motion_on(solo_enc)) { + vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_ON; + if (enc_buf->motion) + vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_DETECTED; + } + + if (solo_enc->fmt == V4L2_PIX_FMT_MPEG4) + ret = solo_fill_mpeg(solo_enc, vb, vh); + else + ret = solo_fill_jpeg(solo_enc, vb, vh); + + if (!ret) { + vb->v4l2_buf.sequence = solo_enc->sequence++; + vb->v4l2_buf.timestamp.tv_sec = vh->sec; + vb->v4l2_buf.timestamp.tv_usec = vh->usec; + } + + vb2_buffer_done(vb, ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + + return ret; +} + +static void solo_enc_handle_one(struct solo_enc_dev *solo_enc, + struct solo_enc_buf *enc_buf) +{ + struct solo_vb2_buf *vb; + unsigned long flags; + + mutex_lock(&solo_enc->lock); + if (solo_enc->type != enc_buf->type) + goto unlock; + + spin_lock_irqsave(&solo_enc->av_lock, flags); + if (list_empty(&solo_enc->vidq_active)) { + spin_unlock_irqrestore(&solo_enc->av_lock, flags); + goto unlock; + } + vb = list_first_entry(&solo_enc->vidq_active, struct solo_vb2_buf, list); + list_del(&vb->list); + spin_unlock_irqrestore(&solo_enc->av_lock, flags); + + solo_enc_fillbuf(solo_enc, &vb->vb, enc_buf); +unlock: + mutex_unlock(&solo_enc->lock); +} + +void solo_enc_v4l2_isr(struct solo_dev *solo_dev) +{ + wake_up_interruptible_all(&solo_dev->ring_thread_wait); +} + +static void solo_handle_ring(struct solo_dev *solo_dev) +{ + for (;;) { + struct solo_enc_dev *solo_enc; + struct solo_enc_buf enc_buf; + u32 mpeg_current, off; + u8 ch; + u8 cur_q; + + /* Check if the hardware has any new ones in the queue */ + cur_q = solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xff; + if (cur_q == solo_dev->enc_idx) + break; + + mpeg_current = solo_reg_read(solo_dev, + SOLO_VE_MPEG4_QUE(solo_dev->enc_idx)); + solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS; + + ch = (mpeg_current >> 24) & 0x1f; + off = mpeg_current & 0x00ffffff; + + if (ch >= SOLO_MAX_CHANNELS) { + ch -= SOLO_MAX_CHANNELS; + enc_buf.type = SOLO_ENC_TYPE_EXT; + } else + enc_buf.type = SOLO_ENC_TYPE_STD; + + solo_enc = solo_dev->v4l2_enc[ch]; + if (solo_enc == NULL) { + dev_err(&solo_dev->pdev->dev, + "Got spurious packet for channel %d\n", ch); + continue; + } + + /* FAIL... */ + if (enc_get_mpeg_dma(solo_dev, solo_dev->vh_dma, off, + sizeof(struct vop_header))) + continue; + + enc_buf.vh = (struct vop_header *)solo_dev->vh_buf; + enc_buf.vh->mpeg_off -= SOLO_MP4E_EXT_ADDR(solo_dev); + enc_buf.vh->jpeg_off -= SOLO_JPEG_EXT_ADDR(solo_dev); + + /* Sanity check */ + if (enc_buf.vh->mpeg_off != off) + continue; + + if (solo_motion_detected(solo_enc)) + enc_buf.motion = 1; + else + enc_buf.motion = 0; + + solo_enc_handle_one(solo_enc, &enc_buf); + } +} + +static int solo_ring_thread(void *data) +{ + struct solo_dev *solo_dev = data; + DECLARE_WAITQUEUE(wait, current); + + set_freezable(); + add_wait_queue(&solo_dev->ring_thread_wait, &wait); + + for (;;) { + long timeout = schedule_timeout_interruptible(HZ); + if (timeout == -ERESTARTSYS || kthread_should_stop()) + break; + solo_irq_off(solo_dev, SOLO_IRQ_ENCODER); + solo_handle_ring(solo_dev); + solo_irq_on(solo_dev, SOLO_IRQ_ENCODER); + try_to_freeze(); + } + + remove_wait_queue(&solo_dev->ring_thread_wait, &wait); + + return 0; +} + +static int solo_enc_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + sizes[0] = FRAME_BUF_SIZE; + *num_planes = 1; + + if (*num_buffers < MIN_VID_BUFFERS) + *num_buffers = MIN_VID_BUFFERS; + + return 0; +} + +static void solo_enc_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vq); + struct solo_vb2_buf *solo_vb = + container_of(vb, struct solo_vb2_buf, vb); + + spin_lock(&solo_enc->av_lock); + list_add_tail(&solo_vb->list, &solo_enc->vidq_active); + spin_unlock(&solo_enc->av_lock); +} + +static int solo_ring_start(struct solo_dev *solo_dev) +{ + solo_dev->ring_thread = kthread_run(solo_ring_thread, solo_dev, + SOLO6X10_NAME "_ring"); + if (IS_ERR(solo_dev->ring_thread)) { + int err = PTR_ERR(solo_dev->ring_thread); + solo_dev->ring_thread = NULL; + return err; + } + + solo_irq_on(solo_dev, SOLO_IRQ_ENCODER); + + return 0; +} + +static void solo_ring_stop(struct solo_dev *solo_dev) +{ + if (solo_dev->ring_thread) { + kthread_stop(solo_dev->ring_thread); + solo_dev->ring_thread = NULL; + } + + solo_irq_off(solo_dev, SOLO_IRQ_ENCODER); +} + +static int solo_enc_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q); + int ret; + + ret = solo_enc_on(solo_enc); + if (ret) + return ret; + return solo_ring_start(solo_enc->solo_dev); +} + +static int solo_enc_stop_streaming(struct vb2_queue *q) +{ + struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q); + + solo_enc_off(solo_enc); + INIT_LIST_HEAD(&solo_enc->vidq_active); + solo_ring_stop(solo_enc->solo_dev); + return 0; +} + +static struct vb2_ops solo_enc_video_qops = { + .queue_setup = solo_enc_queue_setup, + .buf_queue = solo_enc_buf_queue, + .start_streaming = solo_enc_start_streaming, + .stop_streaming = solo_enc_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int solo_enc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; + + strcpy(cap->driver, SOLO6X10_NAME); + snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d", + solo_enc->ch); + snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", + pci_name(solo_dev->pdev)); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int solo_enc_enum_input(struct file *file, void *priv, + struct v4l2_input *input) +{ + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; + + if (input->index) + return -EINVAL; + + snprintf(input->name, sizeof(input->name), "Encoder %d", + solo_enc->ch + 1); + input->type = V4L2_INPUT_TYPE_CAMERA; + input->std = solo_enc->vfd->tvnorms; + + if (!tw28_get_video_status(solo_dev, solo_enc->ch)) + input->status = V4L2_IN_ST_NO_SIGNAL; + + return 0; +} + +static int solo_enc_set_input(struct file *file, void *priv, + unsigned int index) +{ + if (index) + return -EINVAL; + + return 0; +} + +static int solo_enc_get_input(struct file *file, void *priv, + unsigned int *index) +{ + *index = 0; + + return 0; +} + +static int solo_enc_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + switch (f->index) { + case 0: + f->pixelformat = V4L2_PIX_FMT_MPEG4; + strcpy(f->description, "MPEG-4 AVC"); + break; + case 1: + f->pixelformat = V4L2_PIX_FMT_MJPEG; + strcpy(f->description, "MJPEG"); + break; + default: + return -EINVAL; + } + + f->flags = V4L2_FMT_FLAG_COMPRESSED; + + return 0; +} + +static int solo_enc_try_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; + struct v4l2_pix_format *pix = &f->fmt.pix; + + if (pix->pixelformat != V4L2_PIX_FMT_MPEG4 && + pix->pixelformat != V4L2_PIX_FMT_MJPEG) + return -EINVAL; + + if (pix->width < solo_dev->video_hsize || + pix->height < solo_dev->video_vsize << 1) { + /* Default to CIF 1/2 size */ + pix->width = solo_dev->video_hsize >> 1; + pix->height = solo_dev->video_vsize; + } else { + /* Full frame */ + pix->width = solo_dev->video_hsize; + pix->height = solo_dev->video_vsize << 1; + } + + switch (pix->field) { + case V4L2_FIELD_NONE: + case V4L2_FIELD_INTERLACED: + break; + case V4L2_FIELD_ANY: + default: + pix->field = V4L2_FIELD_INTERLACED; + break; + } + + /* Just set these */ + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; + pix->sizeimage = FRAME_BUF_SIZE; + pix->bytesperline = 0; + pix->priv = 0; + + return 0; +} + +static int solo_enc_set_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; + struct v4l2_pix_format *pix = &f->fmt.pix; + int ret; + + if (vb2_is_busy(&solo_enc->vidq)) + return -EBUSY; + + ret = solo_enc_try_fmt_cap(file, priv, f); + if (ret) + return ret; + + if (pix->width == solo_dev->video_hsize) + solo_enc->mode = SOLO_ENC_MODE_D1; + else + solo_enc->mode = SOLO_ENC_MODE_CIF; + + /* This does not change the encoder at all */ + solo_enc->fmt = pix->pixelformat; + + /* + * More information is needed about these 'extended' types. As far + * as I can tell these are basically additional video streams with + * different MPEG encoding attributes that can run in parallel with + * the main stream. If so, then this should be implemented as a + * second video node. Abusing priv like this is certainly not the + * right approach. + if (pix->priv) + solo_enc->type = SOLO_ENC_TYPE_EXT; + */ + return 0; +} + +static int solo_enc_get_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + + pix->width = solo_enc->width; + pix->height = solo_enc->height; + pix->pixelformat = solo_enc->fmt; + pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED : + V4L2_FIELD_NONE; + pix->sizeimage = FRAME_BUF_SIZE; + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; + pix->priv = 0; + + return 0; +} + +static int solo_enc_g_std(struct file *file, void *priv, v4l2_std_id *i) +{ + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; + + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) + *i = V4L2_STD_NTSC_M; + else + *i = V4L2_STD_PAL; + return 0; +} + +static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id std) +{ + struct solo_enc_dev *solo_enc = video_drvdata(file); + + return solo_set_video_type(solo_enc->solo_dev, std & V4L2_STD_PAL); +} + +static int solo_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; + + if (fsize->pixel_format != V4L2_PIX_FMT_MPEG4 && + fsize->pixel_format != V4L2_PIX_FMT_MJPEG) + return -EINVAL; + + switch (fsize->index) { + case 0: + fsize->discrete.width = solo_dev->video_hsize >> 1; + fsize->discrete.height = solo_dev->video_vsize; + break; + case 1: + fsize->discrete.width = solo_dev->video_hsize; + fsize->discrete.height = solo_dev->video_vsize << 1; + break; + default: + return -EINVAL; + } + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + + return 0; +} + +static int solo_enum_frameintervals(struct file *file, void *priv, + struct v4l2_frmivalenum *fintv) +{ + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; + + if (fintv->pixel_format != V4L2_PIX_FMT_MPEG4 && + fintv->pixel_format != V4L2_PIX_FMT_MJPEG) + return -EINVAL; + if (fintv->index) + return -EINVAL; + if ((fintv->width != solo_dev->video_hsize >> 1 || + fintv->height != solo_dev->video_vsize) && + (fintv->width != solo_dev->video_hsize || + fintv->height != solo_dev->video_vsize << 1)) + return -EINVAL; + + fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE; + + fintv->stepwise.min.numerator = 1; + fintv->stepwise.min.denominator = solo_dev->fps; + + fintv->stepwise.max.numerator = 15; + fintv->stepwise.max.denominator = solo_dev->fps; + + fintv->stepwise.step.numerator = 1; + fintv->stepwise.step.denominator = solo_dev->fps; + + return 0; +} + +static int solo_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *sp) +{ + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; + struct v4l2_captureparm *cp = &sp->parm.capture; + + cp->capability = V4L2_CAP_TIMEPERFRAME; + cp->timeperframe.numerator = solo_enc->interval; + cp->timeperframe.denominator = solo_dev->fps; + cp->capturemode = 0; + /* XXX: Shouldn't we be able to get/set this from videobuf? */ + cp->readbuffers = 2; + + return 0; +} + +static int solo_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *sp) +{ + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; + struct v4l2_captureparm *cp = &sp->parm.capture; + + if (vb2_is_streaming(&solo_enc->vidq)) + return -EBUSY; + + if ((cp->timeperframe.numerator == 0) || + (cp->timeperframe.denominator == 0)) { + /* reset framerate */ + cp->timeperframe.numerator = 1; + cp->timeperframe.denominator = solo_dev->fps; + } + + if (cp->timeperframe.denominator != solo_dev->fps) + cp->timeperframe.denominator = solo_dev->fps; + + if (cp->timeperframe.numerator > 15) + cp->timeperframe.numerator = 15; + + solo_enc->interval = cp->timeperframe.numerator; + + cp->capability = V4L2_CAP_TIMEPERFRAME; + cp->readbuffers = 2; + + solo_update_mode(solo_enc); + return 0; +} + +static long solo_enc_default(struct file *file, void *fh, + bool valid_prio, int cmd, void *arg) +{ + struct solo_enc_dev *solo_enc = video_drvdata(file); + struct solo_dev *solo_dev = solo_enc->solo_dev; + struct solo_motion_thresholds *thresholds = arg; + + switch (cmd) { + case SOLO_IOC_G_MOTION_THRESHOLDS: + *thresholds = solo_enc->motion_thresholds; + return 0; + + case SOLO_IOC_S_MOTION_THRESHOLDS: + if (!valid_prio) + return -EBUSY; + solo_enc->motion_thresholds = *thresholds; + if (solo_enc->motion_enabled && !solo_enc->motion_global) + return solo_set_motion_block(solo_dev, solo_enc->ch, + &solo_enc->motion_thresholds); + return 0; + default: + return -ENOTTY; + } +} + +static int solo_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct solo_enc_dev *solo_enc = + container_of(ctrl->handler, struct solo_enc_dev, hdl); + struct solo_dev *solo_dev = solo_enc->solo_dev; + int err; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_CONTRAST: + case V4L2_CID_SATURATION: + case V4L2_CID_HUE: + case V4L2_CID_SHARPNESS: + return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch, + ctrl->val); + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + solo_enc->gop = ctrl->val; + return 0; + case V4L2_CID_MOTION_THRESHOLD: + solo_enc->motion_thresh = ctrl->val; + if (!solo_enc->motion_global || !solo_enc->motion_enabled) + return 0; + return solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->val); + case V4L2_CID_MOTION_MODE: + solo_enc->motion_global = ctrl->val == 1; + solo_enc->motion_enabled = ctrl->val > 0; + if (ctrl->val) { + if (solo_enc->motion_global) + solo_set_motion_threshold(solo_dev, solo_enc->ch, + solo_enc->motion_thresh); + else + solo_set_motion_block(solo_dev, solo_enc->ch, + &solo_enc->motion_thresholds); + } + solo_motion_toggle(solo_enc, ctrl->val); + return 0; + case V4L2_CID_OSD_TEXT: + strcpy(solo_enc->osd_text, ctrl->string); + err = solo_osd_print(solo_enc); + return err; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_file_operations solo_enc_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = { + .vidioc_querycap = solo_enc_querycap, + .vidioc_s_std = solo_enc_s_std, + .vidioc_g_std = solo_enc_g_std, + /* Input callbacks */ + .vidioc_enum_input = solo_enc_enum_input, + .vidioc_s_input = solo_enc_set_input, + .vidioc_g_input = solo_enc_get_input, + /* Video capture format callbacks */ + .vidioc_enum_fmt_vid_cap = solo_enc_enum_fmt_cap, + .vidioc_try_fmt_vid_cap = solo_enc_try_fmt_cap, + .vidioc_s_fmt_vid_cap = solo_enc_set_fmt_cap, + .vidioc_g_fmt_vid_cap = solo_enc_get_fmt_cap, + /* Streaming I/O */ + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + /* Frame size and interval */ + .vidioc_enum_framesizes = solo_enum_framesizes, + .vidioc_enum_frameintervals = solo_enum_frameintervals, + /* Video capture parameters */ + .vidioc_s_parm = solo_s_parm, + .vidioc_g_parm = solo_g_parm, + /* Logging and events */ + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_default = solo_enc_default, +}; + +static const struct video_device solo_enc_template = { + .name = SOLO6X10_NAME, + .fops = &solo_enc_fops, + .ioctl_ops = &solo_enc_ioctl_ops, + .minor = -1, + .release = video_device_release, + .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, +}; + +static const struct v4l2_ctrl_ops solo_ctrl_ops = { + .s_ctrl = solo_s_ctrl, +}; + +static const struct v4l2_ctrl_config solo_motion_threshold_ctrl = { + .ops = &solo_ctrl_ops, + .id = V4L2_CID_MOTION_THRESHOLD, + .name = "Motion Detection Threshold", + .type = V4L2_CTRL_TYPE_INTEGER, + .max = 0xffff, + .def = SOLO_DEF_MOT_THRESH, + .step = 1, + .flags = V4L2_CTRL_FLAG_SLIDER, +}; + +static const char * const solo_motion_mode_menu[] = { + "Disabled", + "Global Threshold", + "Regional Threshold", + NULL +}; + +static const struct v4l2_ctrl_config solo_motion_enable_ctrl = { + .ops = &solo_ctrl_ops, + .id = V4L2_CID_MOTION_MODE, + .name = "Motion Detection Mode", + .type = V4L2_CTRL_TYPE_MENU, + .qmenu = solo_motion_mode_menu, + .max = 2, +}; + +static const struct v4l2_ctrl_config solo_osd_text_ctrl = { + .ops = &solo_ctrl_ops, + .id = V4L2_CID_OSD_TEXT, + .name = "OSD Text", + .type = V4L2_CTRL_TYPE_STRING, + .max = OSD_TEXT_MAX, + .step = 1, +}; + +static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, + u8 ch, unsigned nr) +{ + struct solo_enc_dev *solo_enc; + struct v4l2_ctrl_handler *hdl; + int ret; + int x, y; + + solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL); + if (!solo_enc) + return ERR_PTR(-ENOMEM); + + hdl = &solo_enc->hdl; + v4l2_ctrl_handler_init(hdl, 10); + v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 128); + v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 128); + v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, + V4L2_CID_HUE, 0, 255, 1, 128); + if (tw28_has_sharpness(solo_dev, ch)) + v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 15, 1, 0); + v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps); + v4l2_ctrl_new_custom(hdl, &solo_motion_threshold_ctrl, NULL); + v4l2_ctrl_new_custom(hdl, &solo_motion_enable_ctrl, NULL); + v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL); + if (hdl->error) { + ret = hdl->error; + goto hdl_free; + } + + solo_enc->solo_dev = solo_dev; + solo_enc->ch = ch; + mutex_init(&solo_enc->lock); + spin_lock_init(&solo_enc->av_lock); + INIT_LIST_HEAD(&solo_enc->vidq_active); + solo_enc->fmt = V4L2_PIX_FMT_MPEG4; + solo_enc->type = SOLO_ENC_TYPE_STD; + + solo_enc->qp = SOLO_DEFAULT_QP; + solo_enc->gop = solo_dev->fps; + solo_enc->interval = 1; + solo_enc->mode = SOLO_ENC_MODE_CIF; + solo_enc->motion_global = true; + solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH; + for (y = 0; y < SOLO_MOTION_SZ; y++) + for (x = 0; x < SOLO_MOTION_SZ; x++) + solo_enc->motion_thresholds.thresholds[y][x] = + SOLO_DEF_MOT_THRESH; + + solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; + solo_enc->vidq.ops = &solo_enc_video_qops; + solo_enc->vidq.mem_ops = &vb2_dma_sg_memops; + solo_enc->vidq.drv_priv = solo_enc; + solo_enc->vidq.gfp_flags = __GFP_DMA32; + solo_enc->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf); + solo_enc->vidq.lock = &solo_enc->lock; + ret = vb2_queue_init(&solo_enc->vidq); + if (ret) + goto hdl_free; + solo_update_mode(solo_enc); + + spin_lock_init(&solo_enc->motion_lock); + + /* Initialize this per encoder */ + solo_enc->jpeg_len = sizeof(jpeg_header); + memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len); + + solo_enc->desc_nelts = 32; + solo_enc->desc_items = pci_alloc_consistent(solo_dev->pdev, + sizeof(struct solo_p2m_desc) * + solo_enc->desc_nelts, &solo_enc->desc_dma); + ret = -ENOMEM; + if (solo_enc->desc_items == NULL) + goto hdl_free; + + solo_enc->vfd = video_device_alloc(); + if (!solo_enc->vfd) + goto pci_free; + + *solo_enc->vfd = solo_enc_template; + solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev; + solo_enc->vfd->ctrl_handler = hdl; + solo_enc->vfd->queue = &solo_enc->vidq; + solo_enc->vfd->lock = &solo_enc->lock; + set_bit(V4L2_FL_USE_FH_PRIO, &solo_enc->vfd->flags); + video_set_drvdata(solo_enc->vfd, solo_enc); + ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr); + if (ret < 0) + goto vdev_release; + + snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name), + "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num, + solo_enc->vfd->num); + + return solo_enc; + +vdev_release: + video_device_release(solo_enc->vfd); +pci_free: + pci_free_consistent(solo_enc->solo_dev->pdev, + sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts, + solo_enc->desc_items, solo_enc->desc_dma); +hdl_free: + v4l2_ctrl_handler_free(hdl); + kfree(solo_enc); + return ERR_PTR(ret); +} + +static void solo_enc_free(struct solo_enc_dev *solo_enc) +{ + if (solo_enc == NULL) + return; + + video_unregister_device(solo_enc->vfd); + v4l2_ctrl_handler_free(&solo_enc->hdl); + kfree(solo_enc); +} + +int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr) +{ + int i; + + init_waitqueue_head(&solo_dev->ring_thread_wait); + + solo_dev->vh_size = sizeof(struct vop_header); + solo_dev->vh_buf = pci_alloc_consistent(solo_dev->pdev, + solo_dev->vh_size, + &solo_dev->vh_dma); + if (solo_dev->vh_buf == NULL) + return -ENOMEM; + + for (i = 0; i < solo_dev->nr_chans; i++) { + solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i, nr); + if (IS_ERR(solo_dev->v4l2_enc[i])) + break; + } + + if (i != solo_dev->nr_chans) { + int ret = PTR_ERR(solo_dev->v4l2_enc[i]); + while (i--) + solo_enc_free(solo_dev->v4l2_enc[i]); + pci_free_consistent(solo_dev->pdev, solo_dev->vh_size, + solo_dev->vh_buf, solo_dev->vh_dma); + solo_dev->vh_buf = NULL; + return ret; + } + + if (solo_dev->type == SOLO_DEV_6010) + solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4; + else + solo_dev->enc_bw_remain = solo_dev->fps * 4 * 5; + + dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n", + solo_dev->v4l2_enc[0]->vfd->num, + solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num); + + return 0; +} + +void solo_enc_v4l2_exit(struct solo_dev *solo_dev) +{ + int i; + + for (i = 0; i < solo_dev->nr_chans; i++) + solo_enc_free(solo_dev->v4l2_enc[i]); + + if (solo_dev->vh_buf) + pci_free_consistent(solo_dev->pdev, solo_dev->vh_size, + solo_dev->vh_buf, solo_dev->vh_dma); +} diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2.c b/drivers/staging/media/solo6x10/solo6x10-v4l2.c new file mode 100644 index 0000000..7b26de3 --- /dev/null +++ b/drivers/staging/media/solo6x10/solo6x10-v4l2.c @@ -0,0 +1,734 @@ +/* + * Copyright (C) 2010-2013 Bluecherry, LLC + * + * Original author: + * Ben Collins + * + * Additional work by: + * John Brooks + * + * 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. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "solo6x10.h" +#include "solo6x10-tw28.h" + +/* Image size is two fields, SOLO_HW_BPL is one horizontal line in hardware */ +#define SOLO_HW_BPL 2048 +#define solo_vlines(__solo) (__solo->video_vsize * 2) +#define solo_image_size(__solo) (solo_bytesperline(__solo) * \ + solo_vlines(__solo)) +#define solo_bytesperline(__solo) (__solo->video_hsize * 2) + +#define MIN_VID_BUFFERS 2 + +static inline void erase_on(struct solo_dev *solo_dev) +{ + solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); + solo_dev->erasing = 1; + solo_dev->frame_blank = 0; +} + +static inline int erase_off(struct solo_dev *solo_dev) +{ + if (!solo_dev->erasing) + return 0; + + /* First time around, assert erase off */ + if (!solo_dev->frame_blank) + solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0); + /* Keep the erasing flag on for 8 frames minimum */ + if (solo_dev->frame_blank++ >= 8) + solo_dev->erasing = 0; + + return 1; +} + +void solo_video_in_isr(struct solo_dev *solo_dev) +{ + wake_up_interruptible_all(&solo_dev->disp_thread_wait); +} + +static void solo_win_setup(struct solo_dev *solo_dev, u8 ch, + int sx, int sy, int ex, int ey, int scale) +{ + if (ch >= solo_dev->nr_chans) + return; + + /* Here, we just keep window/channel the same */ + solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch), + SOLO_VI_WIN_CHANNEL(ch) | + SOLO_VI_WIN_SX(sx) | + SOLO_VI_WIN_EX(ex) | + SOLO_VI_WIN_SCALE(scale)); + + solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch), + SOLO_VI_WIN_SY(sy) | + SOLO_VI_WIN_EY(ey)); +} + +static int solo_v4l2_ch_ext_4up(struct solo_dev *solo_dev, u8 idx, int on) +{ + u8 ch = idx * 4; + + if (ch >= solo_dev->nr_chans) + return -EINVAL; + + if (!on) { + u8 i; + for (i = ch; i < ch + 4; i++) + solo_win_setup(solo_dev, i, solo_dev->video_hsize, + solo_vlines(solo_dev), + solo_dev->video_hsize, + solo_vlines(solo_dev), 0); + return 0; + } + + /* Row 1 */ + solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2, + solo_vlines(solo_dev) / 2, 3); + solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0, + solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3); + /* Row 2 */ + solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2, + solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3); + solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2, + solo_vlines(solo_dev) / 2, solo_dev->video_hsize, + solo_vlines(solo_dev), 3); + + return 0; +} + +static int solo_v4l2_ch_ext_16up(struct solo_dev *solo_dev, int on) +{ + int sy, ysize, hsize, i; + + if (!on) { + for (i = 0; i < 16; i++) + solo_win_setup(solo_dev, i, solo_dev->video_hsize, + solo_vlines(solo_dev), + solo_dev->video_hsize, + solo_vlines(solo_dev), 0); + return 0; + } + + ysize = solo_vlines(solo_dev) / 4; + hsize = solo_dev->video_hsize / 4; + + for (sy = 0, i = 0; i < 4; i++, sy += ysize) { + solo_win_setup(solo_dev, i * 4, 0, sy, hsize, + sy + ysize, 5); + solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy, + hsize * 2, sy + ysize, 5); + solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy, + hsize * 3, sy + ysize, 5); + solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy, + solo_dev->video_hsize, sy + ysize, 5); + } + + return 0; +} + +static int solo_v4l2_ch(struct solo_dev *solo_dev, u8 ch, int on) +{ + u8 ext_ch; + + if (ch < solo_dev->nr_chans) { + solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize, + on ? 0 : solo_vlines(solo_dev), + solo_dev->video_hsize, solo_vlines(solo_dev), + on ? 1 : 0); + return 0; + } + + if (ch >= solo_dev->nr_chans + solo_dev->nr_ext) + return -EINVAL; + + ext_ch = ch - solo_dev->nr_chans; + + /* 4up's first */ + if (ext_ch < 4) + return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on); + + /* Remaining case is 16up for 16-port */ + return solo_v4l2_ch_ext_16up(solo_dev, on); +} + +static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch) +{ + if (ch >= solo_dev->nr_chans + solo_dev->nr_ext) + return -EINVAL; + + erase_on(solo_dev); + + solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0); + solo_v4l2_ch(solo_dev, ch, 1); + + solo_dev->cur_disp_ch = ch; + + return 0; +} + +static void solo_fillbuf(struct solo_dev *solo_dev, + struct vb2_buffer *vb) +{ + dma_addr_t vbuf; + unsigned int fdma_addr; + int error = -1; + int i; + + vbuf = vb2_dma_contig_plane_dma_addr(vb, 0); + if (!vbuf) + goto finish_buf; + + if (erase_off(solo_dev)) { + void *p = vb2_plane_vaddr(vb, 0); + int image_size = solo_image_size(solo_dev); + for (i = 0; i < image_size; i += 2) { + ((u8 *)p)[i] = 0x80; + ((u8 *)p)[i + 1] = 0x00; + } + error = 0; + } else { + fdma_addr = SOLO_DISP_EXT_ADDR + (solo_dev->old_write * + (SOLO_HW_BPL * solo_vlines(solo_dev))); + + error = solo_p2m_dma_t(solo_dev, 0, vbuf, fdma_addr, + solo_bytesperline(solo_dev), + solo_vlines(solo_dev), SOLO_HW_BPL); + } + +finish_buf: + if (!error) { + vb2_set_plane_payload(vb, 0, + solo_vlines(solo_dev) * solo_bytesperline(solo_dev)); + vb->v4l2_buf.sequence = solo_dev->sequence++; + v4l2_get_timestamp(&vb->v4l2_buf.timestamp); + } + + vb2_buffer_done(vb, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); +} + +static void solo_thread_try(struct solo_dev *solo_dev) +{ + struct solo_vb2_buf *vb; + + /* Only "break" from this loop if slock is held, otherwise + * just return. */ + for (;;) { + unsigned int cur_write; + + cur_write = SOLO_VI_STATUS0_PAGE( + solo_reg_read(solo_dev, SOLO_VI_STATUS0)); + if (cur_write == solo_dev->old_write) + return; + + spin_lock(&solo_dev->slock); + + if (list_empty(&solo_dev->vidq_active)) + break; + + vb = list_first_entry(&solo_dev->vidq_active, struct solo_vb2_buf, + list); + + solo_dev->old_write = cur_write; + list_del(&vb->list); + + spin_unlock(&solo_dev->slock); + + solo_fillbuf(solo_dev, &vb->vb); + } + + assert_spin_locked(&solo_dev->slock); + spin_unlock(&solo_dev->slock); +} + +static int solo_thread(void *data) +{ + struct solo_dev *solo_dev = data; + DECLARE_WAITQUEUE(wait, current); + + set_freezable(); + add_wait_queue(&solo_dev->disp_thread_wait, &wait); + + for (;;) { + long timeout = schedule_timeout_interruptible(HZ); + if (timeout == -ERESTARTSYS || kthread_should_stop()) + break; + solo_thread_try(solo_dev); + try_to_freeze(); + } + + remove_wait_queue(&solo_dev->disp_thread_wait, &wait); + + return 0; +} + +static int solo_start_thread(struct solo_dev *solo_dev) +{ + int ret = 0; + + solo_dev->kthread = kthread_run(solo_thread, solo_dev, SOLO6X10_NAME "_disp"); + + if (IS_ERR(solo_dev->kthread)) { + ret = PTR_ERR(solo_dev->kthread); + solo_dev->kthread = NULL; + return ret; + } + solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN); + + return ret; +} + +static void solo_stop_thread(struct solo_dev *solo_dev) +{ + if (!solo_dev->kthread) + return; + + solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN); + kthread_stop(solo_dev->kthread); + solo_dev->kthread = NULL; +} + +static int solo_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) +{ + struct solo_dev *solo_dev = vb2_get_drv_priv(q); + + sizes[0] = solo_image_size(solo_dev); + alloc_ctxs[0] = solo_dev->alloc_ctx; + *num_planes = 1; + + if (*num_buffers < MIN_VID_BUFFERS) + *num_buffers = MIN_VID_BUFFERS; + + return 0; +} + +static int solo_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct solo_dev *solo_dev = vb2_get_drv_priv(q); + + solo_dev->sequence = 0; + return solo_start_thread(solo_dev); +} + +static int solo_stop_streaming(struct vb2_queue *q) +{ + struct solo_dev *solo_dev = vb2_get_drv_priv(q); + + solo_stop_thread(solo_dev); + INIT_LIST_HEAD(&solo_dev->vidq_active); + return 0; +} + +static void solo_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct solo_dev *solo_dev = vb2_get_drv_priv(vq); + struct solo_vb2_buf *solo_vb = + container_of(vb, struct solo_vb2_buf, vb); + + spin_lock(&solo_dev->slock); + list_add_tail(&solo_vb->list, &solo_dev->vidq_active); + spin_unlock(&solo_dev->slock); + wake_up_interruptible(&solo_dev->disp_thread_wait); +} + +static const struct vb2_ops solo_video_qops = { + .queue_setup = solo_queue_setup, + .buf_queue = solo_buf_queue, + .start_streaming = solo_start_streaming, + .stop_streaming = solo_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int solo_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct solo_dev *solo_dev = video_drvdata(file); + + strcpy(cap->driver, SOLO6X10_NAME); + strcpy(cap->card, "Softlogic 6x10"); + snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", + pci_name(solo_dev->pdev)); + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int solo_enum_ext_input(struct solo_dev *solo_dev, + struct v4l2_input *input) +{ + static const char * const dispnames_1[] = { "4UP" }; + static const char * const dispnames_2[] = { "4UP-1", "4UP-2" }; + static const char * const dispnames_5[] = { + "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP" + }; + const char * const *dispnames; + + if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext)) + return -EINVAL; + + if (solo_dev->nr_ext == 5) + dispnames = dispnames_5; + else if (solo_dev->nr_ext == 2) + dispnames = dispnames_2; + else + dispnames = dispnames_1; + + snprintf(input->name, sizeof(input->name), "Multi %s", + dispnames[input->index - solo_dev->nr_chans]); + + return 0; +} + +static int solo_enum_input(struct file *file, void *priv, + struct v4l2_input *input) +{ + struct solo_dev *solo_dev = video_drvdata(file); + + if (input->index >= solo_dev->nr_chans) { + int ret = solo_enum_ext_input(solo_dev, input); + if (ret < 0) + return ret; + } else { + snprintf(input->name, sizeof(input->name), "Camera %d", + input->index + 1); + + /* We can only check this for normal inputs */ + if (!tw28_get_video_status(solo_dev, input->index)) + input->status = V4L2_IN_ST_NO_SIGNAL; + } + + input->type = V4L2_INPUT_TYPE_CAMERA; + input->std = solo_dev->vfd->tvnorms; + return 0; +} + +static int solo_set_input(struct file *file, void *priv, unsigned int index) +{ + struct solo_dev *solo_dev = video_drvdata(file); + int ret = solo_v4l2_set_ch(solo_dev, index); + + if (!ret) { + while (erase_off(solo_dev)) + /* Do nothing */; + } + + return ret; +} + +static int solo_get_input(struct file *file, void *priv, unsigned int *index) +{ + struct solo_dev *solo_dev = video_drvdata(file); + + *index = solo_dev->cur_disp_ch; + + return 0; +} + +static int solo_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index) + return -EINVAL; + + f->pixelformat = V4L2_PIX_FMT_UYVY; + strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description)); + + return 0; +} + +static int solo_try_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct solo_dev *solo_dev = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + int image_size = solo_image_size(solo_dev); + + if (pix->pixelformat != V4L2_PIX_FMT_UYVY) + return -EINVAL; + + pix->width = solo_dev->video_hsize; + pix->height = solo_vlines(solo_dev); + pix->sizeimage = image_size; + pix->field = V4L2_FIELD_INTERLACED; + pix->pixelformat = V4L2_PIX_FMT_UYVY; + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; + pix->priv = 0; + return 0; +} + +static int solo_set_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct solo_dev *solo_dev = video_drvdata(file); + + if (vb2_is_busy(&solo_dev->vidq)) + return -EBUSY; + + /* For right now, if it doesn't match our running config, + * then fail */ + return solo_try_fmt_cap(file, priv, f); +} + +static int solo_get_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct solo_dev *solo_dev = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + + pix->width = solo_dev->video_hsize; + pix->height = solo_vlines(solo_dev); + pix->pixelformat = V4L2_PIX_FMT_UYVY; + pix->field = V4L2_FIELD_INTERLACED; + pix->sizeimage = solo_image_size(solo_dev); + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; + pix->bytesperline = solo_bytesperline(solo_dev); + pix->priv = 0; + + return 0; +} + +static int solo_g_std(struct file *file, void *priv, v4l2_std_id *i) +{ + struct solo_dev *solo_dev = video_drvdata(file); + + if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) + *i = V4L2_STD_NTSC_M; + else + *i = V4L2_STD_PAL; + return 0; +} + +int solo_set_video_type(struct solo_dev *solo_dev, bool type) +{ + int i; + + /* Make sure all video nodes are idle */ + if (vb2_is_busy(&solo_dev->vidq)) + return -EBUSY; + for (i = 0; i < solo_dev->nr_chans; i++) + if (vb2_is_busy(&solo_dev->v4l2_enc[i]->vidq)) + return -EBUSY; + solo_dev->video_type = type; + /* Reconfigure for the new standard */ + solo_disp_init(solo_dev); + solo_enc_init(solo_dev); + solo_tw28_init(solo_dev); + for (i = 0; i < solo_dev->nr_chans; i++) + solo_update_mode(solo_dev->v4l2_enc[i]); + return solo_v4l2_set_ch(solo_dev, solo_dev->cur_disp_ch); +} + +static int solo_s_std(struct file *file, void *priv, v4l2_std_id std) +{ + struct solo_dev *solo_dev = video_drvdata(file); + + return solo_set_video_type(solo_dev, std & V4L2_STD_PAL); +} + +static int solo_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct solo_dev *solo_dev = + container_of(ctrl->handler, struct solo_dev, disp_hdl); + + switch (ctrl->id) { + case V4L2_CID_MOTION_TRACE: + if (ctrl->val) { + solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, + SOLO_VI_MOTION_Y_ADD | + SOLO_VI_MOTION_Y_VALUE(0x20) | + SOLO_VI_MOTION_CB_VALUE(0x10) | + SOLO_VI_MOTION_CR_VALUE(0x10)); + solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, + SOLO_VI_MOTION_CR_ADD | + SOLO_VI_MOTION_Y_VALUE(0x10) | + SOLO_VI_MOTION_CB_VALUE(0x80) | + SOLO_VI_MOTION_CR_VALUE(0x10)); + } else { + solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0); + solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); + } + return 0; + default: + break; + } + return -EINVAL; +} + +static const struct v4l2_file_operations solo_v4l2_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = { + .vidioc_querycap = solo_querycap, + .vidioc_s_std = solo_s_std, + .vidioc_g_std = solo_g_std, + /* Input callbacks */ + .vidioc_enum_input = solo_enum_input, + .vidioc_s_input = solo_set_input, + .vidioc_g_input = solo_get_input, + /* Video capture format callbacks */ + .vidioc_enum_fmt_vid_cap = solo_enum_fmt_cap, + .vidioc_try_fmt_vid_cap = solo_try_fmt_cap, + .vidioc_s_fmt_vid_cap = solo_set_fmt_cap, + .vidioc_g_fmt_vid_cap = solo_get_fmt_cap, + /* Streaming I/O */ + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + /* Logging and events */ + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static struct video_device solo_v4l2_template = { + .name = SOLO6X10_NAME, + .fops = &solo_v4l2_fops, + .ioctl_ops = &solo_v4l2_ioctl_ops, + .minor = -1, + .release = video_device_release, + .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, +}; + +static const struct v4l2_ctrl_ops solo_ctrl_ops = { + .s_ctrl = solo_s_ctrl, +}; + +static const struct v4l2_ctrl_config solo_motion_trace_ctrl = { + .ops = &solo_ctrl_ops, + .id = V4L2_CID_MOTION_TRACE, + .name = "Motion Detection Trace", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) +{ + int ret; + int i; + + init_waitqueue_head(&solo_dev->disp_thread_wait); + spin_lock_init(&solo_dev->slock); + mutex_init(&solo_dev->lock); + INIT_LIST_HEAD(&solo_dev->vidq_active); + + solo_dev->vfd = video_device_alloc(); + if (!solo_dev->vfd) + return -ENOMEM; + + *solo_dev->vfd = solo_v4l2_template; + solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev; + solo_dev->vfd->queue = &solo_dev->vidq; + solo_dev->vfd->lock = &solo_dev->lock; + v4l2_ctrl_handler_init(&solo_dev->disp_hdl, 1); + v4l2_ctrl_new_custom(&solo_dev->disp_hdl, &solo_motion_trace_ctrl, NULL); + if (solo_dev->disp_hdl.error) { + ret = solo_dev->disp_hdl.error; + goto fail; + } + solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl; + set_bit(V4L2_FL_USE_FH_PRIO, &solo_dev->vfd->flags); + + video_set_drvdata(solo_dev->vfd, solo_dev); + + solo_dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + solo_dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; + solo_dev->vidq.ops = &solo_video_qops; + solo_dev->vidq.mem_ops = &vb2_dma_contig_memops; + solo_dev->vidq.drv_priv = solo_dev; + solo_dev->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + solo_dev->vidq.gfp_flags = __GFP_DMA32; + solo_dev->vidq.buf_struct_size = sizeof(struct solo_vb2_buf); + solo_dev->vidq.lock = &solo_dev->lock; + ret = vb2_queue_init(&solo_dev->vidq); + if (ret < 0) + goto fail; + + solo_dev->alloc_ctx = vb2_dma_contig_init_ctx(&solo_dev->pdev->dev); + if (IS_ERR(solo_dev->alloc_ctx)) { + dev_err(&solo_dev->pdev->dev, "Can't allocate buffer context"); + return PTR_ERR(solo_dev->alloc_ctx); + } + + /* Cycle all the channels and clear */ + for (i = 0; i < solo_dev->nr_chans; i++) { + solo_v4l2_set_ch(solo_dev, i); + while (erase_off(solo_dev)) + /* Do nothing */; + } + + /* Set the default display channel */ + solo_v4l2_set_ch(solo_dev, 0); + while (erase_off(solo_dev)) + /* Do nothing */; + + ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr); + if (ret < 0) + goto fail; + + snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)", + SOLO6X10_NAME, solo_dev->vfd->num); + + dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with " + "%d inputs (%d extended)\n", solo_dev->vfd->num, + solo_dev->nr_chans, solo_dev->nr_ext); + + return 0; + +fail: + video_device_release(solo_dev->vfd); + vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx); + v4l2_ctrl_handler_free(&solo_dev->disp_hdl); + solo_dev->vfd = NULL; + return ret; +} + +void solo_v4l2_exit(struct solo_dev *solo_dev) +{ + if (solo_dev->vfd == NULL) + return; + + video_unregister_device(solo_dev->vfd); + vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx); + v4l2_ctrl_handler_free(&solo_dev->disp_hdl); + solo_dev->vfd = NULL; +} diff --git a/drivers/staging/media/solo6x10/tw28.c b/drivers/staging/media/solo6x10/tw28.c deleted file mode 100644 index ad00e2b..0000000 --- a/drivers/staging/media/solo6x10/tw28.c +++ /dev/null @@ -1,854 +0,0 @@ -/* - * Copyright (C) 2010-2013 Bluecherry, LLC - * - * Original author: - * Ben Collins - * - * Additional work by: - * John Brooks - * - * 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. - */ - -#include -#include - -#include "solo6x10.h" -#include "solo6x10-tw28.h" - -#define DEFAULT_HDELAY_NTSC (32 - 8) -#define DEFAULT_HACTIVE_NTSC (720 + 16) -#define DEFAULT_VDELAY_NTSC (7 - 2) -#define DEFAULT_VACTIVE_NTSC (240 + 4) - -#define DEFAULT_HDELAY_PAL (32 + 4) -#define DEFAULT_HACTIVE_PAL (864-DEFAULT_HDELAY_PAL) -#define DEFAULT_VDELAY_PAL (6) -#define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL) - - -static const u8 tbl_tw2864_ntsc_template[] = { - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ - 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ - 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */ - 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x30 */ - 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00, - 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ - 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00, - 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */ - 0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01, - 0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */ - 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44, - 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ - 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00, - 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */ - 0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81, - 0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ - 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, - 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */ - 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00, -}; - -static const u8 tbl_tw2864_pal_template[] = { - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */ - 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */ - 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */ - 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */ - 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00, - 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ - 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00, - 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */ - 0x00, 0x28, 0x44, 0x44, 0xa0, 0x90, 0x5a, 0x01, - 0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */ - 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44, - 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ - 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00, - 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */ - 0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81, - 0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ - 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, - 0x83, 0xb5, 0x09, 0x00, 0xa0, 0x00, 0x01, 0x20, /* 0xf0 */ - 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00, -}; - -static const u8 tbl_tw2865_ntsc_template[] = { - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */ - 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */ - 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */ - 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, /* 0x30 */ - 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f, - 0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, /* 0x40 */ - 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43, - 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */ - 0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80, - 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ - 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00, - 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */ - 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13, - 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, /* 0xa0 */ - 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44, - 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */ - 0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8, - 0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ - 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80, - 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */ - 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81, - 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ - 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, - 0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */ - 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0, -}; - -static const u8 tbl_tw2865_pal_template[] = { - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */ - 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */ - 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */ - 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, - 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */ - 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f, - 0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, /* 0x40 */ - 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43, - 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */ - 0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80, - 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */ - 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00, - 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */ - 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13, - 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, /* 0xa0 */ - 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44, - 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */ - 0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8, - 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */ - 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80, - 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */ - 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81, - 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */ - 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00, - 0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, /* 0xf0 */ - 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0, -}; - -#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id))) - -static u8 tw_readbyte(struct solo_dev *solo_dev, int chip_id, u8 tw6x_off, - u8 tw_off) -{ - if (is_tw286x(solo_dev, chip_id)) - return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, - TW_CHIP_OFFSET_ADDR(chip_id), - tw6x_off); - else - return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, - TW_CHIP_OFFSET_ADDR(chip_id), - tw_off); -} - -static void tw_writebyte(struct solo_dev *solo_dev, int chip_id, - u8 tw6x_off, u8 tw_off, u8 val) -{ - if (is_tw286x(solo_dev, chip_id)) - solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, - TW_CHIP_OFFSET_ADDR(chip_id), - tw6x_off, val); - else - solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, - TW_CHIP_OFFSET_ADDR(chip_id), - tw_off, val); -} - -static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off, - u8 val) -{ - int i; - - for (i = 0; i < 5; i++) { - u8 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, addr, off); - if (rval == val) - return; - - solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, addr, off, val); - msleep_interruptible(1); - } - -/* printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n", */ -/* addr, off, val); */ -} - -static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr) -{ - u8 tbl_tw2865_common[256]; - int i; - - if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) - memcpy(tbl_tw2865_common, tbl_tw2865_pal_template, - sizeof(tbl_tw2865_common)); - else - memcpy(tbl_tw2865_common, tbl_tw2865_ntsc_template, - sizeof(tbl_tw2865_common)); - - /* ALINK Mode */ - if (solo_dev->nr_chans == 4) { - tbl_tw2865_common[0xd2] = 0x01; - tbl_tw2865_common[0xcf] = 0x00; - } else if (solo_dev->nr_chans == 8) { - tbl_tw2865_common[0xd2] = 0x02; - if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) - tbl_tw2865_common[0xcf] = 0x80; - } else if (solo_dev->nr_chans == 16) { - tbl_tw2865_common[0xd2] = 0x03; - if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) - tbl_tw2865_common[0xcf] = 0x83; - else if (dev_addr == TW_CHIP_OFFSET_ADDR(2)) - tbl_tw2865_common[0xcf] = 0x83; - else if (dev_addr == TW_CHIP_OFFSET_ADDR(3)) - tbl_tw2865_common[0xcf] = 0x80; - } - - for (i = 0; i < 0xff; i++) { - /* Skip read only registers */ - switch (i) { - case 0xb8 ... 0xc1: - case 0xc4 ... 0xc7: - case 0xfd: - continue; - } - switch (i & ~0x30) { - case 0x00: - case 0x0c ... 0x0d: - continue; - } - - tw_write_and_verify(solo_dev, dev_addr, i, - tbl_tw2865_common[i]); - } - - return 0; -} - -static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr) -{ - u8 tbl_tw2864_common[256]; - int i; - - if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) - memcpy(tbl_tw2864_common, tbl_tw2864_pal_template, - sizeof(tbl_tw2864_common)); - else - memcpy(tbl_tw2864_common, tbl_tw2864_ntsc_template, - sizeof(tbl_tw2864_common)); - - if (solo_dev->tw2865 == 0) { - /* IRQ Mode */ - if (solo_dev->nr_chans == 4) { - tbl_tw2864_common[0xd2] = 0x01; - tbl_tw2864_common[0xcf] = 0x00; - } else if (solo_dev->nr_chans == 8) { - tbl_tw2864_common[0xd2] = 0x02; - if (dev_addr == TW_CHIP_OFFSET_ADDR(0)) - tbl_tw2864_common[0xcf] = 0x43; - else if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) - tbl_tw2864_common[0xcf] = 0x40; - } else if (solo_dev->nr_chans == 16) { - tbl_tw2864_common[0xd2] = 0x03; - if (dev_addr == TW_CHIP_OFFSET_ADDR(0)) - tbl_tw2864_common[0xcf] = 0x43; - else if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) - tbl_tw2864_common[0xcf] = 0x43; - else if (dev_addr == TW_CHIP_OFFSET_ADDR(2)) - tbl_tw2864_common[0xcf] = 0x43; - else if (dev_addr == TW_CHIP_OFFSET_ADDR(3)) - tbl_tw2864_common[0xcf] = 0x40; - } - } else { - /* ALINK Mode. Assumes that the first tw28xx is a - * 2865 and these are in cascade. */ - for (i = 0; i <= 4; i++) - tbl_tw2864_common[0x08 | i << 4] = 0x12; - - if (solo_dev->nr_chans == 8) { - tbl_tw2864_common[0xd2] = 0x02; - if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) - tbl_tw2864_common[0xcf] = 0x80; - } else if (solo_dev->nr_chans == 16) { - tbl_tw2864_common[0xd2] = 0x03; - if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) - tbl_tw2864_common[0xcf] = 0x83; - else if (dev_addr == TW_CHIP_OFFSET_ADDR(2)) - tbl_tw2864_common[0xcf] = 0x83; - else if (dev_addr == TW_CHIP_OFFSET_ADDR(3)) - tbl_tw2864_common[0xcf] = 0x80; - } - } - - for (i = 0; i < 0xff; i++) { - /* Skip read only registers */ - switch (i) { - case 0xb8 ... 0xc1: - case 0xfd: - continue; - } - switch (i & ~0x30) { - case 0x00: - case 0x0c: - case 0x0d: - continue; - } - - tw_write_and_verify(solo_dev, dev_addr, i, - tbl_tw2864_common[i]); - } - - return 0; -} - -static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr) -{ - u8 tbl_ntsc_tw2815_common[] = { - 0x00, 0xc8, 0x20, 0xd0, 0x06, 0xf0, 0x08, 0x80, - 0x80, 0x80, 0x80, 0x02, 0x06, 0x00, 0x11, - }; - - u8 tbl_pal_tw2815_common[] = { - 0x00, 0x88, 0x20, 0xd0, 0x05, 0x20, 0x28, 0x80, - 0x80, 0x80, 0x80, 0x82, 0x06, 0x00, 0x11, - }; - - u8 tbl_tw2815_sfr[] = { - 0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, /* 0x00 */ - 0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00, - 0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, /* 0x10 */ - 0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00, - 0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, /* 0x20 */ - 0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88, - 0x88, 0x11, 0x00, 0x88, 0x88, 0x00, /* 0x30 */ - }; - u8 *tbl_tw2815_common; - int i; - int ch; - - tbl_ntsc_tw2815_common[0x06] = 0; - - /* Horizontal Delay Control */ - tbl_ntsc_tw2815_common[0x02] = DEFAULT_HDELAY_NTSC & 0xff; - tbl_ntsc_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_NTSC >> 8); - - /* Horizontal Active Control */ - tbl_ntsc_tw2815_common[0x03] = DEFAULT_HACTIVE_NTSC & 0xff; - tbl_ntsc_tw2815_common[0x06] |= - ((0x03 & (DEFAULT_HACTIVE_NTSC >> 8)) << 2); - - /* Vertical Delay Control */ - tbl_ntsc_tw2815_common[0x04] = DEFAULT_VDELAY_NTSC & 0xff; - tbl_ntsc_tw2815_common[0x06] |= - ((0x01 & (DEFAULT_VDELAY_NTSC >> 8)) << 4); - - /* Vertical Active Control */ - tbl_ntsc_tw2815_common[0x05] = DEFAULT_VACTIVE_NTSC & 0xff; - tbl_ntsc_tw2815_common[0x06] |= - ((0x01 & (DEFAULT_VACTIVE_NTSC >> 8)) << 5); - - tbl_pal_tw2815_common[0x06] = 0; - - /* Horizontal Delay Control */ - tbl_pal_tw2815_common[0x02] = DEFAULT_HDELAY_PAL & 0xff; - tbl_pal_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_PAL >> 8); - - /* Horizontal Active Control */ - tbl_pal_tw2815_common[0x03] = DEFAULT_HACTIVE_PAL & 0xff; - tbl_pal_tw2815_common[0x06] |= - ((0x03 & (DEFAULT_HACTIVE_PAL >> 8)) << 2); - - /* Vertical Delay Control */ - tbl_pal_tw2815_common[0x04] = DEFAULT_VDELAY_PAL & 0xff; - tbl_pal_tw2815_common[0x06] |= - ((0x01 & (DEFAULT_VDELAY_PAL >> 8)) << 4); - - /* Vertical Active Control */ - tbl_pal_tw2815_common[0x05] = DEFAULT_VACTIVE_PAL & 0xff; - tbl_pal_tw2815_common[0x06] |= - ((0x01 & (DEFAULT_VACTIVE_PAL >> 8)) << 5); - - tbl_tw2815_common = - (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) ? - tbl_ntsc_tw2815_common : tbl_pal_tw2815_common; - - /* Dual ITU-R BT.656 format */ - tbl_tw2815_common[0x0d] |= 0x04; - - /* Audio configuration */ - tbl_tw2815_sfr[0x62 - 0x40] &= ~(3 << 6); - - if (solo_dev->nr_chans == 4) { - tbl_tw2815_sfr[0x63 - 0x40] |= 1; - tbl_tw2815_sfr[0x62 - 0x40] |= 3 << 6; - } else if (solo_dev->nr_chans == 8) { - tbl_tw2815_sfr[0x63 - 0x40] |= 2; - if (dev_addr == TW_CHIP_OFFSET_ADDR(0)) - tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6; - else if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) - tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6; - } else if (solo_dev->nr_chans == 16) { - tbl_tw2815_sfr[0x63 - 0x40] |= 3; - if (dev_addr == TW_CHIP_OFFSET_ADDR(0)) - tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6; - else if (dev_addr == TW_CHIP_OFFSET_ADDR(1)) - tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6; - else if (dev_addr == TW_CHIP_OFFSET_ADDR(2)) - tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6; - else if (dev_addr == TW_CHIP_OFFSET_ADDR(3)) - tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6; - } - - /* Output mode of R_ADATM pin (0 mixing, 1 record) */ - /* tbl_tw2815_sfr[0x63 - 0x40] |= 0 << 2; */ - - /* 8KHz, used to be 16KHz, but changed for remote client compat */ - tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 2; - tbl_tw2815_sfr[0x6c - 0x40] |= 0 << 2; - - /* Playback of right channel */ - tbl_tw2815_sfr[0x6c - 0x40] |= 1 << 5; - - /* Reserved value (XXX ??) */ - tbl_tw2815_sfr[0x5c - 0x40] |= 1 << 5; - - /* Analog output gain and mix ratio playback on full */ - tbl_tw2815_sfr[0x70 - 0x40] |= 0xff; - /* Select playback audio and mute all except */ - tbl_tw2815_sfr[0x71 - 0x40] |= 0x10; - tbl_tw2815_sfr[0x6d - 0x40] |= 0x0f; - - /* End of audio configuration */ - - for (ch = 0; ch < 4; ch++) { - tbl_tw2815_common[0x0d] &= ~3; - switch (ch) { - case 0: - tbl_tw2815_common[0x0d] |= 0x21; - break; - case 1: - tbl_tw2815_common[0x0d] |= 0x20; - break; - case 2: - tbl_tw2815_common[0x0d] |= 0x23; - break; - case 3: - tbl_tw2815_common[0x0d] |= 0x22; - break; - } - - for (i = 0; i < 0x0f; i++) { - if (i == 0x00) - continue; /* read-only */ - solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, - dev_addr, (ch * 0x10) + i, - tbl_tw2815_common[i]); - } - } - - for (i = 0x40; i < 0x76; i++) { - /* Skip read-only and nop registers */ - if (i == 0x40 || i == 0x59 || i == 0x5a || - i == 0x5d || i == 0x5e || i == 0x5f) - continue; - - solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, dev_addr, i, - tbl_tw2815_sfr[i - 0x40]); - } - - return 0; -} - -#define FIRST_ACTIVE_LINE 0x0008 -#define LAST_ACTIVE_LINE 0x0102 - -static void saa7128_setup(struct solo_dev *solo_dev) -{ - int i; - unsigned char regs[128] = { - 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1C, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, - 0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f, 0x00, 0x00, - 0x1c, 0x33, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00, - 0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18, - 0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f, - 0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06, - 0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e, - 0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77, - 0x41, 0x88, 0x41, 0x12, 0xed, 0x10, 0x10, 0x00, - 0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00, - 0x00, 0x00, 0x08, 0xff, 0x80, 0x00, 0xff, 0xff, - }; - - regs[0x7A] = FIRST_ACTIVE_LINE & 0xff; - regs[0x7B] = LAST_ACTIVE_LINE & 0xff; - regs[0x7C] = ((1 << 7) | - (((LAST_ACTIVE_LINE >> 8) & 1) << 6) | - (((FIRST_ACTIVE_LINE >> 8) & 1) << 4)); - - /* PAL: XXX: We could do a second set of regs to avoid this */ - if (solo_dev->video_type != SOLO_VO_FMT_TYPE_NTSC) { - regs[0x28] = 0xE1; - - regs[0x5A] = 0x0F; - regs[0x61] = 0x02; - regs[0x62] = 0x35; - regs[0x63] = 0xCB; - regs[0x64] = 0x8A; - regs[0x65] = 0x09; - regs[0x66] = 0x2A; - - regs[0x6C] = 0xf1; - regs[0x6E] = 0x20; - - regs[0x7A] = 0x06 + 12; - regs[0x7b] = 0x24 + 12; - regs[0x7c] |= 1 << 6; - } - - /* First 0x25 bytes are read-only? */ - for (i = 0x26; i < 128; i++) { - if (i == 0x60 || i == 0x7D) - continue; - solo_i2c_writebyte(solo_dev, SOLO_I2C_SAA, 0x46, i, regs[i]); - } - - return; -} - -int solo_tw28_init(struct solo_dev *solo_dev) -{ - int i; - u8 value; - - solo_dev->tw28_cnt = 0; - - /* Detect techwell chip type(s) */ - for (i = 0; i < solo_dev->nr_chans / 4; i++) { - value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, - TW_CHIP_OFFSET_ADDR(i), 0xFF); - - switch (value >> 3) { - case 0x18: - solo_dev->tw2865 |= 1 << i; - solo_dev->tw28_cnt++; - break; - case 0x0c: - solo_dev->tw2864 |= 1 << i; - solo_dev->tw28_cnt++; - break; - default: - value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, - TW_CHIP_OFFSET_ADDR(i), - 0x59); - if ((value >> 3) == 0x04) { - solo_dev->tw2815 |= 1 << i; - solo_dev->tw28_cnt++; - } - } - } - - if (solo_dev->tw28_cnt != (solo_dev->nr_chans >> 2)) { - dev_err(&solo_dev->pdev->dev, - "Could not initialize any techwell chips\n"); - return -EINVAL; - } - - saa7128_setup(solo_dev); - - for (i = 0; i < solo_dev->tw28_cnt; i++) { - if ((solo_dev->tw2865 & (1 << i))) - tw2865_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i)); - else if ((solo_dev->tw2864 & (1 << i))) - tw2864_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i)); - else - tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i)); - } - - return 0; -} - -/* - * We accessed the video status signal in the Techwell chip through - * iic/i2c because the video status reported by register REG_VI_STATUS1 - * (address 0x012C) of the SOLO6010 chip doesn't give the correct video - * status signal values. - */ -int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch) -{ - u8 val, chip_num; - - /* Get the right chip and on-chip channel */ - chip_num = ch / 4; - ch %= 4; - - val = tw_readbyte(solo_dev, chip_num, TW286x_AV_STAT_ADDR, - TW_AV_STAT_ADDR) & 0x0f; - - return val & (1 << ch) ? 1 : 0; -} - -#if 0 -/* Status of audio from up to 4 techwell chips are combined into 1 variable. - * See techwell datasheet for details. */ -u16 tw28_get_audio_status(struct solo_dev *solo_dev) -{ - u8 val; - u16 status = 0; - int i; - - for (i = 0; i < solo_dev->tw28_cnt; i++) { - val = (tw_readbyte(solo_dev, i, TW286x_AV_STAT_ADDR, - TW_AV_STAT_ADDR) & 0xf0) >> 4; - status |= val << (i * 4); - } - - return status; -} -#endif - -bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch) -{ - return is_tw286x(solo_dev, ch / 4); -} - -int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, - s32 val) -{ - char sval; - u8 chip_num; - - /* Get the right chip and on-chip channel */ - chip_num = ch / 4; - ch %= 4; - - if (val > 255 || val < 0) - return -ERANGE; - - switch (ctrl) { - case V4L2_CID_SHARPNESS: - /* Only 286x has sharpness */ - if (is_tw286x(solo_dev, chip_num)) { - u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, - TW_CHIP_OFFSET_ADDR(chip_num), - TW286x_SHARPNESS(chip_num)); - v &= 0xf0; - v |= val; - solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, - TW_CHIP_OFFSET_ADDR(chip_num), - TW286x_SHARPNESS(chip_num), v); - } else { - return -EINVAL; - } - break; - - case V4L2_CID_HUE: - if (is_tw286x(solo_dev, chip_num)) - sval = val - 128; - else - sval = (char)val; - tw_writebyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch), - TW_HUE_ADDR(ch), sval); - - break; - - case V4L2_CID_SATURATION: - /* 286x chips have a U and V component for saturation */ - if (is_tw286x(solo_dev, chip_num)) { - solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, - TW_CHIP_OFFSET_ADDR(chip_num), - TW286x_SATURATIONU_ADDR(ch), val); - } - tw_writebyte(solo_dev, chip_num, TW286x_SATURATIONV_ADDR(ch), - TW_SATURATION_ADDR(ch), val); - - break; - - case V4L2_CID_CONTRAST: - tw_writebyte(solo_dev, chip_num, TW286x_CONTRAST_ADDR(ch), - TW_CONTRAST_ADDR(ch), val); - break; - - case V4L2_CID_BRIGHTNESS: - if (is_tw286x(solo_dev, chip_num)) - sval = val - 128; - else - sval = (char)val; - tw_writebyte(solo_dev, chip_num, TW286x_BRIGHTNESS_ADDR(ch), - TW_BRIGHTNESS_ADDR(ch), sval); - - break; - default: - return -EINVAL; - } - - return 0; -} - -int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, - s32 *val) -{ - u8 rval, chip_num; - - /* Get the right chip and on-chip channel */ - chip_num = ch / 4; - ch %= 4; - - switch (ctrl) { - case V4L2_CID_SHARPNESS: - /* Only 286x has sharpness */ - if (is_tw286x(solo_dev, chip_num)) { - rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, - TW_CHIP_OFFSET_ADDR(chip_num), - TW286x_SHARPNESS(chip_num)); - *val = rval & 0x0f; - } else - *val = 0; - break; - case V4L2_CID_HUE: - rval = tw_readbyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch), - TW_HUE_ADDR(ch)); - if (is_tw286x(solo_dev, chip_num)) - *val = (s32)((char)rval) + 128; - else - *val = rval; - break; - case V4L2_CID_SATURATION: - *val = tw_readbyte(solo_dev, chip_num, - TW286x_SATURATIONU_ADDR(ch), - TW_SATURATION_ADDR(ch)); - break; - case V4L2_CID_CONTRAST: - *val = tw_readbyte(solo_dev, chip_num, - TW286x_CONTRAST_ADDR(ch), - TW_CONTRAST_ADDR(ch)); - break; - case V4L2_CID_BRIGHTNESS: - rval = tw_readbyte(solo_dev, chip_num, - TW286x_BRIGHTNESS_ADDR(ch), - TW_BRIGHTNESS_ADDR(ch)); - if (is_tw286x(solo_dev, chip_num)) - *val = (s32)((char)rval) + 128; - else - *val = rval; - break; - default: - return -EINVAL; - } - - return 0; -} - -#if 0 -/* - * For audio output volume, the output channel is only 1. In this case we - * don't need to offset TW_CHIP_OFFSET_ADDR. The TW_CHIP_OFFSET_ADDR used - * is the base address of the techwell chip. - */ -void tw2815_Set_AudioOutVol(struct solo_dev *solo_dev, unsigned int u_val) -{ - unsigned int val; - unsigned int chip_num; - - chip_num = (solo_dev->nr_chans - 1) / 4; - - val = tw_readbyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR, - TW_AUDIO_OUTPUT_VOL_ADDR); - - u_val = (val & 0x0f) | (u_val << 4); - - tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR, - TW_AUDIO_OUTPUT_VOL_ADDR, u_val); -} -#endif - -u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch) -{ - u8 val; - u8 chip_num; - - /* Get the right chip and on-chip channel */ - chip_num = ch / 4; - ch %= 4; - - val = tw_readbyte(solo_dev, chip_num, - TW286x_AUDIO_INPUT_GAIN_ADDR(ch), - TW_AUDIO_INPUT_GAIN_ADDR(ch)); - - return (ch % 2) ? (val >> 4) : (val & 0x0f); -} - -void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val) -{ - u8 old_val; - u8 chip_num; - - /* Get the right chip and on-chip channel */ - chip_num = ch / 4; - ch %= 4; - - old_val = tw_readbyte(solo_dev, chip_num, - TW286x_AUDIO_INPUT_GAIN_ADDR(ch), - TW_AUDIO_INPUT_GAIN_ADDR(ch)); - - val = (old_val & ((ch % 2) ? 0x0f : 0xf0)) | - ((ch % 2) ? (val << 4) : val); - - tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_INPUT_GAIN_ADDR(ch), - TW_AUDIO_INPUT_GAIN_ADDR(ch), val); -} diff --git a/drivers/staging/media/solo6x10/v4l2-enc.c b/drivers/staging/media/solo6x10/v4l2-enc.c deleted file mode 100644 index 39a8fb2..0000000 --- a/drivers/staging/media/solo6x10/v4l2-enc.c +++ /dev/null @@ -1,1363 +0,0 @@ -/* - * Copyright (C) 2010-2013 Bluecherry, LLC - * - * Original author: - * Ben Collins - * - * Additional work by: - * John Brooks - * - * 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. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "solo6x10.h" -#include "solo6x10-tw28.h" -#include "solo6x10-jpeg.h" - -#define MIN_VID_BUFFERS 2 -#define FRAME_BUF_SIZE (196 * 1024) -#define MP4_QS 16 -#define DMA_ALIGN 4096 - -/* 6010 M4V */ -static unsigned char vop_6010_ntsc_d1[] = { - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, - 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40, - 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, - 0x1f, 0x4c, 0x58, 0x10, 0xf0, 0x71, 0x18, 0x3f, -}; - -static unsigned char vop_6010_ntsc_cif[] = { - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, - 0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40, - 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, - 0x1f, 0x4c, 0x2c, 0x10, 0x78, 0x51, 0x18, 0x3f, -}; - -static unsigned char vop_6010_pal_d1[] = { - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, - 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40, - 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, - 0x1f, 0x4c, 0x58, 0x11, 0x20, 0x71, 0x18, 0x3f, -}; - -static unsigned char vop_6010_pal_cif[] = { - 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, - 0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40, - 0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04, - 0x1f, 0x4c, 0x2c, 0x10, 0x90, 0x51, 0x18, 0x3f, -}; - -/* 6110 h.264 */ -static unsigned char vop_6110_ntsc_d1[] = { - 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, - 0x9a, 0x74, 0x05, 0x81, 0xec, 0x80, 0x00, 0x00, - 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, -}; - -static unsigned char vop_6110_ntsc_cif[] = { - 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, - 0x9a, 0x74, 0x0b, 0x0f, 0xc8, 0x00, 0x00, 0x00, - 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00, -}; - -static unsigned char vop_6110_pal_d1[] = { - 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, - 0x9a, 0x74, 0x05, 0x80, 0x93, 0x20, 0x00, 0x00, - 0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, -}; - -static unsigned char vop_6110_pal_cif[] = { - 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e, - 0x9a, 0x74, 0x0b, 0x04, 0xb2, 0x00, 0x00, 0x00, - 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00, -}; - -struct vop_header { - /* VE_STATUS0 */ - u32 mpeg_size:20, sad_motion_flag:1, video_motion_flag:1, vop_type:2, - channel:5, source_fl:1, interlace:1, progressive:1; - - /* VE_STATUS1 */ - u32 vsize:8, hsize:8, last_queue:4, nop0:8, scale:4; - - /* VE_STATUS2 */ - u32 mpeg_off; - - /* VE_STATUS3 */ - u32 jpeg_off; - - /* VE_STATUS4 */ - u32 jpeg_size:20, interval:10, nop1:2; - - /* VE_STATUS5/6 */ - u32 sec, usec; - - /* VE_STATUS7/8/9 */ - u32 nop2[3]; - - /* VE_STATUS10 */ - u32 mpeg_size_alt:20, nop3:12; - - u32 end_nops[5]; -} __packed; - -struct solo_enc_buf { - enum solo_enc_types type; - struct vop_header *vh; - int motion; -}; - -static int solo_is_motion_on(struct solo_enc_dev *solo_enc) -{ - struct solo_dev *solo_dev = solo_enc->solo_dev; - - return (solo_dev->motion_mask >> solo_enc->ch) & 1; -} - -static int solo_motion_detected(struct solo_enc_dev *solo_enc) -{ - struct solo_dev *solo_dev = solo_enc->solo_dev; - unsigned long flags; - u32 ch_mask = 1 << solo_enc->ch; - int ret = 0; - - spin_lock_irqsave(&solo_enc->motion_lock, flags); - if (solo_reg_read(solo_dev, SOLO_VI_MOT_STATUS) & ch_mask) { - solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, ch_mask); - ret = 1; - } - spin_unlock_irqrestore(&solo_enc->motion_lock, flags); - - return ret; -} - -static void solo_motion_toggle(struct solo_enc_dev *solo_enc, int on) -{ - struct solo_dev *solo_dev = solo_enc->solo_dev; - u32 mask = 1 << solo_enc->ch; - unsigned long flags; - - spin_lock_irqsave(&solo_enc->motion_lock, flags); - - if (on) - solo_dev->motion_mask |= mask; - else - solo_dev->motion_mask &= ~mask; - - solo_reg_write(solo_dev, SOLO_VI_MOT_CLEAR, mask); - - solo_reg_write(solo_dev, SOLO_VI_MOT_ADR, - SOLO_VI_MOTION_EN(solo_dev->motion_mask) | - (SOLO_MOTION_EXT_ADDR(solo_dev) >> 16)); - - spin_unlock_irqrestore(&solo_enc->motion_lock, flags); -} - -void solo_update_mode(struct solo_enc_dev *solo_enc) -{ - struct solo_dev *solo_dev = solo_enc->solo_dev; - int vop_len; - unsigned char *vop; - - solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0; - solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1); - - if (solo_enc->mode == SOLO_ENC_MODE_CIF) { - solo_enc->width = solo_dev->video_hsize >> 1; - solo_enc->height = solo_dev->video_vsize; - if (solo_dev->type == SOLO_DEV_6110) { - if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { - vop = vop_6110_ntsc_cif; - vop_len = sizeof(vop_6110_ntsc_cif); - } else { - vop = vop_6110_pal_cif; - vop_len = sizeof(vop_6110_pal_cif); - } - } else { - if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { - vop = vop_6010_ntsc_cif; - vop_len = sizeof(vop_6010_ntsc_cif); - } else { - vop = vop_6010_pal_cif; - vop_len = sizeof(vop_6010_pal_cif); - } - } - } else { - solo_enc->width = solo_dev->video_hsize; - solo_enc->height = solo_dev->video_vsize << 1; - solo_enc->bw_weight <<= 2; - if (solo_dev->type == SOLO_DEV_6110) { - if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { - vop = vop_6110_ntsc_d1; - vop_len = sizeof(vop_6110_ntsc_d1); - } else { - vop = vop_6110_pal_d1; - vop_len = sizeof(vop_6110_pal_d1); - } - } else { - if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) { - vop = vop_6010_ntsc_d1; - vop_len = sizeof(vop_6010_ntsc_d1); - } else { - vop = vop_6010_pal_d1; - vop_len = sizeof(vop_6010_pal_d1); - } - } - } - - memcpy(solo_enc->vop, vop, vop_len); - - /* Some fixups for 6010/M4V */ - if (solo_dev->type == SOLO_DEV_6010) { - u16 fps = solo_dev->fps * 1000; - u16 interval = solo_enc->interval * 1000; - - vop = solo_enc->vop; - - /* Frame rate and interval */ - vop[22] = fps >> 4; - vop[23] = ((fps << 4) & 0xf0) | 0x0c - | ((interval >> 13) & 0x3); - vop[24] = (interval >> 5) & 0xff; - vop[25] = ((interval << 3) & 0xf8) | 0x04; - } - - solo_enc->vop_len = vop_len; - - /* Now handle the jpeg header */ - vop = solo_enc->jpeg_header; - vop[SOF0_START + 5] = 0xff & (solo_enc->height >> 8); - vop[SOF0_START + 6] = 0xff & solo_enc->height; - vop[SOF0_START + 7] = 0xff & (solo_enc->width >> 8); - vop[SOF0_START + 8] = 0xff & solo_enc->width; - - memcpy(vop + DQT_START, - jpeg_dqt[solo_g_jpeg_qp(solo_dev, solo_enc->ch)], DQT_LEN); -} - -static int solo_enc_on(struct solo_enc_dev *solo_enc) -{ - u8 ch = solo_enc->ch; - struct solo_dev *solo_dev = solo_enc->solo_dev; - u8 interval; - - solo_update_mode(solo_enc); - - /* Make sure to do a bandwidth check */ - if (solo_enc->bw_weight > solo_dev->enc_bw_remain) - return -EBUSY; - solo_enc->sequence = 0; - solo_dev->enc_bw_remain -= solo_enc->bw_weight; - - if (solo_enc->type == SOLO_ENC_TYPE_EXT) - solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(ch), 1); - - /* Disable all encoding for this channel */ - solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), 0); - - /* Common for both std and ext encoding */ - solo_reg_write(solo_dev, SOLO_VE_CH_INTL(ch), - solo_enc->interlaced ? 1 : 0); - - if (solo_enc->interlaced) - interval = solo_enc->interval - 1; - else - interval = solo_enc->interval; - - /* Standard encoding only */ - solo_reg_write(solo_dev, SOLO_VE_CH_GOP(ch), solo_enc->gop); - solo_reg_write(solo_dev, SOLO_VE_CH_QP(ch), solo_enc->qp); - solo_reg_write(solo_dev, SOLO_CAP_CH_INTV(ch), interval); - - /* Extended encoding only */ - solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(ch), solo_enc->gop); - solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(ch), solo_enc->qp); - solo_reg_write(solo_dev, SOLO_CAP_CH_INTV_E(ch), interval); - - /* Enables the standard encoder */ - solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(ch), solo_enc->mode); - - return 0; -} - -static void solo_enc_off(struct solo_enc_dev *solo_enc) -{ - struct solo_dev *solo_dev = solo_enc->solo_dev; - - solo_dev->enc_bw_remain += solo_enc->bw_weight; - - solo_reg_write(solo_dev, SOLO_CAP_CH_SCALE(solo_enc->ch), 0); - solo_reg_write(solo_dev, SOLO_CAP_CH_COMP_ENA_E(solo_enc->ch), 0); -} - -static int enc_get_mpeg_dma(struct solo_dev *solo_dev, dma_addr_t dma, - unsigned int off, unsigned int size) -{ - int ret; - - if (off > SOLO_MP4E_EXT_SIZE(solo_dev)) - return -EINVAL; - - /* Single shot */ - if (off + size <= SOLO_MP4E_EXT_SIZE(solo_dev)) { - return solo_p2m_dma_t(solo_dev, 0, dma, - SOLO_MP4E_EXT_ADDR(solo_dev) + off, size, - 0, 0); - } - - /* Buffer wrap */ - ret = solo_p2m_dma_t(solo_dev, 0, dma, - SOLO_MP4E_EXT_ADDR(solo_dev) + off, - SOLO_MP4E_EXT_SIZE(solo_dev) - off, 0, 0); - - if (!ret) { - ret = solo_p2m_dma_t(solo_dev, 0, - dma + SOLO_MP4E_EXT_SIZE(solo_dev) - off, - SOLO_MP4E_EXT_ADDR(solo_dev), - size + off - SOLO_MP4E_EXT_SIZE(solo_dev), 0, 0); - } - - return ret; -} - -/* Build a descriptor queue out of an SG list and send it to the P2M for - * processing. */ -static int solo_send_desc(struct solo_enc_dev *solo_enc, int skip, - struct vb2_dma_sg_desc *vbuf, int off, int size, - unsigned int base, unsigned int base_size) -{ - struct solo_dev *solo_dev = solo_enc->solo_dev; - struct scatterlist *sg; - int i; - int ret; - - if (WARN_ON_ONCE(size > FRAME_BUF_SIZE)) - return -EINVAL; - - solo_enc->desc_count = 1; - - for_each_sg(vbuf->sglist, sg, vbuf->num_pages, i) { - struct solo_p2m_desc *desc; - dma_addr_t dma; - int len; - int left = base_size - off; - - desc = &solo_enc->desc_items[solo_enc->desc_count++]; - dma = sg_dma_address(sg); - len = sg_dma_len(sg); - - /* We assume this is smaller than the scatter size */ - BUG_ON(skip >= len); - if (skip) { - len -= skip; - dma += skip; - size -= skip; - skip = 0; - } - - len = min(len, size); - - if (len <= left) { - /* Single descriptor */ - solo_p2m_fill_desc(desc, 0, dma, base + off, - len, 0, 0); - } else { - /* Buffer wrap */ - /* XXX: Do these as separate DMA requests, to avoid - timeout errors triggered by awkwardly sized - descriptors. See - - */ - ret = solo_p2m_dma_t(solo_dev, 0, dma, base + off, - left, 0, 0); - if (ret) - return ret; - - ret = solo_p2m_dma_t(solo_dev, 0, dma + left, base, - len - left, 0, 0); - if (ret) - return ret; - - solo_enc->desc_count--; - } - - size -= len; - if (size <= 0) - break; - - off += len; - if (off >= base_size) - off -= base_size; - - /* Because we may use two descriptors per loop */ - if (solo_enc->desc_count >= (solo_enc->desc_nelts - 1)) { - ret = solo_p2m_dma_desc(solo_dev, solo_enc->desc_items, - solo_enc->desc_dma, - solo_enc->desc_count - 1); - if (ret) - return ret; - solo_enc->desc_count = 1; - } - } - - if (solo_enc->desc_count <= 1) - return 0; - - return solo_p2m_dma_desc(solo_dev, solo_enc->desc_items, solo_enc->desc_dma, - solo_enc->desc_count - 1); -} - -static int solo_fill_jpeg(struct solo_enc_dev *solo_enc, - struct vb2_buffer *vb, struct vop_header *vh) -{ - struct solo_dev *solo_dev = solo_enc->solo_dev; - struct vb2_dma_sg_desc *vbuf = vb2_dma_sg_plane_desc(vb, 0); - int frame_size; - int ret; - - vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; - - if (vb2_plane_size(vb, 0) < vh->jpeg_size + solo_enc->jpeg_len) - return -EIO; - - sg_copy_from_buffer(vbuf->sglist, vbuf->num_pages, - solo_enc->jpeg_header, - solo_enc->jpeg_len); - - frame_size = (vh->jpeg_size + solo_enc->jpeg_len + (DMA_ALIGN - 1)) - & ~(DMA_ALIGN - 1); - vb2_set_plane_payload(vb, 0, vh->jpeg_size + solo_enc->jpeg_len); - - dma_map_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages, - DMA_FROM_DEVICE); - ret = solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf, vh->jpeg_off, - frame_size, SOLO_JPEG_EXT_ADDR(solo_dev), - SOLO_JPEG_EXT_SIZE(solo_dev)); - dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages, - DMA_FROM_DEVICE); - return ret; -} - -static int solo_fill_mpeg(struct solo_enc_dev *solo_enc, - struct vb2_buffer *vb, struct vop_header *vh) -{ - struct solo_dev *solo_dev = solo_enc->solo_dev; - struct vb2_dma_sg_desc *vbuf = vb2_dma_sg_plane_desc(vb, 0); - int frame_off, frame_size; - int skip = 0; - int ret; - - if (vb2_plane_size(vb, 0) < vh->mpeg_size) - return -EIO; - - /* If this is a key frame, add extra header */ - if (!vh->vop_type) { - sg_copy_from_buffer(vbuf->sglist, vbuf->num_pages, - solo_enc->vop, - solo_enc->vop_len); - - skip = solo_enc->vop_len; - - vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; - vb2_set_plane_payload(vb, 0, vh->mpeg_size + solo_enc->vop_len); - } else { - vb->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; - vb2_set_plane_payload(vb, 0, vh->mpeg_size); - } - - /* Now get the actual mpeg payload */ - frame_off = (vh->mpeg_off + sizeof(*vh)) - % SOLO_MP4E_EXT_SIZE(solo_dev); - frame_size = (vh->mpeg_size + skip + (DMA_ALIGN - 1)) - & ~(DMA_ALIGN - 1); - - dma_map_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages, - DMA_FROM_DEVICE); - ret = solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size, - SOLO_MP4E_EXT_ADDR(solo_dev), - SOLO_MP4E_EXT_SIZE(solo_dev)); - dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sglist, vbuf->num_pages, - DMA_FROM_DEVICE); - return ret; -} - -static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, - struct vb2_buffer *vb, struct solo_enc_buf *enc_buf) -{ - struct vop_header *vh = enc_buf->vh; - int ret; - - /* Check for motion flags */ - vb->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_MOTION_ON | - V4L2_BUF_FLAG_MOTION_DETECTED); - if (solo_is_motion_on(solo_enc)) { - vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_ON; - if (enc_buf->motion) - vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_DETECTED; - } - - if (solo_enc->fmt == V4L2_PIX_FMT_MPEG4) - ret = solo_fill_mpeg(solo_enc, vb, vh); - else - ret = solo_fill_jpeg(solo_enc, vb, vh); - - if (!ret) { - vb->v4l2_buf.sequence = solo_enc->sequence++; - vb->v4l2_buf.timestamp.tv_sec = vh->sec; - vb->v4l2_buf.timestamp.tv_usec = vh->usec; - } - - vb2_buffer_done(vb, ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - - return ret; -} - -static void solo_enc_handle_one(struct solo_enc_dev *solo_enc, - struct solo_enc_buf *enc_buf) -{ - struct solo_vb2_buf *vb; - unsigned long flags; - - mutex_lock(&solo_enc->lock); - if (solo_enc->type != enc_buf->type) - goto unlock; - - spin_lock_irqsave(&solo_enc->av_lock, flags); - if (list_empty(&solo_enc->vidq_active)) { - spin_unlock_irqrestore(&solo_enc->av_lock, flags); - goto unlock; - } - vb = list_first_entry(&solo_enc->vidq_active, struct solo_vb2_buf, list); - list_del(&vb->list); - spin_unlock_irqrestore(&solo_enc->av_lock, flags); - - solo_enc_fillbuf(solo_enc, &vb->vb, enc_buf); -unlock: - mutex_unlock(&solo_enc->lock); -} - -void solo_enc_v4l2_isr(struct solo_dev *solo_dev) -{ - wake_up_interruptible_all(&solo_dev->ring_thread_wait); -} - -static void solo_handle_ring(struct solo_dev *solo_dev) -{ - for (;;) { - struct solo_enc_dev *solo_enc; - struct solo_enc_buf enc_buf; - u32 mpeg_current, off; - u8 ch; - u8 cur_q; - - /* Check if the hardware has any new ones in the queue */ - cur_q = solo_reg_read(solo_dev, SOLO_VE_STATE(11)) & 0xff; - if (cur_q == solo_dev->enc_idx) - break; - - mpeg_current = solo_reg_read(solo_dev, - SOLO_VE_MPEG4_QUE(solo_dev->enc_idx)); - solo_dev->enc_idx = (solo_dev->enc_idx + 1) % MP4_QS; - - ch = (mpeg_current >> 24) & 0x1f; - off = mpeg_current & 0x00ffffff; - - if (ch >= SOLO_MAX_CHANNELS) { - ch -= SOLO_MAX_CHANNELS; - enc_buf.type = SOLO_ENC_TYPE_EXT; - } else - enc_buf.type = SOLO_ENC_TYPE_STD; - - solo_enc = solo_dev->v4l2_enc[ch]; - if (solo_enc == NULL) { - dev_err(&solo_dev->pdev->dev, - "Got spurious packet for channel %d\n", ch); - continue; - } - - /* FAIL... */ - if (enc_get_mpeg_dma(solo_dev, solo_dev->vh_dma, off, - sizeof(struct vop_header))) - continue; - - enc_buf.vh = (struct vop_header *)solo_dev->vh_buf; - enc_buf.vh->mpeg_off -= SOLO_MP4E_EXT_ADDR(solo_dev); - enc_buf.vh->jpeg_off -= SOLO_JPEG_EXT_ADDR(solo_dev); - - /* Sanity check */ - if (enc_buf.vh->mpeg_off != off) - continue; - - if (solo_motion_detected(solo_enc)) - enc_buf.motion = 1; - else - enc_buf.motion = 0; - - solo_enc_handle_one(solo_enc, &enc_buf); - } -} - -static int solo_ring_thread(void *data) -{ - struct solo_dev *solo_dev = data; - DECLARE_WAITQUEUE(wait, current); - - set_freezable(); - add_wait_queue(&solo_dev->ring_thread_wait, &wait); - - for (;;) { - long timeout = schedule_timeout_interruptible(HZ); - if (timeout == -ERESTARTSYS || kthread_should_stop()) - break; - solo_irq_off(solo_dev, SOLO_IRQ_ENCODER); - solo_handle_ring(solo_dev); - solo_irq_on(solo_dev, SOLO_IRQ_ENCODER); - try_to_freeze(); - } - - remove_wait_queue(&solo_dev->ring_thread_wait, &wait); - - return 0; -} - -static int solo_enc_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, - unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) -{ - sizes[0] = FRAME_BUF_SIZE; - *num_planes = 1; - - if (*num_buffers < MIN_VID_BUFFERS) - *num_buffers = MIN_VID_BUFFERS; - - return 0; -} - -static void solo_enc_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vq); - struct solo_vb2_buf *solo_vb = - container_of(vb, struct solo_vb2_buf, vb); - - spin_lock(&solo_enc->av_lock); - list_add_tail(&solo_vb->list, &solo_enc->vidq_active); - spin_unlock(&solo_enc->av_lock); -} - -static int solo_ring_start(struct solo_dev *solo_dev) -{ - solo_dev->ring_thread = kthread_run(solo_ring_thread, solo_dev, - SOLO6X10_NAME "_ring"); - if (IS_ERR(solo_dev->ring_thread)) { - int err = PTR_ERR(solo_dev->ring_thread); - solo_dev->ring_thread = NULL; - return err; - } - - solo_irq_on(solo_dev, SOLO_IRQ_ENCODER); - - return 0; -} - -static void solo_ring_stop(struct solo_dev *solo_dev) -{ - if (solo_dev->ring_thread) { - kthread_stop(solo_dev->ring_thread); - solo_dev->ring_thread = NULL; - } - - solo_irq_off(solo_dev, SOLO_IRQ_ENCODER); -} - -static int solo_enc_start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q); - int ret; - - ret = solo_enc_on(solo_enc); - if (ret) - return ret; - return solo_ring_start(solo_enc->solo_dev); -} - -static int solo_enc_stop_streaming(struct vb2_queue *q) -{ - struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q); - - solo_enc_off(solo_enc); - INIT_LIST_HEAD(&solo_enc->vidq_active); - solo_ring_stop(solo_enc->solo_dev); - return 0; -} - -static struct vb2_ops solo_enc_video_qops = { - .queue_setup = solo_enc_queue_setup, - .buf_queue = solo_enc_buf_queue, - .start_streaming = solo_enc_start_streaming, - .stop_streaming = solo_enc_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -static int solo_enc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - struct solo_dev *solo_dev = solo_enc->solo_dev; - - strcpy(cap->driver, SOLO6X10_NAME); - snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d", - solo_enc->ch); - snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", - pci_name(solo_dev->pdev)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; -} - -static int solo_enc_enum_input(struct file *file, void *priv, - struct v4l2_input *input) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - struct solo_dev *solo_dev = solo_enc->solo_dev; - - if (input->index) - return -EINVAL; - - snprintf(input->name, sizeof(input->name), "Encoder %d", - solo_enc->ch + 1); - input->type = V4L2_INPUT_TYPE_CAMERA; - input->std = solo_enc->vfd->tvnorms; - - if (!tw28_get_video_status(solo_dev, solo_enc->ch)) - input->status = V4L2_IN_ST_NO_SIGNAL; - - return 0; -} - -static int solo_enc_set_input(struct file *file, void *priv, - unsigned int index) -{ - if (index) - return -EINVAL; - - return 0; -} - -static int solo_enc_get_input(struct file *file, void *priv, - unsigned int *index) -{ - *index = 0; - - return 0; -} - -static int solo_enc_enum_fmt_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - switch (f->index) { - case 0: - f->pixelformat = V4L2_PIX_FMT_MPEG4; - strcpy(f->description, "MPEG-4 AVC"); - break; - case 1: - f->pixelformat = V4L2_PIX_FMT_MJPEG; - strcpy(f->description, "MJPEG"); - break; - default: - return -EINVAL; - } - - f->flags = V4L2_FMT_FLAG_COMPRESSED; - - return 0; -} - -static int solo_enc_try_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - struct solo_dev *solo_dev = solo_enc->solo_dev; - struct v4l2_pix_format *pix = &f->fmt.pix; - - if (pix->pixelformat != V4L2_PIX_FMT_MPEG4 && - pix->pixelformat != V4L2_PIX_FMT_MJPEG) - return -EINVAL; - - if (pix->width < solo_dev->video_hsize || - pix->height < solo_dev->video_vsize << 1) { - /* Default to CIF 1/2 size */ - pix->width = solo_dev->video_hsize >> 1; - pix->height = solo_dev->video_vsize; - } else { - /* Full frame */ - pix->width = solo_dev->video_hsize; - pix->height = solo_dev->video_vsize << 1; - } - - switch (pix->field) { - case V4L2_FIELD_NONE: - case V4L2_FIELD_INTERLACED: - break; - case V4L2_FIELD_ANY: - default: - pix->field = V4L2_FIELD_INTERLACED; - break; - } - - /* Just set these */ - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - pix->sizeimage = FRAME_BUF_SIZE; - pix->bytesperline = 0; - pix->priv = 0; - - return 0; -} - -static int solo_enc_set_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - struct solo_dev *solo_dev = solo_enc->solo_dev; - struct v4l2_pix_format *pix = &f->fmt.pix; - int ret; - - if (vb2_is_busy(&solo_enc->vidq)) - return -EBUSY; - - ret = solo_enc_try_fmt_cap(file, priv, f); - if (ret) - return ret; - - if (pix->width == solo_dev->video_hsize) - solo_enc->mode = SOLO_ENC_MODE_D1; - else - solo_enc->mode = SOLO_ENC_MODE_CIF; - - /* This does not change the encoder at all */ - solo_enc->fmt = pix->pixelformat; - - /* - * More information is needed about these 'extended' types. As far - * as I can tell these are basically additional video streams with - * different MPEG encoding attributes that can run in parallel with - * the main stream. If so, then this should be implemented as a - * second video node. Abusing priv like this is certainly not the - * right approach. - if (pix->priv) - solo_enc->type = SOLO_ENC_TYPE_EXT; - */ - return 0; -} - -static int solo_enc_get_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - struct v4l2_pix_format *pix = &f->fmt.pix; - - pix->width = solo_enc->width; - pix->height = solo_enc->height; - pix->pixelformat = solo_enc->fmt; - pix->field = solo_enc->interlaced ? V4L2_FIELD_INTERLACED : - V4L2_FIELD_NONE; - pix->sizeimage = FRAME_BUF_SIZE; - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - pix->priv = 0; - - return 0; -} - -static int solo_enc_g_std(struct file *file, void *priv, v4l2_std_id *i) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - struct solo_dev *solo_dev = solo_enc->solo_dev; - - if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) - *i = V4L2_STD_NTSC_M; - else - *i = V4L2_STD_PAL; - return 0; -} - -static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id std) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - - return solo_set_video_type(solo_enc->solo_dev, std & V4L2_STD_PAL); -} - -static int solo_enum_framesizes(struct file *file, void *priv, - struct v4l2_frmsizeenum *fsize) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - struct solo_dev *solo_dev = solo_enc->solo_dev; - - if (fsize->pixel_format != V4L2_PIX_FMT_MPEG4 && - fsize->pixel_format != V4L2_PIX_FMT_MJPEG) - return -EINVAL; - - switch (fsize->index) { - case 0: - fsize->discrete.width = solo_dev->video_hsize >> 1; - fsize->discrete.height = solo_dev->video_vsize; - break; - case 1: - fsize->discrete.width = solo_dev->video_hsize; - fsize->discrete.height = solo_dev->video_vsize << 1; - break; - default: - return -EINVAL; - } - - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - - return 0; -} - -static int solo_enum_frameintervals(struct file *file, void *priv, - struct v4l2_frmivalenum *fintv) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - struct solo_dev *solo_dev = solo_enc->solo_dev; - - if (fintv->pixel_format != V4L2_PIX_FMT_MPEG4 && - fintv->pixel_format != V4L2_PIX_FMT_MJPEG) - return -EINVAL; - if (fintv->index) - return -EINVAL; - if ((fintv->width != solo_dev->video_hsize >> 1 || - fintv->height != solo_dev->video_vsize) && - (fintv->width != solo_dev->video_hsize || - fintv->height != solo_dev->video_vsize << 1)) - return -EINVAL; - - fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE; - - fintv->stepwise.min.numerator = 1; - fintv->stepwise.min.denominator = solo_dev->fps; - - fintv->stepwise.max.numerator = 15; - fintv->stepwise.max.denominator = solo_dev->fps; - - fintv->stepwise.step.numerator = 1; - fintv->stepwise.step.denominator = solo_dev->fps; - - return 0; -} - -static int solo_g_parm(struct file *file, void *priv, - struct v4l2_streamparm *sp) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - struct solo_dev *solo_dev = solo_enc->solo_dev; - struct v4l2_captureparm *cp = &sp->parm.capture; - - cp->capability = V4L2_CAP_TIMEPERFRAME; - cp->timeperframe.numerator = solo_enc->interval; - cp->timeperframe.denominator = solo_dev->fps; - cp->capturemode = 0; - /* XXX: Shouldn't we be able to get/set this from videobuf? */ - cp->readbuffers = 2; - - return 0; -} - -static int solo_s_parm(struct file *file, void *priv, - struct v4l2_streamparm *sp) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - struct solo_dev *solo_dev = solo_enc->solo_dev; - struct v4l2_captureparm *cp = &sp->parm.capture; - - if (vb2_is_streaming(&solo_enc->vidq)) - return -EBUSY; - - if ((cp->timeperframe.numerator == 0) || - (cp->timeperframe.denominator == 0)) { - /* reset framerate */ - cp->timeperframe.numerator = 1; - cp->timeperframe.denominator = solo_dev->fps; - } - - if (cp->timeperframe.denominator != solo_dev->fps) - cp->timeperframe.denominator = solo_dev->fps; - - if (cp->timeperframe.numerator > 15) - cp->timeperframe.numerator = 15; - - solo_enc->interval = cp->timeperframe.numerator; - - cp->capability = V4L2_CAP_TIMEPERFRAME; - cp->readbuffers = 2; - - solo_update_mode(solo_enc); - return 0; -} - -static long solo_enc_default(struct file *file, void *fh, - bool valid_prio, int cmd, void *arg) -{ - struct solo_enc_dev *solo_enc = video_drvdata(file); - struct solo_dev *solo_dev = solo_enc->solo_dev; - struct solo_motion_thresholds *thresholds = arg; - - switch (cmd) { - case SOLO_IOC_G_MOTION_THRESHOLDS: - *thresholds = solo_enc->motion_thresholds; - return 0; - - case SOLO_IOC_S_MOTION_THRESHOLDS: - if (!valid_prio) - return -EBUSY; - solo_enc->motion_thresholds = *thresholds; - if (solo_enc->motion_enabled && !solo_enc->motion_global) - return solo_set_motion_block(solo_dev, solo_enc->ch, - &solo_enc->motion_thresholds); - return 0; - default: - return -ENOTTY; - } -} - -static int solo_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct solo_enc_dev *solo_enc = - container_of(ctrl->handler, struct solo_enc_dev, hdl); - struct solo_dev *solo_dev = solo_enc->solo_dev; - int err; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - case V4L2_CID_CONTRAST: - case V4L2_CID_SATURATION: - case V4L2_CID_HUE: - case V4L2_CID_SHARPNESS: - return tw28_set_ctrl_val(solo_dev, ctrl->id, solo_enc->ch, - ctrl->val); - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - solo_enc->gop = ctrl->val; - return 0; - case V4L2_CID_MOTION_THRESHOLD: - solo_enc->motion_thresh = ctrl->val; - if (!solo_enc->motion_global || !solo_enc->motion_enabled) - return 0; - return solo_set_motion_threshold(solo_dev, solo_enc->ch, ctrl->val); - case V4L2_CID_MOTION_MODE: - solo_enc->motion_global = ctrl->val == 1; - solo_enc->motion_enabled = ctrl->val > 0; - if (ctrl->val) { - if (solo_enc->motion_global) - solo_set_motion_threshold(solo_dev, solo_enc->ch, - solo_enc->motion_thresh); - else - solo_set_motion_block(solo_dev, solo_enc->ch, - &solo_enc->motion_thresholds); - } - solo_motion_toggle(solo_enc, ctrl->val); - return 0; - case V4L2_CID_OSD_TEXT: - strcpy(solo_enc->osd_text, ctrl->string); - err = solo_osd_print(solo_enc); - return err; - default: - return -EINVAL; - } - - return 0; -} - -static const struct v4l2_file_operations solo_enc_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vb2_fop_release, - .read = vb2_fop_read, - .poll = vb2_fop_poll, - .mmap = vb2_fop_mmap, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = { - .vidioc_querycap = solo_enc_querycap, - .vidioc_s_std = solo_enc_s_std, - .vidioc_g_std = solo_enc_g_std, - /* Input callbacks */ - .vidioc_enum_input = solo_enc_enum_input, - .vidioc_s_input = solo_enc_set_input, - .vidioc_g_input = solo_enc_get_input, - /* Video capture format callbacks */ - .vidioc_enum_fmt_vid_cap = solo_enc_enum_fmt_cap, - .vidioc_try_fmt_vid_cap = solo_enc_try_fmt_cap, - .vidioc_s_fmt_vid_cap = solo_enc_set_fmt_cap, - .vidioc_g_fmt_vid_cap = solo_enc_get_fmt_cap, - /* Streaming I/O */ - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - /* Frame size and interval */ - .vidioc_enum_framesizes = solo_enum_framesizes, - .vidioc_enum_frameintervals = solo_enum_frameintervals, - /* Video capture parameters */ - .vidioc_s_parm = solo_s_parm, - .vidioc_g_parm = solo_g_parm, - /* Logging and events */ - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - .vidioc_default = solo_enc_default, -}; - -static const struct video_device solo_enc_template = { - .name = SOLO6X10_NAME, - .fops = &solo_enc_fops, - .ioctl_ops = &solo_enc_ioctl_ops, - .minor = -1, - .release = video_device_release, - .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, -}; - -static const struct v4l2_ctrl_ops solo_ctrl_ops = { - .s_ctrl = solo_s_ctrl, -}; - -static const struct v4l2_ctrl_config solo_motion_threshold_ctrl = { - .ops = &solo_ctrl_ops, - .id = V4L2_CID_MOTION_THRESHOLD, - .name = "Motion Detection Threshold", - .type = V4L2_CTRL_TYPE_INTEGER, - .max = 0xffff, - .def = SOLO_DEF_MOT_THRESH, - .step = 1, - .flags = V4L2_CTRL_FLAG_SLIDER, -}; - -static const char * const solo_motion_mode_menu[] = { - "Disabled", - "Global Threshold", - "Regional Threshold", - NULL -}; - -static const struct v4l2_ctrl_config solo_motion_enable_ctrl = { - .ops = &solo_ctrl_ops, - .id = V4L2_CID_MOTION_MODE, - .name = "Motion Detection Mode", - .type = V4L2_CTRL_TYPE_MENU, - .qmenu = solo_motion_mode_menu, - .max = 2, -}; - -static const struct v4l2_ctrl_config solo_osd_text_ctrl = { - .ops = &solo_ctrl_ops, - .id = V4L2_CID_OSD_TEXT, - .name = "OSD Text", - .type = V4L2_CTRL_TYPE_STRING, - .max = OSD_TEXT_MAX, - .step = 1, -}; - -static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, - u8 ch, unsigned nr) -{ - struct solo_enc_dev *solo_enc; - struct v4l2_ctrl_handler *hdl; - int ret; - int x, y; - - solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL); - if (!solo_enc) - return ERR_PTR(-ENOMEM); - - hdl = &solo_enc->hdl; - v4l2_ctrl_handler_init(hdl, 10); - v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); - v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, 128); - v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, - V4L2_CID_SATURATION, 0, 255, 1, 128); - v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, - V4L2_CID_HUE, 0, 255, 1, 128); - if (tw28_has_sharpness(solo_dev, ch)) - v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, - V4L2_CID_SHARPNESS, 0, 15, 1, 0); - v4l2_ctrl_new_std(hdl, &solo_ctrl_ops, - V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps); - v4l2_ctrl_new_custom(hdl, &solo_motion_threshold_ctrl, NULL); - v4l2_ctrl_new_custom(hdl, &solo_motion_enable_ctrl, NULL); - v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL); - if (hdl->error) { - ret = hdl->error; - goto hdl_free; - } - - solo_enc->solo_dev = solo_dev; - solo_enc->ch = ch; - mutex_init(&solo_enc->lock); - spin_lock_init(&solo_enc->av_lock); - INIT_LIST_HEAD(&solo_enc->vidq_active); - solo_enc->fmt = V4L2_PIX_FMT_MPEG4; - solo_enc->type = SOLO_ENC_TYPE_STD; - - solo_enc->qp = SOLO_DEFAULT_QP; - solo_enc->gop = solo_dev->fps; - solo_enc->interval = 1; - solo_enc->mode = SOLO_ENC_MODE_CIF; - solo_enc->motion_global = true; - solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH; - for (y = 0; y < SOLO_MOTION_SZ; y++) - for (x = 0; x < SOLO_MOTION_SZ; x++) - solo_enc->motion_thresholds.thresholds[y][x] = - SOLO_DEF_MOT_THRESH; - - solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; - solo_enc->vidq.ops = &solo_enc_video_qops; - solo_enc->vidq.mem_ops = &vb2_dma_sg_memops; - solo_enc->vidq.drv_priv = solo_enc; - solo_enc->vidq.gfp_flags = __GFP_DMA32; - solo_enc->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - solo_enc->vidq.buf_struct_size = sizeof(struct solo_vb2_buf); - solo_enc->vidq.lock = &solo_enc->lock; - ret = vb2_queue_init(&solo_enc->vidq); - if (ret) - goto hdl_free; - solo_update_mode(solo_enc); - - spin_lock_init(&solo_enc->motion_lock); - - /* Initialize this per encoder */ - solo_enc->jpeg_len = sizeof(jpeg_header); - memcpy(solo_enc->jpeg_header, jpeg_header, solo_enc->jpeg_len); - - solo_enc->desc_nelts = 32; - solo_enc->desc_items = pci_alloc_consistent(solo_dev->pdev, - sizeof(struct solo_p2m_desc) * - solo_enc->desc_nelts, &solo_enc->desc_dma); - ret = -ENOMEM; - if (solo_enc->desc_items == NULL) - goto hdl_free; - - solo_enc->vfd = video_device_alloc(); - if (!solo_enc->vfd) - goto pci_free; - - *solo_enc->vfd = solo_enc_template; - solo_enc->vfd->v4l2_dev = &solo_dev->v4l2_dev; - solo_enc->vfd->ctrl_handler = hdl; - solo_enc->vfd->queue = &solo_enc->vidq; - solo_enc->vfd->lock = &solo_enc->lock; - set_bit(V4L2_FL_USE_FH_PRIO, &solo_enc->vfd->flags); - video_set_drvdata(solo_enc->vfd, solo_enc); - ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr); - if (ret < 0) - goto vdev_release; - - snprintf(solo_enc->vfd->name, sizeof(solo_enc->vfd->name), - "%s-enc (%i/%i)", SOLO6X10_NAME, solo_dev->vfd->num, - solo_enc->vfd->num); - - return solo_enc; - -vdev_release: - video_device_release(solo_enc->vfd); -pci_free: - pci_free_consistent(solo_enc->solo_dev->pdev, - sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts, - solo_enc->desc_items, solo_enc->desc_dma); -hdl_free: - v4l2_ctrl_handler_free(hdl); - kfree(solo_enc); - return ERR_PTR(ret); -} - -static void solo_enc_free(struct solo_enc_dev *solo_enc) -{ - if (solo_enc == NULL) - return; - - video_unregister_device(solo_enc->vfd); - v4l2_ctrl_handler_free(&solo_enc->hdl); - kfree(solo_enc); -} - -int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr) -{ - int i; - - init_waitqueue_head(&solo_dev->ring_thread_wait); - - solo_dev->vh_size = sizeof(struct vop_header); - solo_dev->vh_buf = pci_alloc_consistent(solo_dev->pdev, - solo_dev->vh_size, - &solo_dev->vh_dma); - if (solo_dev->vh_buf == NULL) - return -ENOMEM; - - for (i = 0; i < solo_dev->nr_chans; i++) { - solo_dev->v4l2_enc[i] = solo_enc_alloc(solo_dev, i, nr); - if (IS_ERR(solo_dev->v4l2_enc[i])) - break; - } - - if (i != solo_dev->nr_chans) { - int ret = PTR_ERR(solo_dev->v4l2_enc[i]); - while (i--) - solo_enc_free(solo_dev->v4l2_enc[i]); - pci_free_consistent(solo_dev->pdev, solo_dev->vh_size, - solo_dev->vh_buf, solo_dev->vh_dma); - solo_dev->vh_buf = NULL; - return ret; - } - - if (solo_dev->type == SOLO_DEV_6010) - solo_dev->enc_bw_remain = solo_dev->fps * 4 * 4; - else - solo_dev->enc_bw_remain = solo_dev->fps * 4 * 5; - - dev_info(&solo_dev->pdev->dev, "Encoders as /dev/video%d-%d\n", - solo_dev->v4l2_enc[0]->vfd->num, - solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num); - - return 0; -} - -void solo_enc_v4l2_exit(struct solo_dev *solo_dev) -{ - int i; - - for (i = 0; i < solo_dev->nr_chans; i++) - solo_enc_free(solo_dev->v4l2_enc[i]); - - if (solo_dev->vh_buf) - pci_free_consistent(solo_dev->pdev, solo_dev->vh_size, - solo_dev->vh_buf, solo_dev->vh_dma); -} diff --git a/drivers/staging/media/solo6x10/v4l2.c b/drivers/staging/media/solo6x10/v4l2.c deleted file mode 100644 index 7b26de3..0000000 --- a/drivers/staging/media/solo6x10/v4l2.c +++ /dev/null @@ -1,734 +0,0 @@ -/* - * Copyright (C) 2010-2013 Bluecherry, LLC - * - * Original author: - * Ben Collins - * - * Additional work by: - * John Brooks - * - * 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. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "solo6x10.h" -#include "solo6x10-tw28.h" - -/* Image size is two fields, SOLO_HW_BPL is one horizontal line in hardware */ -#define SOLO_HW_BPL 2048 -#define solo_vlines(__solo) (__solo->video_vsize * 2) -#define solo_image_size(__solo) (solo_bytesperline(__solo) * \ - solo_vlines(__solo)) -#define solo_bytesperline(__solo) (__solo->video_hsize * 2) - -#define MIN_VID_BUFFERS 2 - -static inline void erase_on(struct solo_dev *solo_dev) -{ - solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, SOLO_VO_DISP_ERASE_ON); - solo_dev->erasing = 1; - solo_dev->frame_blank = 0; -} - -static inline int erase_off(struct solo_dev *solo_dev) -{ - if (!solo_dev->erasing) - return 0; - - /* First time around, assert erase off */ - if (!solo_dev->frame_blank) - solo_reg_write(solo_dev, SOLO_VO_DISP_ERASE, 0); - /* Keep the erasing flag on for 8 frames minimum */ - if (solo_dev->frame_blank++ >= 8) - solo_dev->erasing = 0; - - return 1; -} - -void solo_video_in_isr(struct solo_dev *solo_dev) -{ - wake_up_interruptible_all(&solo_dev->disp_thread_wait); -} - -static void solo_win_setup(struct solo_dev *solo_dev, u8 ch, - int sx, int sy, int ex, int ey, int scale) -{ - if (ch >= solo_dev->nr_chans) - return; - - /* Here, we just keep window/channel the same */ - solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL0(ch), - SOLO_VI_WIN_CHANNEL(ch) | - SOLO_VI_WIN_SX(sx) | - SOLO_VI_WIN_EX(ex) | - SOLO_VI_WIN_SCALE(scale)); - - solo_reg_write(solo_dev, SOLO_VI_WIN_CTRL1(ch), - SOLO_VI_WIN_SY(sy) | - SOLO_VI_WIN_EY(ey)); -} - -static int solo_v4l2_ch_ext_4up(struct solo_dev *solo_dev, u8 idx, int on) -{ - u8 ch = idx * 4; - - if (ch >= solo_dev->nr_chans) - return -EINVAL; - - if (!on) { - u8 i; - for (i = ch; i < ch + 4; i++) - solo_win_setup(solo_dev, i, solo_dev->video_hsize, - solo_vlines(solo_dev), - solo_dev->video_hsize, - solo_vlines(solo_dev), 0); - return 0; - } - - /* Row 1 */ - solo_win_setup(solo_dev, ch, 0, 0, solo_dev->video_hsize / 2, - solo_vlines(solo_dev) / 2, 3); - solo_win_setup(solo_dev, ch + 1, solo_dev->video_hsize / 2, 0, - solo_dev->video_hsize, solo_vlines(solo_dev) / 2, 3); - /* Row 2 */ - solo_win_setup(solo_dev, ch + 2, 0, solo_vlines(solo_dev) / 2, - solo_dev->video_hsize / 2, solo_vlines(solo_dev), 3); - solo_win_setup(solo_dev, ch + 3, solo_dev->video_hsize / 2, - solo_vlines(solo_dev) / 2, solo_dev->video_hsize, - solo_vlines(solo_dev), 3); - - return 0; -} - -static int solo_v4l2_ch_ext_16up(struct solo_dev *solo_dev, int on) -{ - int sy, ysize, hsize, i; - - if (!on) { - for (i = 0; i < 16; i++) - solo_win_setup(solo_dev, i, solo_dev->video_hsize, - solo_vlines(solo_dev), - solo_dev->video_hsize, - solo_vlines(solo_dev), 0); - return 0; - } - - ysize = solo_vlines(solo_dev) / 4; - hsize = solo_dev->video_hsize / 4; - - for (sy = 0, i = 0; i < 4; i++, sy += ysize) { - solo_win_setup(solo_dev, i * 4, 0, sy, hsize, - sy + ysize, 5); - solo_win_setup(solo_dev, (i * 4) + 1, hsize, sy, - hsize * 2, sy + ysize, 5); - solo_win_setup(solo_dev, (i * 4) + 2, hsize * 2, sy, - hsize * 3, sy + ysize, 5); - solo_win_setup(solo_dev, (i * 4) + 3, hsize * 3, sy, - solo_dev->video_hsize, sy + ysize, 5); - } - - return 0; -} - -static int solo_v4l2_ch(struct solo_dev *solo_dev, u8 ch, int on) -{ - u8 ext_ch; - - if (ch < solo_dev->nr_chans) { - solo_win_setup(solo_dev, ch, on ? 0 : solo_dev->video_hsize, - on ? 0 : solo_vlines(solo_dev), - solo_dev->video_hsize, solo_vlines(solo_dev), - on ? 1 : 0); - return 0; - } - - if (ch >= solo_dev->nr_chans + solo_dev->nr_ext) - return -EINVAL; - - ext_ch = ch - solo_dev->nr_chans; - - /* 4up's first */ - if (ext_ch < 4) - return solo_v4l2_ch_ext_4up(solo_dev, ext_ch, on); - - /* Remaining case is 16up for 16-port */ - return solo_v4l2_ch_ext_16up(solo_dev, on); -} - -static int solo_v4l2_set_ch(struct solo_dev *solo_dev, u8 ch) -{ - if (ch >= solo_dev->nr_chans + solo_dev->nr_ext) - return -EINVAL; - - erase_on(solo_dev); - - solo_v4l2_ch(solo_dev, solo_dev->cur_disp_ch, 0); - solo_v4l2_ch(solo_dev, ch, 1); - - solo_dev->cur_disp_ch = ch; - - return 0; -} - -static void solo_fillbuf(struct solo_dev *solo_dev, - struct vb2_buffer *vb) -{ - dma_addr_t vbuf; - unsigned int fdma_addr; - int error = -1; - int i; - - vbuf = vb2_dma_contig_plane_dma_addr(vb, 0); - if (!vbuf) - goto finish_buf; - - if (erase_off(solo_dev)) { - void *p = vb2_plane_vaddr(vb, 0); - int image_size = solo_image_size(solo_dev); - for (i = 0; i < image_size; i += 2) { - ((u8 *)p)[i] = 0x80; - ((u8 *)p)[i + 1] = 0x00; - } - error = 0; - } else { - fdma_addr = SOLO_DISP_EXT_ADDR + (solo_dev->old_write * - (SOLO_HW_BPL * solo_vlines(solo_dev))); - - error = solo_p2m_dma_t(solo_dev, 0, vbuf, fdma_addr, - solo_bytesperline(solo_dev), - solo_vlines(solo_dev), SOLO_HW_BPL); - } - -finish_buf: - if (!error) { - vb2_set_plane_payload(vb, 0, - solo_vlines(solo_dev) * solo_bytesperline(solo_dev)); - vb->v4l2_buf.sequence = solo_dev->sequence++; - v4l2_get_timestamp(&vb->v4l2_buf.timestamp); - } - - vb2_buffer_done(vb, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); -} - -static void solo_thread_try(struct solo_dev *solo_dev) -{ - struct solo_vb2_buf *vb; - - /* Only "break" from this loop if slock is held, otherwise - * just return. */ - for (;;) { - unsigned int cur_write; - - cur_write = SOLO_VI_STATUS0_PAGE( - solo_reg_read(solo_dev, SOLO_VI_STATUS0)); - if (cur_write == solo_dev->old_write) - return; - - spin_lock(&solo_dev->slock); - - if (list_empty(&solo_dev->vidq_active)) - break; - - vb = list_first_entry(&solo_dev->vidq_active, struct solo_vb2_buf, - list); - - solo_dev->old_write = cur_write; - list_del(&vb->list); - - spin_unlock(&solo_dev->slock); - - solo_fillbuf(solo_dev, &vb->vb); - } - - assert_spin_locked(&solo_dev->slock); - spin_unlock(&solo_dev->slock); -} - -static int solo_thread(void *data) -{ - struct solo_dev *solo_dev = data; - DECLARE_WAITQUEUE(wait, current); - - set_freezable(); - add_wait_queue(&solo_dev->disp_thread_wait, &wait); - - for (;;) { - long timeout = schedule_timeout_interruptible(HZ); - if (timeout == -ERESTARTSYS || kthread_should_stop()) - break; - solo_thread_try(solo_dev); - try_to_freeze(); - } - - remove_wait_queue(&solo_dev->disp_thread_wait, &wait); - - return 0; -} - -static int solo_start_thread(struct solo_dev *solo_dev) -{ - int ret = 0; - - solo_dev->kthread = kthread_run(solo_thread, solo_dev, SOLO6X10_NAME "_disp"); - - if (IS_ERR(solo_dev->kthread)) { - ret = PTR_ERR(solo_dev->kthread); - solo_dev->kthread = NULL; - return ret; - } - solo_irq_on(solo_dev, SOLO_IRQ_VIDEO_IN); - - return ret; -} - -static void solo_stop_thread(struct solo_dev *solo_dev) -{ - if (!solo_dev->kthread) - return; - - solo_irq_off(solo_dev, SOLO_IRQ_VIDEO_IN); - kthread_stop(solo_dev->kthread); - solo_dev->kthread = NULL; -} - -static int solo_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, - unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], void *alloc_ctxs[]) -{ - struct solo_dev *solo_dev = vb2_get_drv_priv(q); - - sizes[0] = solo_image_size(solo_dev); - alloc_ctxs[0] = solo_dev->alloc_ctx; - *num_planes = 1; - - if (*num_buffers < MIN_VID_BUFFERS) - *num_buffers = MIN_VID_BUFFERS; - - return 0; -} - -static int solo_start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct solo_dev *solo_dev = vb2_get_drv_priv(q); - - solo_dev->sequence = 0; - return solo_start_thread(solo_dev); -} - -static int solo_stop_streaming(struct vb2_queue *q) -{ - struct solo_dev *solo_dev = vb2_get_drv_priv(q); - - solo_stop_thread(solo_dev); - INIT_LIST_HEAD(&solo_dev->vidq_active); - return 0; -} - -static void solo_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct solo_dev *solo_dev = vb2_get_drv_priv(vq); - struct solo_vb2_buf *solo_vb = - container_of(vb, struct solo_vb2_buf, vb); - - spin_lock(&solo_dev->slock); - list_add_tail(&solo_vb->list, &solo_dev->vidq_active); - spin_unlock(&solo_dev->slock); - wake_up_interruptible(&solo_dev->disp_thread_wait); -} - -static const struct vb2_ops solo_video_qops = { - .queue_setup = solo_queue_setup, - .buf_queue = solo_buf_queue, - .start_streaming = solo_start_streaming, - .stop_streaming = solo_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -static int solo_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct solo_dev *solo_dev = video_drvdata(file); - - strcpy(cap->driver, SOLO6X10_NAME); - strcpy(cap->card, "Softlogic 6x10"); - snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", - pci_name(solo_dev->pdev)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; -} - -static int solo_enum_ext_input(struct solo_dev *solo_dev, - struct v4l2_input *input) -{ - static const char * const dispnames_1[] = { "4UP" }; - static const char * const dispnames_2[] = { "4UP-1", "4UP-2" }; - static const char * const dispnames_5[] = { - "4UP-1", "4UP-2", "4UP-3", "4UP-4", "16UP" - }; - const char * const *dispnames; - - if (input->index >= (solo_dev->nr_chans + solo_dev->nr_ext)) - return -EINVAL; - - if (solo_dev->nr_ext == 5) - dispnames = dispnames_5; - else if (solo_dev->nr_ext == 2) - dispnames = dispnames_2; - else - dispnames = dispnames_1; - - snprintf(input->name, sizeof(input->name), "Multi %s", - dispnames[input->index - solo_dev->nr_chans]); - - return 0; -} - -static int solo_enum_input(struct file *file, void *priv, - struct v4l2_input *input) -{ - struct solo_dev *solo_dev = video_drvdata(file); - - if (input->index >= solo_dev->nr_chans) { - int ret = solo_enum_ext_input(solo_dev, input); - if (ret < 0) - return ret; - } else { - snprintf(input->name, sizeof(input->name), "Camera %d", - input->index + 1); - - /* We can only check this for normal inputs */ - if (!tw28_get_video_status(solo_dev, input->index)) - input->status = V4L2_IN_ST_NO_SIGNAL; - } - - input->type = V4L2_INPUT_TYPE_CAMERA; - input->std = solo_dev->vfd->tvnorms; - return 0; -} - -static int solo_set_input(struct file *file, void *priv, unsigned int index) -{ - struct solo_dev *solo_dev = video_drvdata(file); - int ret = solo_v4l2_set_ch(solo_dev, index); - - if (!ret) { - while (erase_off(solo_dev)) - /* Do nothing */; - } - - return ret; -} - -static int solo_get_input(struct file *file, void *priv, unsigned int *index) -{ - struct solo_dev *solo_dev = video_drvdata(file); - - *index = solo_dev->cur_disp_ch; - - return 0; -} - -static int solo_enum_fmt_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - if (f->index) - return -EINVAL; - - f->pixelformat = V4L2_PIX_FMT_UYVY; - strlcpy(f->description, "UYUV 4:2:2 Packed", sizeof(f->description)); - - return 0; -} - -static int solo_try_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct solo_dev *solo_dev = video_drvdata(file); - struct v4l2_pix_format *pix = &f->fmt.pix; - int image_size = solo_image_size(solo_dev); - - if (pix->pixelformat != V4L2_PIX_FMT_UYVY) - return -EINVAL; - - pix->width = solo_dev->video_hsize; - pix->height = solo_vlines(solo_dev); - pix->sizeimage = image_size; - pix->field = V4L2_FIELD_INTERLACED; - pix->pixelformat = V4L2_PIX_FMT_UYVY; - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - pix->priv = 0; - return 0; -} - -static int solo_set_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct solo_dev *solo_dev = video_drvdata(file); - - if (vb2_is_busy(&solo_dev->vidq)) - return -EBUSY; - - /* For right now, if it doesn't match our running config, - * then fail */ - return solo_try_fmt_cap(file, priv, f); -} - -static int solo_get_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct solo_dev *solo_dev = video_drvdata(file); - struct v4l2_pix_format *pix = &f->fmt.pix; - - pix->width = solo_dev->video_hsize; - pix->height = solo_vlines(solo_dev); - pix->pixelformat = V4L2_PIX_FMT_UYVY; - pix->field = V4L2_FIELD_INTERLACED; - pix->sizeimage = solo_image_size(solo_dev); - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - pix->bytesperline = solo_bytesperline(solo_dev); - pix->priv = 0; - - return 0; -} - -static int solo_g_std(struct file *file, void *priv, v4l2_std_id *i) -{ - struct solo_dev *solo_dev = video_drvdata(file); - - if (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) - *i = V4L2_STD_NTSC_M; - else - *i = V4L2_STD_PAL; - return 0; -} - -int solo_set_video_type(struct solo_dev *solo_dev, bool type) -{ - int i; - - /* Make sure all video nodes are idle */ - if (vb2_is_busy(&solo_dev->vidq)) - return -EBUSY; - for (i = 0; i < solo_dev->nr_chans; i++) - if (vb2_is_busy(&solo_dev->v4l2_enc[i]->vidq)) - return -EBUSY; - solo_dev->video_type = type; - /* Reconfigure for the new standard */ - solo_disp_init(solo_dev); - solo_enc_init(solo_dev); - solo_tw28_init(solo_dev); - for (i = 0; i < solo_dev->nr_chans; i++) - solo_update_mode(solo_dev->v4l2_enc[i]); - return solo_v4l2_set_ch(solo_dev, solo_dev->cur_disp_ch); -} - -static int solo_s_std(struct file *file, void *priv, v4l2_std_id std) -{ - struct solo_dev *solo_dev = video_drvdata(file); - - return solo_set_video_type(solo_dev, std & V4L2_STD_PAL); -} - -static int solo_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct solo_dev *solo_dev = - container_of(ctrl->handler, struct solo_dev, disp_hdl); - - switch (ctrl->id) { - case V4L2_CID_MOTION_TRACE: - if (ctrl->val) { - solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, - SOLO_VI_MOTION_Y_ADD | - SOLO_VI_MOTION_Y_VALUE(0x20) | - SOLO_VI_MOTION_CB_VALUE(0x10) | - SOLO_VI_MOTION_CR_VALUE(0x10)); - solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, - SOLO_VI_MOTION_CR_ADD | - SOLO_VI_MOTION_Y_VALUE(0x10) | - SOLO_VI_MOTION_CB_VALUE(0x80) | - SOLO_VI_MOTION_CR_VALUE(0x10)); - } else { - solo_reg_write(solo_dev, SOLO_VI_MOTION_BORDER, 0); - solo_reg_write(solo_dev, SOLO_VI_MOTION_BAR, 0); - } - return 0; - default: - break; - } - return -EINVAL; -} - -static const struct v4l2_file_operations solo_v4l2_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vb2_fop_release, - .read = vb2_fop_read, - .poll = vb2_fop_poll, - .mmap = vb2_fop_mmap, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops solo_v4l2_ioctl_ops = { - .vidioc_querycap = solo_querycap, - .vidioc_s_std = solo_s_std, - .vidioc_g_std = solo_g_std, - /* Input callbacks */ - .vidioc_enum_input = solo_enum_input, - .vidioc_s_input = solo_set_input, - .vidioc_g_input = solo_get_input, - /* Video capture format callbacks */ - .vidioc_enum_fmt_vid_cap = solo_enum_fmt_cap, - .vidioc_try_fmt_vid_cap = solo_try_fmt_cap, - .vidioc_s_fmt_vid_cap = solo_set_fmt_cap, - .vidioc_g_fmt_vid_cap = solo_get_fmt_cap, - /* Streaming I/O */ - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - /* Logging and events */ - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static struct video_device solo_v4l2_template = { - .name = SOLO6X10_NAME, - .fops = &solo_v4l2_fops, - .ioctl_ops = &solo_v4l2_ioctl_ops, - .minor = -1, - .release = video_device_release, - .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, -}; - -static const struct v4l2_ctrl_ops solo_ctrl_ops = { - .s_ctrl = solo_s_ctrl, -}; - -static const struct v4l2_ctrl_config solo_motion_trace_ctrl = { - .ops = &solo_ctrl_ops, - .id = V4L2_CID_MOTION_TRACE, - .name = "Motion Detection Trace", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - -int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) -{ - int ret; - int i; - - init_waitqueue_head(&solo_dev->disp_thread_wait); - spin_lock_init(&solo_dev->slock); - mutex_init(&solo_dev->lock); - INIT_LIST_HEAD(&solo_dev->vidq_active); - - solo_dev->vfd = video_device_alloc(); - if (!solo_dev->vfd) - return -ENOMEM; - - *solo_dev->vfd = solo_v4l2_template; - solo_dev->vfd->v4l2_dev = &solo_dev->v4l2_dev; - solo_dev->vfd->queue = &solo_dev->vidq; - solo_dev->vfd->lock = &solo_dev->lock; - v4l2_ctrl_handler_init(&solo_dev->disp_hdl, 1); - v4l2_ctrl_new_custom(&solo_dev->disp_hdl, &solo_motion_trace_ctrl, NULL); - if (solo_dev->disp_hdl.error) { - ret = solo_dev->disp_hdl.error; - goto fail; - } - solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl; - set_bit(V4L2_FL_USE_FH_PRIO, &solo_dev->vfd->flags); - - video_set_drvdata(solo_dev->vfd, solo_dev); - - solo_dev->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - solo_dev->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; - solo_dev->vidq.ops = &solo_video_qops; - solo_dev->vidq.mem_ops = &vb2_dma_contig_memops; - solo_dev->vidq.drv_priv = solo_dev; - solo_dev->vidq.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - solo_dev->vidq.gfp_flags = __GFP_DMA32; - solo_dev->vidq.buf_struct_size = sizeof(struct solo_vb2_buf); - solo_dev->vidq.lock = &solo_dev->lock; - ret = vb2_queue_init(&solo_dev->vidq); - if (ret < 0) - goto fail; - - solo_dev->alloc_ctx = vb2_dma_contig_init_ctx(&solo_dev->pdev->dev); - if (IS_ERR(solo_dev->alloc_ctx)) { - dev_err(&solo_dev->pdev->dev, "Can't allocate buffer context"); - return PTR_ERR(solo_dev->alloc_ctx); - } - - /* Cycle all the channels and clear */ - for (i = 0; i < solo_dev->nr_chans; i++) { - solo_v4l2_set_ch(solo_dev, i); - while (erase_off(solo_dev)) - /* Do nothing */; - } - - /* Set the default display channel */ - solo_v4l2_set_ch(solo_dev, 0); - while (erase_off(solo_dev)) - /* Do nothing */; - - ret = video_register_device(solo_dev->vfd, VFL_TYPE_GRABBER, nr); - if (ret < 0) - goto fail; - - snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)", - SOLO6X10_NAME, solo_dev->vfd->num); - - dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with " - "%d inputs (%d extended)\n", solo_dev->vfd->num, - solo_dev->nr_chans, solo_dev->nr_ext); - - return 0; - -fail: - video_device_release(solo_dev->vfd); - vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx); - v4l2_ctrl_handler_free(&solo_dev->disp_hdl); - solo_dev->vfd = NULL; - return ret; -} - -void solo_v4l2_exit(struct solo_dev *solo_dev) -{ - if (solo_dev->vfd == NULL) - return; - - video_unregister_device(solo_dev->vfd); - vb2_dma_contig_cleanup_ctx(solo_dev->alloc_ctx); - v4l2_ctrl_handler_free(&solo_dev->disp_hdl); - solo_dev->vfd = NULL; -} -- cgit v0.10.2 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 diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 70827fe..02bb5e7 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 v0.10.2 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 diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index b81f274..a9e7703 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 v0.10.2 From 820eac0ef8b86f7275acd1f8bccfb0b30f17bbe9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 18 Mar 2013 13:20:00 -0300 Subject: [media] DocBook media: fix syntax problems in dvbproperty.xml Caught by xmllint. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml index 31dc4df..a9b15e3 100644 --- a/Documentation/DocBook/media/dvb/dvbproperty.xml +++ b/Documentation/DocBook/media/dvb/dvbproperty.xml @@ -903,14 +903,12 @@ enum fe_interleaving { svalue is for signed values of the measure (dB measures) and uvalue is for unsigned values (counters, relative scale) scale - Scale for the value. It can be: -
- + FE_SCALE_NOT_AVAILABLE - The parameter is supported by the frontend, but it was not possible to collect it (could be a transitory or permanent condition) FE_SCALE_DECIBEL - parameter is a signed value, measured in 1/1000 dB FE_SCALE_RELATIVE - parameter is a unsigned value, where 0 means 0% and 65535 means 100%. FE_SCALE_COUNTER - parameter is a unsigned value that counts the occurrence of an event, like bit error, block error, or lapsed time. -
@@ -918,9 +916,9 @@ enum fe_interleaving { Indicates the signal strength level at the analog part of the tuner or of the demod. Possible scales for this metric are: - FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. - FE_SCALE_DECIBEL - signal strength is in 0.0001 dBm units, power measured in miliwatts. This value is generally negative. - FE_SCALE_RELATIVE - The frontend provides a 0% to 100% measurement for power (actually, 0 to 65535). + FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. + FE_SCALE_DECIBEL - signal strength is in 0.0001 dBm units, power measured in miliwatts. This value is generally negative. + FE_SCALE_RELATIVE - The frontend provides a 0% to 100% measurement for power (actually, 0 to 65535).
@@ -928,9 +926,9 @@ enum fe_interleaving { Indicates the Signal to Noise ratio for the main carrier. Possible scales for this metric are: - FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. - FE_SCALE_DECIBEL - Signal/Noise ratio is in 0.0001 dB units. - FE_SCALE_RELATIVE - The frontend provides a 0% to 100% measurement for Signal/Noise (actually, 0 to 65535). + FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. + FE_SCALE_DECIBEL - Signal/Noise ratio is in 0.0001 dB units. + FE_SCALE_RELATIVE - The frontend provides a 0% to 100% measurement for Signal/Noise (actually, 0 to 65535).
@@ -943,8 +941,8 @@ enum fe_interleaving { The frontend may reset it when a channel/transponder is tuned. Possible scales for this metric are: - FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. - FE_SCALE_COUNTER - Number of error bits counted before the inner coding. + FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. + FE_SCALE_COUNTER - Number of error bits counted before the inner coding.
@@ -957,9 +955,9 @@ enum fe_interleaving { The frontend may reset it when a channel/transponder is tuned. Possible scales for this metric are: - FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. - FE_SCALE_COUNTER - Number of bits counted while measuring - DTV_STAT_PRE_ERROR_BIT_COUNT. + FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. + FE_SCALE_COUNTER - Number of bits counted while measuring + DTV_STAT_PRE_ERROR_BIT_COUNT.
@@ -972,8 +970,8 @@ enum fe_interleaving { The frontend may reset it when a channel/transponder is tuned. Possible scales for this metric are: - FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. - FE_SCALE_COUNTER - Number of error bits counted after the inner coding. + FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. + FE_SCALE_COUNTER - Number of error bits counted after the inner coding.
@@ -986,9 +984,9 @@ enum fe_interleaving { The frontend may reset it when a channel/transponder is tuned. Possible scales for this metric are: - FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. - FE_SCALE_COUNTER - Number of bits counted while measuring - DTV_STAT_POST_ERROR_BIT_COUNT. + FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. + FE_SCALE_COUNTER - Number of bits counted while measuring + DTV_STAT_POST_ERROR_BIT_COUNT.
@@ -998,8 +996,8 @@ enum fe_interleaving { The frontend may reset it when a channel/transponder is tuned. Possible scales for this metric are: - FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. - FE_SCALE_COUNTER - Number of error blocks counted after the outer coding. + FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. + FE_SCALE_COUNTER - Number of error blocks counted after the outer coding.
@@ -1011,9 +1009,9 @@ enum fe_interleaving { by DTV-STAT-TOTAL-BLOCK-COUNT. Possible scales for this metric are: - FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. - FE_SCALE_COUNTER - Number of blocks counted while measuring - DTV_STAT_ERROR_BLOCK_COUNT. + FE_SCALE_NOT_AVAILABLE - it failed to measure it, or the measurement was not complete yet. + FE_SCALE_COUNTER - Number of blocks counted while measuring + DTV_STAT_ERROR_BLOCK_COUNT.
-- cgit v0.10.2 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 diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index a9e7703..f8fac9c 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 1fbd957..670b9ca 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 83aa39d..336ed2d 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 e10c243..75a7dfc 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 9d57dba..e9c49c5 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 v0.10.2 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 diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index c4c723b..a59153d2 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index d09b5c0..b181723 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 v0.10.2 From b5958dc329f0e4584511c5d8a177122e3d23a657 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 18 Mar 2013 13:28:12 -0300 Subject: [media] DocBook media: add VIDIOC_DBG_G_CHIP_NAME documentation And update the other debug ioctls accordingly. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index dae009a..ec3a0c7 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -156,8 +156,7 @@ applications. --> 2012-12-03 sa, sn Added timestamp types to v4l2_buffer. - Added V4L2_EVENT_CTRL_CH_RANGE control - event changes flag, see . + Added V4L2_EVENT_CTRL_CH_RANGE control event changes flag. @@ -549,6 +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-register; &sub-decoder-cmd; &sub-dqevent; 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 4ecd966..82e43c6 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-ident.xml @@ -200,10 +200,10 @@ the values from . &cs-def; - V4L2_CHIP_MATCH_HOST + V4L2_CHIP_MATCH_BRIDGE 0 Match the nth chip on the card, zero for the - host chip. Does not match &i2c; chips. + bridge chip. Does not match sub-devices. V4L2_CHIP_MATCH_I2C_DRIVER @@ -220,6 +220,16 @@ the values from . 3 Match the nth anciliary AC97 chip. + + V4L2_CHIP_MATCH_SUBDEV_NAME + 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 new file mode 100644 index 0000000..4921346 --- /dev/null +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-name.xml @@ -0,0 +1,234 @@ + + + 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. + + 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_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, +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_NAME + 4 + Match the sub-device by name. + + + V4L2_CHIP_MATCH_SUBDEV_IDX + 5 + 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 a44aebc..3082b41 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml @@ -87,7 +87,7 @@ written into the register. To read a register applications must initialize the match.type, -match.chip or match.name and +match.addr or match.name and reg fields, and call VIDIOC_DBG_G_REGISTER with a pointer to this structure. On success the driver stores the register value in the @@ -95,11 +95,11 @@ structure. On success the driver stores the register value in the unchanged. When match.type is -V4L2_CHIP_MATCH_HOST, -match.addr selects the nth non-&i2c; chip +V4L2_CHIP_MATCH_BRIDGE, +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-IDENT; ioctl. +present with the &VIDIOC-DBG-G-CHIP-NAME; 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-IDENT; ioctl you can find out which &i2c; chips are +&VIDIOC-DBG-G-CHIP-NAME; ioctl you can find out which &i2c; chips are present. When match.type is @@ -122,19 +122,31 @@ bus address. match.addr selects the nth AC97 chip 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, +match.addr selects the nth sub-device. + Success not guaranteed 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-IDENT; +catch the most likely failure we recommend a &VIDIOC-DBG-G-CHIP-NAME; 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-IDENT;. Conversely it may support -VIDIOC_DBG_G_CHIP_IDENT but not these ioctls. +&VIDIOC-DBG-G-CHIP-NAME;. Conversely it may support +VIDIOC_DBG_G_CHIP_NAME but not these ioctls. VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER were introduced in Linux @@ -217,10 +229,10 @@ register. &cs-def; - V4L2_CHIP_MATCH_HOST + V4L2_CHIP_MATCH_BRIDGE 0 Match the nth chip on the card, zero for the - host chip. Does not match &i2c; chips. + bridge chip. Does not match sub-devices. V4L2_CHIP_MATCH_I2C_DRIVER @@ -237,6 +249,16 @@ register. 3 Match the nth anciliary AC97 chip. + + V4L2_CHIP_MATCH_SUBDEV_NAME + 4 + Match the sub-device by name. + + + V4L2_CHIP_MATCH_SUBDEV_IDX + 5 + Match the nth sub-device. + -- cgit v0.10.2 From e3f7586310e80be3f75fe03dabda0a64f54d6d73 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Mar 2013 08:49:15 -0300 Subject: [media] DocBook media: document 3.10 changes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index 5dab338..8c2b368 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2503,6 +2503,10 @@ that used it. It was originally scheduled for removal in 2.6.35. flags V4L2_IN_CAP_PRESETS and V4L2_OUT_CAP_PRESETS. + + Added new debugging ioctl &VIDIOC-DBG-G-CHIP-NAME;. + + diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index ec3a0c7..c1f3340 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -142,12 +142,12 @@ applications. --> 3.10 - 2013-03-24 + 2013-03-25 hv 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. + flags V4L2_IN_CAP_PRESETS and V4L2_OUT_CAP_PRESETS. Added VIDIOC_DBG_G_CHIP_NAME. -- cgit v0.10.2 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 diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c index 526902b..ad46a8f 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 0529699..aa0f16d 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 v0.10.2 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 diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 79f1d510..ba90ffb 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 v0.10.2 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 diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index ba90ffb..8562cca 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 v0.10.2 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 diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 8562cca..d0a438a 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 v0.10.2 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 diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index d0a438a..28071ff 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 v0.10.2 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 diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 1e6f40e..ffd3bcb 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 28071ff..afb600f 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 e579ff6..803af10 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 v0.10.2 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 diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index afb600f..97397a6 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 803af10..ad40048 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 v0.10.2 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 diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 97397a6..5cec18b 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 v0.10.2 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 diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 5cec18b..691df91 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 ad40048..ef1f57f 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c index ad46a8f..2099f21 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 v0.10.2 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 diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index ffd3bcb..bd9d19a 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 691df91..3b525cb 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 v0.10.2 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 diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 3b525cb..2f24e54 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 v0.10.2 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 diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 2f24e54..6f2a626 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 v0.10.2 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 diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 6f2a626..a90a0b9 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 v0.10.2 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 diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index a90a0b9..75ac994 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 v0.10.2 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 diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index f775768..dd8a803 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 v0.10.2 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 diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index dd8a803..5e18f44 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 v0.10.2 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 diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index 5e18f44..f1e8b40 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 v0.10.2 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 diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index f1e8b40..cf9a9af 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index b1f7059..b638fc1 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 v0.10.2 From 02745f63443c08b9b82ab2d654a0f5fc3699e586 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 26 Mar 2013 04:45:11 -0300 Subject: [media] go7007: fix invalid use of sizeof in go7007_usb_i2c_master_xfer() sizeof() when applied to a pointer typed expression gives the size of the pointer, not that of the pointed data. Signed-off-by: Wei Yongjun Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/staging/media/go7007/go7007-usb.c index a734ead..50066e0 100644 --- a/drivers/staging/media/go7007/go7007-usb.c +++ b/drivers/staging/media/go7007/go7007-usb.c @@ -1037,7 +1037,7 @@ static int go7007_usb_i2c_master_xfer(struct i2c_adapter *adapter, buf, buf_len, 0) < 0) goto i2c_done; if (msgs[i].flags & I2C_M_RD) { - memset(buf, 0, sizeof(buf)); + memset(buf, 0, msgs[i].len + 1); if (go7007_usb_vendor_request(go, 0x25, 0, 0, buf, msgs[i].len + 1, 1) < 0) goto i2c_done; -- cgit v0.10.2 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 diff --git a/drivers/media/dvb-frontends/au8522.h b/drivers/media/dvb-frontends/au8522.h index f2111e0..83fe9a6 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index cb7cdd3..033b6cb 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 704f283..4851cc2 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 @@ -279,6 +280,183 @@ static int em28xx_i2c_check_for_device(struct em28xx *dev, u16 addr) } /* + * 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 4c667fd..aeee896 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 033b6cb..54e0362 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 8fd3c7f..1b0ecd6 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 aeee896..7be008f 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index b181723..ef1959b 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index b2dcb3d..575a46a 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 575a46a..a802128 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 1b0ecd6..622871d 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 v0.10.2 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 diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 61e28de..a2f4501 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 54e0362..0962063 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 0962063..c1397db 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index c1397db..de15cdf 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index de15cdf..b745860 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/Makefile b/drivers/media/usb/em28xx/Makefile index 634fb92..ad6d485 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 0000000..28dd848 --- /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 b745860..1d3866f 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 7be008f..a14492f 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 28dd848..2e4856a 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 2e4856a..d744af6 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index d744af6..e8b3322 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index e8b3322..64b70d4 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 64b70d4..73cc50a 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 a14492f..a9323b6 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 v0.10.2 From 2f9e96c39fb4cc0680ccf2ec155133249174780c Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Tue, 26 Mar 2013 11:23:28 -0300 Subject: [media] staging: davinci: Fix typo in staging/media/davinci Correct spelling typo in staging/media/davinci Signed-off-by: Masanari Iida Signed-off-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt b/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt index 1dbd564..a1e9177 100644 --- a/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt +++ b/drivers/staging/media/davinci_vpfe/davinci-vpfe-mc.txt @@ -38,7 +38,7 @@ interface to userspace. DAVINCI RESIZER A DAVINCI RESIZER B -Each possible link in the VPFE is modeled by a link in the Media controller +Each possible link in the VPFE is modelled by a link in the Media controller interface. For an example program see [1]. diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c index c4a5660..5829360 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_isif.c +++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c @@ -685,7 +685,7 @@ static void isif_config_bclamp(struct vpfe_isif_device *isif, val = (bc->bc_mode_color & ISIF_BC_MODE_COLOR_MASK) << ISIF_BC_MODE_COLOR_SHIFT; - /* Enable BC and horizontal clamp caculation paramaters */ + /* Enable BC and horizontal clamp calculation paramaters */ val = val | 1 | ((bc->horz.mode & ISIF_HORZ_BC_MODE_MASK) << ISIF_HORZ_BC_MODE_SHIFT); @@ -722,7 +722,7 @@ static void isif_config_bclamp(struct vpfe_isif_device *isif, isif_write(isif->isif_cfg.base_addr, val, CLHWIN2); } - /* vertical clamp caculation paramaters */ + /* vertical clamp calculation paramaters */ /* OB H Valid */ val = bc->vert.ob_h_sz_calc & ISIF_VERT_BC_OB_H_SZ_MASK; @@ -1569,7 +1569,7 @@ isif_pad_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, crop->rect.width = format->width; crop->rect.height = format->height; } - /* adjust the width to 16 pixel boundry */ + /* adjust the width to 16 pixel boundary */ crop->rect.width = ((crop->rect.width + 15) & ~0xf); vpfe_isif->crop = crop->rect; if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) { diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c index 3670a7b..ba913f1 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c @@ -357,7 +357,7 @@ static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe) * * Set the pipeline to the given stream state. * - * Return 0 if successfull, or the return value of the failed video::s_stream + * Return 0 if successful, or the return value of the failed video::s_stream * operation otherwise. */ static int vpfe_pipeline_set_stream(struct vpfe_pipeline *pipe, @@ -644,7 +644,7 @@ static int vpfe_g_fmt(struct file *file, void *priv, * fills v4l2_fmtdesc structure with output format set on adjacent subdev, * only one format is enumearted as subdevs are already configured * - * Return 0 if successfull, error code otherwise + * Return 0 if successful, error code otherwise */ static int vpfe_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *fmt) @@ -769,7 +769,7 @@ static int vpfe_try_fmt(struct file *file, void *priv, * fills v4l2_input structure with input available on media chain, * only one input is enumearted as media chain is setup by this time * - * Return 0 if successfull, -EINVAL is media chain is invalid + * Return 0 if successful, -EINVAL is media chain is invalid */ static int vpfe_enum_input(struct file *file, void *priv, struct v4l2_input *inp) @@ -779,7 +779,7 @@ static int vpfe_enum_input(struct file *file, void *priv, struct vpfe_device *vpfe_dev = video->vpfe_dev; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n"); - /* enumerate from the subdev user has choosen through mc */ + /* enumerate from the subdev user has chosen through mc */ if (inp->index < sdinfo->num_inputs) { memcpy(inp, &sdinfo->inputs[inp->index], sizeof(struct v4l2_input)); diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.h b/drivers/staging/media/davinci_vpfe/vpfe_video.h index bf8af01..df0aeec 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.h +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.h @@ -138,7 +138,7 @@ struct vpfe_video_device { v4l2_std_id stdid; /* * offset where second field starts from the starting of the - * buffer for field seperated YCbCr formats + * buffer for field separated YCbCr formats */ u32 field_off; }; -- cgit v0.10.2 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 diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 7dbd5a9..aee7b6d 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 50379b2..9cbbce0 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 7859c43..2381b05 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 20db8a0..8c50d30 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 2a2d21e..38b3f15 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 39a8fb2..6c7d20f 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 75a7dfc..b273f0e 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 v0.10.2 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 diff --git a/drivers/media/usb/gspca/etoms.c b/drivers/media/usb/gspca/etoms.c index 948a635..26c9ee1 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 v0.10.2 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 diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index 2ce75d1..a360227 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 v0.10.2 From 9e7664e0827528701074875eef872f2be1dfaab8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 29 Mar 2013 07:20:36 -0300 Subject: [media] solo6x10: The size of the thresholds ioctls was too large On powerpc the maximum size for the ioctl argument is 8191, and it was 8192. However, the 64x64 array of threshold values is more than is actually needed in practice for PAL and NTSC formats. A 45x45 array will do just fine. So change the size accordingly to fix this problem. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/solo6x10-disp.c b/drivers/staging/media/solo6x10/solo6x10-disp.c index 78070c8..32d9953 100644 --- a/drivers/staging/media/solo6x10/solo6x10-disp.c +++ b/drivers/staging/media/solo6x10/solo6x10-disp.c @@ -205,10 +205,11 @@ int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch, const struct solo_motion_thresholds *thresholds) { u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2; - u16 buf[SOLO_MOTION_SZ]; + u16 buf[64]; int x, y; int ret = 0; + memset(buf, 0, sizeof(buf)); for (y = 0; y < SOLO_MOTION_SZ; y++) { for (x = 0; x < SOLO_MOTION_SZ; x++) buf[x] = cpu_to_le16(thresholds->thresholds[y][x]); diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/staging/media/solo6x10/solo6x10.h index 3526d6b..6f91d2e 100644 --- a/drivers/staging/media/solo6x10/solo6x10.h +++ b/drivers/staging/media/solo6x10/solo6x10.h @@ -113,8 +113,14 @@ * each sample representing 16x16 pixels of the source. In * effect, 44x30 samples are used for NTSC, and 44x36 for PAL. * The 5th sample on the 10th row is (10*64)+5 = 645. + * + * Using a 64x64 array will result in a problem on some architectures like + * the powerpc where the size of the argument is limited to 13 bits. + * Since both PAL and NTSC do not use the full table anyway I've chosen + * to limit the array to 45x45 (45*16 = 720, which is the maximum PAL/NTSC + * width). */ -#define SOLO_MOTION_SZ (64) +#define SOLO_MOTION_SZ (45) struct solo_motion_thresholds { __u16 thresholds[SOLO_MOTION_SZ][SOLO_MOTION_SZ]; }; -- cgit v0.10.2 From 626b67c1ad90b450e0afbd1c277fd81ad64c5539 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 26 Mar 2013 22:47:18 -0300 Subject: [media] mfd: Add commands abstraction layer for SI476X MFD This patch adds all the functions used for exchanging commands with the chip. Acked-by: Hans Verkuil Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/mfd/si476x-cmd.c b/drivers/mfd/si476x-cmd.c new file mode 100644 index 0000000..71ac2e8 --- /dev/null +++ b/drivers/mfd/si476x-cmd.c @@ -0,0 +1,1554 @@ +/* + * drivers/mfd/si476x-cmd.c -- Subroutines implementing command + * protocol of si476x series of 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 + +#define msb(x) ((u8)((u16) x >> 8)) +#define lsb(x) ((u8)((u16) x & 0x00FF)) + + + +#define CMD_POWER_UP 0x01 +#define CMD_POWER_UP_A10_NRESP 1 +#define CMD_POWER_UP_A10_NARGS 5 + +#define CMD_POWER_UP_A20_NRESP 1 +#define CMD_POWER_UP_A20_NARGS 5 + +#define POWER_UP_DELAY_MS 110 + +#define CMD_POWER_DOWN 0x11 +#define CMD_POWER_DOWN_A10_NRESP 1 + +#define CMD_POWER_DOWN_A20_NRESP 1 +#define CMD_POWER_DOWN_A20_NARGS 1 + +#define CMD_FUNC_INFO 0x12 +#define CMD_FUNC_INFO_NRESP 7 + +#define CMD_SET_PROPERTY 0x13 +#define CMD_SET_PROPERTY_NARGS 5 +#define CMD_SET_PROPERTY_NRESP 1 + +#define CMD_GET_PROPERTY 0x14 +#define CMD_GET_PROPERTY_NARGS 3 +#define CMD_GET_PROPERTY_NRESP 4 + +#define CMD_AGC_STATUS 0x17 +#define CMD_AGC_STATUS_NRESP_A10 2 +#define CMD_AGC_STATUS_NRESP_A20 6 + +#define PIN_CFG_BYTE(x) (0x7F & (x)) +#define CMD_DIG_AUDIO_PIN_CFG 0x18 +#define CMD_DIG_AUDIO_PIN_CFG_NARGS 4 +#define CMD_DIG_AUDIO_PIN_CFG_NRESP 5 + +#define CMD_ZIF_PIN_CFG 0x19 +#define CMD_ZIF_PIN_CFG_NARGS 4 +#define CMD_ZIF_PIN_CFG_NRESP 5 + +#define CMD_IC_LINK_GPO_CTL_PIN_CFG 0x1A +#define CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS 4 +#define CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP 5 + +#define CMD_ANA_AUDIO_PIN_CFG 0x1B +#define CMD_ANA_AUDIO_PIN_CFG_NARGS 1 +#define CMD_ANA_AUDIO_PIN_CFG_NRESP 2 + +#define CMD_INTB_PIN_CFG 0x1C +#define CMD_INTB_PIN_CFG_NARGS 2 +#define CMD_INTB_PIN_CFG_A10_NRESP 6 +#define CMD_INTB_PIN_CFG_A20_NRESP 3 + +#define CMD_FM_TUNE_FREQ 0x30 +#define CMD_FM_TUNE_FREQ_A10_NARGS 5 +#define CMD_FM_TUNE_FREQ_A20_NARGS 3 +#define CMD_FM_TUNE_FREQ_NRESP 1 + +#define CMD_FM_RSQ_STATUS 0x32 + +#define CMD_FM_RSQ_STATUS_A10_NARGS 1 +#define CMD_FM_RSQ_STATUS_A10_NRESP 17 +#define CMD_FM_RSQ_STATUS_A30_NARGS 1 +#define CMD_FM_RSQ_STATUS_A30_NRESP 23 + + +#define CMD_FM_SEEK_START 0x31 +#define CMD_FM_SEEK_START_NARGS 1 +#define CMD_FM_SEEK_START_NRESP 1 + +#define CMD_FM_RDS_STATUS 0x36 +#define CMD_FM_RDS_STATUS_NARGS 1 +#define CMD_FM_RDS_STATUS_NRESP 16 + +#define CMD_FM_RDS_BLOCKCOUNT 0x37 +#define CMD_FM_RDS_BLOCKCOUNT_NARGS 1 +#define CMD_FM_RDS_BLOCKCOUNT_NRESP 8 + +#define CMD_FM_PHASE_DIVERSITY 0x38 +#define CMD_FM_PHASE_DIVERSITY_NARGS 1 +#define CMD_FM_PHASE_DIVERSITY_NRESP 1 + +#define CMD_FM_PHASE_DIV_STATUS 0x39 +#define CMD_FM_PHASE_DIV_STATUS_NRESP 2 + +#define CMD_AM_TUNE_FREQ 0x40 +#define CMD_AM_TUNE_FREQ_NARGS 3 +#define CMD_AM_TUNE_FREQ_NRESP 1 + +#define CMD_AM_RSQ_STATUS 0x42 +#define CMD_AM_RSQ_STATUS_NARGS 1 +#define CMD_AM_RSQ_STATUS_NRESP 13 + +#define CMD_AM_SEEK_START 0x41 +#define CMD_AM_SEEK_START_NARGS 1 +#define CMD_AM_SEEK_START_NRESP 1 + + +#define CMD_AM_ACF_STATUS 0x45 +#define CMD_AM_ACF_STATUS_NRESP 6 +#define CMD_AM_ACF_STATUS_NARGS 1 + +#define CMD_FM_ACF_STATUS 0x35 +#define CMD_FM_ACF_STATUS_NRESP 8 +#define CMD_FM_ACF_STATUS_NARGS 1 + +#define CMD_MAX_ARGS_COUNT (10) + + +enum si476x_acf_status_report_bits { + SI476X_ACF_BLEND_INT = (1 << 4), + SI476X_ACF_HIBLEND_INT = (1 << 3), + SI476X_ACF_HICUT_INT = (1 << 2), + SI476X_ACF_CHBW_INT = (1 << 1), + SI476X_ACF_SOFTMUTE_INT = (1 << 0), + + SI476X_ACF_SMUTE = (1 << 0), + SI476X_ACF_SMATTN = 0b11111, + SI476X_ACF_PILOT = (1 << 7), + SI476X_ACF_STBLEND = ~SI476X_ACF_PILOT, +}; + +enum si476x_agc_status_report_bits { + SI476X_AGC_MXHI = (1 << 5), + SI476X_AGC_MXLO = (1 << 4), + SI476X_AGC_LNAHI = (1 << 3), + SI476X_AGC_LNALO = (1 << 2), +}; + +enum si476x_errors { + SI476X_ERR_BAD_COMMAND = 0x10, + SI476X_ERR_BAD_ARG1 = 0x11, + SI476X_ERR_BAD_ARG2 = 0x12, + SI476X_ERR_BAD_ARG3 = 0x13, + SI476X_ERR_BAD_ARG4 = 0x14, + SI476X_ERR_BUSY = 0x18, + SI476X_ERR_BAD_INTERNAL_MEMORY = 0x20, + SI476X_ERR_BAD_PATCH = 0x30, + SI476X_ERR_BAD_BOOT_MODE = 0x31, + SI476X_ERR_BAD_PROPERTY = 0x40, +}; + +static int si476x_core_parse_and_nag_about_error(struct si476x_core *core) +{ + int err; + char *cause; + u8 buffer[2]; + + if (core->revision != SI476X_REVISION_A10) { + err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, + buffer, sizeof(buffer)); + if (err == sizeof(buffer)) { + switch (buffer[1]) { + case SI476X_ERR_BAD_COMMAND: + cause = "Bad command"; + err = -EINVAL; + break; + case SI476X_ERR_BAD_ARG1: + cause = "Bad argument #1"; + err = -EINVAL; + break; + case SI476X_ERR_BAD_ARG2: + cause = "Bad argument #2"; + err = -EINVAL; + break; + case SI476X_ERR_BAD_ARG3: + cause = "Bad argument #3"; + err = -EINVAL; + break; + case SI476X_ERR_BAD_ARG4: + cause = "Bad argument #4"; + err = -EINVAL; + break; + case SI476X_ERR_BUSY: + cause = "Chip is busy"; + err = -EBUSY; + break; + case SI476X_ERR_BAD_INTERNAL_MEMORY: + cause = "Bad internal memory"; + err = -EIO; + break; + case SI476X_ERR_BAD_PATCH: + cause = "Bad patch"; + err = -EINVAL; + break; + case SI476X_ERR_BAD_BOOT_MODE: + cause = "Bad boot mode"; + err = -EINVAL; + break; + case SI476X_ERR_BAD_PROPERTY: + cause = "Bad property"; + err = -EINVAL; + break; + default: + cause = "Unknown"; + err = -EIO; + } + + dev_err(&core->client->dev, + "[Chip error status]: %s\n", cause); + } else { + dev_err(&core->client->dev, + "Failed to fetch error code\n"); + err = (err >= 0) ? -EIO : err; + } + } else { + err = -EIO; + } + + return err; +} + +/** + * si476x_core_send_command() - sends a command to si476x and waits its + * response + * @core: si476x_device structure for the device we are + * communicating with + * @command: command id + * @args: command arguments we are sending + * @argn: actual size of @args + * @response: buffer to place the expected response from the device + * @respn: actual size of @response + * @usecs: amount of time to wait before reading the response (in + * usecs) + * + * Function returns 0 on succsess and negative error code on + * failure + */ +static int si476x_core_send_command(struct si476x_core *core, + const u8 command, + const u8 args[], + const int argn, + u8 resp[], + const int respn, + const int usecs) +{ + struct i2c_client *client = core->client; + int err; + u8 data[CMD_MAX_ARGS_COUNT + 1]; + + if (argn > CMD_MAX_ARGS_COUNT) { + err = -ENOMEM; + goto exit; + } + + if (!client->adapter) { + err = -ENODEV; + goto exit; + } + + /* First send the command and its arguments */ + data[0] = command; + memcpy(&data[1], args, argn); + dev_dbg(&client->dev, "Command:\n %*ph\n", argn + 1, data); + + err = si476x_core_i2c_xfer(core, SI476X_I2C_SEND, + (char *) data, argn + 1); + if (err != argn + 1) { + dev_err(&core->client->dev, + "Error while sending command 0x%02x\n", + command); + err = (err >= 0) ? -EIO : err; + goto exit; + } + /* Set CTS to zero only after the command is send to avoid + * possible racing conditions when working in polling mode */ + atomic_set(&core->cts, 0); + + /* if (unlikely(command == CMD_POWER_DOWN) */ + if (!wait_event_timeout(core->command, + atomic_read(&core->cts), + usecs_to_jiffies(usecs) + 1)) + dev_warn(&core->client->dev, + "(%s) [CMD 0x%02x] Answer timeout.\n", + __func__, command); + + /* + When working in polling mode, for some reason the tuner will + report CTS bit as being set in the first status byte read, + but all the consequtive ones will return zeros until the + tuner is actually completed the POWER_UP command. To + workaround that we wait for second CTS to be reported + */ + if (unlikely(!core->client->irq && command == CMD_POWER_UP)) { + if (!wait_event_timeout(core->command, + atomic_read(&core->cts), + usecs_to_jiffies(usecs) + 1)) + dev_warn(&core->client->dev, + "(%s) Power up took too much time.\n", + __func__); + } + + /* Then get the response */ + err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, resp, respn); + if (err != respn) { + dev_err(&core->client->dev, + "Error while reading response for command 0x%02x\n", + command); + err = (err >= 0) ? -EIO : err; + goto exit; + } + dev_dbg(&client->dev, "Response:\n %*ph\n", respn, resp); + + err = 0; + + if (resp[0] & SI476X_ERR) { + dev_err(&core->client->dev, + "[CMD 0x%02x] Chip set error flag\n", command); + err = si476x_core_parse_and_nag_about_error(core); + goto exit; + } + + if (!(resp[0] & SI476X_CTS)) + err = -EBUSY; +exit: + return err; +} + +static int si476x_cmd_clear_stc(struct si476x_core *core) +{ + int err; + struct si476x_rsq_status_args args = { + .primary = false, + .rsqack = false, + .attune = false, + .cancel = false, + .stcack = true, + }; + + switch (core->power_up_parameters.func) { + case SI476X_FUNC_FM_RECEIVER: + err = si476x_core_cmd_fm_rsq_status(core, &args, NULL); + break; + case SI476X_FUNC_AM_RECEIVER: + err = si476x_core_cmd_am_rsq_status(core, &args, NULL); + break; + default: + err = -EINVAL; + } + + return err; +} + +static int si476x_cmd_tune_seek_freq(struct si476x_core *core, + uint8_t cmd, + const uint8_t args[], size_t argn, + uint8_t *resp, size_t respn) +{ + int err; + + + atomic_set(&core->stc, 0); + err = si476x_core_send_command(core, cmd, args, argn, resp, respn, + SI476X_TIMEOUT_TUNE); + if (!err) { + wait_event_killable(core->tuning, + atomic_read(&core->stc)); + si476x_cmd_clear_stc(core); + } + + return err; +} + +/** + * si476x_cmd_func_info() - send 'FUNC_INFO' command to the device + * @core: device to send the command to + * @info: struct si476x_func_info to fill all the information + * returned by the command + * + * The command requests the firmware and patch version for currently + * loaded firmware (dependent on the function of the device FM/AM/WB) + * + * Function returns 0 on succsess and negative error code on + * failure + */ +int si476x_core_cmd_func_info(struct si476x_core *core, + struct si476x_func_info *info) +{ + int err; + u8 resp[CMD_FUNC_INFO_NRESP]; + + err = si476x_core_send_command(core, CMD_FUNC_INFO, + NULL, 0, + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); + + info->firmware.major = resp[1]; + info->firmware.minor[0] = resp[2]; + info->firmware.minor[1] = resp[3]; + + info->patch_id = ((u16) resp[4] << 8) | resp[5]; + info->func = resp[6]; + + return err; +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_func_info); + +/** + * si476x_cmd_set_property() - send 'SET_PROPERTY' command to the device + * @core: device to send the command to + * @property: property address + * @value: property value + * + * Function returns 0 on succsess and negative error code on + * failure + */ +int si476x_core_cmd_set_property(struct si476x_core *core, + u16 property, u16 value) +{ + u8 resp[CMD_SET_PROPERTY_NRESP]; + const u8 args[CMD_SET_PROPERTY_NARGS] = { + 0x00, + msb(property), + lsb(property), + msb(value), + lsb(value), + }; + + return si476x_core_send_command(core, CMD_SET_PROPERTY, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_set_property); + +/** + * si476x_cmd_get_property() - send 'GET_PROPERTY' command to the device + * @core: device to send the command to + * @property: property address + * + * Function return the value of property as u16 on success or a + * negative error on failure + */ +int si476x_core_cmd_get_property(struct si476x_core *core, u16 property) +{ + int err; + u8 resp[CMD_GET_PROPERTY_NRESP]; + const u8 args[CMD_GET_PROPERTY_NARGS] = { + 0x00, + msb(property), + lsb(property), + }; + + err = si476x_core_send_command(core, CMD_GET_PROPERTY, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); + if (err < 0) + return err; + else + return be16_to_cpup((__be16 *)(resp + 2)); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_get_property); + +/** + * si476x_cmd_dig_audio_pin_cfg() - send 'DIG_AUDIO_PIN_CFG' command to + * the device + * @core: device to send the command to + * @dclk: DCLK pin function configuration: + * #SI476X_DCLK_NOOP - do not modify the behaviour + * #SI476X_DCLK_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * #SI476X_DCLK_DAUDIO - set the pin to be a part of digital + * audio interface + * @dfs: DFS pin function configuration: + * #SI476X_DFS_NOOP - do not modify the behaviour + * #SI476X_DFS_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * SI476X_DFS_DAUDIO - set the pin to be a part of digital + * audio interface + * @dout - DOUT pin function configuration: + * SI476X_DOUT_NOOP - do not modify the behaviour + * SI476X_DOUT_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * SI476X_DOUT_I2S_OUTPUT - set this pin to be digital out on I2S + * port 1 + * SI476X_DOUT_I2S_INPUT - set this pin to be digital in on I2S + * port 1 + * @xout - XOUT pin function configuration: + * SI476X_XOUT_NOOP - do not modify the behaviour + * SI476X_XOUT_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * SI476X_XOUT_I2S_INPUT - set this pin to be digital in on I2S + * port 1 + * SI476X_XOUT_MODE_SELECT - set this pin to be the input that + * selects the mode of the I2S audio + * combiner (analog or HD) + * [SI4761/63/65/67 Only] + * + * Function returns 0 on success and negative error code on failure + */ +int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *core, + enum si476x_dclk_config dclk, + enum si476x_dfs_config dfs, + enum si476x_dout_config dout, + enum si476x_xout_config xout) +{ + u8 resp[CMD_DIG_AUDIO_PIN_CFG_NRESP]; + const u8 args[CMD_DIG_AUDIO_PIN_CFG_NARGS] = { + PIN_CFG_BYTE(dclk), + PIN_CFG_BYTE(dfs), + PIN_CFG_BYTE(dout), + PIN_CFG_BYTE(xout), + }; + + return si476x_core_send_command(core, CMD_DIG_AUDIO_PIN_CFG, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_dig_audio_pin_cfg); + +/** + * si476x_cmd_zif_pin_cfg - send 'ZIF_PIN_CFG_COMMAND' + * @core - device to send the command to + * @iqclk - IQCL pin function configuration: + * SI476X_IQCLK_NOOP - do not modify the behaviour + * SI476X_IQCLK_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * SI476X_IQCLK_IQ - set pin to be a part of I/Q interace + * in master mode + * @iqfs - IQFS pin function configuration: + * SI476X_IQFS_NOOP - do not modify the behaviour + * SI476X_IQFS_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * SI476X_IQFS_IQ - set pin to be a part of I/Q interace + * in master mode + * @iout - IOUT pin function configuration: + * SI476X_IOUT_NOOP - do not modify the behaviour + * SI476X_IOUT_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * SI476X_IOUT_OUTPUT - set pin to be I out + * @qout - QOUT pin function configuration: + * SI476X_QOUT_NOOP - do not modify the behaviour + * SI476X_QOUT_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * SI476X_QOUT_OUTPUT - set pin to be Q out + * + * Function returns 0 on success and negative error code on failure + */ +int si476x_core_cmd_zif_pin_cfg(struct si476x_core *core, + enum si476x_iqclk_config iqclk, + enum si476x_iqfs_config iqfs, + enum si476x_iout_config iout, + enum si476x_qout_config qout) +{ + u8 resp[CMD_ZIF_PIN_CFG_NRESP]; + const u8 args[CMD_ZIF_PIN_CFG_NARGS] = { + PIN_CFG_BYTE(iqclk), + PIN_CFG_BYTE(iqfs), + PIN_CFG_BYTE(iout), + PIN_CFG_BYTE(qout), + }; + + return si476x_core_send_command(core, CMD_ZIF_PIN_CFG, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_zif_pin_cfg); + +/** + * si476x_cmd_ic_link_gpo_ctl_pin_cfg - send + * 'IC_LINK_GPIO_CTL_PIN_CFG' comand to the device + * @core - device to send the command to + * @icin - ICIN pin function configuration: + * SI476X_ICIN_NOOP - do not modify the behaviour + * SI476X_ICIN_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * SI476X_ICIN_GPO1_HIGH - set pin to be an output, drive it high + * SI476X_ICIN_GPO1_LOW - set pin to be an output, drive it low + * SI476X_ICIN_IC_LINK - set the pin to be a part of Inter-Chip link + * @icip - ICIP pin function configuration: + * SI476X_ICIP_NOOP - do not modify the behaviour + * SI476X_ICIP_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * SI476X_ICIP_GPO1_HIGH - set pin to be an output, drive it high + * SI476X_ICIP_GPO1_LOW - set pin to be an output, drive it low + * SI476X_ICIP_IC_LINK - set the pin to be a part of Inter-Chip link + * @icon - ICON pin function configuration: + * SI476X_ICON_NOOP - do not modify the behaviour + * SI476X_ICON_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * SI476X_ICON_I2S - set the pin to be a part of audio + * interface in slave mode (DCLK) + * SI476X_ICON_IC_LINK - set the pin to be a part of Inter-Chip link + * @icop - ICOP pin function configuration: + * SI476X_ICOP_NOOP - do not modify the behaviour + * SI476X_ICOP_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * SI476X_ICOP_I2S - set the pin to be a part of audio + * interface in slave mode (DOUT) + * [Si4761/63/65/67 Only] + * SI476X_ICOP_IC_LINK - set the pin to be a part of Inter-Chip link + * + * Function returns 0 on success and negative error code on failure + */ +int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *core, + enum si476x_icin_config icin, + enum si476x_icip_config icip, + enum si476x_icon_config icon, + enum si476x_icop_config icop) +{ + u8 resp[CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP]; + const u8 args[CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS] = { + PIN_CFG_BYTE(icin), + PIN_CFG_BYTE(icip), + PIN_CFG_BYTE(icon), + PIN_CFG_BYTE(icop), + }; + + return si476x_core_send_command(core, CMD_IC_LINK_GPO_CTL_PIN_CFG, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_ic_link_gpo_ctl_pin_cfg); + +/** + * si476x_cmd_ana_audio_pin_cfg - send 'ANA_AUDIO_PIN_CFG' to the + * device + * @core - device to send the command to + * @lrout - LROUT pin function configuration: + * SI476X_LROUT_NOOP - do not modify the behaviour + * SI476X_LROUT_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * SI476X_LROUT_AUDIO - set pin to be audio output + * SI476X_LROUT_MPX - set pin to be MPX output + * + * Function returns 0 on success and negative error code on failure + */ +int si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *core, + enum si476x_lrout_config lrout) +{ + u8 resp[CMD_ANA_AUDIO_PIN_CFG_NRESP]; + const u8 args[CMD_ANA_AUDIO_PIN_CFG_NARGS] = { + PIN_CFG_BYTE(lrout), + }; + + return si476x_core_send_command(core, CMD_ANA_AUDIO_PIN_CFG, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_ana_audio_pin_cfg); + + +/** + * si476x_cmd_intb_pin_cfg - send 'INTB_PIN_CFG' command to the device + * @core - device to send the command to + * @intb - INTB pin function configuration: + * SI476X_INTB_NOOP - do not modify the behaviour + * SI476X_INTB_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * SI476X_INTB_DAUDIO - set pin to be a part of digital + * audio interface in slave mode + * SI476X_INTB_IRQ - set pin to be an interrupt request line + * @a1 - A1 pin function configuration: + * SI476X_A1_NOOP - do not modify the behaviour + * SI476X_A1_TRISTATE - put the pin in tristate condition, + * enable 1MOhm pulldown + * SI476X_A1_IRQ - set pin to be an interrupt request line + * + * Function returns 0 on success and negative error code on failure + */ +static int si476x_core_cmd_intb_pin_cfg_a10(struct si476x_core *core, + enum si476x_intb_config intb, + enum si476x_a1_config a1) +{ + u8 resp[CMD_INTB_PIN_CFG_A10_NRESP]; + const u8 args[CMD_INTB_PIN_CFG_NARGS] = { + PIN_CFG_BYTE(intb), + PIN_CFG_BYTE(a1), + }; + + return si476x_core_send_command(core, CMD_INTB_PIN_CFG, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); +} + +static int si476x_core_cmd_intb_pin_cfg_a20(struct si476x_core *core, + enum si476x_intb_config intb, + enum si476x_a1_config a1) +{ + u8 resp[CMD_INTB_PIN_CFG_A20_NRESP]; + const u8 args[CMD_INTB_PIN_CFG_NARGS] = { + PIN_CFG_BYTE(intb), + PIN_CFG_BYTE(a1), + }; + + return si476x_core_send_command(core, CMD_INTB_PIN_CFG, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); +} + + + +/** + * si476x_cmd_am_rsq_status - send 'AM_RSQ_STATUS' command to the + * device + * @core - device to send the command to + * @rsqack - if set command clears RSQINT, SNRINT, SNRLINT, RSSIHINT, + * RSSSILINT, BLENDINT, MULTHINT and MULTLINT + * @attune - when set the values in the status report are the values + * that were calculated at tune + * @cancel - abort ongoing seek/tune opertation + * @stcack - clear the STCINT bin in status register + * @report - all signal quality information retured by the command + * (if NULL then the output of the command is ignored) + * + * Function returns 0 on success and negative error code on failure + */ +int si476x_core_cmd_am_rsq_status(struct si476x_core *core, + struct si476x_rsq_status_args *rsqargs, + struct si476x_rsq_status_report *report) +{ + int err; + u8 resp[CMD_AM_RSQ_STATUS_NRESP]; + const u8 args[CMD_AM_RSQ_STATUS_NARGS] = { + rsqargs->rsqack << 3 | rsqargs->attune << 2 | + rsqargs->cancel << 1 | rsqargs->stcack, + }; + + err = si476x_core_send_command(core, CMD_AM_RSQ_STATUS, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); + /* + * Besides getting received signal quality information this + * command can be used to just acknowledge different interrupt + * flags in those cases it is useless to copy and parse + * received data so user can pass NULL, and thus avoid + * unnecessary copying. + */ + if (!report) + return err; + + report->snrhint = 0b00001000 & resp[1]; + report->snrlint = 0b00000100 & resp[1]; + report->rssihint = 0b00000010 & resp[1]; + report->rssilint = 0b00000001 & resp[1]; + + report->bltf = 0b10000000 & resp[2]; + report->snr_ready = 0b00100000 & resp[2]; + report->rssiready = 0b00001000 & resp[2]; + report->afcrl = 0b00000010 & resp[2]; + report->valid = 0b00000001 & resp[2]; + + report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); + report->freqoff = resp[5]; + report->rssi = resp[6]; + report->snr = resp[7]; + report->lassi = resp[9]; + report->hassi = resp[10]; + report->mult = resp[11]; + report->dev = resp[12]; + + return err; +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_am_rsq_status); + +int si476x_core_cmd_fm_acf_status(struct si476x_core *core, + struct si476x_acf_status_report *report) +{ + int err; + u8 resp[CMD_FM_ACF_STATUS_NRESP]; + const u8 args[CMD_FM_ACF_STATUS_NARGS] = { + 0x0, + }; + + if (!report) + return -EINVAL; + + err = si476x_core_send_command(core, CMD_FM_ACF_STATUS, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); + if (err < 0) + return err; + + report->blend_int = resp[1] & SI476X_ACF_BLEND_INT; + report->hblend_int = resp[1] & SI476X_ACF_HIBLEND_INT; + report->hicut_int = resp[1] & SI476X_ACF_HICUT_INT; + report->chbw_int = resp[1] & SI476X_ACF_CHBW_INT; + report->softmute_int = resp[1] & SI476X_ACF_SOFTMUTE_INT; + report->smute = resp[2] & SI476X_ACF_SMUTE; + report->smattn = resp[3] & SI476X_ACF_SMATTN; + report->chbw = resp[4]; + report->hicut = resp[5]; + report->hiblend = resp[6]; + report->pilot = resp[7] & SI476X_ACF_PILOT; + report->stblend = resp[7] & SI476X_ACF_STBLEND; + + return err; +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_acf_status); + +int si476x_core_cmd_am_acf_status(struct si476x_core *core, + struct si476x_acf_status_report *report) +{ + int err; + u8 resp[CMD_AM_ACF_STATUS_NRESP]; + const u8 args[CMD_AM_ACF_STATUS_NARGS] = { + 0x0, + }; + + if (!report) + return -EINVAL; + + err = si476x_core_send_command(core, CMD_AM_ACF_STATUS, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); + if (err < 0) + return err; + + report->blend_int = resp[1] & SI476X_ACF_BLEND_INT; + report->hblend_int = resp[1] & SI476X_ACF_HIBLEND_INT; + report->hicut_int = resp[1] & SI476X_ACF_HICUT_INT; + report->chbw_int = resp[1] & SI476X_ACF_CHBW_INT; + report->softmute_int = resp[1] & SI476X_ACF_SOFTMUTE_INT; + report->smute = resp[2] & SI476X_ACF_SMUTE; + report->smattn = resp[3] & SI476X_ACF_SMATTN; + report->chbw = resp[4]; + report->hicut = resp[5]; + + return err; +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_am_acf_status); + + +/** + * si476x_cmd_fm_seek_start - send 'FM_SEEK_START' command to the + * device + * @core - device to send the command to + * @seekup - if set the direction of the search is 'up' + * @wrap - if set seek wraps when hitting band limit + * + * This function begins search for a valid station. The station is + * considered valid when 'FM_VALID_SNR_THRESHOLD' and + * 'FM_VALID_RSSI_THRESHOLD' and 'FM_VALID_MAX_TUNE_ERROR' criteria + * are met. +} * + * Function returns 0 on success and negative error code on failure + */ +int si476x_core_cmd_fm_seek_start(struct si476x_core *core, + bool seekup, bool wrap) +{ + u8 resp[CMD_FM_SEEK_START_NRESP]; + const u8 args[CMD_FM_SEEK_START_NARGS] = { + seekup << 3 | wrap << 2, + }; + + return si476x_cmd_tune_seek_freq(core, CMD_FM_SEEK_START, + args, sizeof(args), + resp, sizeof(resp)); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_seek_start); + +/** + * si476x_cmd_fm_rds_status - send 'FM_RDS_STATUS' command to the + * device + * @core - device to send the command to + * @status_only - if set the data is not removed from RDSFIFO, + * RDSFIFOUSED is not decremented and data in all the + * rest RDS data contains the last valid info received + * @mtfifo if set the command clears RDS receive FIFO + * @intack if set the command clards the RDSINT bit. + * + * Function returns 0 on success and negative error code on failure + */ +int si476x_core_cmd_fm_rds_status(struct si476x_core *core, + bool status_only, + bool mtfifo, + bool intack, + struct si476x_rds_status_report *report) +{ + int err; + u8 resp[CMD_FM_RDS_STATUS_NRESP]; + const u8 args[CMD_FM_RDS_STATUS_NARGS] = { + status_only << 2 | mtfifo << 1 | intack, + }; + + err = si476x_core_send_command(core, CMD_FM_RDS_STATUS, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); + /* + * Besides getting RDS status information this command can be + * used to just acknowledge different interrupt flags in those + * cases it is useless to copy and parse received data so user + * can pass NULL, and thus avoid unnecessary copying. + */ + if (err < 0 || report == NULL) + return err; + + report->rdstpptyint = 0b00010000 & resp[1]; + report->rdspiint = 0b00001000 & resp[1]; + report->rdssyncint = 0b00000010 & resp[1]; + report->rdsfifoint = 0b00000001 & resp[1]; + + report->tpptyvalid = 0b00010000 & resp[2]; + report->pivalid = 0b00001000 & resp[2]; + report->rdssync = 0b00000010 & resp[2]; + report->rdsfifolost = 0b00000001 & resp[2]; + + report->tp = 0b00100000 & resp[3]; + report->pty = 0b00011111 & resp[3]; + + report->pi = be16_to_cpup((__be16 *)(resp + 4)); + report->rdsfifoused = resp[6]; + + report->ble[V4L2_RDS_BLOCK_A] = 0b11000000 & resp[7]; + report->ble[V4L2_RDS_BLOCK_B] = 0b00110000 & resp[7]; + report->ble[V4L2_RDS_BLOCK_C] = 0b00001100 & resp[7]; + report->ble[V4L2_RDS_BLOCK_D] = 0b00000011 & resp[7]; + + report->rds[V4L2_RDS_BLOCK_A].block = V4L2_RDS_BLOCK_A; + report->rds[V4L2_RDS_BLOCK_A].msb = resp[8]; + report->rds[V4L2_RDS_BLOCK_A].lsb = resp[9]; + + report->rds[V4L2_RDS_BLOCK_B].block = V4L2_RDS_BLOCK_B; + report->rds[V4L2_RDS_BLOCK_B].msb = resp[10]; + report->rds[V4L2_RDS_BLOCK_B].lsb = resp[11]; + + report->rds[V4L2_RDS_BLOCK_C].block = V4L2_RDS_BLOCK_C; + report->rds[V4L2_RDS_BLOCK_C].msb = resp[12]; + report->rds[V4L2_RDS_BLOCK_C].lsb = resp[13]; + + report->rds[V4L2_RDS_BLOCK_D].block = V4L2_RDS_BLOCK_D; + report->rds[V4L2_RDS_BLOCK_D].msb = resp[14]; + report->rds[V4L2_RDS_BLOCK_D].lsb = resp[15]; + + return err; +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rds_status); + +int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *core, + bool clear, + struct si476x_rds_blockcount_report *report) +{ + int err; + u8 resp[CMD_FM_RDS_BLOCKCOUNT_NRESP]; + const u8 args[CMD_FM_RDS_BLOCKCOUNT_NARGS] = { + clear, + }; + + if (!report) + return -EINVAL; + + err = si476x_core_send_command(core, CMD_FM_RDS_BLOCKCOUNT, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); + + if (!err) { + report->expected = be16_to_cpup((__be16 *)(resp + 2)); + report->received = be16_to_cpup((__be16 *)(resp + 4)); + report->uncorrectable = be16_to_cpup((__be16 *)(resp + 6)); + } + + return err; +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rds_blockcount); + +int si476x_core_cmd_fm_phase_diversity(struct si476x_core *core, + enum si476x_phase_diversity_mode mode) +{ + u8 resp[CMD_FM_PHASE_DIVERSITY_NRESP]; + const u8 args[CMD_FM_PHASE_DIVERSITY_NARGS] = { + mode & 0b111, + }; + + return si476x_core_send_command(core, CMD_FM_PHASE_DIVERSITY, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_diversity); +/** + * si476x_core_cmd_fm_phase_div_status() - get the phase diversity + * status + * + * @core: si476x device + * + * NOTE caller must hold core lock + * + * Function returns the value of the status bit in case of success and + * negative error code in case of failre. + */ +int si476x_core_cmd_fm_phase_div_status(struct si476x_core *core) +{ + int err; + u8 resp[CMD_FM_PHASE_DIV_STATUS_NRESP]; + + err = si476x_core_send_command(core, CMD_FM_PHASE_DIV_STATUS, + NULL, 0, + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); + + return (err < 0) ? err : resp[1]; +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_div_status); + + +/** + * si476x_cmd_am_seek_start - send 'FM_SEEK_START' command to the + * device + * @core - device to send the command to + * @seekup - if set the direction of the search is 'up' + * @wrap - if set seek wraps when hitting band limit + * + * This function begins search for a valid station. The station is + * considered valid when 'FM_VALID_SNR_THRESHOLD' and + * 'FM_VALID_RSSI_THRESHOLD' and 'FM_VALID_MAX_TUNE_ERROR' criteria + * are met. + * + * Function returns 0 on success and negative error code on failure + */ +int si476x_core_cmd_am_seek_start(struct si476x_core *core, + bool seekup, bool wrap) +{ + u8 resp[CMD_AM_SEEK_START_NRESP]; + const u8 args[CMD_AM_SEEK_START_NARGS] = { + seekup << 3 | wrap << 2, + }; + + return si476x_cmd_tune_seek_freq(core, CMD_AM_SEEK_START, + args, sizeof(args), + resp, sizeof(resp)); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_am_seek_start); + + + +static int si476x_core_cmd_power_up_a10(struct si476x_core *core, + struct si476x_power_up_args *puargs) +{ + u8 resp[CMD_POWER_UP_A10_NRESP]; + const bool intsel = (core->pinmux.a1 == SI476X_A1_IRQ); + const bool ctsen = (core->client->irq != 0); + const u8 args[CMD_POWER_UP_A10_NARGS] = { + 0xF7, /* Reserved, always 0xF7 */ + 0x3F & puargs->xcload, /* First two bits are reserved to be + * zeros */ + ctsen << 7 | intsel << 6 | 0x07, /* Last five bits + * are reserved to + * be written as 0x7 */ + puargs->func << 4 | puargs->freq, + 0x11, /* Reserved, always 0x11 */ + }; + + return si476x_core_send_command(core, CMD_POWER_UP, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_TIMEOUT_POWER_UP); +} + +static int si476x_core_cmd_power_up_a20(struct si476x_core *core, + struct si476x_power_up_args *puargs) +{ + u8 resp[CMD_POWER_UP_A20_NRESP]; + const bool intsel = (core->pinmux.a1 == SI476X_A1_IRQ); + const bool ctsen = (core->client->irq != 0); + const u8 args[CMD_POWER_UP_A20_NARGS] = { + puargs->ibias6x << 7 | puargs->xstart, + 0x3F & puargs->xcload, /* First two bits are reserved to be + * zeros */ + ctsen << 7 | intsel << 6 | puargs->fastboot << 5 | + puargs->xbiashc << 3 | puargs->xbias, + puargs->func << 4 | puargs->freq, + 0x10 | puargs->xmode, + }; + + return si476x_core_send_command(core, CMD_POWER_UP, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_TIMEOUT_POWER_UP); +} + +static int si476x_core_cmd_power_down_a10(struct si476x_core *core, + struct si476x_power_down_args *pdargs) +{ + u8 resp[CMD_POWER_DOWN_A10_NRESP]; + + return si476x_core_send_command(core, CMD_POWER_DOWN, + NULL, 0, + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); +} + +static int si476x_core_cmd_power_down_a20(struct si476x_core *core, + struct si476x_power_down_args *pdargs) +{ + u8 resp[CMD_POWER_DOWN_A20_NRESP]; + const u8 args[CMD_POWER_DOWN_A20_NARGS] = { + pdargs->xosc, + }; + return si476x_core_send_command(core, CMD_POWER_DOWN, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); +} + +static int si476x_core_cmd_am_tune_freq_a10(struct si476x_core *core, + struct si476x_tune_freq_args *tuneargs) +{ + + const int am_freq = tuneargs->freq; + u8 resp[CMD_AM_TUNE_FREQ_NRESP]; + const u8 args[CMD_AM_TUNE_FREQ_NARGS] = { + (tuneargs->hd << 6), + msb(am_freq), + lsb(am_freq), + }; + + return si476x_cmd_tune_seek_freq(core, CMD_AM_TUNE_FREQ, args, + sizeof(args), + resp, sizeof(resp)); +} + +static int si476x_core_cmd_am_tune_freq_a20(struct si476x_core *core, + struct si476x_tune_freq_args *tuneargs) +{ + const int am_freq = tuneargs->freq; + u8 resp[CMD_AM_TUNE_FREQ_NRESP]; + const u8 args[CMD_AM_TUNE_FREQ_NARGS] = { + (tuneargs->zifsr << 6) | (tuneargs->injside & 0b11), + msb(am_freq), + lsb(am_freq), + }; + + return si476x_cmd_tune_seek_freq(core, CMD_AM_TUNE_FREQ, + args, sizeof(args), + resp, sizeof(resp)); +} + +static int si476x_core_cmd_fm_rsq_status_a10(struct si476x_core *core, + struct si476x_rsq_status_args *rsqargs, + struct si476x_rsq_status_report *report) +{ + int err; + u8 resp[CMD_FM_RSQ_STATUS_A10_NRESP]; + const u8 args[CMD_FM_RSQ_STATUS_A10_NARGS] = { + rsqargs->rsqack << 3 | rsqargs->attune << 2 | + rsqargs->cancel << 1 | rsqargs->stcack, + }; + + err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); + /* + * Besides getting received signal quality information this + * command can be used to just acknowledge different interrupt + * flags in those cases it is useless to copy and parse + * received data so user can pass NULL, and thus avoid + * unnecessary copying. + */ + if (err < 0 || report == NULL) + return err; + + report->multhint = 0b10000000 & resp[1]; + report->multlint = 0b01000000 & resp[1]; + report->snrhint = 0b00001000 & resp[1]; + report->snrlint = 0b00000100 & resp[1]; + report->rssihint = 0b00000010 & resp[1]; + report->rssilint = 0b00000001 & resp[1]; + + report->bltf = 0b10000000 & resp[2]; + report->snr_ready = 0b00100000 & resp[2]; + report->rssiready = 0b00001000 & resp[2]; + report->afcrl = 0b00000010 & resp[2]; + report->valid = 0b00000001 & resp[2]; + + report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); + report->freqoff = resp[5]; + report->rssi = resp[6]; + report->snr = resp[7]; + report->lassi = resp[9]; + report->hassi = resp[10]; + report->mult = resp[11]; + report->dev = resp[12]; + report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); + report->assi = resp[15]; + report->usn = resp[16]; + + return err; +} + +static int si476x_core_cmd_fm_rsq_status_a20(struct si476x_core *core, + struct si476x_rsq_status_args *rsqargs, + struct si476x_rsq_status_report *report) +{ + int err; + u8 resp[CMD_FM_RSQ_STATUS_A10_NRESP]; + const u8 args[CMD_FM_RSQ_STATUS_A30_NARGS] = { + rsqargs->primary << 4 | rsqargs->rsqack << 3 | + rsqargs->attune << 2 | rsqargs->cancel << 1 | + rsqargs->stcack, + }; + + err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); + /* + * Besides getting received signal quality information this + * command can be used to just acknowledge different interrupt + * flags in those cases it is useless to copy and parse + * received data so user can pass NULL, and thus avoid + * unnecessary copying. + */ + if (err < 0 || report == NULL) + return err; + + report->multhint = 0b10000000 & resp[1]; + report->multlint = 0b01000000 & resp[1]; + report->snrhint = 0b00001000 & resp[1]; + report->snrlint = 0b00000100 & resp[1]; + report->rssihint = 0b00000010 & resp[1]; + report->rssilint = 0b00000001 & resp[1]; + + report->bltf = 0b10000000 & resp[2]; + report->snr_ready = 0b00100000 & resp[2]; + report->rssiready = 0b00001000 & resp[2]; + report->afcrl = 0b00000010 & resp[2]; + report->valid = 0b00000001 & resp[2]; + + report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); + report->freqoff = resp[5]; + report->rssi = resp[6]; + report->snr = resp[7]; + report->lassi = resp[9]; + report->hassi = resp[10]; + report->mult = resp[11]; + report->dev = resp[12]; + report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); + report->assi = resp[15]; + report->usn = resp[16]; + + return err; +} + + +static int si476x_core_cmd_fm_rsq_status_a30(struct si476x_core *core, + struct si476x_rsq_status_args *rsqargs, + struct si476x_rsq_status_report *report) +{ + int err; + u8 resp[CMD_FM_RSQ_STATUS_A30_NRESP]; + const u8 args[CMD_FM_RSQ_STATUS_A30_NARGS] = { + rsqargs->primary << 4 | rsqargs->rsqack << 3 | + rsqargs->attune << 2 | rsqargs->cancel << 1 | + rsqargs->stcack, + }; + + err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, + args, ARRAY_SIZE(args), + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); + /* + * Besides getting received signal quality information this + * command can be used to just acknowledge different interrupt + * flags in those cases it is useless to copy and parse + * received data so user can pass NULL, and thus avoid + * unnecessary copying. + */ + if (err < 0 || report == NULL) + return err; + + report->multhint = 0b10000000 & resp[1]; + report->multlint = 0b01000000 & resp[1]; + report->snrhint = 0b00001000 & resp[1]; + report->snrlint = 0b00000100 & resp[1]; + report->rssihint = 0b00000010 & resp[1]; + report->rssilint = 0b00000001 & resp[1]; + + report->bltf = 0b10000000 & resp[2]; + report->snr_ready = 0b00100000 & resp[2]; + report->rssiready = 0b00001000 & resp[2]; + report->injside = 0b00000100 & resp[2]; + report->afcrl = 0b00000010 & resp[2]; + report->valid = 0b00000001 & resp[2]; + + report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); + report->freqoff = resp[5]; + report->rssi = resp[6]; + report->snr = resp[7]; + report->issi = resp[8]; + report->lassi = resp[9]; + report->hassi = resp[10]; + report->mult = resp[11]; + report->dev = resp[12]; + report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); + report->assi = resp[15]; + report->usn = resp[16]; + + report->pilotdev = resp[17]; + report->rdsdev = resp[18]; + report->assidev = resp[19]; + report->strongdev = resp[20]; + report->rdspi = be16_to_cpup((__be16 *)(resp + 21)); + + return err; +} + +static int si476x_core_cmd_fm_tune_freq_a10(struct si476x_core *core, + struct si476x_tune_freq_args *tuneargs) +{ + u8 resp[CMD_FM_TUNE_FREQ_NRESP]; + const u8 args[CMD_FM_TUNE_FREQ_A10_NARGS] = { + (tuneargs->hd << 6) | (tuneargs->tunemode << 4) + | (tuneargs->smoothmetrics << 2), + msb(tuneargs->freq), + lsb(tuneargs->freq), + msb(tuneargs->antcap), + lsb(tuneargs->antcap) + }; + + return si476x_cmd_tune_seek_freq(core, CMD_FM_TUNE_FREQ, + args, sizeof(args), + resp, sizeof(resp)); +} + +static int si476x_core_cmd_fm_tune_freq_a20(struct si476x_core *core, + struct si476x_tune_freq_args *tuneargs) +{ + u8 resp[CMD_FM_TUNE_FREQ_NRESP]; + const u8 args[CMD_FM_TUNE_FREQ_A20_NARGS] = { + (tuneargs->hd << 6) | (tuneargs->tunemode << 4) + | (tuneargs->smoothmetrics << 2) | (tuneargs->injside), + msb(tuneargs->freq), + lsb(tuneargs->freq), + }; + + return si476x_cmd_tune_seek_freq(core, CMD_FM_TUNE_FREQ, + args, sizeof(args), + resp, sizeof(resp)); +} + +static int si476x_core_cmd_agc_status_a20(struct si476x_core *core, + struct si476x_agc_status_report *report) +{ + int err; + u8 resp[CMD_AGC_STATUS_NRESP_A20]; + + if (!report) + return -EINVAL; + + err = si476x_core_send_command(core, CMD_AGC_STATUS, + NULL, 0, + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); + if (err < 0) + return err; + + report->mxhi = resp[1] & SI476X_AGC_MXHI; + report->mxlo = resp[1] & SI476X_AGC_MXLO; + report->lnahi = resp[1] & SI476X_AGC_LNAHI; + report->lnalo = resp[1] & SI476X_AGC_LNALO; + report->fmagc1 = resp[2]; + report->fmagc2 = resp[3]; + report->pgagain = resp[4]; + report->fmwblang = resp[5]; + + return err; +} + +static int si476x_core_cmd_agc_status_a10(struct si476x_core *core, + struct si476x_agc_status_report *report) +{ + int err; + u8 resp[CMD_AGC_STATUS_NRESP_A10]; + + if (!report) + return -EINVAL; + + err = si476x_core_send_command(core, CMD_AGC_STATUS, + NULL, 0, + resp, ARRAY_SIZE(resp), + SI476X_DEFAULT_TIMEOUT); + if (err < 0) + return err; + + report->mxhi = resp[1] & SI476X_AGC_MXHI; + report->mxlo = resp[1] & SI476X_AGC_MXLO; + report->lnahi = resp[1] & SI476X_AGC_LNAHI; + report->lnalo = resp[1] & SI476X_AGC_LNALO; + + return err; +} + +typedef int (*tune_freq_func_t) (struct si476x_core *core, + struct si476x_tune_freq_args *tuneargs); + +static struct { + int (*power_up) (struct si476x_core *, + struct si476x_power_up_args *); + int (*power_down) (struct si476x_core *, + struct si476x_power_down_args *); + + tune_freq_func_t fm_tune_freq; + tune_freq_func_t am_tune_freq; + + int (*fm_rsq_status)(struct si476x_core *, + struct si476x_rsq_status_args *, + struct si476x_rsq_status_report *); + + int (*agc_status)(struct si476x_core *, + struct si476x_agc_status_report *); + int (*intb_pin_cfg)(struct si476x_core *core, + enum si476x_intb_config intb, + enum si476x_a1_config a1); +} si476x_cmds_vtable[] = { + [SI476X_REVISION_A10] = { + .power_up = si476x_core_cmd_power_up_a10, + .power_down = si476x_core_cmd_power_down_a10, + .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a10, + .am_tune_freq = si476x_core_cmd_am_tune_freq_a10, + .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a10, + .agc_status = si476x_core_cmd_agc_status_a10, + .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a10, + }, + [SI476X_REVISION_A20] = { + .power_up = si476x_core_cmd_power_up_a20, + .power_down = si476x_core_cmd_power_down_a20, + .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a20, + .am_tune_freq = si476x_core_cmd_am_tune_freq_a20, + .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a20, + .agc_status = si476x_core_cmd_agc_status_a20, + .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a20, + }, + [SI476X_REVISION_A30] = { + .power_up = si476x_core_cmd_power_up_a20, + .power_down = si476x_core_cmd_power_down_a20, + .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a20, + .am_tune_freq = si476x_core_cmd_am_tune_freq_a20, + .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a30, + .agc_status = si476x_core_cmd_agc_status_a20, + .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a20, + }, +}; + +int si476x_core_cmd_power_up(struct si476x_core *core, + struct si476x_power_up_args *args) +{ + BUG_ON(core->revision > SI476X_REVISION_A30 || + core->revision == -1); + return si476x_cmds_vtable[core->revision].power_up(core, args); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_power_up); + +int si476x_core_cmd_power_down(struct si476x_core *core, + struct si476x_power_down_args *args) +{ + BUG_ON(core->revision > SI476X_REVISION_A30 || + core->revision == -1); + return si476x_cmds_vtable[core->revision].power_down(core, args); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_power_down); + +int si476x_core_cmd_fm_tune_freq(struct si476x_core *core, + struct si476x_tune_freq_args *args) +{ + BUG_ON(core->revision > SI476X_REVISION_A30 || + core->revision == -1); + return si476x_cmds_vtable[core->revision].fm_tune_freq(core, args); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_tune_freq); + +int si476x_core_cmd_am_tune_freq(struct si476x_core *core, + struct si476x_tune_freq_args *args) +{ + BUG_ON(core->revision > SI476X_REVISION_A30 || + core->revision == -1); + return si476x_cmds_vtable[core->revision].am_tune_freq(core, args); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_am_tune_freq); + +int si476x_core_cmd_fm_rsq_status(struct si476x_core *core, + struct si476x_rsq_status_args *args, + struct si476x_rsq_status_report *report) + +{ + BUG_ON(core->revision > SI476X_REVISION_A30 || + core->revision == -1); + return si476x_cmds_vtable[core->revision].fm_rsq_status(core, args, + report); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rsq_status); + +int si476x_core_cmd_agc_status(struct si476x_core *core, + struct si476x_agc_status_report *report) + +{ + BUG_ON(core->revision > SI476X_REVISION_A30 || + core->revision == -1); + return si476x_cmds_vtable[core->revision].agc_status(core, report); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_agc_status); + +int si476x_core_cmd_intb_pin_cfg(struct si476x_core *core, + enum si476x_intb_config intb, + enum si476x_a1_config a1) +{ + BUG_ON(core->revision > SI476X_REVISION_A30 || + core->revision == -1); + + return si476x_cmds_vtable[core->revision].intb_pin_cfg(core, intb, a1); +} +EXPORT_SYMBOL_GPL(si476x_core_cmd_intb_pin_cfg); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Andrey Smirnov "); +MODULE_DESCRIPTION("API for command exchange for si476x"); -- cgit v0.10.2 From b40fe4f67de2c826868f408e03f2ef9fe39d85b9 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 26 Mar 2013 22:47:19 -0300 Subject: [media] mfd: Add the main bulk of core driver for SI476x code This patch adds main part(out of three) of the I2C driver for the "core" of MFD device. Acked-by: Hans Verkuil Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c new file mode 100644 index 0000000..118c6b1 --- /dev/null +++ b/drivers/mfd/si476x-i2c.c @@ -0,0 +1,886 @@ +/* + * drivers/mfd/si476x-i2c.c -- Core device driver for si476x MFD + * device + * + * 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 + +#define SI476X_MAX_IO_ERRORS 10 +#define SI476X_DRIVER_RDS_FIFO_DEPTH 128 + +/** + * si476x_core_config_pinmux() - pin function configuration function + * + * @core: Core device structure + * + * Configure the functions of the pins of the radio chip. + * + * The function returns zero in case of succes or negative error code + * otherwise. + */ +static int si476x_core_config_pinmux(struct si476x_core *core) +{ + int err; + dev_dbg(&core->client->dev, "Configuring pinmux\n"); + err = si476x_core_cmd_dig_audio_pin_cfg(core, + core->pinmux.dclk, + core->pinmux.dfs, + core->pinmux.dout, + core->pinmux.xout); + if (err < 0) { + dev_err(&core->client->dev, + "Failed to configure digital audio pins(err = %d)\n", + err); + return err; + } + + err = si476x_core_cmd_zif_pin_cfg(core, + core->pinmux.iqclk, + core->pinmux.iqfs, + core->pinmux.iout, + core->pinmux.qout); + if (err < 0) { + dev_err(&core->client->dev, + "Failed to configure ZIF pins(err = %d)\n", + err); + return err; + } + + err = si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(core, + core->pinmux.icin, + core->pinmux.icip, + core->pinmux.icon, + core->pinmux.icop); + if (err < 0) { + dev_err(&core->client->dev, + "Failed to configure IC-Link/GPO pins(err = %d)\n", + err); + return err; + } + + err = si476x_core_cmd_ana_audio_pin_cfg(core, + core->pinmux.lrout); + if (err < 0) { + dev_err(&core->client->dev, + "Failed to configure analog audio pins(err = %d)\n", + err); + return err; + } + + err = si476x_core_cmd_intb_pin_cfg(core, + core->pinmux.intb, + core->pinmux.a1); + if (err < 0) { + dev_err(&core->client->dev, + "Failed to configure interrupt pins(err = %d)\n", + err); + return err; + } + + return 0; +} + +static inline void si476x_core_schedule_polling_work(struct si476x_core *core) +{ + schedule_delayed_work(&core->status_monitor, + usecs_to_jiffies(SI476X_STATUS_POLL_US)); +} + +/** + * si476x_core_start() - early chip startup function + * @core: Core device structure + * @soft: When set, this flag forces "soft" startup, where "soft" + * power down is the one done by sending appropriate command instead + * of using reset pin of the tuner + * + * Perform required startup sequence to correctly power + * up the chip and perform initial configuration. It does the + * following sequence of actions: + * 1. Claims and enables the power supplies VD and VIO1 required + * for I2C interface of the chip operation. + * 2. Waits for 100us, pulls the reset line up, enables irq, + * waits for another 100us as it is specified by the + * datasheet. + * 3. Sends 'POWER_UP' command to the device with all provided + * information about power-up parameters. + * 4. Configures, pin multiplexor, disables digital audio and + * configures interrupt sources. + * + * The function returns zero in case of succes or negative error code + * otherwise. + */ +int si476x_core_start(struct si476x_core *core, bool soft) +{ + struct i2c_client *client = core->client; + int err; + + if (!soft) { + if (gpio_is_valid(core->gpio_reset)) + gpio_set_value_cansleep(core->gpio_reset, 1); + + if (client->irq) + enable_irq(client->irq); + + udelay(100); + + if (!client->irq) { + atomic_set(&core->is_alive, 1); + si476x_core_schedule_polling_work(core); + } + } else { + if (client->irq) + enable_irq(client->irq); + else { + atomic_set(&core->is_alive, 1); + si476x_core_schedule_polling_work(core); + } + } + + err = si476x_core_cmd_power_up(core, + &core->power_up_parameters); + + if (err < 0) { + dev_err(&core->client->dev, + "Power up failure(err = %d)\n", + err); + goto disable_irq; + } + + if (client->irq) + atomic_set(&core->is_alive, 1); + + err = si476x_core_config_pinmux(core); + if (err < 0) { + dev_err(&core->client->dev, + "Failed to configure pinmux(err = %d)\n", + err); + goto disable_irq; + } + + if (client->irq) { + err = regmap_write(core->regmap, + SI476X_PROP_INT_CTL_ENABLE, + SI476X_RDSIEN | + SI476X_STCIEN | + SI476X_CTSIEN); + if (err < 0) { + dev_err(&core->client->dev, + "Failed to configure interrupt sources" + "(err = %d)\n", err); + goto disable_irq; + } + } + + return 0; + +disable_irq: + if (err == -ENODEV) + atomic_set(&core->is_alive, 0); + + if (client->irq) + disable_irq(client->irq); + else + cancel_delayed_work_sync(&core->status_monitor); + + if (gpio_is_valid(core->gpio_reset)) + gpio_set_value_cansleep(core->gpio_reset, 0); + + return err; +} +EXPORT_SYMBOL_GPL(si476x_core_start); + +/** + * si476x_core_stop() - chip power-down function + * @core: Core device structure + * @soft: When set, function sends a POWER_DOWN command instead of + * bringing reset line low + * + * Power down the chip by performing following actions: + * 1. Disable IRQ or stop the polling worker + * 2. Send the POWER_DOWN command if the power down is soft or bring + * reset line low if not. + * + * The function returns zero in case of succes or negative error code + * otherwise. + */ +int si476x_core_stop(struct si476x_core *core, bool soft) +{ + int err = 0; + atomic_set(&core->is_alive, 0); + + if (soft) { + /* TODO: This probably shoud be a configurable option, + * so it is possible to have the chips keep their + * oscillators running + */ + struct si476x_power_down_args args = { + .xosc = false, + }; + err = si476x_core_cmd_power_down(core, &args); + } + + /* We couldn't disable those before + * 'si476x_core_cmd_power_down' since we expect to get CTS + * interrupt */ + if (core->client->irq) + disable_irq(core->client->irq); + else + cancel_delayed_work_sync(&core->status_monitor); + + if (!soft) { + if (gpio_is_valid(core->gpio_reset)) + gpio_set_value_cansleep(core->gpio_reset, 0); + } + return err; +} +EXPORT_SYMBOL_GPL(si476x_core_stop); + +/** + * si476x_core_set_power_state() - set the level at which the power is + * supplied for the chip. + * @core: Core device structure + * @next_state: enum si476x_power_state describing power state to + * switch to. + * + * Switch on all the required power supplies + * + * This function returns 0 in case of suvccess and negative error code + * otherwise. + */ +int si476x_core_set_power_state(struct si476x_core *core, + enum si476x_power_state next_state) +{ + /* + It is not clear form the datasheet if it is possible to + work with device if not all power domains are operational. + So for now the power-up policy is "power-up all the things!" + */ + int err = 0; + + if (core->power_state == SI476X_POWER_INCONSISTENT) { + dev_err(&core->client->dev, + "The device in inconsistent power state\n"); + return -EINVAL; + } + + if (next_state != core->power_state) { + switch (next_state) { + case SI476X_POWER_UP_FULL: + err = regulator_bulk_enable(ARRAY_SIZE(core->supplies), + core->supplies); + if (err < 0) { + core->power_state = SI476X_POWER_INCONSISTENT; + break; + } + /* + * Startup timing diagram recommends to have a + * 100 us delay between enabling of the power + * supplies and turning the tuner on. + */ + udelay(100); + + err = si476x_core_start(core, false); + if (err < 0) + goto disable_regulators; + + core->power_state = next_state; + break; + + case SI476X_POWER_DOWN: + core->power_state = next_state; + err = si476x_core_stop(core, false); + if (err < 0) + core->power_state = SI476X_POWER_INCONSISTENT; +disable_regulators: + err = regulator_bulk_disable(ARRAY_SIZE(core->supplies), + core->supplies); + if (err < 0) + core->power_state = SI476X_POWER_INCONSISTENT; + break; + default: + BUG(); + } + } + + return err; +} +EXPORT_SYMBOL_GPL(si476x_core_set_power_state); + +/** + * si476x_core_report_drainer_stop() - mark the completion of the RDS + * buffer drain porcess by the worker. + * + * @core: Core device structure + */ +static inline void si476x_core_report_drainer_stop(struct si476x_core *core) +{ + mutex_lock(&core->rds_drainer_status_lock); + core->rds_drainer_is_working = false; + mutex_unlock(&core->rds_drainer_status_lock); +} + +/** + * si476x_core_start_rds_drainer_once() - start RDS drainer worker if + * ther is none working, do nothing otherwise + * + * @core: Datastructure corresponding to the chip. + */ +static inline void si476x_core_start_rds_drainer_once(struct si476x_core *core) +{ + mutex_lock(&core->rds_drainer_status_lock); + if (!core->rds_drainer_is_working) { + core->rds_drainer_is_working = true; + schedule_work(&core->rds_fifo_drainer); + } + mutex_unlock(&core->rds_drainer_status_lock); +} +/** + * si476x_drain_rds_fifo() - RDS buffer drainer. + * @work: struct work_struct being ppassed to the function by the + * kernel. + * + * Drain the contents of the RDS FIFO of + */ +static void si476x_core_drain_rds_fifo(struct work_struct *work) +{ + int err; + + struct si476x_core *core = container_of(work, struct si476x_core, + rds_fifo_drainer); + + struct si476x_rds_status_report report; + + si476x_core_lock(core); + err = si476x_core_cmd_fm_rds_status(core, true, false, false, &report); + if (!err) { + int i = report.rdsfifoused; + dev_dbg(&core->client->dev, + "%d elements in RDS FIFO. Draining.\n", i); + for (; i > 0; --i) { + err = si476x_core_cmd_fm_rds_status(core, false, false, + (i == 1), &report); + if (err < 0) + goto unlock; + + 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); + } + dev_dbg(&core->client->dev, "Drrrrained!\n"); + wake_up_interruptible(&core->rds_read_queue); + } + +unlock: + si476x_core_unlock(core); + si476x_core_report_drainer_stop(core); +} + +/** + * si476x_core_pronounce_dead() + * + * @core: Core device structure + * + * Mark the device as being dead and wake up all potentially waiting + * threads of execution. + * + */ +static void si476x_core_pronounce_dead(struct si476x_core *core) +{ + dev_info(&core->client->dev, "Core device is dead.\n"); + + atomic_set(&core->is_alive, 0); + + /* Wake up al possible waiting processes */ + wake_up_interruptible(&core->rds_read_queue); + + atomic_set(&core->cts, 1); + wake_up(&core->command); + + atomic_set(&core->stc, 1); + wake_up(&core->tuning); +} + +/** + * si476x_core_i2c_xfer() + * + * @core: Core device structure + * @type: Transfer type + * @buf: Transfer buffer for/with data + * @count: Transfer buffer size + * + * Perfrom and I2C transfer(either read or write) and keep a counter + * of I/O errors. If the error counter rises above the threshold + * pronounce device dead. + * + * The function returns zero on succes or negative error code on + * failure. + */ +int si476x_core_i2c_xfer(struct si476x_core *core, + enum si476x_i2c_type type, + char *buf, int count) +{ + static int io_errors_count; + int err; + if (type == SI476X_I2C_SEND) + err = i2c_master_send(core->client, buf, count); + else + err = i2c_master_recv(core->client, buf, count); + + if (err < 0) { + if (io_errors_count++ > SI476X_MAX_IO_ERRORS) + si476x_core_pronounce_dead(core); + } else { + io_errors_count = 0; + } + + return err; +} +EXPORT_SYMBOL_GPL(si476x_core_i2c_xfer); + +/** + * si476x_get_status() + * @core: Core device structure + * + * Get the status byte of the core device by berforming one byte I2C + * read. + * + * The function returns a status value or a negative error code on + * error. + */ +static int si476x_core_get_status(struct si476x_core *core) +{ + u8 response; + int err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, + &response, sizeof(response)); + + return (err < 0) ? err : response; +} + +/** + * si476x_get_and_signal_status() - IRQ dispatcher + * @core: Core device structure + * + * Dispatch the arrived interrupt request based on the value of the + * status byte reported by the tuner. + * + */ +static void si476x_core_get_and_signal_status(struct si476x_core *core) +{ + int status = si476x_core_get_status(core); + if (status < 0) { + dev_err(&core->client->dev, "Failed to get status\n"); + return; + } + + if (status & SI476X_CTS) { + /* Unfortunately completions could not be used for + * signalling CTS since this flag cannot be cleared + * in status byte, and therefore once it becomes true + * multiple calls to 'complete' would cause the + * commands following the current one to be completed + * before they actually are */ + dev_dbg(&core->client->dev, "[interrupt] CTSINT\n"); + atomic_set(&core->cts, 1); + wake_up(&core->command); + } + + if (status & SI476X_FM_RDS_INT) { + dev_dbg(&core->client->dev, "[interrupt] RDSINT\n"); + si476x_core_start_rds_drainer_once(core); + } + + if (status & SI476X_STC_INT) { + dev_dbg(&core->client->dev, "[interrupt] STCINT\n"); + atomic_set(&core->stc, 1); + wake_up(&core->tuning); + } +} + +static void si476x_core_poll_loop(struct work_struct *work) +{ + struct si476x_core *core = SI476X_WORK_TO_CORE(work); + + si476x_core_get_and_signal_status(core); + + if (atomic_read(&core->is_alive)) + si476x_core_schedule_polling_work(core); +} + +static irqreturn_t si476x_core_interrupt(int irq, void *dev) +{ + struct si476x_core *core = dev; + + si476x_core_get_and_signal_status(core); + + return IRQ_HANDLED; +} + +/** + * si476x_firmware_version_to_revision() + * @core: Core device structure + * @major: Firmware major number + * @minor1: Firmware first minor number + * @minor2: Firmware second minor number + * + * Convert a chip's firmware version number into an offset that later + * will be used to as offset in "vtable" of tuner functions + * + * This function returns a positive offset in case of success and a -1 + * in case of failure. + */ +static int si476x_core_fwver_to_revision(struct si476x_core *core, + int func, int major, + int minor1, int minor2) +{ + switch (func) { + case SI476X_FUNC_FM_RECEIVER: + switch (major) { + case 5: + return SI476X_REVISION_A10; + case 8: + return SI476X_REVISION_A20; + case 10: + return SI476X_REVISION_A30; + default: + goto unknown_revision; + } + case SI476X_FUNC_AM_RECEIVER: + switch (major) { + case 5: + return SI476X_REVISION_A10; + case 7: + return SI476X_REVISION_A20; + case 9: + return SI476X_REVISION_A30; + default: + goto unknown_revision; + } + case SI476X_FUNC_WB_RECEIVER: + switch (major) { + case 3: + return SI476X_REVISION_A10; + case 5: + return SI476X_REVISION_A20; + case 7: + return SI476X_REVISION_A30; + default: + goto unknown_revision; + } + case SI476X_FUNC_BOOTLOADER: + default: /* FALLTHROUG */ + BUG(); + return -1; + } + +unknown_revision: + dev_err(&core->client->dev, + "Unsupported version of the firmware: %d.%d.%d, " + "reverting to A10 comptible functions\n", + major, minor1, minor2); + + return SI476X_REVISION_A10; +} + +/** + * si476x_get_revision_info() + * @core: Core device structure + * + * Get the firmware version number of the device. It is done in + * following three steps: + * 1. Power-up the device + * 2. Send the 'FUNC_INFO' command + * 3. Powering the device down. + * + * The function return zero on success and a negative error code on + * failure. + */ +static int si476x_core_get_revision_info(struct si476x_core *core) +{ + int rval; + struct si476x_func_info info; + + si476x_core_lock(core); + rval = si476x_core_set_power_state(core, SI476X_POWER_UP_FULL); + if (rval < 0) + goto exit; + + rval = si476x_core_cmd_func_info(core, &info); + if (rval < 0) + goto power_down; + + core->revision = si476x_core_fwver_to_revision(core, info.func, + info.firmware.major, + info.firmware.minor[0], + info.firmware.minor[1]); +power_down: + si476x_core_set_power_state(core, SI476X_POWER_DOWN); +exit: + si476x_core_unlock(core); + + return rval; +} + +bool si476x_core_has_am(struct si476x_core *core) +{ + return core->chip_id == SI476X_CHIP_SI4761 || + core->chip_id == SI476X_CHIP_SI4764; +} +EXPORT_SYMBOL_GPL(si476x_core_has_am); + +bool si476x_core_has_diversity(struct si476x_core *core) +{ + return core->chip_id == SI476X_CHIP_SI4764; +} +EXPORT_SYMBOL_GPL(si476x_core_has_diversity); + +bool si476x_core_is_a_secondary_tuner(struct si476x_core *core) +{ + return si476x_core_has_diversity(core) && + (core->diversity_mode == SI476X_PHDIV_SECONDARY_ANTENNA || + core->diversity_mode == SI476X_PHDIV_SECONDARY_COMBINING); +} +EXPORT_SYMBOL_GPL(si476x_core_is_a_secondary_tuner); + +bool si476x_core_is_a_primary_tuner(struct si476x_core *core) +{ + return si476x_core_has_diversity(core) && + (core->diversity_mode == SI476X_PHDIV_PRIMARY_ANTENNA || + core->diversity_mode == SI476X_PHDIV_PRIMARY_COMBINING); +} +EXPORT_SYMBOL_GPL(si476x_core_is_a_primary_tuner); + +bool si476x_core_is_in_am_receiver_mode(struct si476x_core *core) +{ + return si476x_core_has_am(core) && + (core->power_up_parameters.func == SI476X_FUNC_AM_RECEIVER); +} +EXPORT_SYMBOL_GPL(si476x_core_is_in_am_receiver_mode); + +bool si476x_core_is_powered_up(struct si476x_core *core) +{ + return core->power_state == SI476X_POWER_UP_FULL; +} +EXPORT_SYMBOL_GPL(si476x_core_is_powered_up); + +static int si476x_core_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rval; + struct si476x_core *core; + struct si476x_platform_data *pdata; + struct mfd_cell *cell; + int cell_num; + + core = devm_kzalloc(&client->dev, sizeof(*core), GFP_KERNEL); + if (!core) { + dev_err(&client->dev, + "failed to allocate 'struct si476x_core'\n"); + return -ENOMEM; + } + core->client = client; + + core->regmap = devm_regmap_init_si476x(core); + if (IS_ERR(core->regmap)) { + rval = PTR_ERR(core->regmap); + dev_err(&client->dev, + "Failed to allocate register map: %d\n", + rval); + return rval; + } + + i2c_set_clientdata(client, core); + + atomic_set(&core->is_alive, 0); + core->power_state = SI476X_POWER_DOWN; + + pdata = client->dev.platform_data; + if (pdata) { + memcpy(&core->power_up_parameters, + &pdata->power_up_parameters, + sizeof(core->power_up_parameters)); + + core->gpio_reset = -1; + if (gpio_is_valid(pdata->gpio_reset)) { + rval = gpio_request(pdata->gpio_reset, "si476x reset"); + if (rval) { + dev_err(&client->dev, + "Failed to request gpio: %d\n", rval); + return rval; + } + core->gpio_reset = pdata->gpio_reset; + gpio_direction_output(core->gpio_reset, 0); + } + + core->diversity_mode = pdata->diversity_mode; + memcpy(&core->pinmux, &pdata->pinmux, + sizeof(struct si476x_pinmux)); + } else { + dev_err(&client->dev, "No platform data provided\n"); + return -EINVAL; + } + + core->supplies[0].supply = "vd"; + core->supplies[1].supply = "va"; + core->supplies[2].supply = "vio1"; + core->supplies[3].supply = "vio2"; + + rval = devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(core->supplies), + core->supplies); + if (rval) { + dev_err(&client->dev, "Failet to gett all of the regulators\n"); + goto free_gpio; + } + + mutex_init(&core->cmd_lock); + init_waitqueue_head(&core->command); + init_waitqueue_head(&core->tuning); + + rval = kfifo_alloc(&core->rds_fifo, + SI476X_DRIVER_RDS_FIFO_DEPTH * + sizeof(struct v4l2_rds_data), + GFP_KERNEL); + if (rval) { + dev_err(&client->dev, "Could not alloate the FIFO\n"); + goto free_gpio; + } + mutex_init(&core->rds_drainer_status_lock); + init_waitqueue_head(&core->rds_read_queue); + INIT_WORK(&core->rds_fifo_drainer, si476x_core_drain_rds_fifo); + + if (client->irq) { + rval = devm_request_threaded_irq(&client->dev, + client->irq, NULL, + si476x_core_interrupt, + IRQF_TRIGGER_FALLING, + client->name, core); + if (rval < 0) { + dev_err(&client->dev, "Could not request IRQ %d\n", + client->irq); + goto free_kfifo; + } + disable_irq(client->irq); + dev_dbg(&client->dev, "IRQ requested.\n"); + + core->rds_fifo_depth = 20; + } else { + INIT_DELAYED_WORK(&core->status_monitor, + si476x_core_poll_loop); + dev_info(&client->dev, + "No IRQ number specified, will use polling\n"); + + core->rds_fifo_depth = 5; + } + + core->chip_id = id->driver_data; + + rval = si476x_core_get_revision_info(core); + if (rval < 0) { + rval = -ENODEV; + goto free_kfifo; + } + + cell_num = 0; + + cell = &core->cells[SI476X_RADIO_CELL]; + cell->name = "si476x-radio"; + cell_num++; + +#ifdef CONFIG_SND_SOC_SI476X + if ((core->chip_id == SI476X_CHIP_SI4761 || + core->chip_id == SI476X_CHIP_SI4764) && + core->pinmux.dclk == SI476X_DCLK_DAUDIO && + core->pinmux.dfs == SI476X_DFS_DAUDIO && + core->pinmux.dout == SI476X_DOUT_I2S_OUTPUT && + core->pinmux.xout == SI476X_XOUT_TRISTATE) { + cell = &core->cells[SI476X_CODEC_CELL]; + cell->name = "si476x-codec"; + cell_num++; + } +#endif + rval = mfd_add_devices(&client->dev, + (client->adapter->nr << 8) + client->addr, + core->cells, cell_num, + NULL, 0, NULL); + if (!rval) + return 0; + +free_kfifo: + kfifo_free(&core->rds_fifo); + +free_gpio: + if (gpio_is_valid(core->gpio_reset)) + gpio_free(core->gpio_reset); + + return rval; +} + +static int si476x_core_remove(struct i2c_client *client) +{ + struct si476x_core *core = i2c_get_clientdata(client); + + si476x_core_pronounce_dead(core); + mfd_remove_devices(&client->dev); + + if (client->irq) + disable_irq(client->irq); + else + cancel_delayed_work_sync(&core->status_monitor); + + kfifo_free(&core->rds_fifo); + + if (gpio_is_valid(core->gpio_reset)) + gpio_free(core->gpio_reset); + + return 0; +} + + +static const struct i2c_device_id si476x_id[] = { + { "si4761", SI476X_CHIP_SI4761 }, + { "si4764", SI476X_CHIP_SI4764 }, + { "si4768", SI476X_CHIP_SI4768 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, si476x_id); + +static struct i2c_driver si476x_core_driver = { + .driver = { + .name = "si476x-core", + .owner = THIS_MODULE, + }, + .probe = si476x_core_probe, + .remove = si476x_core_remove, + .id_table = si476x_id, +}; +module_i2c_driver(si476x_core_driver); + + +MODULE_AUTHOR("Andrey Smirnov "); +MODULE_DESCRIPTION("Si4761/64/68 AM/FM MFD core device driver"); +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From a118e9c122969a924061b48b6cc6bb73ccc8de4c Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 26 Mar 2013 22:47:20 -0300 Subject: [media] mfd: Add chip properties handling code for SI476X MFD This patch adds code related to manipulation of the properties of SI476X chips. Acked-by: Hans Verkuil Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/mfd/si476x-prop.c b/drivers/mfd/si476x-prop.c new file mode 100644 index 0000000..d1f548a --- /dev/null +++ b/drivers/mfd/si476x-prop.c @@ -0,0 +1,242 @@ +/* + * drivers/mfd/si476x-prop.c -- Subroutines to access + * properties of 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 + +struct si476x_property_range { + u16 low, high; +}; + +static bool si476x_core_element_is_in_array(u16 element, + const u16 array[], + size_t size) +{ + int i; + + for (i = 0; i < size; i++) + if (element == array[i]) + return true; + + return false; +} + +static bool si476x_core_element_is_in_range(u16 element, + const struct si476x_property_range range[], + size_t size) +{ + int i; + + for (i = 0; i < size; i++) + if (element <= range[i].high && element >= range[i].low) + return true; + + return false; +} + +static bool si476x_core_is_valid_property_a10(struct si476x_core *core, + u16 property) +{ + static const u16 valid_properties[] = { + 0x0000, + 0x0500, 0x0501, + 0x0600, + 0x0709, 0x070C, 0x070D, 0x70E, 0x710, + 0x0718, + 0x1207, 0x1208, + 0x2007, + 0x2300, + }; + + static const struct si476x_property_range valid_ranges[] = { + { 0x0200, 0x0203 }, + { 0x0300, 0x0303 }, + { 0x0400, 0x0404 }, + { 0x0700, 0x0707 }, + { 0x1100, 0x1102 }, + { 0x1200, 0x1204 }, + { 0x1300, 0x1306 }, + { 0x2000, 0x2005 }, + { 0x2100, 0x2104 }, + { 0x2106, 0x2106 }, + { 0x2200, 0x220E }, + { 0x3100, 0x3104 }, + { 0x3207, 0x320F }, + { 0x3300, 0x3304 }, + { 0x3500, 0x3517 }, + { 0x3600, 0x3617 }, + { 0x3700, 0x3717 }, + { 0x4000, 0x4003 }, + }; + + return si476x_core_element_is_in_range(property, valid_ranges, + ARRAY_SIZE(valid_ranges)) || + si476x_core_element_is_in_array(property, valid_properties, + ARRAY_SIZE(valid_properties)); +} + +static bool si476x_core_is_valid_property_a20(struct si476x_core *core, + u16 property) +{ + static const u16 valid_properties[] = { + 0x071B, + 0x1006, + 0x2210, + 0x3401, + }; + + static const struct si476x_property_range valid_ranges[] = { + { 0x2215, 0x2219 }, + }; + + return si476x_core_is_valid_property_a10(core, property) || + si476x_core_element_is_in_range(property, valid_ranges, + ARRAY_SIZE(valid_ranges)) || + si476x_core_element_is_in_array(property, valid_properties, + ARRAY_SIZE(valid_properties)); +} + +static bool si476x_core_is_valid_property_a30(struct si476x_core *core, + u16 property) +{ + static const u16 valid_properties[] = { + 0x071C, 0x071D, + 0x1007, 0x1008, + 0x220F, 0x2214, + 0x2301, + 0x3105, 0x3106, + 0x3402, + }; + + static const struct si476x_property_range valid_ranges[] = { + { 0x0405, 0x0411 }, + { 0x2008, 0x200B }, + { 0x2220, 0x2223 }, + { 0x3100, 0x3106 }, + }; + + return si476x_core_is_valid_property_a20(core, property) || + si476x_core_element_is_in_range(property, valid_ranges, + ARRAY_SIZE(valid_ranges)) || + si476x_core_element_is_in_array(property, valid_properties, + ARRAY_SIZE(valid_properties)); +} + +typedef bool (*valid_property_pred_t) (struct si476x_core *, u16); + +static bool si476x_core_is_valid_property(struct si476x_core *core, + u16 property) +{ + static const valid_property_pred_t is_valid_property[] = { + [SI476X_REVISION_A10] = si476x_core_is_valid_property_a10, + [SI476X_REVISION_A20] = si476x_core_is_valid_property_a20, + [SI476X_REVISION_A30] = si476x_core_is_valid_property_a30, + }; + + BUG_ON(core->revision > SI476X_REVISION_A30 || + core->revision == -1); + return is_valid_property[core->revision](core, property); +} + + +static bool si476x_core_is_readonly_property(struct si476x_core *core, + u16 property) +{ + BUG_ON(core->revision > SI476X_REVISION_A30 || + core->revision == -1); + + switch (core->revision) { + case SI476X_REVISION_A10: + return (property == 0x3200); + case SI476X_REVISION_A20: + return (property == 0x1006 || + property == 0x2210 || + property == 0x3200); + case SI476X_REVISION_A30: + return false; + } + + return false; +} + +static bool si476x_core_regmap_readable_register(struct device *dev, + unsigned int reg) +{ + struct i2c_client *client = to_i2c_client(dev); + struct si476x_core *core = i2c_get_clientdata(client); + + return si476x_core_is_valid_property(core, (u16) reg); + +} + +static bool si476x_core_regmap_writable_register(struct device *dev, + unsigned int reg) +{ + struct i2c_client *client = to_i2c_client(dev); + struct si476x_core *core = i2c_get_clientdata(client); + + return si476x_core_is_valid_property(core, (u16) reg) && + !si476x_core_is_readonly_property(core, (u16) reg); +} + + +static int si476x_core_regmap_write(void *context, unsigned int reg, + unsigned int val) +{ + return si476x_core_cmd_set_property(context, reg, val); +} + +static int si476x_core_regmap_read(void *context, unsigned int reg, + unsigned *val) +{ + struct si476x_core *core = context; + int err; + + err = si476x_core_cmd_get_property(core, reg); + if (err < 0) + return err; + + *val = err; + + return 0; +} + + +static const struct regmap_config si476x_regmap_config = { + .reg_bits = 16, + .val_bits = 16, + + .max_register = 0x4003, + + .writeable_reg = si476x_core_regmap_writable_register, + .readable_reg = si476x_core_regmap_readable_register, + + .reg_read = si476x_core_regmap_read, + .reg_write = si476x_core_regmap_write, + + .cache_type = REGCACHE_RBTREE, +}; + +struct regmap *devm_regmap_init_si476x(struct si476x_core *core) +{ + return devm_regmap_init(&core->client->dev, NULL, + core, &si476x_regmap_config); +} +EXPORT_SYMBOL_GPL(devm_regmap_init_si476x); -- cgit v0.10.2 From 3f8ec5df11aa2ad7402cfb3368532a96b63426a4 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 26 Mar 2013 22:47:21 -0300 Subject: [media] mfd: Add header files and Kbuild plumbing for SI476x MFD core This patch adds all necessary header files and Kbuild plumbing for the core driver for Silicon Laboratories Si476x series of AM/FM tuner chips. The driver as a whole is implemented as an MFD device and this patch adds a core portion of it that provides all the necessary functionality to the two other drivers that represent radio and audio codec subsystems of the chip. Acked-by: Hans Verkuil Acked-by: Sam Ravnborg Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 671f5b1..9b80e1e 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -976,6 +976,18 @@ config MFD_WL1273_CORE driver connects the radio-wl1273 V4L2 module and the wl1273 audio codec. +config MFD_SI476X_CORE + tristate "Support for Silicon Laboratories 4761/64/68 AM/FM radio." + depends on I2C + select MFD_CORE + help + This is the core driver for the SI476x series of AM/FM + radio. This MFD driver connects the radio-si476x V4L2 module + and the si476x audio codec. + + To compile this driver as a module, choose M here: the + module will be called si476x-core. + config MFD_OMAP_USB_HOST bool "Support OMAP USBHS core and TLL driver" depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index b90409c..b7aaa1e 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -131,6 +131,10 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o obj-$(CONFIG_MFD_VX855) += vx855.o obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o + +si476x-core-y := si476x-cmd.o si476x-prop.o si476x-i2c.o +obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o + obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o diff --git a/include/linux/mfd/si476x-core.h b/include/linux/mfd/si476x-core.h new file mode 100644 index 0000000..2136b26 --- /dev/null +++ b/include/linux/mfd/si476x-core.h @@ -0,0 +1,525 @@ +/* + * include/media/si476x-core.h -- Common definitions for si476x core + * device + * + * Copyright (C) 2012 Innovative Converged Devices(ICD) + * + * 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_CORE_H +#define SI476X_CORE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Command Timeouts */ +#define SI476X_DEFAULT_TIMEOUT 100000 +#define SI476X_TIMEOUT_TUNE 700000 +#define SI476X_TIMEOUT_POWER_UP 330000 +#define SI476X_STATUS_POLL_US 0 + +/* -------------------- si476x-i2c.c ----------------------- */ + +enum si476x_freq_supported_chips { + SI476X_CHIP_SI4761 = 1, + SI476X_CHIP_SI4764, + SI476X_CHIP_SI4768, +}; + +enum si476x_mfd_cells { + SI476X_RADIO_CELL = 0, + SI476X_CODEC_CELL, + SI476X_MFD_CELLS, +}; + +/** + * enum si476x_power_state - possible power state of the si476x + * device. + * + * @SI476X_POWER_DOWN: In this state all regulators are turned off + * and the reset line is pulled low. The device is completely + * inactive. + * @SI476X_POWER_UP_FULL: In this state all the power regualtors are + * turned on, reset line pulled high, IRQ line is enabled(polling is + * active for polling use scenario) and device is turned on with + * POWER_UP command. The device is ready to be used. + * @SI476X_POWER_INCONSISTENT: This state indicates that previous + * power down was inconsistent, meaning some of the regulators were + * not turned down and thus use of the device, without power-cycling + * is impossible. + */ +enum si476x_power_state { + SI476X_POWER_DOWN = 0, + SI476X_POWER_UP_FULL = 1, + SI476X_POWER_INCONSISTENT = 2, +}; + +/** + * struct si476x_core - internal data structure representing the + * underlying "core" device which all the MFD cell-devices use. + * + * @client: Actual I2C client used to transfer commands to the chip. + * @chip_id: Last digit of the chip model(E.g. "1" for SI4761) + * @cells: MFD cell devices created by this driver. + * @cmd_lock: Mutex used to serialize all the requests to the core + * device. This filed should not be used directly. Instead + * si476x_core_lock()/si476x_core_unlock() should be used to get + * exclusive access to the "core" device. + * @users: Active users counter(Used by the radio cell) + * @rds_read_queue: Wait queue used to wait for RDS data. + * @rds_fifo: FIFO in which all the RDS data received from the chip is + * placed. + * @rds_fifo_drainer: Worker that drains on-chip RDS FIFO. + * @rds_drainer_is_working: Flag used for launching only one instance + * of the @rds_fifo_drainer. + * @rds_drainer_status_lock: Lock used to guard access to the + * @rds_drainer_is_working variable. + * @command: Wait queue for wainting on the command comapletion. + * @cts: Clear To Send flag set upon receiving first status with CTS + * set. + * @tuning: Wait queue used for wainting for tune/seek comand + * completion. + * @stc: Similar to @cts, but for the STC bit of the status value. + * @power_up_parameters: Parameters used as argument for POWER_UP + * command when the device is started. + * @state: Current power state of the device. + * @supplues: Structure containing handles to all power supplies used + * by the device (NULL ones are ignored). + * @gpio_reset: GPIO pin connectet to the RSTB pin of the chip. + * @pinmux: Chip's configurable pins configuration. + * @diversity_mode: Chips role when functioning in diversity mode. + * @status_monitor: Polling worker used in polling use case scenarion + * (when IRQ is not avalible). + * @revision: Chip's running firmware revision number(Used for correct + * command set support). + */ + +struct si476x_core { + struct i2c_client *client; + struct regmap *regmap; + int chip_id; + struct mfd_cell cells[SI476X_MFD_CELLS]; + + struct mutex cmd_lock; /* for serializing fm radio operations */ + atomic_t users; + + wait_queue_head_t rds_read_queue; + struct kfifo rds_fifo; + struct work_struct rds_fifo_drainer; + bool rds_drainer_is_working; + struct mutex rds_drainer_status_lock; + + wait_queue_head_t command; + atomic_t cts; + + wait_queue_head_t tuning; + atomic_t stc; + + struct si476x_power_up_args power_up_parameters; + + enum si476x_power_state power_state; + + struct regulator_bulk_data supplies[4]; + + int gpio_reset; + + struct si476x_pinmux pinmux; + enum si476x_phase_diversity_mode diversity_mode; + + atomic_t is_alive; + + struct delayed_work status_monitor; +#define SI476X_WORK_TO_CORE(w) container_of(to_delayed_work(w), \ + struct si476x_core, \ + status_monitor) + + int revision; + + int rds_fifo_depth; +}; + +static inline struct si476x_core *i2c_mfd_cell_to_core(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev->parent); + return i2c_get_clientdata(client); +} + + +/** + * si476x_core_lock() - lock the core device to get an exclusive access + * to it. + */ +static inline void si476x_core_lock(struct si476x_core *core) +{ + mutex_lock(&core->cmd_lock); +} + +/** + * si476x_core_unlock() - unlock the core device to relinquish an + * exclusive access to it. + */ +static inline void si476x_core_unlock(struct si476x_core *core) +{ + mutex_unlock(&core->cmd_lock); +} + +/* *_TUNE_FREQ family of commands accept frequency in multiples of + 10kHz */ +static inline u16 hz_to_si476x(struct si476x_core *core, int freq) +{ + u16 result; + + switch (core->power_up_parameters.func) { + default: + case SI476X_FUNC_FM_RECEIVER: + result = freq / 10000; + break; + case SI476X_FUNC_AM_RECEIVER: + result = freq / 1000; + break; + } + + return result; +} + +static inline int si476x_to_hz(struct si476x_core *core, u16 freq) +{ + int result; + + switch (core->power_up_parameters.func) { + default: + case SI476X_FUNC_FM_RECEIVER: + result = freq * 10000; + break; + case SI476X_FUNC_AM_RECEIVER: + result = freq * 1000; + break; + } + + return result; +} + +/* Since the V4L2_TUNER_CAP_LOW flag is supplied, V4L2 subsystem + * mesures frequency in 62.5 Hz units */ + +static inline int hz_to_v4l2(int freq) +{ + return (freq * 10) / 625; +} + +static inline int v4l2_to_hz(int freq) +{ + return (freq * 625) / 10; +} + +static inline u16 v4l2_to_si476x(struct si476x_core *core, int freq) +{ + return hz_to_si476x(core, v4l2_to_hz(freq)); +} + +static inline int si476x_to_v4l2(struct si476x_core *core, u16 freq) +{ + return hz_to_v4l2(si476x_to_hz(core, freq)); +} + + + +/** + * struct si476x_func_info - structure containing result of the + * FUNC_INFO command. + * + * @firmware.major: Firmware major number. + * @firmware.minor[...]: Firmware minor numbers. + * @patch_id: + * @func: Mode tuner is working in. + */ +struct si476x_func_info { + struct { + u8 major, minor[2]; + } firmware; + u16 patch_id; + enum si476x_func func; +}; + +/** + * struct si476x_power_down_args - structure used to pass parameters + * to POWER_DOWN command + * + * @xosc: true - Power down, but leav oscillator running. + * false - Full power down. + */ +struct si476x_power_down_args { + bool xosc; +}; + +/** + * enum si476x_tunemode - enum representing possible tune modes for + * the chip. + * @SI476X_TM_VALIDATED_NORMAL_TUNE: Unconditionally stay on the new + * channel after tune, tune status is valid. + * @SI476X_TM_INVALIDATED_FAST_TUNE: Unconditionally stay in the new + * channel after tune, tune status invalid. + * @SI476X_TM_VALIDATED_AF_TUNE: Jump back to previous channel if + * metric thresholds are not met. + * @SI476X_TM_VALIDATED_AF_CHECK: Unconditionally jump back to the + * previous channel. + */ +enum si476x_tunemode { + SI476X_TM_VALIDATED_NORMAL_TUNE = 0, + SI476X_TM_INVALIDATED_FAST_TUNE = 1, + SI476X_TM_VALIDATED_AF_TUNE = 2, + SI476X_TM_VALIDATED_AF_CHECK = 3, +}; + +/** + * enum si476x_smoothmetrics - enum containing the possible setting fo + * audio transitioning of the chip + * @SI476X_SM_INITIALIZE_AUDIO: Initialize audio state to match this + * new channel + * @SI476X_SM_TRANSITION_AUDIO: Transition audio state from previous + * channel values to the new values + */ +enum si476x_smoothmetrics { + SI476X_SM_INITIALIZE_AUDIO = 0, + SI476X_SM_TRANSITION_AUDIO = 1, +}; + +/** + * struct si476x_rds_status_report - the structure representing the + * response to 'FM_RD_STATUS' command + * @rdstpptyint: Traffic program flag(TP) and/or program type(PTY) + * code has changed. + * @rdspiint: Program indentifiaction(PI) code has changed. + * @rdssyncint: RDS synchronization has changed. + * @rdsfifoint: RDS was received and the RDS FIFO has at least + * 'FM_RDS_INTERRUPT_FIFO_COUNT' elements in it. + * @tpptyvalid: TP flag and PTY code are valid falg. + * @pivalid: PI code is valid flag. + * @rdssync: RDS is currently synchronized. + * @rdsfifolost: On or more RDS groups have been lost/discarded flag. + * @tp: Current channel's TP flag. + * @pty: Current channel's PTY code. + * @pi: Current channel's PI code. + * @rdsfifoused: Number of blocks remaining in the RDS FIFO (0 if + * empty). + */ +struct si476x_rds_status_report { + bool rdstpptyint, rdspiint, rdssyncint, rdsfifoint; + bool tpptyvalid, pivalid, rdssync, rdsfifolost; + bool tp; + + u8 pty; + u16 pi; + + u8 rdsfifoused; + u8 ble[4]; + + struct v4l2_rds_data rds[4]; +}; + +struct si476x_rsq_status_args { + bool primary; + bool rsqack; + bool attune; + bool cancel; + bool stcack; +}; + +enum si476x_injside { + SI476X_INJSIDE_AUTO = 0, + SI476X_INJSIDE_LOW = 1, + SI476X_INJSIDE_HIGH = 2, +}; + +struct si476x_tune_freq_args { + bool zifsr; + bool hd; + enum si476x_injside injside; + int freq; + enum si476x_tunemode tunemode; + enum si476x_smoothmetrics smoothmetrics; + int antcap; +}; + +int si476x_core_stop(struct si476x_core *, bool); +int si476x_core_start(struct si476x_core *, bool); +int si476x_core_set_power_state(struct si476x_core *, enum si476x_power_state); +bool si476x_core_has_am(struct si476x_core *); +bool si476x_core_has_diversity(struct si476x_core *); +bool si476x_core_is_a_secondary_tuner(struct si476x_core *); +bool si476x_core_is_a_primary_tuner(struct si476x_core *); +bool si476x_core_is_in_am_receiver_mode(struct si476x_core *core); +bool si476x_core_is_powered_up(struct si476x_core *core); + +enum si476x_i2c_type { + SI476X_I2C_SEND, + SI476X_I2C_RECV +}; + +int si476x_core_i2c_xfer(struct si476x_core *, + enum si476x_i2c_type, + char *, int); + + +/* -------------------- si476x-cmd.c ----------------------- */ + +int si476x_core_cmd_func_info(struct si476x_core *, struct si476x_func_info *); +int si476x_core_cmd_set_property(struct si476x_core *, u16, u16); +int si476x_core_cmd_get_property(struct si476x_core *, u16); +int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *, + enum si476x_dclk_config, + enum si476x_dfs_config, + enum si476x_dout_config, + enum si476x_xout_config); +int si476x_core_cmd_zif_pin_cfg(struct si476x_core *, + enum si476x_iqclk_config, + enum si476x_iqfs_config, + enum si476x_iout_config, + enum si476x_qout_config); +int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *, + enum si476x_icin_config, + enum si476x_icip_config, + enum si476x_icon_config, + enum si476x_icop_config); +int si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *, + enum si476x_lrout_config); +int si476x_core_cmd_intb_pin_cfg(struct si476x_core *, enum si476x_intb_config, + enum si476x_a1_config); +int si476x_core_cmd_fm_seek_start(struct si476x_core *, bool, bool); +int si476x_core_cmd_am_seek_start(struct si476x_core *, bool, bool); +int si476x_core_cmd_fm_rds_status(struct si476x_core *, bool, bool, bool, + struct si476x_rds_status_report *); +int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *, bool, + struct si476x_rds_blockcount_report *); +int si476x_core_cmd_fm_tune_freq(struct si476x_core *, + struct si476x_tune_freq_args *); +int si476x_core_cmd_am_tune_freq(struct si476x_core *, + struct si476x_tune_freq_args *); +int si476x_core_cmd_am_rsq_status(struct si476x_core *, + struct si476x_rsq_status_args *, + struct si476x_rsq_status_report *); +int si476x_core_cmd_fm_rsq_status(struct si476x_core *, + struct si476x_rsq_status_args *, + struct si476x_rsq_status_report *); +int si476x_core_cmd_power_up(struct si476x_core *, + struct si476x_power_up_args *); +int si476x_core_cmd_power_down(struct si476x_core *, + struct si476x_power_down_args *); +int si476x_core_cmd_fm_phase_div_status(struct si476x_core *); +int si476x_core_cmd_fm_phase_diversity(struct si476x_core *, + enum si476x_phase_diversity_mode); + +int si476x_core_cmd_fm_acf_status(struct si476x_core *, + struct si476x_acf_status_report *); +int si476x_core_cmd_am_acf_status(struct si476x_core *, + struct si476x_acf_status_report *); +int si476x_core_cmd_agc_status(struct si476x_core *, + struct si476x_agc_status_report *); + +enum si476x_power_grid_type { + SI476X_POWER_GRID_50HZ = 0, + SI476X_POWER_GRID_60HZ, +}; + +/* Properties */ + +enum si476x_interrupt_flags { + SI476X_STCIEN = (1 << 0), + SI476X_ACFIEN = (1 << 1), + SI476X_RDSIEN = (1 << 2), + SI476X_RSQIEN = (1 << 3), + + SI476X_ERRIEN = (1 << 6), + SI476X_CTSIEN = (1 << 7), + + SI476X_STCREP = (1 << 8), + SI476X_ACFREP = (1 << 9), + SI476X_RDSREP = (1 << 10), + SI476X_RSQREP = (1 << 11), +}; + +enum si476x_rdsint_sources { + SI476X_RDSTPPTY = (1 << 4), + SI476X_RDSPI = (1 << 3), + SI476X_RDSSYNC = (1 << 1), + SI476X_RDSRECV = (1 << 0), +}; + +enum si476x_status_response_bits { + SI476X_CTS = (1 << 7), + SI476X_ERR = (1 << 6), + /* Status response for WB receiver */ + SI476X_WB_ASQ_INT = (1 << 4), + SI476X_RSQ_INT = (1 << 3), + /* Status response for FM receiver */ + SI476X_FM_RDS_INT = (1 << 2), + SI476X_ACF_INT = (1 << 1), + SI476X_STC_INT = (1 << 0), +}; + +/* -------------------- si476x-prop.c ----------------------- */ + +enum si476x_common_receiver_properties { + SI476X_PROP_INT_CTL_ENABLE = 0x0000, + SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE = 0x0200, + SI476X_PROP_DIGITAL_IO_INPUT_FORMAT = 0x0201, + SI476X_PROP_DIGITAL_IO_OUTPUT_SAMPLE_RATE = 0x0202, + SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT = 0x0203, + + SI476X_PROP_SEEK_BAND_BOTTOM = 0x1100, + SI476X_PROP_SEEK_BAND_TOP = 0x1101, + SI476X_PROP_SEEK_FREQUENCY_SPACING = 0x1102, + + SI476X_PROP_VALID_MAX_TUNE_ERROR = 0x2000, + SI476X_PROP_VALID_SNR_THRESHOLD = 0x2003, + SI476X_PROP_VALID_RSSI_THRESHOLD = 0x2004, +}; + +enum si476x_am_receiver_properties { + SI476X_PROP_AUDIO_PWR_LINE_FILTER = 0x0303, +}; + +enum si476x_fm_receiver_properties { + SI476X_PROP_AUDIO_DEEMPHASIS = 0x0302, + + SI476X_PROP_FM_RDS_INTERRUPT_SOURCE = 0x4000, + SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT = 0x4001, + SI476X_PROP_FM_RDS_CONFIG = 0x4002, +}; + +enum si476x_prop_audio_pwr_line_filter_bits { + SI476X_PROP_PWR_HARMONICS_MASK = 0b0000000000011111, + SI476X_PROP_PWR_GRID_MASK = 0b0000000100000000, + SI476X_PROP_PWR_ENABLE_MASK = 0b0000001000000000, + SI476X_PROP_PWR_GRID_50HZ = 0b0000000000000000, + SI476X_PROP_PWR_GRID_60HZ = 0b0000000100000000, +}; + +enum si476x_prop_fm_rds_config_bits { + SI476X_PROP_RDSEN_MASK = 0x1, + SI476X_PROP_RDSEN = 0x1, +}; + + +struct regmap *devm_regmap_init_si476x(struct si476x_core *); + +#endif /* SI476X_CORE_H */ -- cgit v0.10.2 From af720c7c414befed0aad1c92f6e33271cf4f83d3 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 26 Mar 2013 22:47:22 -0300 Subject: [media] v4l2: Fix the type of V4L2_CID_TUNE_PREEMPHASIS in the documentation Change the type of V4L2_CID_TUNE_PREEMPHASIS from 'integer' to 'enum v4l2_preemphasis' Acked-by: Hans Verkuil Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index b4952e2..06e9a5f 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -3854,7 +3854,7 @@ in Hz. The range and step are driver-specific. V4L2_CID_TUNE_PREEMPHASIS  - integer + enum v4l2_preemphasis Configures the pre-emphasis value for broadcasting. A pre-emphasis filter is applied to the broadcast to accentuate the high audio frequencies. -- cgit v0.10.2 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 diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index f662df3..ec89fd1 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 844dc02..7d26048 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 v0.10.2 From b4e96a7e9f9511d1b57a10a08cd10af6e517966b Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 26 Mar 2013 22:47:24 -0300 Subject: [media] v4l2: Add documentation for the FM RX controls Add appropriate documentation for all the newly added standard controls. Based on the patch by Manjunatha Halli [1] [1] http://lists-archives.com/linux-kernel/27641303-media-update-docs-for-v4l2-fm-new-features.html Acked-by: Hans Verkuil Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index 8c2b368..e44161f 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2310,6 +2310,9 @@ more information. Added FM Modulator (FM TX) Extended Control Class: V4L2_CTRL_CLASS_FM_TX and their Control IDs. + + Added FM Receiver (FM RX) Extended Control Class: V4L2_CTRL_CLASS_FM_RX and their Control IDs. + Added Remote Controller chapter, describing the default Remote Controller mapping for media devices. diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 06e9a5f..c8eb6c2 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -4693,4 +4693,76 @@ interface and may change in the future. + +
+ FM Receiver Control Reference + + The FM Receiver (FM_RX) class includes controls for common features of + FM Reception capable devices. + + + FM_RX Control IDs + + + + + + + + + + + ID + Type + Description + + + + + + V4L2_CID_FM_RX_CLASS  + class + The FM_RX class +descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a +description of this control class. + + + V4L2_CID_RDS_RECEPTION  + boolean + Enables/disables RDS + reception by the radio tuner + + + V4L2_CID_TUNE_DEEMPHASIS  + enum v4l2_deemphasis + + Configures the de-emphasis value for reception. +A de-emphasis filter is applied to the broadcast to accentuate the high audio frequencies. +Depending on the region, a time constant of either 50 or 75 useconds is used. The enum v4l2_deemphasis +defines possible values for de-emphasis. Here they are: + + + + + V4L2_DEEMPHASIS_DISABLED  + No de-emphasis is applied. + + + V4L2_DEEMPHASIS_50_uS  + A de-emphasis of 50 uS is used. + + + V4L2_DEEMPHASIS_75_uS  + A de-emphasis of 75 uS is used. + + + + + + + + +
+ +
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml index 4e16112..b3bb957 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml @@ -319,6 +319,15 @@ These controls are described in .
+ + + V4L2_CTRL_CLASS_FM_RX + 0xa10000 + The class containing FM Receiver (FM RX) controls. +These controls are described in . + + -- cgit v0.10.2 From 33a80fc2eb43afbc25f04cc1d5ed899da213c21f Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 26 Mar 2013 22:47:25 -0300 Subject: [media] v4l2: Add private controls base for SI476X Add a base to be used for allocation of all the SI476X specific controls in the corresponding driver. Acked-by: Hans Verkuil Signed-off-by: Andrey Smirnov Signed-off-by: Mauro Carvalho Chehab diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 7d26048..910d7cd 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -156,6 +156,10 @@ enum v4l2_colorfx { * We reserve 8 controls for this driver. */ #define V4L2_CID_USER_S2255_BASE (V4L2_CID_USER_BASE + 0x1010) +/* The base for the si476x driver controls. See include/media/si476x.h for the list + * of controls. Total of 16 controls is reserved for that driver */ +#define V4L2_CID_USER_SI476X_BASE (V4L2_CID_USER_BASE + 0x1010) + /* MPEG-class control IDs */ #define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) -- cgit v0.10.2 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 diff --git a/Documentation/video4linux/si476x.txt b/Documentation/video4linux/si476x.txt new file mode 100644 index 0000000..d1a08db --- /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 24e64a0..28ded24 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 303eaeb..0dcdb32 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 0000000..0895a0c --- /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 0000000..beb6433 --- /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 v0.10.2 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 diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index 0895a0c..9430c6a 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 v0.10.2 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 diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index 56c25e6..ba666c7 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 8f8d187..d208de3 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 0000000..577e820 --- /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 0000000..e493cbc --- /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 2d4abfa..9aff035 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 b76f58e..2c06714 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 70ec80d..44c64ef3 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 cfb1733..0000000 --- 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 80085fd..0000000 --- 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 b10f996..6cdc6ba 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 bbc8a32..9c6ad4a 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 4ce53d6..f846ad5 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 v0.10.2 From 2cb5972da8ee95c58db3375c288563f3b75bc61c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 29 Mar 2013 10:14:32 -0300 Subject: [media] v4l2-controls.h: update private control ranges to prevent overlap These ranges shouldn't overlap. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 910d7cd..7da22cec 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -153,12 +153,12 @@ enum v4l2_colorfx { /* 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) + * We reserve 16 controls for this driver. */ +#define V4L2_CID_USER_S2255_BASE (V4L2_CID_USER_BASE + 0x1030) /* The base for the si476x driver controls. See include/media/si476x.h for the list - * of controls. Total of 16 controls is reserved for that driver */ -#define V4L2_CID_USER_SI476X_BASE (V4L2_CID_USER_BASE + 0x1010) + * of controls. Total of 16 controls is reserved for this driver */ +#define V4L2_CID_USER_SI476X_BASE (V4L2_CID_USER_BASE + 0x1040) /* MPEG-class control IDs */ -- cgit v0.10.2 From 53c5b6c95f1850b0f95b445e0c6f1c133b00bfef Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 11 Sep 2012 12:44:18 -0300 Subject: [media] Add common video interfaces OF bindings documentation This patch adds a document describing common OF bindings for video capture, output and video processing devices. It is curently mainly focused on video capture devices, with data busses defined by standards such as ITU-R BT.656 or MIPI-CSI2. It also documents a method of describing data links between devices. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt new file mode 100644 index 0000000..e022d2d --- /dev/null +++ b/Documentation/devicetree/bindings/media/video-interfaces.txt @@ -0,0 +1,228 @@ +Common bindings for video receiver and transmitter interfaces + +General concept +--------------- + +Video data pipelines usually consist of external devices, e.g. camera sensors, +controlled over an I2C, SPI or UART bus, and SoC internal IP blocks, including +video DMA engines and video data processors. + +SoC internal blocks are described by DT nodes, placed similarly to other SoC +blocks. External devices are represented as child nodes of their respective +bus controller nodes, e.g. I2C. + +Data interfaces on all video devices are described by their child 'port' nodes. +Configuration of a port depends on other devices participating in the data +transfer and is described by 'endpoint' subnodes. + +device { + ... + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + ... + endpoint@0 { ... }; + endpoint@1 { ... }; + }; + port@1 { ... }; + }; +}; + +If a port can be configured to work with more than one remote device on the same +bus, an 'endpoint' child node must be provided for each of them. If more than +one port is present in a device node or there is more than one endpoint at a +port, or port node needs to be associated with a selected hardware interface, +a common scheme using '#address-cells', '#size-cells' and 'reg' properties is +used. + +All 'port' nodes can be grouped under optional 'ports' node, which allows to +specify #address-cells, #size-cells properties independently for the 'port' +and 'endpoint' nodes and any child device nodes a device might have. + +Two 'endpoint' nodes are linked with each other through their 'remote-endpoint' +phandles. An endpoint subnode of a device contains all properties needed for +configuration of this device for data exchange with other device. In most +cases properties at the peer 'endpoint' nodes will be identical, however they +might need to be different when there is any signal modifications on the bus +between two devices, e.g. there are logic signal inverters on the lines. + +It is allowed for multiple endpoints at a port to be active simultaneously, +where supported by a device. For example, in case where a data interface of +a device is partitioned into multiple data busses, e.g. 16-bit input port +divided into two separate ITU-R BT.656 8-bit busses. In such case bus-width +and data-shift properties can be used to assign physical data lines to each +endpoint node (logical bus). + + +Required properties +------------------- + +If there is more than one 'port' or more than one 'endpoint' node or 'reg' +property is present in port and/or endpoint nodes the following properties +are required in a relevant parent node: + + - #address-cells : number of cells required to define port/endpoint + identifier, should be 1. + - #size-cells : should be zero. + +Optional endpoint properties +---------------------------- + +- remote-endpoint: phandle to an 'endpoint' subnode of a remote device node. +- slave-mode: a boolean property indicating that the link is run in slave mode. + The default when this property is not specified is master mode. In the slave + mode horizontal and vertical synchronization signals are provided to the + slave device (data source) by the master device (data sink). In the master + mode the data source device is also the source of the synchronization signals. +- bus-width: number of data lines actively used, valid for the parallel busses. +- data-shift: on the parallel data busses, if bus-width is used to specify the + number of data lines, data-shift can be used to specify which data lines are + used, e.g. "bus-width=<8>; data-shift=<2>;" means, that lines 9:2 are used. +- hsync-active: active state of the HSYNC signal, 0/1 for LOW/HIGH respectively. +- vsync-active: active state of the VSYNC signal, 0/1 for LOW/HIGH respectively. + Note, that if HSYNC and VSYNC polarities are not specified, embedded + synchronization may be required, where supported. +- data-active: similar to HSYNC and VSYNC, specifies data line polarity. +- field-even-active: field signal level during the even field data transmission. +- pclk-sample: sample data on rising (1) or falling (0) edge of the pixel clock + signal. +- data-lanes: an array of physical data lane indexes. Position of an entry + determines the logical lane number, while the value of an entry indicates + physical lane, e.g. for 2-lane MIPI CSI-2 bus we could have + "data-lanes = <1 2>;", assuming the clock lane is on hardware lane 0. + This property is valid for serial busses only (e.g. MIPI CSI-2). +- clock-lanes: an array of physical clock lane indexes. Position of an entry + determines the logical lane number, while the value of an entry indicates + physical lane, e.g. for a MIPI CSI-2 bus we could have "clock-lanes = <0>;", + which places the clock lane on hardware lane 0. This property is valid for + serial busses only (e.g. MIPI CSI-2). Note that for the MIPI CSI-2 bus this + array contains only one entry. +- clock-noncontinuous: a boolean property to allow MIPI CSI-2 non-continuous + clock mode. + + +Example +------- + +The example snippet below describes two data pipelines. ov772x and imx074 are +camera sensors with a parallel and serial (MIPI CSI-2) video bus respectively. +Both sensors are on the I2C control bus corresponding to the i2c0 controller +node. ov772x sensor is linked directly to the ceu0 video host interface. +imx074 is linked to ceu0 through the MIPI CSI-2 receiver (csi2). ceu0 has a +(single) DMA engine writing captured data to memory. ceu0 node has a single +'port' node which may indicate that at any time only one of the following data +pipelines can be active: ov772x -> ceu0 or imx074 -> csi2 -> ceu0. + + ceu0: ceu@0xfe910000 { + compatible = "renesas,sh-mobile-ceu"; + reg = <0xfe910000 0xa0>; + interrupts = <0x880>; + + mclk: master_clock { + compatible = "renesas,ceu-clock"; + #clock-cells = <1>; + clock-frequency = <50000000>; /* Max clock frequency */ + clock-output-names = "mclk"; + }; + + port { + #address-cells = <1>; + #size-cells = <0>; + + /* Parallel bus endpoint */ + ceu0_1: endpoint@1 { + reg = <1>; /* Local endpoint # */ + remote = <&ov772x_1_1>; /* Remote phandle */ + bus-width = <8>; /* Used data lines */ + data-shift = <2>; /* Lines 9:2 are used */ + + /* If hsync-active/vsync-active are missing, + embedded BT.656 sync is used */ + hsync-active = <0>; /* Active low */ + vsync-active = <0>; /* Active low */ + data-active = <1>; /* Active high */ + pclk-sample = <1>; /* Rising */ + }; + + /* MIPI CSI-2 bus endpoint */ + ceu0_0: endpoint@0 { + reg = <0>; + remote = <&csi2_2>; + }; + }; + }; + + i2c0: i2c@0xfff20000 { + ... + ov772x_1: camera@0x21 { + compatible = "omnivision,ov772x"; + reg = <0x21>; + vddio-supply = <®ulator1>; + vddcore-supply = <®ulator2>; + + clock-frequency = <20000000>; + clocks = <&mclk 0>; + clock-names = "xclk"; + + port { + /* With 1 endpoint per port no need for addresses. */ + ov772x_1_1: endpoint { + bus-width = <8>; + remote-endpoint = <&ceu0_1>; + hsync-active = <1>; + vsync-active = <0>; /* Who came up with an + inverter here ?... */ + data-active = <1>; + pclk-sample = <1>; + }; + }; + }; + + imx074: camera@0x1a { + compatible = "sony,imx074"; + reg = <0x1a>; + vddio-supply = <®ulator1>; + vddcore-supply = <®ulator2>; + + clock-frequency = <30000000>; /* Shared clock with ov772x_1 */ + clocks = <&mclk 0>; + clock-names = "sysclk"; /* Assuming this is the + name in the datasheet */ + port { + imx074_1: endpoint { + clock-lanes = <0>; + data-lanes = <1 2>; + remote-endpoint = <&csi2_1>; + }; + }; + }; + }; + + csi2: csi2@0xffc90000 { + compatible = "renesas,sh-mobile-csi2"; + reg = <0xffc90000 0x1000>; + interrupts = <0x17a0>; + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + compatible = "renesas,csi2c"; /* One of CSI2I and CSI2C. */ + reg = <1>; /* CSI-2 PHY #1 of 2: PHY_S, + PHY_M has port address 0, + is unused. */ + csi2_1: endpoint { + clock-lanes = <0>; + data-lanes = <2 1>; + remote-endpoint = <&imx074_1>; + }; + }; + port@2 { + reg = <2>; /* port 2: link to the CEU */ + + csi2_2: endpoint { + remote-endpoint = <&ceu0_0>; + }; + }; + }; -- cgit v0.10.2 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 diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index a9d3552..00c4a19 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 0000000..e38e210 --- /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 0000000..00f9147 --- /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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index 87b6842..257afc1 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 47fbf7b..d8afbbc 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index 257afc1..e9928cd 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 f3d535c..c8509dd 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index d8afbbc..b64297b 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 v0.10.2 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 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 0000000..5f8e28e --- /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 981863d..8636bcd 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 2709286..28c11c4 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 28f3590..d6dbb79 100644 --- a/include/media/s5p_fimc.h +++ b/include/media/s5p_fimc.h @@ -15,6 +15,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. */ enum fimc_bus_type { -- cgit v0.10.2 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 diff --git a/Documentation/devicetree/bindings/media/samsung-fimc.txt b/Documentation/devicetree/bindings/media/samsung-fimc.txt new file mode 100644 index 0000000..22e2889 --- /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 e9928cd..724cd8b 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 e3916bd..d39e47a 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 412d507..145b8cc 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 c8509dd..a224dac 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 50b97c7..4d2fc69 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 v0.10.2 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 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 0000000..3f62adf --- /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 b64297b..65082fe 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-fimc/fimc-core.c b/drivers/media/platform/s5p-fimc/fimc-core.c index d39e47a..6a8098c 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 a17fcb2..d34106c 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 06b0d82..b6ceb59 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 d6dbb79..e2c5989 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 v0.10.2 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 diff --git a/Documentation/devicetree/bindings/media/samsung-fimc.txt b/Documentation/devicetree/bindings/media/samsung-fimc.txt index 22e2889..bcb0de7 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 d34106c..bfa02abd 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 e2c5989..e2434bb 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 v0.10.2 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 diff --git a/Documentation/devicetree/bindings/media/samsung-fimc.txt b/Documentation/devicetree/bindings/media/samsung-fimc.txt index bcb0de7..2a63ddd 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 bfa02abd..5e96775 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 b6ceb59..5d6146e 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 v0.10.2 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 diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index c8eb6c2..8d7a779 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 ec89fd1..ebb8e48 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 7da22cec..69bd5bb 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index 724cd8b..ff9ca63 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index 5e96775..6972f52 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index 6972f52..c4a3978 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 5d6146e..46f3b82 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-fimc/Kconfig b/drivers/media/platform/s5p-fimc/Kconfig index f997a52..c5caf08 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 ff9ca63..1675d38 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 6a8098c..1edd3aa 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 @@ -79,6 +80,10 @@ static struct fimc_fmt fimc_formats[] = { .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 }, @@ -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 145b8cc..6355b33 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 c4a3978..1f29f51 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 4d2fc69..ee88b94 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 1a40df6..01da7f3 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index 1f29f51..e7164ce 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 46f3b82..1d5cea5 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index e7164ce..b224899 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index b224899..77075a4d1 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-fimc/fimc-core.h b/drivers/media/platform/s5p-fimc/fimc-core.h index 6355b33..793333a 100644 --- a/drivers/media/platform/s5p-fimc/fimc-core.h +++ b/drivers/media/platform/s5p-fimc/fimc-core.h @@ -137,37 +137,6 @@ enum fimc_color_fmt { #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 * @y_v: y value vertical offset diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index 65082fe..a37282e 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 7085761..4c234508 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 e2434bb..2363aff 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 v0.10.2 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 diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 42c62aa..ae89545 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 42089ba..eee28dd 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 0000000..91dbd4b --- /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 0000000..8c67441 --- /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 0000000..965b07f --- /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 0000000..1248cdd --- /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 0000000..793333a --- /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 0000000..f0af075 --- /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 0000000..0e34584 --- /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 0000000..bbcd743 --- /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 0000000..4c234508 --- /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 0000000..8449c07 --- /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 0000000..c276eb8 --- /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 0000000..01da7f3 --- /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 0000000..4a00577 --- /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 0000000..1d5cea5 --- /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 0000000..8636bcd --- /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 0000000..28c11c4 --- /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 c5caf08..0000000 --- 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 4648514..0000000 --- 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 1675d38..0000000 --- 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 1edd3aa..0000000 --- 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 793333a..0000000 --- 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 f0af075..0000000 --- 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 0e34584..0000000 --- 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 a37282e..0000000 --- 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 4c234508..0000000 --- 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 a224dac..0000000 --- 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 77075a4d1..0000000 --- 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 1d5cea5..0000000 --- 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 ee88b94..0000000 --- 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 01da7f3..0000000 --- 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 8636bcd..0000000 --- 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 28c11c4..0000000 --- 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index ef1959b..792ead1 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index 79b31ae..c2b635d 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 v0.10.2 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 diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 28ded24..fef427e 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 9b80e1e..2f97ad1 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 118c6b1..f5bc8e4 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 v0.10.2 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 diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index ebb9ece..45ac9ee 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 v0.10.2 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 diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index bf55abf..eea832c 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 v0.10.2 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 diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index c314ff9..e7ccc5e 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 v0.10.2 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 diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 048c26a..7ca9dba 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 v0.10.2 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 diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml index cc51372..adc6198 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 1f6593d..6a8b715 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 89dce09..7569e77 100644 --- a/drivers/media/platform/soc_camera/soc_mediabus.c +++ b/drivers/media/platform/soc_camera/soc_mediabus.c @@ -97,6 +97,42 @@ static const struct soc_mbus_lookup mbus_fmt[] = { .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 = { .fourcc = V4L2_PIX_FMT_SBGGR8, @@ -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 2cc70cf..ff77d08 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 0dc6f46..d33f6d0 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 b9b7bea..6ee63d0 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 v0.10.2 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 diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index e7ccc5e..1abbb36 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 v0.10.2 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 diff --git a/drivers/media/platform/soc_camera/mx1_camera.c b/drivers/media/platform/soc_camera/mx1_camera.c index 4389f43..a3fd8d6 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 v0.10.2 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 diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 7ca9dba..5bbeb43 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 v0.10.2 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 diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index 2c3bd69..5da3377 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 v0.10.2 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 diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index 42abbce..b0e6f3b 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 v0.10.2 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 diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index b0e6f3b..d665242 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 v0.10.2 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 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 d7294ef..143d29fe 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 v0.10.2 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 diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c index ce3b1d6..1b7a88c 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.c b/drivers/media/platform/exynos-gsc/gsc-regs.c index 6f5b5a4..e22d147 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 d90d228..39b77d2 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index 91dbd4b..ae57920 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 44239e5..6b4a244 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 793333a..7d361b2 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 c276eb8..c82e9bd 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 v0.10.2 From 05a70a4079f2a73de6c61abf4dd70b6bcf1b3200 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 2 Apr 2013 06:45:59 -0300 Subject: [media] exynos4-is: Correct clock properties description at the DT binding documentation The 'camera' DT node needs to have sclk_cam0/1 and pxl_async0/1 clocks specified, while 'fimc' nodes should have only "fimc" and "sclk_fimc". "mux" and "parent" are leftovers from early versions of patches adding DT support, when the IP bus clock parent clock was being set by the driver. A better solution is needed to have e.g. clocks driver setting all required parent clocks, before clock consumers start using the clocks. Currently this binding doesn't describe parent clocks setup, it needs to be specified and handled somewhere else. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/devicetree/bindings/media/samsung-fimc.txt b/Documentation/devicetree/bindings/media/samsung-fimc.txt index 2a63ddd..51c776b 100644 --- a/Documentation/devicetree/bindings/media/samsung-fimc.txt +++ b/Documentation/devicetree/bindings/media/samsung-fimc.txt @@ -17,9 +17,9 @@ 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 clock-names property; +- clock-names : must contain "sclk_cam0", "sclk_cam1", "pxl_async0", + "pxl_async1" 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: @@ -32,7 +32,6 @@ way around. The 'camera' node must include at least one 'fimc' child node. - 'fimc' device nodes ------------------- @@ -44,8 +43,7 @@ Required properties: - 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. +- clock-names: must contain "fimc", "sclk_fimc" entries. - 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: -- cgit v0.10.2 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 diff --git a/drivers/media/v4l2-core/v4l2-of.c b/drivers/media/v4l2-core/v4l2-of.c index e38e210..aa59639 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 00f9147..3a8a841 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 v0.10.2 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 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 0000000..0d1f52e --- /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 0000000..e8519e1 --- /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 0000000..3de6f6d --- /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 0000000..efb9da0 --- /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 0000000..5fa2fda --- /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 0000000..c5e4c53 --- /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 0000000..936e2ca --- /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 0000000..59502b1 --- /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 0000000..800aba7 --- /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 v0.10.2 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 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 0000000..1ec6b3c --- /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 0000000..0d38d6b --- /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 v0.10.2 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 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 0000000..37fd5fe --- /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 0000000..71464a5 --- /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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index ae57920..6ff99b5 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 8c67441..f25f463 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 0000000..02b2719 --- /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 0000000..50b8e4d --- /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 v0.10.2 From 0580abc2b5d04fca31578c7a9cc4adc0ed3677ac Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 26 Mar 2013 09:21:23 -0300 Subject: [media] exynos4-is: Add Exynos4x12 FIMC-IS device tree binding documentation This patch adds DT binding documentaton for the Imaging Subsystem (camera ISP) found on Samsung Exynos4x12 SoCs. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab diff --git a/Documentation/devicetree/bindings/media/exynos4-fimc-is.txt b/Documentation/devicetree/bindings/media/exynos4-fimc-is.txt new file mode 100644 index 0000000..55c9ad6 --- /dev/null +++ b/Documentation/devicetree/bindings/media/exynos4-fimc-is.txt @@ -0,0 +1,49 @@ +Exynos4x12 SoC series Imaging Subsystem (FIMC-IS) + +The FIMC-IS is a subsystem for processing image signal from an image sensor. +The Exynos4x12 SoC series FIMC-IS V1.5 comprises of a dedicated ARM Cortex-A5 +processor, ISP, DRC and FD IP blocks and peripheral devices such as UART, I2C +and SPI bus controllers, PWM and ADC. + +fimc-is node +------------ + +Required properties: +- compatible : should be "samsung,exynos4212-fimc-is" for Exynos4212 and + Exynos4412 SoCs; +- reg : physical base address and length of the registers set; +- interrupts : must contain two FIMC-IS interrupts, in order: ISP0, ISP1; +- clocks : list of clock specifiers, corresponding to entries in + clock-names property; +- clock-names : must contain "ppmuispx", "ppmuispx", "lite0", "lite1" + "mpll", "sysreg", "isp", "drc", "fd", "mcuisp", "uart", + "ispdiv0", "ispdiv1", "mcuispdiv0", "mcuispdiv1", "aclk200", + "div_aclk200", "aclk400mcuisp", "div_aclk400mcuisp" entries, + matching entries in the clocks property. +pmu subnode +----------- + +Required properties: + - reg : must contain PMU physical base address and size of the register set. + +The following are the FIMC-IS peripheral device nodes and can be specified +either standalone or as the fimc-is node child nodes. + +i2c-isp (ISP I2C bus controller) nodes +------------------------------------------ + +Required properties: + +- compatible : should be "samsung,exynos4212-i2c-isp" for Exynos4212 and + Exynos4412 SoCs; +- reg : physical base address and length of the registers set; +- clocks : must contain gate clock specifier for this controller; +- clock-names : must contain "i2c_isp" entry. + +For the above nodes it is required to specify a pinctrl state named "default", +according to the pinctrl bindings defined in ../pinctrl/pinctrl-bindings.txt. + +Device tree nodes of the image sensors' controlled directly by the FIMC-IS +firmware must be child nodes of their corresponding ISP I2C bus controller node. +The data link of these image sensors must be specified using the common video +interfaces bindings, defined in video-interfaces.txt. -- cgit v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index a0fd8cc..597648e 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 1d5cea5..0b14cd5 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 597648e..44d6c1d 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index 6b4a244..90d907e 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 70c0cc2..ba35328 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 4c234508..0b6380b 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c index ac9663c..8cc0d39 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 0e34584..3903839 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 ba35328..b11e358 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 0b6380b..8a8d26f 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 2363aff..e316d15 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index 90d907e..f25807d 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 c82e9bd..f079f36 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 01da7f3..6c97798 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 965b07f..28c6b26 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 7d361b2..d2fe162 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 b11e358..cb196b8 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 8a8d26f..71fed51 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 v0.10.2 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 diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h index eb91fd8..833191bc 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 8896993..a1a3a51 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 71641b2..3485655 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 fa7188a..ae7fc33 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 44225b1..e17cb85 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 eb7496e..f710e17 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 3dc7aa9..f38329d 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 e407185..21b9049 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 504c812..e52c3b9 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 b2a9ad8..b4fb650 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 v0.10.2 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 diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c index cf0d47f..891762d 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 v0.10.2 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 diff --git a/drivers/media/common/b2c2/flexcop-fe-tuner.c b/drivers/media/common/b2c2/flexcop-fe-tuner.c index 850a6c6..7e14e90 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 0cb3f0f..c77002f 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 e7ca7d1..630e7f8 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 e2e0b8f..07b700a 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 672b267..053ed1b 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 eca02c2..4e29c9d 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 27915e5..4527139 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 v0.10.2 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 diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c index 8c48521..a2b7a9f 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 e12ecba..b5b51a9 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 v0.10.2 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 diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c index a2b7a9f..c1ade88 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 b5b51a9..97f1d0f 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 v0.10.2 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 diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index dc68cf1..29fb7a9 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 62169dd..b90b488 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 cf9a9af..7d60c5d 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 24eaafe..b46ebb4 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 v0.10.2 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 diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 2586e46..8e2f79c 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 29fb7a9..67e06e1 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, + }, + }, }; @@ -7037,6 +7073,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .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, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -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 4527139..4a08ae3 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 a176ec3..c68169d 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 e761262..6f43126 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 b7a99be..0f34e09 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 b90b488..1f6c41e 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 v0.10.2 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 diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index 67e06e1..d45e7f6 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 e778686..4995b89 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 a0d1762..73453a2 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 9432b5b..b642921 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 c1ade88..20cc7da 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 97f1d0f..cf96e58 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index d04b52e..80a8ee0 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 80a8ee0..70158aa 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 70158aa..f256589 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index f256589..d25df75 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index d25df75..856374b 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c index 68c88ab..a771da3 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 9b658c1..7ca5c69 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 e82d82a..c2bfea7 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 v0.10.2 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 diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c index 7e6e43a..6ccc488 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 7379dc6..f608b77 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 4582473..4af53bd 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 c7ad329..0af05a2 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 33de88b..db57f25 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 v0.10.2 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 diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index 5dbb65e..b353c50 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index f608b77..e810b1a 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h index 0b14cd5..7f126c3 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 e316d15..f509690 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index cb196b8..3ea4fc7 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 28c6b26..72c516a 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 3ea4fc7..661d0d1 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 44d6c1d..1dbd554 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 7f126c3..44d86b6 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c index 37fd5fe..58123e3 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 71464a5..f9358c2 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 efb9da0..f59a289 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 c5e4c53..10ec173 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 936e2ca..9406894 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 59502b1..b11c001 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c index 58123e3..254740f 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 f59a289..b0ff67b 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 10ec173..3c81c88 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 9406894..f5275a5 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 b11c001..7b8fbab 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-is-param.c b/drivers/media/platform/exynos4-is/fimc-is-param.c index 254740f..53fe2a2 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c index 7b8fbab..3b9a664 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 v0.10.2 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 diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c index 2526b66..2f40a35 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 v0.10.2 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 diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c index 2f40a35..8edb3d8 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 v0.10.2 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 diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index e328332..e0bad59 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 v0.10.2 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 diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index e0bad59..ecf4492 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 v0.10.2 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 diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index ecf4492..28cf95b 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 0c97b19..b1e63f2 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 v0.10.2 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 diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 1363e97..88e84c3 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 v0.10.2 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 diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 88e84c3..0f2d3bd 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 v0.10.2 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 diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index 8fd24e7..45f0aca 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 0f2d3bd..941e2eb 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 1f6c41e..fc07b19 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 v0.10.2 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 diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 941e2eb..506a9f4 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 fc07b19..d2ad16c 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 v0.10.2 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 diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 506a9f4..b832684 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 v0.10.2 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 diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index b832684..40245e4 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 v0.10.2 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 diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 40245e4..3a2649f 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 v0.10.2 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 diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 3a2649f..cc40938 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 v0.10.2 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 diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index b34922a..44fad1c 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 cdb645d..300005c 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 7d60c5d..a0b10e6 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 v0.10.2 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 diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 44fad1c..371b6ca 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 20cc7da..ab4106c 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 39e7e58..ca274c2 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 a0b10e6..ddc9379 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 v0.10.2 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 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 4921346..5fce8d8 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 792ead1..39951f5 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 670b9ca..1c3b43c 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 336ed2d..feac07e 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 b273f0e..6b917d6 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 v0.10.2 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 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 82e43c6..921e185 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 5fce8d8..fa3bd42 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 3082b41..db7844f 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 f8fac9c..3fed63f 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 feac07e..7a96162 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 e9c49c5..4c941c1 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 v0.10.2 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 diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 7a96162..c48d0ac 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 v0.10.2 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 diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index e44161f..f43542a 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 c1f3340..bfc93cd 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 0000000..e1cece6 --- /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 fa3bd42..0000000 --- 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 db7844f..d13bac9 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 39951f5..c27c1f6 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 1c3b43c..5923c5d 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 c48d0ac..f81bda1 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 6b917d6..931652f 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 4c941c1..be43b46 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 v0.10.2 From b8399b83058848979538932473d817559f7ff8fb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 8 Apr 2013 11:53:55 -0300 Subject: [media] videodev2.h: increase size of 'reserved' array Increase the size of the 'reserved' array to give more room for future extensions. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index be43b46..1282cd3 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1844,7 +1844,7 @@ struct v4l2_dbg_chip_info { struct v4l2_dbg_match match; char name[32]; __u32 flags; - __u32 reserved[8]; + __u32 reserved[32]; } __attribute__ ((packed)); /** -- cgit v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 42a6a26..1f1f56f 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 v0.10.2 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 diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 38b3f15..320f301 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 v0.10.2 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 diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 320f301..70dc652 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 v0.10.2 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 diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 70dc652..f0f0a90 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 v0.10.2 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 diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index f0f0a90..633c545 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 e305c14..1cb9a2e 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 c6dfa7f..979828d 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 v0.10.2 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 diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index 1cb9a2e..56c9241 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 v0.10.2 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 diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index 633c545..f8c6137 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 56c9241..fe16088 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 979828d..25cdea2 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 v0.10.2 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 diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c index f8c6137..ba4cfc9 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 v0.10.2 From 292a878720b26213bc773619715525e9f7a4f4a1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Mar 2013 15:26:36 -0300 Subject: [media] videodev2.h: fix incorrect V4L2_DV_FL_HALF_LINE bitmask This was set to 1 << 0 which is the same as V4L2_DV_FL_REDUCED_BLANKING. It should be 1 << 3 instead. Luckily interlaced formats are rarely used, which is why this bug wasn't seen until now. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 1282cd3..97fb392 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -1074,7 +1074,7 @@ struct v4l2_bt_timings { longer and field 2 is really one half-line shorter, so each field has exactly the same number of half-lines. Whether half-lines can be detected or used depends on the hardware. */ -#define V4L2_DV_FL_HALF_LINE (1 << 0) +#define V4L2_DV_FL_HALF_LINE (1 << 3) /** struct v4l2_dv_timings - DV timings -- cgit v0.10.2 From a7b74bd82a26379495e0e727d2c0fa9b0b97d917 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Mar 2013 14:31:34 -0300 Subject: [media] v4l2-dv-timings.h: add 480i59.94 and 576i50 CEA-861-E timings These formats are supported by the HDPVR, but they were missing in the list. Note that these formats are different from the common PAL/NTSC/SECAM formats since all color channels are transmitted separately and so there is no PAL or NTSC or SECAM color encoding involved. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/include/uapi/linux/v4l2-dv-timings.h b/include/uapi/linux/v4l2-dv-timings.h index 9ef8172..4e0c58d 100644 --- a/include/uapi/linux/v4l2-dv-timings.h +++ b/include/uapi/linux/v4l2-dv-timings.h @@ -42,6 +42,15 @@ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CEA861, 0) \ } +/* Note: these are the nominal timings, for HDMI links this format is typically + * double-clocked to meet the minimum pixelclock requirements. */ +#define V4L2_DV_BT_CEA_720X480I59_94 { \ + .type = V4L2_DV_BT_656_1120, \ + V4L2_INIT_BT_TIMINGS(720, 480, 1, 0, \ + 13500000, 19, 62, 57, 4, 3, 15, 4, 3, 16, \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \ +} + #define V4L2_DV_BT_CEA_720X480P59_94 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(720, 480, 0, 0, \ @@ -49,6 +58,15 @@ V4L2_DV_BT_STD_CEA861, 0) \ } +/* Note: these are the nominal timings, for HDMI links this format is typically + * double-clocked to meet the minimum pixelclock requirements. */ +#define V4L2_DV_BT_CEA_720X576I50 { \ + .type = V4L2_DV_BT_656_1120, \ + V4L2_INIT_BT_TIMINGS(720, 576, 1, 0, \ + 13500000, 12, 63, 69, 2, 3, 19, 2, 3, 20, \ + V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \ +} + #define V4L2_DV_BT_CEA_720X576P50 { \ .type = V4L2_DV_BT_656_1120, \ V4L2_INIT_BT_TIMINGS(720, 576, 0, 0, \ -- cgit v0.10.2 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 diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 2983bf0..a890127 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 fea3c69..2a4deab 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 v0.10.2 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 diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index a890127..4bbcf48 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 2a4deab..9450093 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 v0.10.2 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 diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 4bbcf48..e30ece2 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 v0.10.2 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 diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index e30ece2..406eda8 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 v0.10.2 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 diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 406eda8..e14bf49 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 v0.10.2 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 diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index 73195fe..248835b 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 v0.10.2 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 diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index 248835b..8247c19 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 9450093..1c12981 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 v0.10.2 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 diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index e14bf49..042f204 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 1c12981..050c6b9 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 v0.10.2 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 diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 042f204..43763097 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 050c6b9..1478f3d 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 v0.10.2 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 diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 43763097..774ba0e 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 v0.10.2 From 48fc9e26705f3c681a5a5fcd97f28be2c2393237 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 11 Apr 2013 03:36:49 -0300 Subject: [media] MAINTAINERS: add hdpvr entry Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index 154b02c..8396b9c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3593,6 +3593,14 @@ W: http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/ S: Maintained F: drivers/platform/x86/hdaps.c +HDPVR USB VIDEO ENCODER DRIVER +M: Hans Verkuil +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +W: http://linuxtv.org +S: Odd Fixes +F: drivers/media/usb/hdpvr + HWPOISON MEMORY FAILURE HANDLING M: Andi Kleen L: linux-mm@kvack.org -- cgit v0.10.2 From 228b791bfd52f437fd9a04fe9432dfec9c0d0333 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 10 Apr 2013 08:05:00 -0300 Subject: [media] dt3155v4l: fix incorrect mutex locking A mutex_unlock was missing in the 'success' path of the open() call, and also at one error path in the same function. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c index 073b3b3..57fadea 100644 --- a/drivers/staging/media/dt3155v4l/dt3155v4l.c +++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c @@ -398,7 +398,7 @@ dt3155_open(struct file *filp) pd->field_count = 0; ret = vb2_queue_init(pd->q); if (ret < 0) - return ret; + goto err_request_irq; INIT_LIST_HEAD(&pd->dmaq); spin_lock_init(&pd->lock); /* disable all irqs, clear all irq flags */ @@ -410,6 +410,7 @@ dt3155_open(struct file *filp) goto err_request_irq; } pd->users++; + mutex_unlock(&pd->mux); return 0; /* success */ err_request_irq: kfree(pd->q); -- cgit v0.10.2 From 0dcb953a6eeae84566fe288d507aed49ead4cc6e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 10 Apr 2013 08:07:07 -0300 Subject: [media] dt3155v4l: fix timestamp handling Use the monotonic clock and set the timestamp_type that vb2 expects. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c index 57fadea..c32e0ac 100644 --- a/drivers/staging/media/dt3155v4l/dt3155v4l.c +++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "dt3155v4l.h" @@ -341,7 +342,7 @@ dt3155_irq_handler_even(int irq, void *dev_id) spin_lock(&ipd->lock); if (ipd->curr_buf) { - do_gettimeofday(&ipd->curr_buf->v4l2_buf.timestamp); + v4l2_get_timestamp(&ipd->curr_buf->v4l2_buf.timestamp); ipd->curr_buf->v4l2_buf.sequence = (ipd->field_count) >> 1; vb2_buffer_done(ipd->curr_buf, VB2_BUF_STATE_DONE); } @@ -390,6 +391,7 @@ dt3155_open(struct file *filp) goto err_alloc_queue; } pd->q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + pd->q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; pd->q->io_modes = VB2_READ | VB2_MMAP; pd->q->ops = &q_ops; pd->q->mem_ops = &vb2_dma_contig_memops; -- cgit v0.10.2 From 402f6ae4d52e5f6c0fe053f307c18360f69e0132 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 9 Apr 2013 21:30:41 -0300 Subject: [media] MAINTAINERS: update CYPRESS_FIRMWARE media driver It is moved to the different location and renamed. Signed-off-by: Antti Palosaari Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index 8396b9c..de6ec85 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2367,6 +2367,16 @@ W: http://www.cyclades.com/ S: Orphan F: drivers/net/wan/pc300* +CYPRESS_FIRMWARE MEDIA DRIVER +M: Antti Palosaari +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +W: http://palosaari.fi/linux/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/anttip/media_tree.git +S: Maintained +F: drivers/media/common/cypress_firmware* + CYTTSP TOUCHSCREEN DRIVER M: Javier Martinez Canillas L: linux-input@vger.kernel.org @@ -2731,16 +2741,6 @@ T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/usb/dvb-usb/cxusb* -DVB_USB_CYPRESS_FIRMWARE MEDIA DRIVER -M: Antti Palosaari -L: linux-media@vger.kernel.org -W: http://linuxtv.org/ -W: http://palosaari.fi/linux/ -Q: http://patchwork.linuxtv.org/project/linux-media/list/ -T: git git://linuxtv.org/anttip/media_tree.git -S: Maintained -F: drivers/media/usb/dvb-usb-v2/cypress_firmware* - DVB_USB_EC168 MEDIA DRIVER M: Antti Palosaari L: linux-media@vger.kernel.org -- cgit v0.10.2 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 diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index ba666c7..b85f88c 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 1d3866f..a3c3055 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index a3c3055..54ead1e 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 v0.10.2 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 diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 34f39d3..afd561a 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 v0.10.2 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 diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig index ccfde4e..afb3aec 100644 --- a/drivers/media/platform/davinci/Kconfig +++ b/drivers/media/platform/davinci/Kconfig @@ -1,79 +1,47 @@ 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 sensor module such as MT9T001 over a raw interface. This 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 f40f521..d74d9ee 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 v0.10.2 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 diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c index 3bc4db8..ea82a8b 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 v0.10.2 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 diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index b49c3b7..8e98bb0 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 6c39805..c61dd94 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 ee0e994..c2a9273 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 c90250e..6b98413 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 2364dba..05f8fb7 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 971d639..30fa084 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 abc3ae3..3332cca 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 a19c552..d36429d 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 v0.10.2 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 diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c index f15f211..87eef9b 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 v0.10.2 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 diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c index d36429d..8a2f01e 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 v0.10.2 From 120c66046cc8931259867ac1cdc6de0d0e742fb5 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Tue, 19 Mar 2013 07:34:36 -0300 Subject: [media] ARM: davinci: dm365: add support for v4l2 video display Create platform devices for various video modules like venc,osd, vpbe and v4l2 driver for dm365. Signed-off-by: Lad, Prabhakar Acked-by: Sekhar Nori Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index c2d4958..cf77c46 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -564,8 +564,6 @@ static struct davinci_uart_config uart_config __initdata = { static void __init dm365_evm_map_io(void) { - /* setup input configuration for VPFE input devices */ - dm365_set_vpfe_config(&vpfe_cfg); dm365_init(); } @@ -597,6 +595,8 @@ static __init void dm365_evm_init(void) davinci_setup_mmc(0, &dm365evm_mmc_config); + dm365_init_video(&vpfe_cfg, NULL); + /* maybe setup mmc1/etc ... _after_ mmc0 */ evm_init_cpld(); diff --git a/arch/arm/mach-davinci/davinci.h b/arch/arm/mach-davinci/davinci.h index 12d544b..c8b1e0b 100644 --- a/arch/arm/mach-davinci/davinci.h +++ b/arch/arm/mach-davinci/davinci.h @@ -36,12 +36,18 @@ #include #define DAVINCI_SYSTEM_MODULE_BASE 0x01c40000 +#define SYSMOD_VDAC_CONFIG 0x2c #define SYSMOD_VIDCLKCTL 0x38 #define SYSMOD_VPSS_CLKCTL 0x44 #define SYSMOD_VDD3P3VPWDN 0x48 #define SYSMOD_VSCLKDIS 0x6c #define SYSMOD_PUPDCTL1 0x7c +/* VPSS CLKCTL bit definitions */ +#define VPSS_VENCCLKEN_ENABLE BIT(3) +#define VPSS_DACCLKEN_ENABLE BIT(4) +#define VPSS_PLLC2SYSCLK5_ENABLE BIT(5) + extern void __iomem *davinci_sysmod_base; #define DAVINCI_SYSMOD_VIRT(x) (davinci_sysmod_base + (x)) void davinci_map_sysmod(void); @@ -84,7 +90,7 @@ void __init dm365_init_ks(struct davinci_ks_platform_data *pdata); void __init dm365_init_rtc(void); void dm365_init_spi0(unsigned chipselect_mask, const struct spi_board_info *info, unsigned len); -void dm365_set_vpfe_config(struct vpfe_config *cfg); +int dm365_init_video(struct vpfe_config *, struct vpbe_config *); /* DM644x function declarations */ void __init dm644x_init(void); diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index c61dd94..ff771ce 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -39,16 +39,13 @@ #include "asp.h" #define DM365_REF_FREQ 24000000 /* 24 MHz on the DM365 EVM */ - -/* Base of key scan register bank */ -#define DM365_KEYSCAN_BASE 0x01c69400 - #define DM365_RTC_BASE 0x01c69000 - +#define DM365_KEYSCAN_BASE 0x01c69400 +#define DM365_OSD_BASE 0x01c71c00 +#define DM365_VENC_BASE 0x01c71e00 #define DAVINCI_DM365_VC_BASE 0x01d0c000 #define DAVINCI_DMA_VC_TX 2 #define DAVINCI_DMA_VC_RX 3 - #define DM365_EMAC_BASE 0x01d07000 #define DM365_EMAC_MDIO_BASE (DM365_EMAC_BASE + 0x4000) #define DM365_EMAC_CNTRL_OFFSET 0x0000 @@ -1233,6 +1230,173 @@ static struct platform_device dm365_isif_dev = { }, }; +static struct resource dm365_osd_resources[] = { + { + .start = DM365_OSD_BASE, + .end = DM365_OSD_BASE + 0xff, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 dm365_video_dma_mask = DMA_BIT_MASK(32); + +static struct platform_device dm365_osd_dev = { + .name = DM365_VPBE_OSD_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm365_osd_resources), + .resource = dm365_osd_resources, + .dev = { + .dma_mask = &dm365_video_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct resource dm365_venc_resources[] = { + { + .start = IRQ_VENCINT, + .end = IRQ_VENCINT, + .flags = IORESOURCE_IRQ, + }, + /* venc registers io space */ + { + .start = DM365_VENC_BASE, + .end = DM365_VENC_BASE + 0x177, + .flags = IORESOURCE_MEM, + }, + /* vdaccfg registers io space */ + { + .start = DAVINCI_SYSTEM_MODULE_BASE + SYSMOD_VDAC_CONFIG, + .end = DAVINCI_SYSTEM_MODULE_BASE + SYSMOD_VDAC_CONFIG + 3, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource dm365_v4l2_disp_resources[] = { + { + .start = IRQ_VENCINT, + .end = IRQ_VENCINT, + .flags = IORESOURCE_IRQ, + }, + /* venc registers io space */ + { + .start = DM365_VENC_BASE, + .end = DM365_VENC_BASE + 0x177, + .flags = IORESOURCE_MEM, + }, +}; + +static int dm365_vpbe_setup_pinmux(enum v4l2_mbus_pixelcode if_type, + int field) +{ + switch (if_type) { + case V4L2_MBUS_FMT_SGRBG8_1X8: + davinci_cfg_reg(DM365_VOUT_FIELD_G81); + davinci_cfg_reg(DM365_VOUT_COUTL_EN); + davinci_cfg_reg(DM365_VOUT_COUTH_EN); + break; + case V4L2_MBUS_FMT_YUYV10_1X20: + if (field) + davinci_cfg_reg(DM365_VOUT_FIELD); + else + davinci_cfg_reg(DM365_VOUT_FIELD_G81); + davinci_cfg_reg(DM365_VOUT_COUTL_EN); + davinci_cfg_reg(DM365_VOUT_COUTH_EN); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int dm365_venc_setup_clock(enum vpbe_enc_timings_type type, + unsigned int pclock) +{ + void __iomem *vpss_clkctl_reg; + u32 val; + + vpss_clkctl_reg = DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL); + + switch (type) { + case VPBE_ENC_STD: + val = VPSS_VENCCLKEN_ENABLE | VPSS_DACCLKEN_ENABLE; + break; + case VPBE_ENC_DV_TIMINGS: + if (pclock <= 27000000) { + val = VPSS_VENCCLKEN_ENABLE | VPSS_DACCLKEN_ENABLE; + } else { + /* set sysclk4 to output 74.25 MHz from pll1 */ + val = VPSS_PLLC2SYSCLK5_ENABLE | VPSS_DACCLKEN_ENABLE | + VPSS_VENCCLKEN_ENABLE; + } + break; + default: + return -EINVAL; + } + writel(val, vpss_clkctl_reg); + + return 0; +} + +static struct platform_device dm365_vpbe_display = { + .name = "vpbe-v4l2", + .id = -1, + .num_resources = ARRAY_SIZE(dm365_v4l2_disp_resources), + .resource = dm365_v4l2_disp_resources, + .dev = { + .dma_mask = &dm365_video_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +struct venc_platform_data dm365_venc_pdata = { + .setup_pinmux = dm365_vpbe_setup_pinmux, + .setup_clock = dm365_venc_setup_clock, +}; + +static struct platform_device dm365_venc_dev = { + .name = DM365_VPBE_VENC_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm365_venc_resources), + .resource = dm365_venc_resources, + .dev = { + .dma_mask = &dm365_video_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = (void *)&dm365_venc_pdata, + }, +}; + +static struct platform_device dm365_vpbe_dev = { + .name = "vpbe_controller", + .id = -1, + .dev = { + .dma_mask = &dm365_video_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +int __init dm365_init_video(struct vpfe_config *vpfe_cfg, + struct vpbe_config *vpbe_cfg) +{ + if (vpfe_cfg || vpbe_cfg) + platform_device_register(&dm365_vpss_device); + + if (vpfe_cfg) { + vpfe_capture_dev.dev.platform_data = vpfe_cfg; + platform_device_register(&dm365_isif_dev); + platform_device_register(&vpfe_capture_dev); + } + if (vpbe_cfg) { + dm365_vpbe_dev.dev.platform_data = vpbe_cfg; + platform_device_register(&dm365_osd_dev); + platform_device_register(&dm365_venc_dev); + platform_device_register(&dm365_vpbe_dev); + platform_device_register(&dm365_vpbe_display); + } + + return 0; +} + static int __init dm365_init_devices(void) { if (!cpu_is_davinci_dm365()) @@ -1246,14 +1410,6 @@ static int __init dm365_init_devices(void) clk_add_alias(NULL, dev_name(&dm365_mdio_device.dev), NULL, &dm365_emac_device.dev); - platform_device_register(&dm365_vpss_device); - platform_device_register(&dm365_isif_dev); - platform_device_register(&vpfe_capture_dev); return 0; } postcore_initcall(dm365_init_devices); - -void dm365_set_vpfe_config(struct vpfe_config *cfg) -{ - vpfe_capture_dev.dev.platform_data = cfg; -} -- cgit v0.10.2 From 542b5bd226b0f5d5e9190cb96e6d96a912394795 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 14 Mar 2013 04:12:34 -0300 Subject: [media] ARM: davinci: dm365 EVM: add support for VPBE display add support for V4L2 video display to DM365 EVM. Support for SD and ED modes is provided, along with Composite and Component outputs. Signed-off-by: Lad, Prabhakar Acked-by: Sekhar Nori Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index cf77c46..0518ce5 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ #include #include +#include #include #include "davinci.h" @@ -374,6 +376,166 @@ static struct vpfe_config vpfe_cfg = { .ccdc = "ISIF", }; +/* venc standards timings */ +static struct vpbe_enc_mode_info dm365evm_enc_std_timing[] = { + { + .name = "ntsc", + .timings_type = VPBE_ENC_STD, + .std_id = V4L2_STD_525_60, + .interlaced = 1, + .xres = 720, + .yres = 480, + .aspect = {11, 10}, + .fps = {30000, 1001}, + .left_margin = 0x79, + .upper_margin = 0x10, + }, + { + .name = "pal", + .timings_type = VPBE_ENC_STD, + .std_id = V4L2_STD_625_50, + .interlaced = 1, + .xres = 720, + .yres = 576, + .aspect = {54, 59}, + .fps = {25, 1}, + .left_margin = 0x7E, + .upper_margin = 0x16, + }, +}; + +/* venc dv timings */ +static struct vpbe_enc_mode_info dm365evm_enc_preset_timing[] = { + { + .name = "480p59_94", + .timings_type = VPBE_ENC_DV_TIMINGS, + .dv_timings = V4L2_DV_BT_CEA_720X480P59_94, + .interlaced = 0, + .xres = 720, + .yres = 480, + .aspect = {1, 1}, + .fps = {5994, 100}, + .left_margin = 0x8F, + .upper_margin = 0x2D, + }, + { + .name = "576p50", + .timings_type = VPBE_ENC_DV_TIMINGS, + .dv_timings = V4L2_DV_BT_CEA_720X576P50, + .interlaced = 0, + .xres = 720, + .yres = 576, + .aspect = {1, 1}, + .fps = {50, 1}, + .left_margin = 0x8C, + .upper_margin = 0x36, + }, + { + .name = "720p60", + .timings_type = VPBE_ENC_DV_TIMINGS, + .dv_timings = V4L2_DV_BT_CEA_1280X720P60, + .interlaced = 0, + .xres = 1280, + .yres = 720, + .aspect = {1, 1}, + .fps = {60, 1}, + .left_margin = 0x117, + .right_margin = 70, + .upper_margin = 38, + .lower_margin = 3, + .hsync_len = 80, + .vsync_len = 5, + }, + { + .name = "1080i60", + .timings_type = VPBE_ENC_DV_TIMINGS, + .dv_timings = V4L2_DV_BT_CEA_1920X1080I60, + .interlaced = 1, + .xres = 1920, + .yres = 1080, + .aspect = {1, 1}, + .fps = {30, 1}, + .left_margin = 0xc9, + .right_margin = 80, + .upper_margin = 30, + .lower_margin = 3, + .hsync_len = 88, + .vsync_len = 5, + }, +}; + +#define VENC_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) + +/* + * The outputs available from VPBE + ecnoders. Keep the + * the order same as that of encoders. First those from venc followed by that + * from encoders. Index in the output refers to index on a particular + * encoder.Driver uses this index to pass it to encoder when it supports more + * than one output. Application uses index of the array to set an output. + */ +static struct vpbe_output dm365evm_vpbe_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .std = VENC_STD_ALL, + .capabilities = V4L2_OUT_CAP_STD, + }, + .subdev_name = DM365_VPBE_VENC_SUBDEV_NAME, + .default_mode = "ntsc", + .num_modes = ARRAY_SIZE(dm365evm_enc_std_timing), + .modes = dm365evm_enc_std_timing, + .if_params = V4L2_MBUS_FMT_FIXED, + }, + { + .output = { + .index = 1, + .name = "Component", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .capabilities = V4L2_OUT_CAP_DV_TIMINGS, + }, + .subdev_name = DM365_VPBE_VENC_SUBDEV_NAME, + .default_mode = "480p59_94", + .num_modes = ARRAY_SIZE(dm365evm_enc_preset_timing), + .modes = dm365evm_enc_preset_timing, + .if_params = V4L2_MBUS_FMT_FIXED, + }, +}; + +/* + * Amplifiers on the board + */ +struct ths7303_platform_data ths7303_pdata = { + .ch_1 = 3, + .ch_2 = 3, + .ch_3 = 3, + .init_enable = 1, +}; + +static struct amp_config_info vpbe_amp = { + .module_name = "ths7303", + .is_i2c = 1, + .board_info = { + I2C_BOARD_INFO("ths7303", 0x2c), + .platform_data = &ths7303_pdata, + } +}; + +static struct vpbe_config dm365evm_display_cfg = { + .module_name = "dm365-vpbe-display", + .i2c_adapter_id = 1, + .amp = &vpbe_amp, + .osd = { + .module_name = DM365_VPBE_OSD_SUBDEV_NAME, + }, + .venc = { + .module_name = DM365_VPBE_VENC_SUBDEV_NAME, + }, + .num_outputs = ARRAY_SIZE(dm365evm_vpbe_outputs), + .outputs = dm365evm_vpbe_outputs, +}; + static void __init evm_init_i2c(void) { davinci_init_i2c(&i2c_pdata); @@ -595,7 +757,7 @@ static __init void dm365_evm_init(void) davinci_setup_mmc(0, &dm365evm_mmc_config); - dm365_init_video(&vpfe_cfg, NULL); + dm365_init_video(&vpfe_cfg, &dm365evm_display_cfg); /* maybe setup mmc1/etc ... _after_ mmc0 */ evm_init_cpld(); -- cgit v0.10.2 From 62a2d6cd56a4db3ab59322ad6c95f762a842d7ab Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Tue, 9 Apr 2013 10:35:05 -0300 Subject: [media] ARM: davinci: dm355: add support for v4l2 video display Create platform devices for various video modules like venc,osd, vpbe and v4l2 driver for dm355. Signed-off-by: Lad, Prabhakar Acked-by: Sekhar Nori Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index 147b8e1..37d12cc 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -253,8 +253,6 @@ static struct davinci_uart_config uart_config __initdata = { static void __init dm355_evm_map_io(void) { - /* setup input configuration for VPFE input devices */ - dm355_set_vpfe_config(&vpfe_cfg); dm355_init(); } @@ -344,6 +342,8 @@ static __init void dm355_evm_init(void) davinci_setup_mmc(0, &dm355evm_mmc_config); davinci_setup_mmc(1, &dm355evm_mmc_config); + dm355_init_video(&vpfe_cfg, NULL); + dm355_init_spi0(BIT(0), dm355_evm_spi_info, ARRAY_SIZE(dm355_evm_spi_info)); diff --git a/arch/arm/mach-davinci/davinci.h b/arch/arm/mach-davinci/davinci.h index c8b1e0b..1ab3df4 100644 --- a/arch/arm/mach-davinci/davinci.h +++ b/arch/arm/mach-davinci/davinci.h @@ -44,6 +44,7 @@ #define SYSMOD_PUPDCTL1 0x7c /* VPSS CLKCTL bit definitions */ +#define VPSS_MUXSEL_EXTCLK_ENABLE BIT(1) #define VPSS_VENCCLKEN_ENABLE BIT(3) #define VPSS_DACCLKEN_ENABLE BIT(4) #define VPSS_PLLC2SYSCLK5_ENABLE BIT(5) @@ -80,7 +81,7 @@ void __init dm355_init(void); void dm355_init_spi0(unsigned chipselect_mask, const struct spi_board_info *info, unsigned len); void __init dm355_init_asp1(u32 evt_enable, struct snd_platform_data *pdata); -void dm355_set_vpfe_config(struct vpfe_config *cfg); +int dm355_init_video(struct vpfe_config *, struct vpbe_config *); /* DM365 function declarations */ void __init dm365_init(void); diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index 8e98bb0..bf9a9d4 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -35,6 +35,8 @@ #include "asp.h" #define DM355_UART2_BASE (IO_PHYS + 0x206000) +#define DM355_OSD_BASE (IO_PHYS + 0x70200) +#define DM355_VENC_BASE (IO_PHYS + 0x70400) /* * Device specific clocks @@ -744,11 +746,146 @@ static struct platform_device vpfe_capture_dev = { }, }; -void dm355_set_vpfe_config(struct vpfe_config *cfg) +static struct resource dm355_osd_resources[] = { + { + .start = DM355_OSD_BASE, + .end = DM355_OSD_BASE + 0x17f, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device dm355_osd_dev = { + .name = DM355_VPBE_OSD_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm355_osd_resources), + .resource = dm355_osd_resources, + .dev = { + .dma_mask = &vpfe_capture_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct resource dm355_venc_resources[] = { + { + .start = IRQ_VENCINT, + .end = IRQ_VENCINT, + .flags = IORESOURCE_IRQ, + }, + /* venc registers io space */ + { + .start = DM355_VENC_BASE, + .end = DM355_VENC_BASE + 0x17f, + .flags = IORESOURCE_MEM, + }, + /* VDAC config register io space */ + { + .start = DAVINCI_SYSTEM_MODULE_BASE + SYSMOD_VDAC_CONFIG, + .end = DAVINCI_SYSTEM_MODULE_BASE + SYSMOD_VDAC_CONFIG + 3, + .flags = IORESOURCE_MEM, + }, +}; + +static struct resource dm355_v4l2_disp_resources[] = { + { + .start = IRQ_VENCINT, + .end = IRQ_VENCINT, + .flags = IORESOURCE_IRQ, + }, + /* venc registers io space */ + { + .start = DM355_VENC_BASE, + .end = DM355_VENC_BASE + 0x17f, + .flags = IORESOURCE_MEM, + }, +}; + +static int dm355_vpbe_setup_pinmux(enum v4l2_mbus_pixelcode if_type, + int field) +{ + switch (if_type) { + case V4L2_MBUS_FMT_SGRBG8_1X8: + davinci_cfg_reg(DM355_VOUT_FIELD_G70); + break; + case V4L2_MBUS_FMT_YUYV10_1X20: + if (field) + davinci_cfg_reg(DM355_VOUT_FIELD); + else + davinci_cfg_reg(DM355_VOUT_FIELD_G70); + break; + default: + return -EINVAL; + } + + davinci_cfg_reg(DM355_VOUT_COUTL_EN); + davinci_cfg_reg(DM355_VOUT_COUTH_EN); + + return 0; +} + +static int dm355_venc_setup_clock(enum vpbe_enc_timings_type type, + unsigned int pclock) { - vpfe_capture_dev.dev.platform_data = cfg; + void __iomem *vpss_clk_ctrl_reg; + + vpss_clk_ctrl_reg = DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL); + + switch (type) { + case VPBE_ENC_STD: + writel(VPSS_DACCLKEN_ENABLE | VPSS_VENCCLKEN_ENABLE, + vpss_clk_ctrl_reg); + break; + case VPBE_ENC_DV_TIMINGS: + if (pclock > 27000000) + /* + * For HD, use external clock source since we cannot + * support HD mode with internal clocks. + */ + writel(VPSS_MUXSEL_EXTCLK_ENABLE, vpss_clk_ctrl_reg); + break; + default: + return -EINVAL; + } + + return 0; } +static struct platform_device dm355_vpbe_display = { + .name = "vpbe-v4l2", + .id = -1, + .num_resources = ARRAY_SIZE(dm355_v4l2_disp_resources), + .resource = dm355_v4l2_disp_resources, + .dev = { + .dma_mask = &vpfe_capture_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +struct venc_platform_data dm355_venc_pdata = { + .setup_pinmux = dm355_vpbe_setup_pinmux, + .setup_clock = dm355_venc_setup_clock, +}; + +static struct platform_device dm355_venc_dev = { + .name = DM355_VPBE_VENC_SUBDEV_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(dm355_venc_resources), + .resource = dm355_venc_resources, + .dev = { + .dma_mask = &vpfe_capture_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = (void *)&dm355_venc_pdata, + }, +}; + +static struct platform_device dm355_vpbe_dev = { + .name = "vpbe_controller", + .id = -1, + .dev = { + .dma_mask = &vpfe_capture_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + /*----------------------------------------------------------------------*/ static struct map_desc dm355_io_desc[] = { @@ -868,6 +1005,29 @@ void __init dm355_init(void) davinci_map_sysmod(); } +int __init dm355_init_video(struct vpfe_config *vpfe_cfg, + struct vpbe_config *vpbe_cfg) +{ + if (vpfe_cfg || vpbe_cfg) + platform_device_register(&dm355_vpss_device); + + if (vpfe_cfg) { + vpfe_capture_dev.dev.platform_data = vpfe_cfg; + platform_device_register(&dm355_ccdc_dev); + platform_device_register(&vpfe_capture_dev); + } + + if (vpbe_cfg) { + dm355_vpbe_dev.dev.platform_data = vpbe_cfg; + platform_device_register(&dm355_osd_dev); + platform_device_register(&dm355_venc_dev); + platform_device_register(&dm355_vpbe_dev); + platform_device_register(&dm355_vpbe_display); + } + + return 0; +} + static int __init dm355_init_devices(void) { if (!cpu_is_davinci_dm355()) @@ -875,9 +1035,6 @@ static int __init dm355_init_devices(void) davinci_cfg_reg(DM355_INT_EDMA_CC); platform_device_register(&dm355_edma_device); - platform_device_register(&dm355_vpss_device); - platform_device_register(&dm355_ccdc_dev); - platform_device_register(&vpfe_capture_dev); return 0; } -- cgit v0.10.2 From 8775617701868d590d8e6069d9d64bfab0ea3db5 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Tue, 7 Aug 2012 07:42:56 -0300 Subject: [media] ARM: davinci: dm355 EVM: add support for VPBE display add support for V4L2 video display to DM355 EVM. Support for SD modes is provided, along with Composite output Signed-off-by: Lad, Prabhakar Acked-by: Sekhar Nori Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index 37d12cc..1043506 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -242,6 +242,73 @@ static struct vpfe_config vpfe_cfg = { .ccdc = "DM355 CCDC", }; +/* venc standards timings */ +static struct vpbe_enc_mode_info dm355evm_enc_preset_timing[] = { + { + .name = "ntsc", + .timings_type = VPBE_ENC_STD, + .std_id = V4L2_STD_525_60, + .interlaced = 1, + .xres = 720, + .yres = 480, + .aspect = {11, 10}, + .fps = {30000, 1001}, + .left_margin = 0x79, + .upper_margin = 0x10, + }, + { + .name = "pal", + .timings_type = VPBE_ENC_STD, + .std_id = V4L2_STD_625_50, + .interlaced = 1, + .xres = 720, + .yres = 576, + .aspect = {54, 59}, + .fps = {25, 1}, + .left_margin = 0x7E, + .upper_margin = 0x16 + }, +}; + +#define VENC_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL) + +/* + * The outputs available from VPBE + ecnoders. Keep the + * the order same as that of encoders. First those from venc followed by that + * from encoders. Index in the output refers to index on a particular encoder. + * Driver uses this index to pass it to encoder when it supports more than + * one output. Application uses index of the array to set an output. + */ +static struct vpbe_output dm355evm_vpbe_outputs[] = { + { + .output = { + .index = 0, + .name = "Composite", + .type = V4L2_OUTPUT_TYPE_ANALOG, + .std = VENC_STD_ALL, + .capabilities = V4L2_OUT_CAP_STD, + }, + .subdev_name = DM355_VPBE_VENC_SUBDEV_NAME, + .default_mode = "ntsc", + .num_modes = ARRAY_SIZE(dm355evm_enc_preset_timing), + .modes = dm355evm_enc_preset_timing, + .if_params = V4L2_MBUS_FMT_FIXED, + }, +}; + +static struct vpbe_config dm355evm_display_cfg = { + .module_name = "dm355-vpbe-display", + .i2c_adapter_id = 1, + .osd = { + .module_name = DM355_VPBE_OSD_SUBDEV_NAME, + }, + .venc = { + .module_name = DM355_VPBE_VENC_SUBDEV_NAME, + }, + .num_outputs = ARRAY_SIZE(dm355evm_vpbe_outputs), + .outputs = dm355evm_vpbe_outputs, +}; + static struct platform_device *davinci_evm_devices[] __initdata = { &dm355evm_dm9000, &davinci_nand_device, @@ -342,7 +409,7 @@ static __init void dm355_evm_init(void) davinci_setup_mmc(0, &dm355evm_mmc_config); davinci_setup_mmc(1, &dm355evm_mmc_config); - dm355_init_video(&vpfe_cfg, NULL); + dm355_init_video(&vpfe_cfg, &dm355evm_display_cfg); dm355_init_spi0(BIT(0), dm355_evm_spi_info, ARRAY_SIZE(dm355_evm_spi_info)); -- cgit v0.10.2 From 89cdbba84157a41404ee2de30142d839596eece9 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Fri, 12 Apr 2013 07:46:19 -0300 Subject: [media] ARM: daVinci: dm644x/dm355/dm365: replace V4L2_STD_525_60/625_50 with V4L2_STD_NTSC/PAL This patch replaces V4L2_STD_525_60/625_50 with V4L2_STD_NTSC/PAL respectively as this are the proper video standards. Signed-off-by: Lad, Prabhakar Reported-by: Hans Verkuil Acked-by: Sekhar Nori Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index 1043506..886481c 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -247,7 +247,7 @@ static struct vpbe_enc_mode_info dm355evm_enc_preset_timing[] = { { .name = "ntsc", .timings_type = VPBE_ENC_STD, - .std_id = V4L2_STD_525_60, + .std_id = V4L2_STD_NTSC, .interlaced = 1, .xres = 720, .yres = 480, @@ -259,7 +259,7 @@ static struct vpbe_enc_mode_info dm355evm_enc_preset_timing[] = { { .name = "pal", .timings_type = VPBE_ENC_STD, - .std_id = V4L2_STD_625_50, + .std_id = V4L2_STD_PAL, .interlaced = 1, .xres = 720, .yres = 576, diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index 0518ce5..2a66743 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -381,7 +381,7 @@ static struct vpbe_enc_mode_info dm365evm_enc_std_timing[] = { { .name = "ntsc", .timings_type = VPBE_ENC_STD, - .std_id = V4L2_STD_525_60, + .std_id = V4L2_STD_NTSC, .interlaced = 1, .xres = 720, .yres = 480, @@ -393,7 +393,7 @@ static struct vpbe_enc_mode_info dm365evm_enc_std_timing[] = { { .name = "pal", .timings_type = VPBE_ENC_STD, - .std_id = V4L2_STD_625_50, + .std_id = V4L2_STD_PAL, .interlaced = 1, .xres = 720, .yres = 576, diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index a021800..745280d 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -622,7 +622,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = { { .name = "ntsc", .timings_type = VPBE_ENC_STD, - .std_id = V4L2_STD_525_60, + .std_id = V4L2_STD_NTSC, .interlaced = 1, .xres = 720, .yres = 480, @@ -634,7 +634,7 @@ static struct vpbe_enc_mode_info dm644xevm_enc_std_timing[] = { { .name = "pal", .timings_type = VPBE_ENC_STD, - .std_id = V4L2_STD_625_50, + .std_id = V4L2_STD_PAL, .interlaced = 1, .xres = 720, .yres = 576, -- cgit v0.10.2 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 diff --git a/drivers/media/platform/soc_camera/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c index 7569e77..dc02dec 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 v0.10.2 From 4290fd1a5688f3510caa0625c62d73de568ed2c2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 4 Apr 2013 10:31:58 -0300 Subject: [media] MAINTAINERS: Mark the SH VOU driver as Odd Fixes The driver isn't actively maintained anymore, update its status. Signed-off-by: Laurent Pinchart Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index de6ec85..4252aa4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7183,7 +7183,7 @@ F: drivers/media/platform/sh_veu.c SH_VOU V4L2 OUTPUT DRIVER M: Guennadi Liakhovetski L: linux-media@vger.kernel.org -S: Maintained +S: Odd Fixes F: drivers/media/platform/sh_vou.c F: include/media/sh_vou.h -- cgit v0.10.2 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 diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 535a18d..87af2d3 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 v0.10.2 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 diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index dd82373..63b4225 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 v0.10.2 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 diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 40125d7..21ee0dc 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 v0.10.2 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 diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index ee6c984..ed184f6 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 v0.10.2 From 5560983b5dc29f50c91336ddc8769e9b90f62651 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 9 Apr 2013 20:30:42 -0300 Subject: [media] MAINTAINERS: add DVB_USB_GL861 I have the hardware and I have already made almost all changes what are needed during the recent few years, so lets mark it as maintained. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index 4252aa4..1a7438b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2751,6 +2751,15 @@ T: git git://linuxtv.org/anttip/media_tree.git S: Maintained F: drivers/media/usb/dvb-usb-v2/ec168* +DVB_USB_GL861 MEDIA DRIVER +M: Antti Palosaari +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/anttip/media_tree.git +S: Maintained +F: drivers/media/usb/dvb-usb-v2/gl861* + DVB_USB_MXL111SF MEDIA DRIVER M: Michael Krufky L: linux-media@vger.kernel.org -- cgit v0.10.2 From 27a0aacf3ee4e7f91b95d69c954a6ba6540a5c0a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Tue, 9 Apr 2013 20:30:43 -0300 Subject: [media] MAINTAINERS: add RTL2832 media driver Driver author has disappeared, even mails are bouncing back. I will keep care with that as I have done for a while. Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index 1a7438b..bbe872e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6713,6 +6713,16 @@ T: git git://linuxtv.org/anttip/media_tree.git S: Maintained F: drivers/media/dvb-frontends/rtl2830* +RTL2832 MEDIA DRIVER +M: Antti Palosaari +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +W: http://palosaari.fi/linux/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/anttip/media_tree.git +S: Maintained +F: drivers/media/dvb-frontends/rtl2832* + RTL8180 WIRELESS DRIVER M: "John W. Linville" L: linux-wireless@vger.kernel.org -- cgit v0.10.2 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 diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 02bb5e7..58c1744 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 v0.10.2 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 diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 7786619..04baac4 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 0000000..b80b336 --- /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 f74ee6f..5d5d3a3 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 54ead1e..cc63f19 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 v0.10.2 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 diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 04baac4..5ab94ea 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 v0.10.2 From 9ce5eca7c4c7f9fe451715cb5c96d4d776481a82 Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Mon, 15 Apr 2013 01:32:44 -0300 Subject: [media] MAINTAINERS: change entry for davinci media driver As of now TI has no maintainer/supporter for davinci media drivers, Until it has any I'll be maintaining it. Signed-off-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab diff --git a/MAINTAINERS b/MAINTAINERS index bbe872e..4cf48e3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7244,14 +7244,13 @@ F: arch/arm/mach-davinci F: drivers/i2c/busses/i2c-davinci.c TI DAVINCI SERIES MEDIA DRIVER -M: Manjunath Hadli -M: Prabhakar Lad +M: Lad, Prabhakar L: linux-media@vger.kernel.org L: davinci-linux-open-source@linux.davincidsp.com (moderated for non-subscribers) W: http://linuxtv.org/ Q: http://patchwork.linuxtv.org/project/linux-media/list/ T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git -S: Supported +S: Maintained F: drivers/media/platform/davinci/ F: include/media/davinci/ -- cgit v0.10.2 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 diff --git a/drivers/media/dvb-frontends/cxd2820r_t2.c b/drivers/media/dvb-frontends/cxd2820r_t2.c index c2bfea7..2ba130e 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 1465591..6b18320 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 1884e2c..1f47422 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 6b18320..8bf9c89 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 8bf9c89..4eaa67a 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 8a9c0c8..85693cd 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 1f47422..2b38a50 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 4eaa67a..e785bb9 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 11ba5eb..37cb0c1 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 85693cd..04c3cb0 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-cards.c b/drivers/media/pci/cx25821/cx25821-cards.c index 99988c9..c09ec68 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 e785bb9..8ff8fc2 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 37cb0c1..eb12e35 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 04c3cb0..fdeecdf 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 8ff8fc2..7cd8885 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 1858a45d..b3cac75 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 ea97320..b9be535 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 2b38a50..48faf6f 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 cf2723c..2381bdc 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 7fc9711..223aae7 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 7cd8885..c418e0d 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 eb12e35..505b7f0 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 fdeecdf..d7e71f4 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index b3cac75..81361c2 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 { @@ -627,34 +626,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 */ static int cx25821_audio_initdev(struct cx25821_dev *dev) @@ -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 48faf6f..6205ade 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 c418e0d..a9aa096 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 d7e71f4..195b004 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index a9aa096..9ddc7ac 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 9ddc7ac..9e948ef 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 505b7f0..9d70020 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 195b004..033993f 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 9e948ef..9919a0e 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/Kconfig b/drivers/media/pci/cx25821/Kconfig index 4017c94..6439a84 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 caa32b7b..b54a32e 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 c09ec68..2b2f1f4 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 6205ade..82c2db0 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 29e43b0..95e8ddf 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 a8dc945..dca37c7 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 033993f..61c6cfc 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 82c2db0..f3a48a1 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 9919a0e..41e3475 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 61c6cfc..df2ea22 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index f3a48a1..bf6c181 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 41e3475..0c11f31 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 df2ea22..c63f7f5 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index bf6c181..ba417c9 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 6a92e5c..6ab3ae0 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 c63f7f5..95dbf70 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 0c11f31..6088ee9 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-medusa-video.c b/drivers/media/pci/cx25821/cx25821-medusa-video.c index 6ab3ae0..22fa044 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 6088ee9..ab79bd5 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 9d70020..b0f0d53 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 95dbf70..ad56232 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index ab79bd5..2aba24f 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 ad56232..d1c91c9 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 2aba24f..d88316c5 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 d1c91c9..06dadb5 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index d88316c5..e7a2db1 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 06dadb5..128c9f3 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index e7a2db1..f82da1e 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 b0f0d53..eb54e53 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 128c9f3..40b16b0 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index f82da1e..aec6fdf 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index aec6fdf..d3aa166 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 eb54e53..8871c4e 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 40b16b0..cfda5ac 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-cards.c b/drivers/media/pci/cx25821/cx25821-cards.c index 2b2f1f4..3b409fe 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 d3aa166..4968644 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 cfda5ac..67b3c55 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index ba417c9..9068d53 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 4968644..8d5d13b 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 8871c4e..ab63b38 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 67b3c55..156ad6f 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 8d5d13b..d3cf259 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index d3cf259..dca3391 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index dca3391..70e33b12 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/Makefile b/drivers/media/pci/cx25821/Makefile index b54a32e..407830c 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 9068d53..230bd86 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 2381bdc..0000000 --- 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 d42dab5..0000000 --- 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 223aae7..37cfc83 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 70e33b12..dde0ba3 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 156ad6f..b0bc2e6 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 230bd86..35bea79 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 37cfc83..88ffef4 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 dde0ba3..b194138 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 b0bc2e6..90bdc19 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/Makefile b/drivers/media/pci/cx25821/Makefile index 407830c..fb76c3d 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 35bea79..b762c5b 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index c27c1f6..32d60e5 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 v0.10.2 From 16b196e5b275040cbe679e7a917e8eefe5643475 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 16 Apr 2013 11:33:22 -0300 Subject: [media] staging/media: fix go7007 dependencies and build VIDEO_GO7007 uses usb interfaces so it should depend on USB. It also selects CYPRESS_FIRMWARE, which depends on USB. Fixes build errors and a kconfig warning: go7007-loader.c:(.text+0xcc7d0): undefined reference to `usb_get_dev' go7007-loader.c:(.init.text+0x49f0): undefined reference to `usb_register_driver' go7007-loader.c:(.exit.text+0x17ce): undefined reference to `usb_deregister' warning: (DVB_USB_AZ6007 && VIDEO_GO7007) selects CYPRESS_FIRMWARE which has unmet direct dependencies (MEDIA_SUPPORT && USB) Signed-off-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/Kconfig b/drivers/staging/media/go7007/Kconfig index 6cdc6ba..04bd0fb 100644 --- a/drivers/staging/media/go7007/Kconfig +++ b/drivers/staging/media/go7007/Kconfig @@ -1,7 +1,7 @@ config VIDEO_GO7007 tristate "WIS GO7007 MPEG encoder support" depends on VIDEO_DEV && I2C - depends on SND + depends on SND && USB select VIDEOBUF2_VMALLOC select VIDEO_TUNER select CYPRESS_FIRMWARE -- cgit v0.10.2 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 diff --git a/drivers/media/pci/zoran/zoran_procfs.c b/drivers/media/pci/zoran/zoran_procfs.c index e084b0a..1512b5d 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 v0.10.2 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 diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 5b5b6e6..3c76101 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 v0.10.2 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 diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile index f136a6d..2ebe4b7 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 4d7a247..0000000 --- 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 12dd36b..0000000 --- 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 00dcf3c..0000000 --- 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 0000000..6f30d7e --- /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 0000000..12dd36b --- /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 0000000..ce65210 --- /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 0f42b6c..b5827ca 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 v0.10.2 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 diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig index a94ccad..0313015 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 v0.10.2 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 diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index ffabd66..f6768ca 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 2ebe4b7..308f108 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 0000000..7e02920 --- /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 0000000..a64a7b6 --- /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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 9aff035..a3c8ecf 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 3d128a5..18756a6 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 2f3af2d..533a331 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 7e02920..ed9cd65 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index ed9cd65..0fa355d1 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -321,6 +321,20 @@ static int r820t_xtal_capacitor[][2] = { }; /* + * 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 */ static void shadow_store(struct r820t_priv *priv, u8 reg, const u8 *val, @@ -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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 18756a6..22015fe 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 0fa355d1..5cd8256 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 5cd8256..1821cf1 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 1821cf1..2ecf1d2 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 7388769..b6f50c7 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 fefba0e..91b2dcf 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 7d97ce9..b5f2b80 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 2ecf1d2..48ff6bb 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index b6f50c7..2f5a2b5 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 48ff6bb..79ab2b7 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 79ab2b7..1880807e 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 1880807e..bb154449 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index bb154449..5be4635 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 a64a7b6..949575a 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 5be4635..d5686e8 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index d5686e8..ef100ab 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index ef100ab..e9367d8 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index e9367d8..279be4f 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 279be4f..07d0323 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 949575a..4c0823b 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 07d0323..fa2e9ae 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index fa2e9ae..0125de8 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 0125de8..2e6a690 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 2e6a690..fc660f2 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index fc660f2..b679a3f 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index b679a3f..f5a5fb0 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index f5a5fb0..c644e90 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index c644e90..e63ee94 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 2f5a2b5..facb848 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index e63ee94..8d99779 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 8d99779..905a106 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 v0.10.2 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 diff --git a/Documentation/video4linux/si476x.txt b/Documentation/video4linux/si476x.txt deleted file mode 100644 index d1a08db..0000000 --- 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 fef427e..24e64a0 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 0dcdb32..303eaeb 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 9430c6a..0000000 --- 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 beb6433..0000000 --- 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 v0.10.2 From 33a31edd4a4b7d26b962b32decfd8ea2377eaa0d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 17 Apr 2013 06:07:01 -0300 Subject: Revert "[media] mfd: Add header files and Kbuild plumbing for SI476x MFD core" As requested by Samuel Ortiz , revert this patch. This reverts commit 3f8ec5df11aa2ad7402cfb3368532a96b63426a4. Conflicts: drivers/mfd/Kconfig Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b6bb6d5..c346941 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -977,19 +977,6 @@ config MFD_WL1273_CORE driver connects the radio-wl1273 V4L2 module and the wl1273 audio codec. -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 - and the si476x audio codec. - - To compile this driver as a module, choose M here: the - module will be called si476x-core. - config MFD_OMAP_USB_HOST bool "Support OMAP USBHS core and TLL driver" depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index b7aaa1e..b90409c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -131,10 +131,6 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o obj-$(CONFIG_MFD_VX855) += vx855.o obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o - -si476x-core-y := si476x-cmd.o si476x-prop.o si476x-i2c.o -obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o - obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o diff --git a/include/linux/mfd/si476x-core.h b/include/linux/mfd/si476x-core.h deleted file mode 100644 index 2136b26..0000000 --- a/include/linux/mfd/si476x-core.h +++ /dev/null @@ -1,525 +0,0 @@ -/* - * include/media/si476x-core.h -- Common definitions for si476x core - * device - * - * Copyright (C) 2012 Innovative Converged Devices(ICD) - * - * 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_CORE_H -#define SI476X_CORE_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* Command Timeouts */ -#define SI476X_DEFAULT_TIMEOUT 100000 -#define SI476X_TIMEOUT_TUNE 700000 -#define SI476X_TIMEOUT_POWER_UP 330000 -#define SI476X_STATUS_POLL_US 0 - -/* -------------------- si476x-i2c.c ----------------------- */ - -enum si476x_freq_supported_chips { - SI476X_CHIP_SI4761 = 1, - SI476X_CHIP_SI4764, - SI476X_CHIP_SI4768, -}; - -enum si476x_mfd_cells { - SI476X_RADIO_CELL = 0, - SI476X_CODEC_CELL, - SI476X_MFD_CELLS, -}; - -/** - * enum si476x_power_state - possible power state of the si476x - * device. - * - * @SI476X_POWER_DOWN: In this state all regulators are turned off - * and the reset line is pulled low. The device is completely - * inactive. - * @SI476X_POWER_UP_FULL: In this state all the power regualtors are - * turned on, reset line pulled high, IRQ line is enabled(polling is - * active for polling use scenario) and device is turned on with - * POWER_UP command. The device is ready to be used. - * @SI476X_POWER_INCONSISTENT: This state indicates that previous - * power down was inconsistent, meaning some of the regulators were - * not turned down and thus use of the device, without power-cycling - * is impossible. - */ -enum si476x_power_state { - SI476X_POWER_DOWN = 0, - SI476X_POWER_UP_FULL = 1, - SI476X_POWER_INCONSISTENT = 2, -}; - -/** - * struct si476x_core - internal data structure representing the - * underlying "core" device which all the MFD cell-devices use. - * - * @client: Actual I2C client used to transfer commands to the chip. - * @chip_id: Last digit of the chip model(E.g. "1" for SI4761) - * @cells: MFD cell devices created by this driver. - * @cmd_lock: Mutex used to serialize all the requests to the core - * device. This filed should not be used directly. Instead - * si476x_core_lock()/si476x_core_unlock() should be used to get - * exclusive access to the "core" device. - * @users: Active users counter(Used by the radio cell) - * @rds_read_queue: Wait queue used to wait for RDS data. - * @rds_fifo: FIFO in which all the RDS data received from the chip is - * placed. - * @rds_fifo_drainer: Worker that drains on-chip RDS FIFO. - * @rds_drainer_is_working: Flag used for launching only one instance - * of the @rds_fifo_drainer. - * @rds_drainer_status_lock: Lock used to guard access to the - * @rds_drainer_is_working variable. - * @command: Wait queue for wainting on the command comapletion. - * @cts: Clear To Send flag set upon receiving first status with CTS - * set. - * @tuning: Wait queue used for wainting for tune/seek comand - * completion. - * @stc: Similar to @cts, but for the STC bit of the status value. - * @power_up_parameters: Parameters used as argument for POWER_UP - * command when the device is started. - * @state: Current power state of the device. - * @supplues: Structure containing handles to all power supplies used - * by the device (NULL ones are ignored). - * @gpio_reset: GPIO pin connectet to the RSTB pin of the chip. - * @pinmux: Chip's configurable pins configuration. - * @diversity_mode: Chips role when functioning in diversity mode. - * @status_monitor: Polling worker used in polling use case scenarion - * (when IRQ is not avalible). - * @revision: Chip's running firmware revision number(Used for correct - * command set support). - */ - -struct si476x_core { - struct i2c_client *client; - struct regmap *regmap; - int chip_id; - struct mfd_cell cells[SI476X_MFD_CELLS]; - - struct mutex cmd_lock; /* for serializing fm radio operations */ - atomic_t users; - - wait_queue_head_t rds_read_queue; - struct kfifo rds_fifo; - struct work_struct rds_fifo_drainer; - bool rds_drainer_is_working; - struct mutex rds_drainer_status_lock; - - wait_queue_head_t command; - atomic_t cts; - - wait_queue_head_t tuning; - atomic_t stc; - - struct si476x_power_up_args power_up_parameters; - - enum si476x_power_state power_state; - - struct regulator_bulk_data supplies[4]; - - int gpio_reset; - - struct si476x_pinmux pinmux; - enum si476x_phase_diversity_mode diversity_mode; - - atomic_t is_alive; - - struct delayed_work status_monitor; -#define SI476X_WORK_TO_CORE(w) container_of(to_delayed_work(w), \ - struct si476x_core, \ - status_monitor) - - int revision; - - int rds_fifo_depth; -}; - -static inline struct si476x_core *i2c_mfd_cell_to_core(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev->parent); - return i2c_get_clientdata(client); -} - - -/** - * si476x_core_lock() - lock the core device to get an exclusive access - * to it. - */ -static inline void si476x_core_lock(struct si476x_core *core) -{ - mutex_lock(&core->cmd_lock); -} - -/** - * si476x_core_unlock() - unlock the core device to relinquish an - * exclusive access to it. - */ -static inline void si476x_core_unlock(struct si476x_core *core) -{ - mutex_unlock(&core->cmd_lock); -} - -/* *_TUNE_FREQ family of commands accept frequency in multiples of - 10kHz */ -static inline u16 hz_to_si476x(struct si476x_core *core, int freq) -{ - u16 result; - - switch (core->power_up_parameters.func) { - default: - case SI476X_FUNC_FM_RECEIVER: - result = freq / 10000; - break; - case SI476X_FUNC_AM_RECEIVER: - result = freq / 1000; - break; - } - - return result; -} - -static inline int si476x_to_hz(struct si476x_core *core, u16 freq) -{ - int result; - - switch (core->power_up_parameters.func) { - default: - case SI476X_FUNC_FM_RECEIVER: - result = freq * 10000; - break; - case SI476X_FUNC_AM_RECEIVER: - result = freq * 1000; - break; - } - - return result; -} - -/* Since the V4L2_TUNER_CAP_LOW flag is supplied, V4L2 subsystem - * mesures frequency in 62.5 Hz units */ - -static inline int hz_to_v4l2(int freq) -{ - return (freq * 10) / 625; -} - -static inline int v4l2_to_hz(int freq) -{ - return (freq * 625) / 10; -} - -static inline u16 v4l2_to_si476x(struct si476x_core *core, int freq) -{ - return hz_to_si476x(core, v4l2_to_hz(freq)); -} - -static inline int si476x_to_v4l2(struct si476x_core *core, u16 freq) -{ - return hz_to_v4l2(si476x_to_hz(core, freq)); -} - - - -/** - * struct si476x_func_info - structure containing result of the - * FUNC_INFO command. - * - * @firmware.major: Firmware major number. - * @firmware.minor[...]: Firmware minor numbers. - * @patch_id: - * @func: Mode tuner is working in. - */ -struct si476x_func_info { - struct { - u8 major, minor[2]; - } firmware; - u16 patch_id; - enum si476x_func func; -}; - -/** - * struct si476x_power_down_args - structure used to pass parameters - * to POWER_DOWN command - * - * @xosc: true - Power down, but leav oscillator running. - * false - Full power down. - */ -struct si476x_power_down_args { - bool xosc; -}; - -/** - * enum si476x_tunemode - enum representing possible tune modes for - * the chip. - * @SI476X_TM_VALIDATED_NORMAL_TUNE: Unconditionally stay on the new - * channel after tune, tune status is valid. - * @SI476X_TM_INVALIDATED_FAST_TUNE: Unconditionally stay in the new - * channel after tune, tune status invalid. - * @SI476X_TM_VALIDATED_AF_TUNE: Jump back to previous channel if - * metric thresholds are not met. - * @SI476X_TM_VALIDATED_AF_CHECK: Unconditionally jump back to the - * previous channel. - */ -enum si476x_tunemode { - SI476X_TM_VALIDATED_NORMAL_TUNE = 0, - SI476X_TM_INVALIDATED_FAST_TUNE = 1, - SI476X_TM_VALIDATED_AF_TUNE = 2, - SI476X_TM_VALIDATED_AF_CHECK = 3, -}; - -/** - * enum si476x_smoothmetrics - enum containing the possible setting fo - * audio transitioning of the chip - * @SI476X_SM_INITIALIZE_AUDIO: Initialize audio state to match this - * new channel - * @SI476X_SM_TRANSITION_AUDIO: Transition audio state from previous - * channel values to the new values - */ -enum si476x_smoothmetrics { - SI476X_SM_INITIALIZE_AUDIO = 0, - SI476X_SM_TRANSITION_AUDIO = 1, -}; - -/** - * struct si476x_rds_status_report - the structure representing the - * response to 'FM_RD_STATUS' command - * @rdstpptyint: Traffic program flag(TP) and/or program type(PTY) - * code has changed. - * @rdspiint: Program indentifiaction(PI) code has changed. - * @rdssyncint: RDS synchronization has changed. - * @rdsfifoint: RDS was received and the RDS FIFO has at least - * 'FM_RDS_INTERRUPT_FIFO_COUNT' elements in it. - * @tpptyvalid: TP flag and PTY code are valid falg. - * @pivalid: PI code is valid flag. - * @rdssync: RDS is currently synchronized. - * @rdsfifolost: On or more RDS groups have been lost/discarded flag. - * @tp: Current channel's TP flag. - * @pty: Current channel's PTY code. - * @pi: Current channel's PI code. - * @rdsfifoused: Number of blocks remaining in the RDS FIFO (0 if - * empty). - */ -struct si476x_rds_status_report { - bool rdstpptyint, rdspiint, rdssyncint, rdsfifoint; - bool tpptyvalid, pivalid, rdssync, rdsfifolost; - bool tp; - - u8 pty; - u16 pi; - - u8 rdsfifoused; - u8 ble[4]; - - struct v4l2_rds_data rds[4]; -}; - -struct si476x_rsq_status_args { - bool primary; - bool rsqack; - bool attune; - bool cancel; - bool stcack; -}; - -enum si476x_injside { - SI476X_INJSIDE_AUTO = 0, - SI476X_INJSIDE_LOW = 1, - SI476X_INJSIDE_HIGH = 2, -}; - -struct si476x_tune_freq_args { - bool zifsr; - bool hd; - enum si476x_injside injside; - int freq; - enum si476x_tunemode tunemode; - enum si476x_smoothmetrics smoothmetrics; - int antcap; -}; - -int si476x_core_stop(struct si476x_core *, bool); -int si476x_core_start(struct si476x_core *, bool); -int si476x_core_set_power_state(struct si476x_core *, enum si476x_power_state); -bool si476x_core_has_am(struct si476x_core *); -bool si476x_core_has_diversity(struct si476x_core *); -bool si476x_core_is_a_secondary_tuner(struct si476x_core *); -bool si476x_core_is_a_primary_tuner(struct si476x_core *); -bool si476x_core_is_in_am_receiver_mode(struct si476x_core *core); -bool si476x_core_is_powered_up(struct si476x_core *core); - -enum si476x_i2c_type { - SI476X_I2C_SEND, - SI476X_I2C_RECV -}; - -int si476x_core_i2c_xfer(struct si476x_core *, - enum si476x_i2c_type, - char *, int); - - -/* -------------------- si476x-cmd.c ----------------------- */ - -int si476x_core_cmd_func_info(struct si476x_core *, struct si476x_func_info *); -int si476x_core_cmd_set_property(struct si476x_core *, u16, u16); -int si476x_core_cmd_get_property(struct si476x_core *, u16); -int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *, - enum si476x_dclk_config, - enum si476x_dfs_config, - enum si476x_dout_config, - enum si476x_xout_config); -int si476x_core_cmd_zif_pin_cfg(struct si476x_core *, - enum si476x_iqclk_config, - enum si476x_iqfs_config, - enum si476x_iout_config, - enum si476x_qout_config); -int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *, - enum si476x_icin_config, - enum si476x_icip_config, - enum si476x_icon_config, - enum si476x_icop_config); -int si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *, - enum si476x_lrout_config); -int si476x_core_cmd_intb_pin_cfg(struct si476x_core *, enum si476x_intb_config, - enum si476x_a1_config); -int si476x_core_cmd_fm_seek_start(struct si476x_core *, bool, bool); -int si476x_core_cmd_am_seek_start(struct si476x_core *, bool, bool); -int si476x_core_cmd_fm_rds_status(struct si476x_core *, bool, bool, bool, - struct si476x_rds_status_report *); -int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *, bool, - struct si476x_rds_blockcount_report *); -int si476x_core_cmd_fm_tune_freq(struct si476x_core *, - struct si476x_tune_freq_args *); -int si476x_core_cmd_am_tune_freq(struct si476x_core *, - struct si476x_tune_freq_args *); -int si476x_core_cmd_am_rsq_status(struct si476x_core *, - struct si476x_rsq_status_args *, - struct si476x_rsq_status_report *); -int si476x_core_cmd_fm_rsq_status(struct si476x_core *, - struct si476x_rsq_status_args *, - struct si476x_rsq_status_report *); -int si476x_core_cmd_power_up(struct si476x_core *, - struct si476x_power_up_args *); -int si476x_core_cmd_power_down(struct si476x_core *, - struct si476x_power_down_args *); -int si476x_core_cmd_fm_phase_div_status(struct si476x_core *); -int si476x_core_cmd_fm_phase_diversity(struct si476x_core *, - enum si476x_phase_diversity_mode); - -int si476x_core_cmd_fm_acf_status(struct si476x_core *, - struct si476x_acf_status_report *); -int si476x_core_cmd_am_acf_status(struct si476x_core *, - struct si476x_acf_status_report *); -int si476x_core_cmd_agc_status(struct si476x_core *, - struct si476x_agc_status_report *); - -enum si476x_power_grid_type { - SI476X_POWER_GRID_50HZ = 0, - SI476X_POWER_GRID_60HZ, -}; - -/* Properties */ - -enum si476x_interrupt_flags { - SI476X_STCIEN = (1 << 0), - SI476X_ACFIEN = (1 << 1), - SI476X_RDSIEN = (1 << 2), - SI476X_RSQIEN = (1 << 3), - - SI476X_ERRIEN = (1 << 6), - SI476X_CTSIEN = (1 << 7), - - SI476X_STCREP = (1 << 8), - SI476X_ACFREP = (1 << 9), - SI476X_RDSREP = (1 << 10), - SI476X_RSQREP = (1 << 11), -}; - -enum si476x_rdsint_sources { - SI476X_RDSTPPTY = (1 << 4), - SI476X_RDSPI = (1 << 3), - SI476X_RDSSYNC = (1 << 1), - SI476X_RDSRECV = (1 << 0), -}; - -enum si476x_status_response_bits { - SI476X_CTS = (1 << 7), - SI476X_ERR = (1 << 6), - /* Status response for WB receiver */ - SI476X_WB_ASQ_INT = (1 << 4), - SI476X_RSQ_INT = (1 << 3), - /* Status response for FM receiver */ - SI476X_FM_RDS_INT = (1 << 2), - SI476X_ACF_INT = (1 << 1), - SI476X_STC_INT = (1 << 0), -}; - -/* -------------------- si476x-prop.c ----------------------- */ - -enum si476x_common_receiver_properties { - SI476X_PROP_INT_CTL_ENABLE = 0x0000, - SI476X_PROP_DIGITAL_IO_INPUT_SAMPLE_RATE = 0x0200, - SI476X_PROP_DIGITAL_IO_INPUT_FORMAT = 0x0201, - SI476X_PROP_DIGITAL_IO_OUTPUT_SAMPLE_RATE = 0x0202, - SI476X_PROP_DIGITAL_IO_OUTPUT_FORMAT = 0x0203, - - SI476X_PROP_SEEK_BAND_BOTTOM = 0x1100, - SI476X_PROP_SEEK_BAND_TOP = 0x1101, - SI476X_PROP_SEEK_FREQUENCY_SPACING = 0x1102, - - SI476X_PROP_VALID_MAX_TUNE_ERROR = 0x2000, - SI476X_PROP_VALID_SNR_THRESHOLD = 0x2003, - SI476X_PROP_VALID_RSSI_THRESHOLD = 0x2004, -}; - -enum si476x_am_receiver_properties { - SI476X_PROP_AUDIO_PWR_LINE_FILTER = 0x0303, -}; - -enum si476x_fm_receiver_properties { - SI476X_PROP_AUDIO_DEEMPHASIS = 0x0302, - - SI476X_PROP_FM_RDS_INTERRUPT_SOURCE = 0x4000, - SI476X_PROP_FM_RDS_INTERRUPT_FIFO_COUNT = 0x4001, - SI476X_PROP_FM_RDS_CONFIG = 0x4002, -}; - -enum si476x_prop_audio_pwr_line_filter_bits { - SI476X_PROP_PWR_HARMONICS_MASK = 0b0000000000011111, - SI476X_PROP_PWR_GRID_MASK = 0b0000000100000000, - SI476X_PROP_PWR_ENABLE_MASK = 0b0000001000000000, - SI476X_PROP_PWR_GRID_50HZ = 0b0000000000000000, - SI476X_PROP_PWR_GRID_60HZ = 0b0000000100000000, -}; - -enum si476x_prop_fm_rds_config_bits { - SI476X_PROP_RDSEN_MASK = 0x1, - SI476X_PROP_RDSEN = 0x1, -}; - - -struct regmap *devm_regmap_init_si476x(struct si476x_core *); - -#endif /* SI476X_CORE_H */ -- cgit v0.10.2 From 6695be6863b75620ffa6d422965680ce785cb7c8 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 2 Apr 2013 12:28:11 -0300 Subject: [media] DT: export of_get_next_parent() for use by modules: fix modular V4L2 Currently modular V4L2 build with enabled OF is broken dur to the of_get_next_parent() function being unavailable to modules. Export it to fix the build. Signed-off-by: Guennadi Liakhovetski Acked-by: Grant Likely Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/of/base.c b/drivers/of/base.c index 321d3ef..1733081 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -382,6 +382,7 @@ struct device_node *of_get_next_parent(struct device_node *node) raw_spin_unlock_irqrestore(&devtree_lock, flags); return parent; } +EXPORT_SYMBOL(of_get_next_parent); /** * of_get_next_child - Iterate a node childs -- cgit v0.10.2 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 diff --git a/Documentation/video4linux/si476x.txt b/Documentation/video4linux/si476x.txt new file mode 100644 index 0000000..d1a08db --- /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 24e64a0..c0beee2 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 303eaeb..0dcdb32 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 0000000..9430c6a --- /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 0000000..e02e241 --- /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 v0.10.2 From cbce0957d16ec1218d40538f5becb6cf6108b66a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 18 Apr 2013 20:51:00 -0300 Subject: Revert "[media] mfd: Add commands abstraction layer for SI476X MFD" This reverts commit 626b67c1ad90b450e0afbd1c277fd81ad64c5539. Requested-by: Samuel Ortiz Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/mfd/si476x-cmd.c b/drivers/mfd/si476x-cmd.c deleted file mode 100644 index 71ac2e8..0000000 --- a/drivers/mfd/si476x-cmd.c +++ /dev/null @@ -1,1554 +0,0 @@ -/* - * drivers/mfd/si476x-cmd.c -- Subroutines implementing command - * protocol of si476x series of 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 - -#define msb(x) ((u8)((u16) x >> 8)) -#define lsb(x) ((u8)((u16) x & 0x00FF)) - - - -#define CMD_POWER_UP 0x01 -#define CMD_POWER_UP_A10_NRESP 1 -#define CMD_POWER_UP_A10_NARGS 5 - -#define CMD_POWER_UP_A20_NRESP 1 -#define CMD_POWER_UP_A20_NARGS 5 - -#define POWER_UP_DELAY_MS 110 - -#define CMD_POWER_DOWN 0x11 -#define CMD_POWER_DOWN_A10_NRESP 1 - -#define CMD_POWER_DOWN_A20_NRESP 1 -#define CMD_POWER_DOWN_A20_NARGS 1 - -#define CMD_FUNC_INFO 0x12 -#define CMD_FUNC_INFO_NRESP 7 - -#define CMD_SET_PROPERTY 0x13 -#define CMD_SET_PROPERTY_NARGS 5 -#define CMD_SET_PROPERTY_NRESP 1 - -#define CMD_GET_PROPERTY 0x14 -#define CMD_GET_PROPERTY_NARGS 3 -#define CMD_GET_PROPERTY_NRESP 4 - -#define CMD_AGC_STATUS 0x17 -#define CMD_AGC_STATUS_NRESP_A10 2 -#define CMD_AGC_STATUS_NRESP_A20 6 - -#define PIN_CFG_BYTE(x) (0x7F & (x)) -#define CMD_DIG_AUDIO_PIN_CFG 0x18 -#define CMD_DIG_AUDIO_PIN_CFG_NARGS 4 -#define CMD_DIG_AUDIO_PIN_CFG_NRESP 5 - -#define CMD_ZIF_PIN_CFG 0x19 -#define CMD_ZIF_PIN_CFG_NARGS 4 -#define CMD_ZIF_PIN_CFG_NRESP 5 - -#define CMD_IC_LINK_GPO_CTL_PIN_CFG 0x1A -#define CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS 4 -#define CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP 5 - -#define CMD_ANA_AUDIO_PIN_CFG 0x1B -#define CMD_ANA_AUDIO_PIN_CFG_NARGS 1 -#define CMD_ANA_AUDIO_PIN_CFG_NRESP 2 - -#define CMD_INTB_PIN_CFG 0x1C -#define CMD_INTB_PIN_CFG_NARGS 2 -#define CMD_INTB_PIN_CFG_A10_NRESP 6 -#define CMD_INTB_PIN_CFG_A20_NRESP 3 - -#define CMD_FM_TUNE_FREQ 0x30 -#define CMD_FM_TUNE_FREQ_A10_NARGS 5 -#define CMD_FM_TUNE_FREQ_A20_NARGS 3 -#define CMD_FM_TUNE_FREQ_NRESP 1 - -#define CMD_FM_RSQ_STATUS 0x32 - -#define CMD_FM_RSQ_STATUS_A10_NARGS 1 -#define CMD_FM_RSQ_STATUS_A10_NRESP 17 -#define CMD_FM_RSQ_STATUS_A30_NARGS 1 -#define CMD_FM_RSQ_STATUS_A30_NRESP 23 - - -#define CMD_FM_SEEK_START 0x31 -#define CMD_FM_SEEK_START_NARGS 1 -#define CMD_FM_SEEK_START_NRESP 1 - -#define CMD_FM_RDS_STATUS 0x36 -#define CMD_FM_RDS_STATUS_NARGS 1 -#define CMD_FM_RDS_STATUS_NRESP 16 - -#define CMD_FM_RDS_BLOCKCOUNT 0x37 -#define CMD_FM_RDS_BLOCKCOUNT_NARGS 1 -#define CMD_FM_RDS_BLOCKCOUNT_NRESP 8 - -#define CMD_FM_PHASE_DIVERSITY 0x38 -#define CMD_FM_PHASE_DIVERSITY_NARGS 1 -#define CMD_FM_PHASE_DIVERSITY_NRESP 1 - -#define CMD_FM_PHASE_DIV_STATUS 0x39 -#define CMD_FM_PHASE_DIV_STATUS_NRESP 2 - -#define CMD_AM_TUNE_FREQ 0x40 -#define CMD_AM_TUNE_FREQ_NARGS 3 -#define CMD_AM_TUNE_FREQ_NRESP 1 - -#define CMD_AM_RSQ_STATUS 0x42 -#define CMD_AM_RSQ_STATUS_NARGS 1 -#define CMD_AM_RSQ_STATUS_NRESP 13 - -#define CMD_AM_SEEK_START 0x41 -#define CMD_AM_SEEK_START_NARGS 1 -#define CMD_AM_SEEK_START_NRESP 1 - - -#define CMD_AM_ACF_STATUS 0x45 -#define CMD_AM_ACF_STATUS_NRESP 6 -#define CMD_AM_ACF_STATUS_NARGS 1 - -#define CMD_FM_ACF_STATUS 0x35 -#define CMD_FM_ACF_STATUS_NRESP 8 -#define CMD_FM_ACF_STATUS_NARGS 1 - -#define CMD_MAX_ARGS_COUNT (10) - - -enum si476x_acf_status_report_bits { - SI476X_ACF_BLEND_INT = (1 << 4), - SI476X_ACF_HIBLEND_INT = (1 << 3), - SI476X_ACF_HICUT_INT = (1 << 2), - SI476X_ACF_CHBW_INT = (1 << 1), - SI476X_ACF_SOFTMUTE_INT = (1 << 0), - - SI476X_ACF_SMUTE = (1 << 0), - SI476X_ACF_SMATTN = 0b11111, - SI476X_ACF_PILOT = (1 << 7), - SI476X_ACF_STBLEND = ~SI476X_ACF_PILOT, -}; - -enum si476x_agc_status_report_bits { - SI476X_AGC_MXHI = (1 << 5), - SI476X_AGC_MXLO = (1 << 4), - SI476X_AGC_LNAHI = (1 << 3), - SI476X_AGC_LNALO = (1 << 2), -}; - -enum si476x_errors { - SI476X_ERR_BAD_COMMAND = 0x10, - SI476X_ERR_BAD_ARG1 = 0x11, - SI476X_ERR_BAD_ARG2 = 0x12, - SI476X_ERR_BAD_ARG3 = 0x13, - SI476X_ERR_BAD_ARG4 = 0x14, - SI476X_ERR_BUSY = 0x18, - SI476X_ERR_BAD_INTERNAL_MEMORY = 0x20, - SI476X_ERR_BAD_PATCH = 0x30, - SI476X_ERR_BAD_BOOT_MODE = 0x31, - SI476X_ERR_BAD_PROPERTY = 0x40, -}; - -static int si476x_core_parse_and_nag_about_error(struct si476x_core *core) -{ - int err; - char *cause; - u8 buffer[2]; - - if (core->revision != SI476X_REVISION_A10) { - err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, - buffer, sizeof(buffer)); - if (err == sizeof(buffer)) { - switch (buffer[1]) { - case SI476X_ERR_BAD_COMMAND: - cause = "Bad command"; - err = -EINVAL; - break; - case SI476X_ERR_BAD_ARG1: - cause = "Bad argument #1"; - err = -EINVAL; - break; - case SI476X_ERR_BAD_ARG2: - cause = "Bad argument #2"; - err = -EINVAL; - break; - case SI476X_ERR_BAD_ARG3: - cause = "Bad argument #3"; - err = -EINVAL; - break; - case SI476X_ERR_BAD_ARG4: - cause = "Bad argument #4"; - err = -EINVAL; - break; - case SI476X_ERR_BUSY: - cause = "Chip is busy"; - err = -EBUSY; - break; - case SI476X_ERR_BAD_INTERNAL_MEMORY: - cause = "Bad internal memory"; - err = -EIO; - break; - case SI476X_ERR_BAD_PATCH: - cause = "Bad patch"; - err = -EINVAL; - break; - case SI476X_ERR_BAD_BOOT_MODE: - cause = "Bad boot mode"; - err = -EINVAL; - break; - case SI476X_ERR_BAD_PROPERTY: - cause = "Bad property"; - err = -EINVAL; - break; - default: - cause = "Unknown"; - err = -EIO; - } - - dev_err(&core->client->dev, - "[Chip error status]: %s\n", cause); - } else { - dev_err(&core->client->dev, - "Failed to fetch error code\n"); - err = (err >= 0) ? -EIO : err; - } - } else { - err = -EIO; - } - - return err; -} - -/** - * si476x_core_send_command() - sends a command to si476x and waits its - * response - * @core: si476x_device structure for the device we are - * communicating with - * @command: command id - * @args: command arguments we are sending - * @argn: actual size of @args - * @response: buffer to place the expected response from the device - * @respn: actual size of @response - * @usecs: amount of time to wait before reading the response (in - * usecs) - * - * Function returns 0 on succsess and negative error code on - * failure - */ -static int si476x_core_send_command(struct si476x_core *core, - const u8 command, - const u8 args[], - const int argn, - u8 resp[], - const int respn, - const int usecs) -{ - struct i2c_client *client = core->client; - int err; - u8 data[CMD_MAX_ARGS_COUNT + 1]; - - if (argn > CMD_MAX_ARGS_COUNT) { - err = -ENOMEM; - goto exit; - } - - if (!client->adapter) { - err = -ENODEV; - goto exit; - } - - /* First send the command and its arguments */ - data[0] = command; - memcpy(&data[1], args, argn); - dev_dbg(&client->dev, "Command:\n %*ph\n", argn + 1, data); - - err = si476x_core_i2c_xfer(core, SI476X_I2C_SEND, - (char *) data, argn + 1); - if (err != argn + 1) { - dev_err(&core->client->dev, - "Error while sending command 0x%02x\n", - command); - err = (err >= 0) ? -EIO : err; - goto exit; - } - /* Set CTS to zero only after the command is send to avoid - * possible racing conditions when working in polling mode */ - atomic_set(&core->cts, 0); - - /* if (unlikely(command == CMD_POWER_DOWN) */ - if (!wait_event_timeout(core->command, - atomic_read(&core->cts), - usecs_to_jiffies(usecs) + 1)) - dev_warn(&core->client->dev, - "(%s) [CMD 0x%02x] Answer timeout.\n", - __func__, command); - - /* - When working in polling mode, for some reason the tuner will - report CTS bit as being set in the first status byte read, - but all the consequtive ones will return zeros until the - tuner is actually completed the POWER_UP command. To - workaround that we wait for second CTS to be reported - */ - if (unlikely(!core->client->irq && command == CMD_POWER_UP)) { - if (!wait_event_timeout(core->command, - atomic_read(&core->cts), - usecs_to_jiffies(usecs) + 1)) - dev_warn(&core->client->dev, - "(%s) Power up took too much time.\n", - __func__); - } - - /* Then get the response */ - err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, resp, respn); - if (err != respn) { - dev_err(&core->client->dev, - "Error while reading response for command 0x%02x\n", - command); - err = (err >= 0) ? -EIO : err; - goto exit; - } - dev_dbg(&client->dev, "Response:\n %*ph\n", respn, resp); - - err = 0; - - if (resp[0] & SI476X_ERR) { - dev_err(&core->client->dev, - "[CMD 0x%02x] Chip set error flag\n", command); - err = si476x_core_parse_and_nag_about_error(core); - goto exit; - } - - if (!(resp[0] & SI476X_CTS)) - err = -EBUSY; -exit: - return err; -} - -static int si476x_cmd_clear_stc(struct si476x_core *core) -{ - int err; - struct si476x_rsq_status_args args = { - .primary = false, - .rsqack = false, - .attune = false, - .cancel = false, - .stcack = true, - }; - - switch (core->power_up_parameters.func) { - case SI476X_FUNC_FM_RECEIVER: - err = si476x_core_cmd_fm_rsq_status(core, &args, NULL); - break; - case SI476X_FUNC_AM_RECEIVER: - err = si476x_core_cmd_am_rsq_status(core, &args, NULL); - break; - default: - err = -EINVAL; - } - - return err; -} - -static int si476x_cmd_tune_seek_freq(struct si476x_core *core, - uint8_t cmd, - const uint8_t args[], size_t argn, - uint8_t *resp, size_t respn) -{ - int err; - - - atomic_set(&core->stc, 0); - err = si476x_core_send_command(core, cmd, args, argn, resp, respn, - SI476X_TIMEOUT_TUNE); - if (!err) { - wait_event_killable(core->tuning, - atomic_read(&core->stc)); - si476x_cmd_clear_stc(core); - } - - return err; -} - -/** - * si476x_cmd_func_info() - send 'FUNC_INFO' command to the device - * @core: device to send the command to - * @info: struct si476x_func_info to fill all the information - * returned by the command - * - * The command requests the firmware and patch version for currently - * loaded firmware (dependent on the function of the device FM/AM/WB) - * - * Function returns 0 on succsess and negative error code on - * failure - */ -int si476x_core_cmd_func_info(struct si476x_core *core, - struct si476x_func_info *info) -{ - int err; - u8 resp[CMD_FUNC_INFO_NRESP]; - - err = si476x_core_send_command(core, CMD_FUNC_INFO, - NULL, 0, - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - - info->firmware.major = resp[1]; - info->firmware.minor[0] = resp[2]; - info->firmware.minor[1] = resp[3]; - - info->patch_id = ((u16) resp[4] << 8) | resp[5]; - info->func = resp[6]; - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_func_info); - -/** - * si476x_cmd_set_property() - send 'SET_PROPERTY' command to the device - * @core: device to send the command to - * @property: property address - * @value: property value - * - * Function returns 0 on succsess and negative error code on - * failure - */ -int si476x_core_cmd_set_property(struct si476x_core *core, - u16 property, u16 value) -{ - u8 resp[CMD_SET_PROPERTY_NRESP]; - const u8 args[CMD_SET_PROPERTY_NARGS] = { - 0x00, - msb(property), - lsb(property), - msb(value), - lsb(value), - }; - - return si476x_core_send_command(core, CMD_SET_PROPERTY, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_set_property); - -/** - * si476x_cmd_get_property() - send 'GET_PROPERTY' command to the device - * @core: device to send the command to - * @property: property address - * - * Function return the value of property as u16 on success or a - * negative error on failure - */ -int si476x_core_cmd_get_property(struct si476x_core *core, u16 property) -{ - int err; - u8 resp[CMD_GET_PROPERTY_NRESP]; - const u8 args[CMD_GET_PROPERTY_NARGS] = { - 0x00, - msb(property), - lsb(property), - }; - - err = si476x_core_send_command(core, CMD_GET_PROPERTY, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - if (err < 0) - return err; - else - return be16_to_cpup((__be16 *)(resp + 2)); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_get_property); - -/** - * si476x_cmd_dig_audio_pin_cfg() - send 'DIG_AUDIO_PIN_CFG' command to - * the device - * @core: device to send the command to - * @dclk: DCLK pin function configuration: - * #SI476X_DCLK_NOOP - do not modify the behaviour - * #SI476X_DCLK_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * #SI476X_DCLK_DAUDIO - set the pin to be a part of digital - * audio interface - * @dfs: DFS pin function configuration: - * #SI476X_DFS_NOOP - do not modify the behaviour - * #SI476X_DFS_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_DFS_DAUDIO - set the pin to be a part of digital - * audio interface - * @dout - DOUT pin function configuration: - * SI476X_DOUT_NOOP - do not modify the behaviour - * SI476X_DOUT_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_DOUT_I2S_OUTPUT - set this pin to be digital out on I2S - * port 1 - * SI476X_DOUT_I2S_INPUT - set this pin to be digital in on I2S - * port 1 - * @xout - XOUT pin function configuration: - * SI476X_XOUT_NOOP - do not modify the behaviour - * SI476X_XOUT_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_XOUT_I2S_INPUT - set this pin to be digital in on I2S - * port 1 - * SI476X_XOUT_MODE_SELECT - set this pin to be the input that - * selects the mode of the I2S audio - * combiner (analog or HD) - * [SI4761/63/65/67 Only] - * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_dig_audio_pin_cfg(struct si476x_core *core, - enum si476x_dclk_config dclk, - enum si476x_dfs_config dfs, - enum si476x_dout_config dout, - enum si476x_xout_config xout) -{ - u8 resp[CMD_DIG_AUDIO_PIN_CFG_NRESP]; - const u8 args[CMD_DIG_AUDIO_PIN_CFG_NARGS] = { - PIN_CFG_BYTE(dclk), - PIN_CFG_BYTE(dfs), - PIN_CFG_BYTE(dout), - PIN_CFG_BYTE(xout), - }; - - return si476x_core_send_command(core, CMD_DIG_AUDIO_PIN_CFG, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_dig_audio_pin_cfg); - -/** - * si476x_cmd_zif_pin_cfg - send 'ZIF_PIN_CFG_COMMAND' - * @core - device to send the command to - * @iqclk - IQCL pin function configuration: - * SI476X_IQCLK_NOOP - do not modify the behaviour - * SI476X_IQCLK_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_IQCLK_IQ - set pin to be a part of I/Q interace - * in master mode - * @iqfs - IQFS pin function configuration: - * SI476X_IQFS_NOOP - do not modify the behaviour - * SI476X_IQFS_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_IQFS_IQ - set pin to be a part of I/Q interace - * in master mode - * @iout - IOUT pin function configuration: - * SI476X_IOUT_NOOP - do not modify the behaviour - * SI476X_IOUT_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_IOUT_OUTPUT - set pin to be I out - * @qout - QOUT pin function configuration: - * SI476X_QOUT_NOOP - do not modify the behaviour - * SI476X_QOUT_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_QOUT_OUTPUT - set pin to be Q out - * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_zif_pin_cfg(struct si476x_core *core, - enum si476x_iqclk_config iqclk, - enum si476x_iqfs_config iqfs, - enum si476x_iout_config iout, - enum si476x_qout_config qout) -{ - u8 resp[CMD_ZIF_PIN_CFG_NRESP]; - const u8 args[CMD_ZIF_PIN_CFG_NARGS] = { - PIN_CFG_BYTE(iqclk), - PIN_CFG_BYTE(iqfs), - PIN_CFG_BYTE(iout), - PIN_CFG_BYTE(qout), - }; - - return si476x_core_send_command(core, CMD_ZIF_PIN_CFG, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_zif_pin_cfg); - -/** - * si476x_cmd_ic_link_gpo_ctl_pin_cfg - send - * 'IC_LINK_GPIO_CTL_PIN_CFG' comand to the device - * @core - device to send the command to - * @icin - ICIN pin function configuration: - * SI476X_ICIN_NOOP - do not modify the behaviour - * SI476X_ICIN_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_ICIN_GPO1_HIGH - set pin to be an output, drive it high - * SI476X_ICIN_GPO1_LOW - set pin to be an output, drive it low - * SI476X_ICIN_IC_LINK - set the pin to be a part of Inter-Chip link - * @icip - ICIP pin function configuration: - * SI476X_ICIP_NOOP - do not modify the behaviour - * SI476X_ICIP_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_ICIP_GPO1_HIGH - set pin to be an output, drive it high - * SI476X_ICIP_GPO1_LOW - set pin to be an output, drive it low - * SI476X_ICIP_IC_LINK - set the pin to be a part of Inter-Chip link - * @icon - ICON pin function configuration: - * SI476X_ICON_NOOP - do not modify the behaviour - * SI476X_ICON_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_ICON_I2S - set the pin to be a part of audio - * interface in slave mode (DCLK) - * SI476X_ICON_IC_LINK - set the pin to be a part of Inter-Chip link - * @icop - ICOP pin function configuration: - * SI476X_ICOP_NOOP - do not modify the behaviour - * SI476X_ICOP_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_ICOP_I2S - set the pin to be a part of audio - * interface in slave mode (DOUT) - * [Si4761/63/65/67 Only] - * SI476X_ICOP_IC_LINK - set the pin to be a part of Inter-Chip link - * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(struct si476x_core *core, - enum si476x_icin_config icin, - enum si476x_icip_config icip, - enum si476x_icon_config icon, - enum si476x_icop_config icop) -{ - u8 resp[CMD_IC_LINK_GPO_CTL_PIN_CFG_NRESP]; - const u8 args[CMD_IC_LINK_GPO_CTL_PIN_CFG_NARGS] = { - PIN_CFG_BYTE(icin), - PIN_CFG_BYTE(icip), - PIN_CFG_BYTE(icon), - PIN_CFG_BYTE(icop), - }; - - return si476x_core_send_command(core, CMD_IC_LINK_GPO_CTL_PIN_CFG, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_ic_link_gpo_ctl_pin_cfg); - -/** - * si476x_cmd_ana_audio_pin_cfg - send 'ANA_AUDIO_PIN_CFG' to the - * device - * @core - device to send the command to - * @lrout - LROUT pin function configuration: - * SI476X_LROUT_NOOP - do not modify the behaviour - * SI476X_LROUT_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_LROUT_AUDIO - set pin to be audio output - * SI476X_LROUT_MPX - set pin to be MPX output - * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_ana_audio_pin_cfg(struct si476x_core *core, - enum si476x_lrout_config lrout) -{ - u8 resp[CMD_ANA_AUDIO_PIN_CFG_NRESP]; - const u8 args[CMD_ANA_AUDIO_PIN_CFG_NARGS] = { - PIN_CFG_BYTE(lrout), - }; - - return si476x_core_send_command(core, CMD_ANA_AUDIO_PIN_CFG, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_ana_audio_pin_cfg); - - -/** - * si476x_cmd_intb_pin_cfg - send 'INTB_PIN_CFG' command to the device - * @core - device to send the command to - * @intb - INTB pin function configuration: - * SI476X_INTB_NOOP - do not modify the behaviour - * SI476X_INTB_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_INTB_DAUDIO - set pin to be a part of digital - * audio interface in slave mode - * SI476X_INTB_IRQ - set pin to be an interrupt request line - * @a1 - A1 pin function configuration: - * SI476X_A1_NOOP - do not modify the behaviour - * SI476X_A1_TRISTATE - put the pin in tristate condition, - * enable 1MOhm pulldown - * SI476X_A1_IRQ - set pin to be an interrupt request line - * - * Function returns 0 on success and negative error code on failure - */ -static int si476x_core_cmd_intb_pin_cfg_a10(struct si476x_core *core, - enum si476x_intb_config intb, - enum si476x_a1_config a1) -{ - u8 resp[CMD_INTB_PIN_CFG_A10_NRESP]; - const u8 args[CMD_INTB_PIN_CFG_NARGS] = { - PIN_CFG_BYTE(intb), - PIN_CFG_BYTE(a1), - }; - - return si476x_core_send_command(core, CMD_INTB_PIN_CFG, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} - -static int si476x_core_cmd_intb_pin_cfg_a20(struct si476x_core *core, - enum si476x_intb_config intb, - enum si476x_a1_config a1) -{ - u8 resp[CMD_INTB_PIN_CFG_A20_NRESP]; - const u8 args[CMD_INTB_PIN_CFG_NARGS] = { - PIN_CFG_BYTE(intb), - PIN_CFG_BYTE(a1), - }; - - return si476x_core_send_command(core, CMD_INTB_PIN_CFG, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} - - - -/** - * si476x_cmd_am_rsq_status - send 'AM_RSQ_STATUS' command to the - * device - * @core - device to send the command to - * @rsqack - if set command clears RSQINT, SNRINT, SNRLINT, RSSIHINT, - * RSSSILINT, BLENDINT, MULTHINT and MULTLINT - * @attune - when set the values in the status report are the values - * that were calculated at tune - * @cancel - abort ongoing seek/tune opertation - * @stcack - clear the STCINT bin in status register - * @report - all signal quality information retured by the command - * (if NULL then the output of the command is ignored) - * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_am_rsq_status(struct si476x_core *core, - struct si476x_rsq_status_args *rsqargs, - struct si476x_rsq_status_report *report) -{ - int err; - u8 resp[CMD_AM_RSQ_STATUS_NRESP]; - const u8 args[CMD_AM_RSQ_STATUS_NARGS] = { - rsqargs->rsqack << 3 | rsqargs->attune << 2 | - rsqargs->cancel << 1 | rsqargs->stcack, - }; - - err = si476x_core_send_command(core, CMD_AM_RSQ_STATUS, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - /* - * Besides getting received signal quality information this - * command can be used to just acknowledge different interrupt - * flags in those cases it is useless to copy and parse - * received data so user can pass NULL, and thus avoid - * unnecessary copying. - */ - if (!report) - return err; - - report->snrhint = 0b00001000 & resp[1]; - report->snrlint = 0b00000100 & resp[1]; - report->rssihint = 0b00000010 & resp[1]; - report->rssilint = 0b00000001 & resp[1]; - - report->bltf = 0b10000000 & resp[2]; - report->snr_ready = 0b00100000 & resp[2]; - report->rssiready = 0b00001000 & resp[2]; - report->afcrl = 0b00000010 & resp[2]; - report->valid = 0b00000001 & resp[2]; - - report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); - report->freqoff = resp[5]; - report->rssi = resp[6]; - report->snr = resp[7]; - report->lassi = resp[9]; - report->hassi = resp[10]; - report->mult = resp[11]; - report->dev = resp[12]; - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_am_rsq_status); - -int si476x_core_cmd_fm_acf_status(struct si476x_core *core, - struct si476x_acf_status_report *report) -{ - int err; - u8 resp[CMD_FM_ACF_STATUS_NRESP]; - const u8 args[CMD_FM_ACF_STATUS_NARGS] = { - 0x0, - }; - - if (!report) - return -EINVAL; - - err = si476x_core_send_command(core, CMD_FM_ACF_STATUS, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - if (err < 0) - return err; - - report->blend_int = resp[1] & SI476X_ACF_BLEND_INT; - report->hblend_int = resp[1] & SI476X_ACF_HIBLEND_INT; - report->hicut_int = resp[1] & SI476X_ACF_HICUT_INT; - report->chbw_int = resp[1] & SI476X_ACF_CHBW_INT; - report->softmute_int = resp[1] & SI476X_ACF_SOFTMUTE_INT; - report->smute = resp[2] & SI476X_ACF_SMUTE; - report->smattn = resp[3] & SI476X_ACF_SMATTN; - report->chbw = resp[4]; - report->hicut = resp[5]; - report->hiblend = resp[6]; - report->pilot = resp[7] & SI476X_ACF_PILOT; - report->stblend = resp[7] & SI476X_ACF_STBLEND; - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_acf_status); - -int si476x_core_cmd_am_acf_status(struct si476x_core *core, - struct si476x_acf_status_report *report) -{ - int err; - u8 resp[CMD_AM_ACF_STATUS_NRESP]; - const u8 args[CMD_AM_ACF_STATUS_NARGS] = { - 0x0, - }; - - if (!report) - return -EINVAL; - - err = si476x_core_send_command(core, CMD_AM_ACF_STATUS, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - if (err < 0) - return err; - - report->blend_int = resp[1] & SI476X_ACF_BLEND_INT; - report->hblend_int = resp[1] & SI476X_ACF_HIBLEND_INT; - report->hicut_int = resp[1] & SI476X_ACF_HICUT_INT; - report->chbw_int = resp[1] & SI476X_ACF_CHBW_INT; - report->softmute_int = resp[1] & SI476X_ACF_SOFTMUTE_INT; - report->smute = resp[2] & SI476X_ACF_SMUTE; - report->smattn = resp[3] & SI476X_ACF_SMATTN; - report->chbw = resp[4]; - report->hicut = resp[5]; - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_am_acf_status); - - -/** - * si476x_cmd_fm_seek_start - send 'FM_SEEK_START' command to the - * device - * @core - device to send the command to - * @seekup - if set the direction of the search is 'up' - * @wrap - if set seek wraps when hitting band limit - * - * This function begins search for a valid station. The station is - * considered valid when 'FM_VALID_SNR_THRESHOLD' and - * 'FM_VALID_RSSI_THRESHOLD' and 'FM_VALID_MAX_TUNE_ERROR' criteria - * are met. -} * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_fm_seek_start(struct si476x_core *core, - bool seekup, bool wrap) -{ - u8 resp[CMD_FM_SEEK_START_NRESP]; - const u8 args[CMD_FM_SEEK_START_NARGS] = { - seekup << 3 | wrap << 2, - }; - - return si476x_cmd_tune_seek_freq(core, CMD_FM_SEEK_START, - args, sizeof(args), - resp, sizeof(resp)); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_seek_start); - -/** - * si476x_cmd_fm_rds_status - send 'FM_RDS_STATUS' command to the - * device - * @core - device to send the command to - * @status_only - if set the data is not removed from RDSFIFO, - * RDSFIFOUSED is not decremented and data in all the - * rest RDS data contains the last valid info received - * @mtfifo if set the command clears RDS receive FIFO - * @intack if set the command clards the RDSINT bit. - * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_fm_rds_status(struct si476x_core *core, - bool status_only, - bool mtfifo, - bool intack, - struct si476x_rds_status_report *report) -{ - int err; - u8 resp[CMD_FM_RDS_STATUS_NRESP]; - const u8 args[CMD_FM_RDS_STATUS_NARGS] = { - status_only << 2 | mtfifo << 1 | intack, - }; - - err = si476x_core_send_command(core, CMD_FM_RDS_STATUS, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - /* - * Besides getting RDS status information this command can be - * used to just acknowledge different interrupt flags in those - * cases it is useless to copy and parse received data so user - * can pass NULL, and thus avoid unnecessary copying. - */ - if (err < 0 || report == NULL) - return err; - - report->rdstpptyint = 0b00010000 & resp[1]; - report->rdspiint = 0b00001000 & resp[1]; - report->rdssyncint = 0b00000010 & resp[1]; - report->rdsfifoint = 0b00000001 & resp[1]; - - report->tpptyvalid = 0b00010000 & resp[2]; - report->pivalid = 0b00001000 & resp[2]; - report->rdssync = 0b00000010 & resp[2]; - report->rdsfifolost = 0b00000001 & resp[2]; - - report->tp = 0b00100000 & resp[3]; - report->pty = 0b00011111 & resp[3]; - - report->pi = be16_to_cpup((__be16 *)(resp + 4)); - report->rdsfifoused = resp[6]; - - report->ble[V4L2_RDS_BLOCK_A] = 0b11000000 & resp[7]; - report->ble[V4L2_RDS_BLOCK_B] = 0b00110000 & resp[7]; - report->ble[V4L2_RDS_BLOCK_C] = 0b00001100 & resp[7]; - report->ble[V4L2_RDS_BLOCK_D] = 0b00000011 & resp[7]; - - report->rds[V4L2_RDS_BLOCK_A].block = V4L2_RDS_BLOCK_A; - report->rds[V4L2_RDS_BLOCK_A].msb = resp[8]; - report->rds[V4L2_RDS_BLOCK_A].lsb = resp[9]; - - report->rds[V4L2_RDS_BLOCK_B].block = V4L2_RDS_BLOCK_B; - report->rds[V4L2_RDS_BLOCK_B].msb = resp[10]; - report->rds[V4L2_RDS_BLOCK_B].lsb = resp[11]; - - report->rds[V4L2_RDS_BLOCK_C].block = V4L2_RDS_BLOCK_C; - report->rds[V4L2_RDS_BLOCK_C].msb = resp[12]; - report->rds[V4L2_RDS_BLOCK_C].lsb = resp[13]; - - report->rds[V4L2_RDS_BLOCK_D].block = V4L2_RDS_BLOCK_D; - report->rds[V4L2_RDS_BLOCK_D].msb = resp[14]; - report->rds[V4L2_RDS_BLOCK_D].lsb = resp[15]; - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rds_status); - -int si476x_core_cmd_fm_rds_blockcount(struct si476x_core *core, - bool clear, - struct si476x_rds_blockcount_report *report) -{ - int err; - u8 resp[CMD_FM_RDS_BLOCKCOUNT_NRESP]; - const u8 args[CMD_FM_RDS_BLOCKCOUNT_NARGS] = { - clear, - }; - - if (!report) - return -EINVAL; - - err = si476x_core_send_command(core, CMD_FM_RDS_BLOCKCOUNT, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - - if (!err) { - report->expected = be16_to_cpup((__be16 *)(resp + 2)); - report->received = be16_to_cpup((__be16 *)(resp + 4)); - report->uncorrectable = be16_to_cpup((__be16 *)(resp + 6)); - } - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rds_blockcount); - -int si476x_core_cmd_fm_phase_diversity(struct si476x_core *core, - enum si476x_phase_diversity_mode mode) -{ - u8 resp[CMD_FM_PHASE_DIVERSITY_NRESP]; - const u8 args[CMD_FM_PHASE_DIVERSITY_NARGS] = { - mode & 0b111, - }; - - return si476x_core_send_command(core, CMD_FM_PHASE_DIVERSITY, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_diversity); -/** - * si476x_core_cmd_fm_phase_div_status() - get the phase diversity - * status - * - * @core: si476x device - * - * NOTE caller must hold core lock - * - * Function returns the value of the status bit in case of success and - * negative error code in case of failre. - */ -int si476x_core_cmd_fm_phase_div_status(struct si476x_core *core) -{ - int err; - u8 resp[CMD_FM_PHASE_DIV_STATUS_NRESP]; - - err = si476x_core_send_command(core, CMD_FM_PHASE_DIV_STATUS, - NULL, 0, - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - - return (err < 0) ? err : resp[1]; -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_div_status); - - -/** - * si476x_cmd_am_seek_start - send 'FM_SEEK_START' command to the - * device - * @core - device to send the command to - * @seekup - if set the direction of the search is 'up' - * @wrap - if set seek wraps when hitting band limit - * - * This function begins search for a valid station. The station is - * considered valid when 'FM_VALID_SNR_THRESHOLD' and - * 'FM_VALID_RSSI_THRESHOLD' and 'FM_VALID_MAX_TUNE_ERROR' criteria - * are met. - * - * Function returns 0 on success and negative error code on failure - */ -int si476x_core_cmd_am_seek_start(struct si476x_core *core, - bool seekup, bool wrap) -{ - u8 resp[CMD_AM_SEEK_START_NRESP]; - const u8 args[CMD_AM_SEEK_START_NARGS] = { - seekup << 3 | wrap << 2, - }; - - return si476x_cmd_tune_seek_freq(core, CMD_AM_SEEK_START, - args, sizeof(args), - resp, sizeof(resp)); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_am_seek_start); - - - -static int si476x_core_cmd_power_up_a10(struct si476x_core *core, - struct si476x_power_up_args *puargs) -{ - u8 resp[CMD_POWER_UP_A10_NRESP]; - const bool intsel = (core->pinmux.a1 == SI476X_A1_IRQ); - const bool ctsen = (core->client->irq != 0); - const u8 args[CMD_POWER_UP_A10_NARGS] = { - 0xF7, /* Reserved, always 0xF7 */ - 0x3F & puargs->xcload, /* First two bits are reserved to be - * zeros */ - ctsen << 7 | intsel << 6 | 0x07, /* Last five bits - * are reserved to - * be written as 0x7 */ - puargs->func << 4 | puargs->freq, - 0x11, /* Reserved, always 0x11 */ - }; - - return si476x_core_send_command(core, CMD_POWER_UP, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_TIMEOUT_POWER_UP); -} - -static int si476x_core_cmd_power_up_a20(struct si476x_core *core, - struct si476x_power_up_args *puargs) -{ - u8 resp[CMD_POWER_UP_A20_NRESP]; - const bool intsel = (core->pinmux.a1 == SI476X_A1_IRQ); - const bool ctsen = (core->client->irq != 0); - const u8 args[CMD_POWER_UP_A20_NARGS] = { - puargs->ibias6x << 7 | puargs->xstart, - 0x3F & puargs->xcload, /* First two bits are reserved to be - * zeros */ - ctsen << 7 | intsel << 6 | puargs->fastboot << 5 | - puargs->xbiashc << 3 | puargs->xbias, - puargs->func << 4 | puargs->freq, - 0x10 | puargs->xmode, - }; - - return si476x_core_send_command(core, CMD_POWER_UP, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_TIMEOUT_POWER_UP); -} - -static int si476x_core_cmd_power_down_a10(struct si476x_core *core, - struct si476x_power_down_args *pdargs) -{ - u8 resp[CMD_POWER_DOWN_A10_NRESP]; - - return si476x_core_send_command(core, CMD_POWER_DOWN, - NULL, 0, - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} - -static int si476x_core_cmd_power_down_a20(struct si476x_core *core, - struct si476x_power_down_args *pdargs) -{ - u8 resp[CMD_POWER_DOWN_A20_NRESP]; - const u8 args[CMD_POWER_DOWN_A20_NARGS] = { - pdargs->xosc, - }; - return si476x_core_send_command(core, CMD_POWER_DOWN, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); -} - -static int si476x_core_cmd_am_tune_freq_a10(struct si476x_core *core, - struct si476x_tune_freq_args *tuneargs) -{ - - const int am_freq = tuneargs->freq; - u8 resp[CMD_AM_TUNE_FREQ_NRESP]; - const u8 args[CMD_AM_TUNE_FREQ_NARGS] = { - (tuneargs->hd << 6), - msb(am_freq), - lsb(am_freq), - }; - - return si476x_cmd_tune_seek_freq(core, CMD_AM_TUNE_FREQ, args, - sizeof(args), - resp, sizeof(resp)); -} - -static int si476x_core_cmd_am_tune_freq_a20(struct si476x_core *core, - struct si476x_tune_freq_args *tuneargs) -{ - const int am_freq = tuneargs->freq; - u8 resp[CMD_AM_TUNE_FREQ_NRESP]; - const u8 args[CMD_AM_TUNE_FREQ_NARGS] = { - (tuneargs->zifsr << 6) | (tuneargs->injside & 0b11), - msb(am_freq), - lsb(am_freq), - }; - - return si476x_cmd_tune_seek_freq(core, CMD_AM_TUNE_FREQ, - args, sizeof(args), - resp, sizeof(resp)); -} - -static int si476x_core_cmd_fm_rsq_status_a10(struct si476x_core *core, - struct si476x_rsq_status_args *rsqargs, - struct si476x_rsq_status_report *report) -{ - int err; - u8 resp[CMD_FM_RSQ_STATUS_A10_NRESP]; - const u8 args[CMD_FM_RSQ_STATUS_A10_NARGS] = { - rsqargs->rsqack << 3 | rsqargs->attune << 2 | - rsqargs->cancel << 1 | rsqargs->stcack, - }; - - err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - /* - * Besides getting received signal quality information this - * command can be used to just acknowledge different interrupt - * flags in those cases it is useless to copy and parse - * received data so user can pass NULL, and thus avoid - * unnecessary copying. - */ - if (err < 0 || report == NULL) - return err; - - report->multhint = 0b10000000 & resp[1]; - report->multlint = 0b01000000 & resp[1]; - report->snrhint = 0b00001000 & resp[1]; - report->snrlint = 0b00000100 & resp[1]; - report->rssihint = 0b00000010 & resp[1]; - report->rssilint = 0b00000001 & resp[1]; - - report->bltf = 0b10000000 & resp[2]; - report->snr_ready = 0b00100000 & resp[2]; - report->rssiready = 0b00001000 & resp[2]; - report->afcrl = 0b00000010 & resp[2]; - report->valid = 0b00000001 & resp[2]; - - report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); - report->freqoff = resp[5]; - report->rssi = resp[6]; - report->snr = resp[7]; - report->lassi = resp[9]; - report->hassi = resp[10]; - report->mult = resp[11]; - report->dev = resp[12]; - report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); - report->assi = resp[15]; - report->usn = resp[16]; - - return err; -} - -static int si476x_core_cmd_fm_rsq_status_a20(struct si476x_core *core, - struct si476x_rsq_status_args *rsqargs, - struct si476x_rsq_status_report *report) -{ - int err; - u8 resp[CMD_FM_RSQ_STATUS_A10_NRESP]; - const u8 args[CMD_FM_RSQ_STATUS_A30_NARGS] = { - rsqargs->primary << 4 | rsqargs->rsqack << 3 | - rsqargs->attune << 2 | rsqargs->cancel << 1 | - rsqargs->stcack, - }; - - err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - /* - * Besides getting received signal quality information this - * command can be used to just acknowledge different interrupt - * flags in those cases it is useless to copy and parse - * received data so user can pass NULL, and thus avoid - * unnecessary copying. - */ - if (err < 0 || report == NULL) - return err; - - report->multhint = 0b10000000 & resp[1]; - report->multlint = 0b01000000 & resp[1]; - report->snrhint = 0b00001000 & resp[1]; - report->snrlint = 0b00000100 & resp[1]; - report->rssihint = 0b00000010 & resp[1]; - report->rssilint = 0b00000001 & resp[1]; - - report->bltf = 0b10000000 & resp[2]; - report->snr_ready = 0b00100000 & resp[2]; - report->rssiready = 0b00001000 & resp[2]; - report->afcrl = 0b00000010 & resp[2]; - report->valid = 0b00000001 & resp[2]; - - report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); - report->freqoff = resp[5]; - report->rssi = resp[6]; - report->snr = resp[7]; - report->lassi = resp[9]; - report->hassi = resp[10]; - report->mult = resp[11]; - report->dev = resp[12]; - report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); - report->assi = resp[15]; - report->usn = resp[16]; - - return err; -} - - -static int si476x_core_cmd_fm_rsq_status_a30(struct si476x_core *core, - struct si476x_rsq_status_args *rsqargs, - struct si476x_rsq_status_report *report) -{ - int err; - u8 resp[CMD_FM_RSQ_STATUS_A30_NRESP]; - const u8 args[CMD_FM_RSQ_STATUS_A30_NARGS] = { - rsqargs->primary << 4 | rsqargs->rsqack << 3 | - rsqargs->attune << 2 | rsqargs->cancel << 1 | - rsqargs->stcack, - }; - - err = si476x_core_send_command(core, CMD_FM_RSQ_STATUS, - args, ARRAY_SIZE(args), - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - /* - * Besides getting received signal quality information this - * command can be used to just acknowledge different interrupt - * flags in those cases it is useless to copy and parse - * received data so user can pass NULL, and thus avoid - * unnecessary copying. - */ - if (err < 0 || report == NULL) - return err; - - report->multhint = 0b10000000 & resp[1]; - report->multlint = 0b01000000 & resp[1]; - report->snrhint = 0b00001000 & resp[1]; - report->snrlint = 0b00000100 & resp[1]; - report->rssihint = 0b00000010 & resp[1]; - report->rssilint = 0b00000001 & resp[1]; - - report->bltf = 0b10000000 & resp[2]; - report->snr_ready = 0b00100000 & resp[2]; - report->rssiready = 0b00001000 & resp[2]; - report->injside = 0b00000100 & resp[2]; - report->afcrl = 0b00000010 & resp[2]; - report->valid = 0b00000001 & resp[2]; - - report->readfreq = be16_to_cpup((__be16 *)(resp + 3)); - report->freqoff = resp[5]; - report->rssi = resp[6]; - report->snr = resp[7]; - report->issi = resp[8]; - report->lassi = resp[9]; - report->hassi = resp[10]; - report->mult = resp[11]; - report->dev = resp[12]; - report->readantcap = be16_to_cpup((__be16 *)(resp + 13)); - report->assi = resp[15]; - report->usn = resp[16]; - - report->pilotdev = resp[17]; - report->rdsdev = resp[18]; - report->assidev = resp[19]; - report->strongdev = resp[20]; - report->rdspi = be16_to_cpup((__be16 *)(resp + 21)); - - return err; -} - -static int si476x_core_cmd_fm_tune_freq_a10(struct si476x_core *core, - struct si476x_tune_freq_args *tuneargs) -{ - u8 resp[CMD_FM_TUNE_FREQ_NRESP]; - const u8 args[CMD_FM_TUNE_FREQ_A10_NARGS] = { - (tuneargs->hd << 6) | (tuneargs->tunemode << 4) - | (tuneargs->smoothmetrics << 2), - msb(tuneargs->freq), - lsb(tuneargs->freq), - msb(tuneargs->antcap), - lsb(tuneargs->antcap) - }; - - return si476x_cmd_tune_seek_freq(core, CMD_FM_TUNE_FREQ, - args, sizeof(args), - resp, sizeof(resp)); -} - -static int si476x_core_cmd_fm_tune_freq_a20(struct si476x_core *core, - struct si476x_tune_freq_args *tuneargs) -{ - u8 resp[CMD_FM_TUNE_FREQ_NRESP]; - const u8 args[CMD_FM_TUNE_FREQ_A20_NARGS] = { - (tuneargs->hd << 6) | (tuneargs->tunemode << 4) - | (tuneargs->smoothmetrics << 2) | (tuneargs->injside), - msb(tuneargs->freq), - lsb(tuneargs->freq), - }; - - return si476x_cmd_tune_seek_freq(core, CMD_FM_TUNE_FREQ, - args, sizeof(args), - resp, sizeof(resp)); -} - -static int si476x_core_cmd_agc_status_a20(struct si476x_core *core, - struct si476x_agc_status_report *report) -{ - int err; - u8 resp[CMD_AGC_STATUS_NRESP_A20]; - - if (!report) - return -EINVAL; - - err = si476x_core_send_command(core, CMD_AGC_STATUS, - NULL, 0, - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - if (err < 0) - return err; - - report->mxhi = resp[1] & SI476X_AGC_MXHI; - report->mxlo = resp[1] & SI476X_AGC_MXLO; - report->lnahi = resp[1] & SI476X_AGC_LNAHI; - report->lnalo = resp[1] & SI476X_AGC_LNALO; - report->fmagc1 = resp[2]; - report->fmagc2 = resp[3]; - report->pgagain = resp[4]; - report->fmwblang = resp[5]; - - return err; -} - -static int si476x_core_cmd_agc_status_a10(struct si476x_core *core, - struct si476x_agc_status_report *report) -{ - int err; - u8 resp[CMD_AGC_STATUS_NRESP_A10]; - - if (!report) - return -EINVAL; - - err = si476x_core_send_command(core, CMD_AGC_STATUS, - NULL, 0, - resp, ARRAY_SIZE(resp), - SI476X_DEFAULT_TIMEOUT); - if (err < 0) - return err; - - report->mxhi = resp[1] & SI476X_AGC_MXHI; - report->mxlo = resp[1] & SI476X_AGC_MXLO; - report->lnahi = resp[1] & SI476X_AGC_LNAHI; - report->lnalo = resp[1] & SI476X_AGC_LNALO; - - return err; -} - -typedef int (*tune_freq_func_t) (struct si476x_core *core, - struct si476x_tune_freq_args *tuneargs); - -static struct { - int (*power_up) (struct si476x_core *, - struct si476x_power_up_args *); - int (*power_down) (struct si476x_core *, - struct si476x_power_down_args *); - - tune_freq_func_t fm_tune_freq; - tune_freq_func_t am_tune_freq; - - int (*fm_rsq_status)(struct si476x_core *, - struct si476x_rsq_status_args *, - struct si476x_rsq_status_report *); - - int (*agc_status)(struct si476x_core *, - struct si476x_agc_status_report *); - int (*intb_pin_cfg)(struct si476x_core *core, - enum si476x_intb_config intb, - enum si476x_a1_config a1); -} si476x_cmds_vtable[] = { - [SI476X_REVISION_A10] = { - .power_up = si476x_core_cmd_power_up_a10, - .power_down = si476x_core_cmd_power_down_a10, - .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a10, - .am_tune_freq = si476x_core_cmd_am_tune_freq_a10, - .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a10, - .agc_status = si476x_core_cmd_agc_status_a10, - .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a10, - }, - [SI476X_REVISION_A20] = { - .power_up = si476x_core_cmd_power_up_a20, - .power_down = si476x_core_cmd_power_down_a20, - .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a20, - .am_tune_freq = si476x_core_cmd_am_tune_freq_a20, - .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a20, - .agc_status = si476x_core_cmd_agc_status_a20, - .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a20, - }, - [SI476X_REVISION_A30] = { - .power_up = si476x_core_cmd_power_up_a20, - .power_down = si476x_core_cmd_power_down_a20, - .fm_tune_freq = si476x_core_cmd_fm_tune_freq_a20, - .am_tune_freq = si476x_core_cmd_am_tune_freq_a20, - .fm_rsq_status = si476x_core_cmd_fm_rsq_status_a30, - .agc_status = si476x_core_cmd_agc_status_a20, - .intb_pin_cfg = si476x_core_cmd_intb_pin_cfg_a20, - }, -}; - -int si476x_core_cmd_power_up(struct si476x_core *core, - struct si476x_power_up_args *args) -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - return si476x_cmds_vtable[core->revision].power_up(core, args); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_power_up); - -int si476x_core_cmd_power_down(struct si476x_core *core, - struct si476x_power_down_args *args) -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - return si476x_cmds_vtable[core->revision].power_down(core, args); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_power_down); - -int si476x_core_cmd_fm_tune_freq(struct si476x_core *core, - struct si476x_tune_freq_args *args) -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - return si476x_cmds_vtable[core->revision].fm_tune_freq(core, args); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_tune_freq); - -int si476x_core_cmd_am_tune_freq(struct si476x_core *core, - struct si476x_tune_freq_args *args) -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - return si476x_cmds_vtable[core->revision].am_tune_freq(core, args); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_am_tune_freq); - -int si476x_core_cmd_fm_rsq_status(struct si476x_core *core, - struct si476x_rsq_status_args *args, - struct si476x_rsq_status_report *report) - -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - return si476x_cmds_vtable[core->revision].fm_rsq_status(core, args, - report); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_rsq_status); - -int si476x_core_cmd_agc_status(struct si476x_core *core, - struct si476x_agc_status_report *report) - -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - return si476x_cmds_vtable[core->revision].agc_status(core, report); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_agc_status); - -int si476x_core_cmd_intb_pin_cfg(struct si476x_core *core, - enum si476x_intb_config intb, - enum si476x_a1_config a1) -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - - return si476x_cmds_vtable[core->revision].intb_pin_cfg(core, intb, a1); -} -EXPORT_SYMBOL_GPL(si476x_core_cmd_intb_pin_cfg); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Andrey Smirnov "); -MODULE_DESCRIPTION("API for command exchange for si476x"); -- cgit v0.10.2 From 9af5cc54c281d671b6ac3c52121a66a2c9c5c900 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 18 Apr 2013 20:52:33 -0300 Subject: Revert "[media] mfd: Add the main bulk of core driver for SI476x code" This reverts commit b40fe4f67de2c826868f408e03f2ef9fe39d85b9. Conflicts: drivers/mfd/si476x-i2c.c Requested-by: Samuel Ortiz Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c deleted file mode 100644 index f5bc8e4..0000000 --- a/drivers/mfd/si476x-i2c.c +++ /dev/null @@ -1,886 +0,0 @@ -/* - * drivers/mfd/si476x-i2c.c -- Core device driver for si476x MFD - * device - * - * 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 - -#define SI476X_MAX_IO_ERRORS 10 -#define SI476X_DRIVER_RDS_FIFO_DEPTH 128 - -/** - * si476x_core_config_pinmux() - pin function configuration function - * - * @core: Core device structure - * - * Configure the functions of the pins of the radio chip. - * - * The function returns zero in case of succes or negative error code - * otherwise. - */ -static int si476x_core_config_pinmux(struct si476x_core *core) -{ - int err; - dev_dbg(&core->client->dev, "Configuring pinmux\n"); - err = si476x_core_cmd_dig_audio_pin_cfg(core, - core->pinmux.dclk, - core->pinmux.dfs, - core->pinmux.dout, - core->pinmux.xout); - if (err < 0) { - dev_err(&core->client->dev, - "Failed to configure digital audio pins(err = %d)\n", - err); - return err; - } - - err = si476x_core_cmd_zif_pin_cfg(core, - core->pinmux.iqclk, - core->pinmux.iqfs, - core->pinmux.iout, - core->pinmux.qout); - if (err < 0) { - dev_err(&core->client->dev, - "Failed to configure ZIF pins(err = %d)\n", - err); - return err; - } - - err = si476x_core_cmd_ic_link_gpo_ctl_pin_cfg(core, - core->pinmux.icin, - core->pinmux.icip, - core->pinmux.icon, - core->pinmux.icop); - if (err < 0) { - dev_err(&core->client->dev, - "Failed to configure IC-Link/GPO pins(err = %d)\n", - err); - return err; - } - - err = si476x_core_cmd_ana_audio_pin_cfg(core, - core->pinmux.lrout); - if (err < 0) { - dev_err(&core->client->dev, - "Failed to configure analog audio pins(err = %d)\n", - err); - return err; - } - - err = si476x_core_cmd_intb_pin_cfg(core, - core->pinmux.intb, - core->pinmux.a1); - if (err < 0) { - dev_err(&core->client->dev, - "Failed to configure interrupt pins(err = %d)\n", - err); - return err; - } - - return 0; -} - -static inline void si476x_core_schedule_polling_work(struct si476x_core *core) -{ - schedule_delayed_work(&core->status_monitor, - usecs_to_jiffies(SI476X_STATUS_POLL_US)); -} - -/** - * si476x_core_start() - early chip startup function - * @core: Core device structure - * @soft: When set, this flag forces "soft" startup, where "soft" - * power down is the one done by sending appropriate command instead - * of using reset pin of the tuner - * - * Perform required startup sequence to correctly power - * up the chip and perform initial configuration. It does the - * following sequence of actions: - * 1. Claims and enables the power supplies VD and VIO1 required - * for I2C interface of the chip operation. - * 2. Waits for 100us, pulls the reset line up, enables irq, - * waits for another 100us as it is specified by the - * datasheet. - * 3. Sends 'POWER_UP' command to the device with all provided - * information about power-up parameters. - * 4. Configures, pin multiplexor, disables digital audio and - * configures interrupt sources. - * - * The function returns zero in case of succes or negative error code - * otherwise. - */ -int si476x_core_start(struct si476x_core *core, bool soft) -{ - struct i2c_client *client = core->client; - int err; - - if (!soft) { - if (gpio_is_valid(core->gpio_reset)) - gpio_set_value_cansleep(core->gpio_reset, 1); - - if (client->irq) - enable_irq(client->irq); - - udelay(100); - - if (!client->irq) { - atomic_set(&core->is_alive, 1); - si476x_core_schedule_polling_work(core); - } - } else { - if (client->irq) - enable_irq(client->irq); - else { - atomic_set(&core->is_alive, 1); - si476x_core_schedule_polling_work(core); - } - } - - err = si476x_core_cmd_power_up(core, - &core->power_up_parameters); - - if (err < 0) { - dev_err(&core->client->dev, - "Power up failure(err = %d)\n", - err); - goto disable_irq; - } - - if (client->irq) - atomic_set(&core->is_alive, 1); - - err = si476x_core_config_pinmux(core); - if (err < 0) { - dev_err(&core->client->dev, - "Failed to configure pinmux(err = %d)\n", - err); - goto disable_irq; - } - - if (client->irq) { - err = regmap_write(core->regmap, - SI476X_PROP_INT_CTL_ENABLE, - SI476X_RDSIEN | - SI476X_STCIEN | - SI476X_CTSIEN); - if (err < 0) { - dev_err(&core->client->dev, - "Failed to configure interrupt sources" - "(err = %d)\n", err); - goto disable_irq; - } - } - - return 0; - -disable_irq: - if (err == -ENODEV) - atomic_set(&core->is_alive, 0); - - if (client->irq) - disable_irq(client->irq); - else - cancel_delayed_work_sync(&core->status_monitor); - - if (gpio_is_valid(core->gpio_reset)) - gpio_set_value_cansleep(core->gpio_reset, 0); - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_start); - -/** - * si476x_core_stop() - chip power-down function - * @core: Core device structure - * @soft: When set, function sends a POWER_DOWN command instead of - * bringing reset line low - * - * Power down the chip by performing following actions: - * 1. Disable IRQ or stop the polling worker - * 2. Send the POWER_DOWN command if the power down is soft or bring - * reset line low if not. - * - * The function returns zero in case of succes or negative error code - * otherwise. - */ -int si476x_core_stop(struct si476x_core *core, bool soft) -{ - int err = 0; - atomic_set(&core->is_alive, 0); - - if (soft) { - /* TODO: This probably shoud be a configurable option, - * so it is possible to have the chips keep their - * oscillators running - */ - struct si476x_power_down_args args = { - .xosc = false, - }; - err = si476x_core_cmd_power_down(core, &args); - } - - /* We couldn't disable those before - * 'si476x_core_cmd_power_down' since we expect to get CTS - * interrupt */ - if (core->client->irq) - disable_irq(core->client->irq); - else - cancel_delayed_work_sync(&core->status_monitor); - - if (!soft) { - if (gpio_is_valid(core->gpio_reset)) - gpio_set_value_cansleep(core->gpio_reset, 0); - } - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_stop); - -/** - * si476x_core_set_power_state() - set the level at which the power is - * supplied for the chip. - * @core: Core device structure - * @next_state: enum si476x_power_state describing power state to - * switch to. - * - * Switch on all the required power supplies - * - * This function returns 0 in case of suvccess and negative error code - * otherwise. - */ -int si476x_core_set_power_state(struct si476x_core *core, - enum si476x_power_state next_state) -{ - /* - It is not clear form the datasheet if it is possible to - work with device if not all power domains are operational. - So for now the power-up policy is "power-up all the things!" - */ - int err = 0; - - if (core->power_state == SI476X_POWER_INCONSISTENT) { - dev_err(&core->client->dev, - "The device in inconsistent power state\n"); - return -EINVAL; - } - - if (next_state != core->power_state) { - switch (next_state) { - case SI476X_POWER_UP_FULL: - err = regulator_bulk_enable(ARRAY_SIZE(core->supplies), - core->supplies); - if (err < 0) { - core->power_state = SI476X_POWER_INCONSISTENT; - break; - } - /* - * Startup timing diagram recommends to have a - * 100 us delay between enabling of the power - * supplies and turning the tuner on. - */ - udelay(100); - - err = si476x_core_start(core, false); - if (err < 0) - goto disable_regulators; - - core->power_state = next_state; - break; - - case SI476X_POWER_DOWN: - core->power_state = next_state; - err = si476x_core_stop(core, false); - if (err < 0) - core->power_state = SI476X_POWER_INCONSISTENT; -disable_regulators: - err = regulator_bulk_disable(ARRAY_SIZE(core->supplies), - core->supplies); - if (err < 0) - core->power_state = SI476X_POWER_INCONSISTENT; - break; - default: - BUG(); - } - } - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_set_power_state); - -/** - * si476x_core_report_drainer_stop() - mark the completion of the RDS - * buffer drain porcess by the worker. - * - * @core: Core device structure - */ -static inline void si476x_core_report_drainer_stop(struct si476x_core *core) -{ - mutex_lock(&core->rds_drainer_status_lock); - core->rds_drainer_is_working = false; - mutex_unlock(&core->rds_drainer_status_lock); -} - -/** - * si476x_core_start_rds_drainer_once() - start RDS drainer worker if - * ther is none working, do nothing otherwise - * - * @core: Datastructure corresponding to the chip. - */ -static inline void si476x_core_start_rds_drainer_once(struct si476x_core *core) -{ - mutex_lock(&core->rds_drainer_status_lock); - if (!core->rds_drainer_is_working) { - core->rds_drainer_is_working = true; - schedule_work(&core->rds_fifo_drainer); - } - mutex_unlock(&core->rds_drainer_status_lock); -} -/** - * si476x_drain_rds_fifo() - RDS buffer drainer. - * @work: struct work_struct being ppassed to the function by the - * kernel. - * - * Drain the contents of the RDS FIFO of - */ -static void si476x_core_drain_rds_fifo(struct work_struct *work) -{ - int err; - - struct si476x_core *core = container_of(work, struct si476x_core, - rds_fifo_drainer); - - struct si476x_rds_status_report report; - - si476x_core_lock(core); - err = si476x_core_cmd_fm_rds_status(core, true, false, false, &report); - if (!err) { - int i = report.rdsfifoused; - dev_dbg(&core->client->dev, - "%d elements in RDS FIFO. Draining.\n", i); - for (; i > 0; --i) { - err = si476x_core_cmd_fm_rds_status(core, false, false, - (i == 1), &report); - if (err < 0) - goto unlock; - - kfifo_in(&core->rds_fifo, report.rds, - sizeof(report.rds)); - dev_dbg(&core->client->dev, "RDS data:\n %*ph\n", - (int)sizeof(report.rds), report.rds); - } - dev_dbg(&core->client->dev, "Drrrrained!\n"); - wake_up_interruptible(&core->rds_read_queue); - } - -unlock: - si476x_core_unlock(core); - si476x_core_report_drainer_stop(core); -} - -/** - * si476x_core_pronounce_dead() - * - * @core: Core device structure - * - * Mark the device as being dead and wake up all potentially waiting - * threads of execution. - * - */ -static void si476x_core_pronounce_dead(struct si476x_core *core) -{ - dev_info(&core->client->dev, "Core device is dead.\n"); - - atomic_set(&core->is_alive, 0); - - /* Wake up al possible waiting processes */ - wake_up_interruptible(&core->rds_read_queue); - - atomic_set(&core->cts, 1); - wake_up(&core->command); - - atomic_set(&core->stc, 1); - wake_up(&core->tuning); -} - -/** - * si476x_core_i2c_xfer() - * - * @core: Core device structure - * @type: Transfer type - * @buf: Transfer buffer for/with data - * @count: Transfer buffer size - * - * Perfrom and I2C transfer(either read or write) and keep a counter - * of I/O errors. If the error counter rises above the threshold - * pronounce device dead. - * - * The function returns zero on succes or negative error code on - * failure. - */ -int si476x_core_i2c_xfer(struct si476x_core *core, - enum si476x_i2c_type type, - char *buf, int count) -{ - static int io_errors_count; - int err; - if (type == SI476X_I2C_SEND) - err = i2c_master_send(core->client, buf, count); - else - err = i2c_master_recv(core->client, buf, count); - - if (err < 0) { - if (io_errors_count++ > SI476X_MAX_IO_ERRORS) - si476x_core_pronounce_dead(core); - } else { - io_errors_count = 0; - } - - return err; -} -EXPORT_SYMBOL_GPL(si476x_core_i2c_xfer); - -/** - * si476x_get_status() - * @core: Core device structure - * - * Get the status byte of the core device by berforming one byte I2C - * read. - * - * The function returns a status value or a negative error code on - * error. - */ -static int si476x_core_get_status(struct si476x_core *core) -{ - u8 response; - int err = si476x_core_i2c_xfer(core, SI476X_I2C_RECV, - &response, sizeof(response)); - - return (err < 0) ? err : response; -} - -/** - * si476x_get_and_signal_status() - IRQ dispatcher - * @core: Core device structure - * - * Dispatch the arrived interrupt request based on the value of the - * status byte reported by the tuner. - * - */ -static void si476x_core_get_and_signal_status(struct si476x_core *core) -{ - int status = si476x_core_get_status(core); - if (status < 0) { - dev_err(&core->client->dev, "Failed to get status\n"); - return; - } - - if (status & SI476X_CTS) { - /* Unfortunately completions could not be used for - * signalling CTS since this flag cannot be cleared - * in status byte, and therefore once it becomes true - * multiple calls to 'complete' would cause the - * commands following the current one to be completed - * before they actually are */ - dev_dbg(&core->client->dev, "[interrupt] CTSINT\n"); - atomic_set(&core->cts, 1); - wake_up(&core->command); - } - - if (status & SI476X_FM_RDS_INT) { - dev_dbg(&core->client->dev, "[interrupt] RDSINT\n"); - si476x_core_start_rds_drainer_once(core); - } - - if (status & SI476X_STC_INT) { - dev_dbg(&core->client->dev, "[interrupt] STCINT\n"); - atomic_set(&core->stc, 1); - wake_up(&core->tuning); - } -} - -static void si476x_core_poll_loop(struct work_struct *work) -{ - struct si476x_core *core = SI476X_WORK_TO_CORE(work); - - si476x_core_get_and_signal_status(core); - - if (atomic_read(&core->is_alive)) - si476x_core_schedule_polling_work(core); -} - -static irqreturn_t si476x_core_interrupt(int irq, void *dev) -{ - struct si476x_core *core = dev; - - si476x_core_get_and_signal_status(core); - - return IRQ_HANDLED; -} - -/** - * si476x_firmware_version_to_revision() - * @core: Core device structure - * @major: Firmware major number - * @minor1: Firmware first minor number - * @minor2: Firmware second minor number - * - * Convert a chip's firmware version number into an offset that later - * will be used to as offset in "vtable" of tuner functions - * - * This function returns a positive offset in case of success and a -1 - * in case of failure. - */ -static int si476x_core_fwver_to_revision(struct si476x_core *core, - int func, int major, - int minor1, int minor2) -{ - switch (func) { - case SI476X_FUNC_FM_RECEIVER: - switch (major) { - case 5: - return SI476X_REVISION_A10; - case 8: - return SI476X_REVISION_A20; - case 10: - return SI476X_REVISION_A30; - default: - goto unknown_revision; - } - case SI476X_FUNC_AM_RECEIVER: - switch (major) { - case 5: - return SI476X_REVISION_A10; - case 7: - return SI476X_REVISION_A20; - case 9: - return SI476X_REVISION_A30; - default: - goto unknown_revision; - } - case SI476X_FUNC_WB_RECEIVER: - switch (major) { - case 3: - return SI476X_REVISION_A10; - case 5: - return SI476X_REVISION_A20; - case 7: - return SI476X_REVISION_A30; - default: - goto unknown_revision; - } - case SI476X_FUNC_BOOTLOADER: - default: /* FALLTHROUG */ - BUG(); - return -1; - } - -unknown_revision: - dev_err(&core->client->dev, - "Unsupported version of the firmware: %d.%d.%d, " - "reverting to A10 comptible functions\n", - major, minor1, minor2); - - return SI476X_REVISION_A10; -} - -/** - * si476x_get_revision_info() - * @core: Core device structure - * - * Get the firmware version number of the device. It is done in - * following three steps: - * 1. Power-up the device - * 2. Send the 'FUNC_INFO' command - * 3. Powering the device down. - * - * The function return zero on success and a negative error code on - * failure. - */ -static int si476x_core_get_revision_info(struct si476x_core *core) -{ - int rval; - struct si476x_func_info info; - - si476x_core_lock(core); - rval = si476x_core_set_power_state(core, SI476X_POWER_UP_FULL); - if (rval < 0) - goto exit; - - rval = si476x_core_cmd_func_info(core, &info); - if (rval < 0) - goto power_down; - - core->revision = si476x_core_fwver_to_revision(core, info.func, - info.firmware.major, - info.firmware.minor[0], - info.firmware.minor[1]); -power_down: - si476x_core_set_power_state(core, SI476X_POWER_DOWN); -exit: - si476x_core_unlock(core); - - return rval; -} - -bool si476x_core_has_am(struct si476x_core *core) -{ - return core->chip_id == SI476X_CHIP_SI4761 || - core->chip_id == SI476X_CHIP_SI4764; -} -EXPORT_SYMBOL_GPL(si476x_core_has_am); - -bool si476x_core_has_diversity(struct si476x_core *core) -{ - return core->chip_id == SI476X_CHIP_SI4764; -} -EXPORT_SYMBOL_GPL(si476x_core_has_diversity); - -bool si476x_core_is_a_secondary_tuner(struct si476x_core *core) -{ - return si476x_core_has_diversity(core) && - (core->diversity_mode == SI476X_PHDIV_SECONDARY_ANTENNA || - core->diversity_mode == SI476X_PHDIV_SECONDARY_COMBINING); -} -EXPORT_SYMBOL_GPL(si476x_core_is_a_secondary_tuner); - -bool si476x_core_is_a_primary_tuner(struct si476x_core *core) -{ - return si476x_core_has_diversity(core) && - (core->diversity_mode == SI476X_PHDIV_PRIMARY_ANTENNA || - core->diversity_mode == SI476X_PHDIV_PRIMARY_COMBINING); -} -EXPORT_SYMBOL_GPL(si476x_core_is_a_primary_tuner); - -bool si476x_core_is_in_am_receiver_mode(struct si476x_core *core) -{ - return si476x_core_has_am(core) && - (core->power_up_parameters.func == SI476X_FUNC_AM_RECEIVER); -} -EXPORT_SYMBOL_GPL(si476x_core_is_in_am_receiver_mode); - -bool si476x_core_is_powered_up(struct si476x_core *core) -{ - return core->power_state == SI476X_POWER_UP_FULL; -} -EXPORT_SYMBOL_GPL(si476x_core_is_powered_up); - -static int si476x_core_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int rval; - struct si476x_core *core; - struct si476x_platform_data *pdata; - struct mfd_cell *cell; - int cell_num; - - core = devm_kzalloc(&client->dev, sizeof(*core), GFP_KERNEL); - if (!core) { - dev_err(&client->dev, - "failed to allocate 'struct si476x_core'\n"); - return -ENOMEM; - } - core->client = client; - - core->regmap = devm_regmap_init_si476x(core); - if (IS_ERR(core->regmap)) { - rval = PTR_ERR(core->regmap); - dev_err(&client->dev, - "Failed to allocate register map: %d\n", - rval); - return rval; - } - - i2c_set_clientdata(client, core); - - atomic_set(&core->is_alive, 0); - core->power_state = SI476X_POWER_DOWN; - - pdata = client->dev.platform_data; - if (pdata) { - memcpy(&core->power_up_parameters, - &pdata->power_up_parameters, - sizeof(core->power_up_parameters)); - - core->gpio_reset = -1; - if (gpio_is_valid(pdata->gpio_reset)) { - rval = gpio_request(pdata->gpio_reset, "si476x reset"); - if (rval) { - dev_err(&client->dev, - "Failed to request gpio: %d\n", rval); - return rval; - } - core->gpio_reset = pdata->gpio_reset; - gpio_direction_output(core->gpio_reset, 0); - } - - core->diversity_mode = pdata->diversity_mode; - memcpy(&core->pinmux, &pdata->pinmux, - sizeof(struct si476x_pinmux)); - } else { - dev_err(&client->dev, "No platform data provided\n"); - return -EINVAL; - } - - core->supplies[0].supply = "vd"; - core->supplies[1].supply = "va"; - core->supplies[2].supply = "vio1"; - core->supplies[3].supply = "vio2"; - - rval = devm_regulator_bulk_get(&client->dev, - ARRAY_SIZE(core->supplies), - core->supplies); - if (rval) { - dev_err(&client->dev, "Failet to gett all of the regulators\n"); - goto free_gpio; - } - - mutex_init(&core->cmd_lock); - init_waitqueue_head(&core->command); - init_waitqueue_head(&core->tuning); - - rval = kfifo_alloc(&core->rds_fifo, - SI476X_DRIVER_RDS_FIFO_DEPTH * - sizeof(struct v4l2_rds_data), - GFP_KERNEL); - if (rval) { - dev_err(&client->dev, "Could not alloate the FIFO\n"); - goto free_gpio; - } - mutex_init(&core->rds_drainer_status_lock); - init_waitqueue_head(&core->rds_read_queue); - INIT_WORK(&core->rds_fifo_drainer, si476x_core_drain_rds_fifo); - - if (client->irq) { - rval = devm_request_threaded_irq(&client->dev, - client->irq, NULL, - si476x_core_interrupt, - IRQF_TRIGGER_FALLING, - client->name, core); - if (rval < 0) { - dev_err(&client->dev, "Could not request IRQ %d\n", - client->irq); - goto free_kfifo; - } - disable_irq(client->irq); - dev_dbg(&client->dev, "IRQ requested.\n"); - - core->rds_fifo_depth = 20; - } else { - INIT_DELAYED_WORK(&core->status_monitor, - si476x_core_poll_loop); - dev_info(&client->dev, - "No IRQ number specified, will use polling\n"); - - core->rds_fifo_depth = 5; - } - - core->chip_id = id->driver_data; - - rval = si476x_core_get_revision_info(core); - if (rval < 0) { - rval = -ENODEV; - goto free_kfifo; - } - - cell_num = 0; - - cell = &core->cells[SI476X_RADIO_CELL]; - cell->name = "si476x-radio"; - cell_num++; - -#ifdef CONFIG_SND_SOC_SI476X - if ((core->chip_id == SI476X_CHIP_SI4761 || - core->chip_id == SI476X_CHIP_SI4764) && - core->pinmux.dclk == SI476X_DCLK_DAUDIO && - core->pinmux.dfs == SI476X_DFS_DAUDIO && - core->pinmux.dout == SI476X_DOUT_I2S_OUTPUT && - core->pinmux.xout == SI476X_XOUT_TRISTATE) { - cell = &core->cells[SI476X_CODEC_CELL]; - cell->name = "si476x-codec"; - cell_num++; - } -#endif - rval = mfd_add_devices(&client->dev, - (client->adapter->nr << 8) + client->addr, - core->cells, cell_num, - NULL, 0, NULL); - if (!rval) - return 0; - -free_kfifo: - kfifo_free(&core->rds_fifo); - -free_gpio: - if (gpio_is_valid(core->gpio_reset)) - gpio_free(core->gpio_reset); - - return rval; -} - -static int si476x_core_remove(struct i2c_client *client) -{ - struct si476x_core *core = i2c_get_clientdata(client); - - si476x_core_pronounce_dead(core); - mfd_remove_devices(&client->dev); - - if (client->irq) - disable_irq(client->irq); - else - cancel_delayed_work_sync(&core->status_monitor); - - kfifo_free(&core->rds_fifo); - - if (gpio_is_valid(core->gpio_reset)) - gpio_free(core->gpio_reset); - - return 0; -} - - -static const struct i2c_device_id si476x_id[] = { - { "si4761", SI476X_CHIP_SI4761 }, - { "si4764", SI476X_CHIP_SI4764 }, - { "si4768", SI476X_CHIP_SI4768 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, si476x_id); - -static struct i2c_driver si476x_core_driver = { - .driver = { - .name = "si476x-core", - .owner = THIS_MODULE, - }, - .probe = si476x_core_probe, - .remove = si476x_core_remove, - .id_table = si476x_id, -}; -module_i2c_driver(si476x_core_driver); - - -MODULE_AUTHOR("Andrey Smirnov "); -MODULE_DESCRIPTION("Si4761/64/68 AM/FM MFD core device driver"); -MODULE_LICENSE("GPL"); -- cgit v0.10.2 From a9dc73e2952d76ed7961aa12b182c9a95c0be8dd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 18 Apr 2013 20:53:23 -0300 Subject: Revert "[media] mfd: Add chip properties handling code for SI476X MFD" This reverts commit a118e9c122969a924061b48b6cc6bb73ccc8de4c. Requested-by: Samuel Ortiz Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/mfd/si476x-prop.c b/drivers/mfd/si476x-prop.c deleted file mode 100644 index d1f548a..0000000 --- a/drivers/mfd/si476x-prop.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * drivers/mfd/si476x-prop.c -- Subroutines to access - * properties of 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 - -struct si476x_property_range { - u16 low, high; -}; - -static bool si476x_core_element_is_in_array(u16 element, - const u16 array[], - size_t size) -{ - int i; - - for (i = 0; i < size; i++) - if (element == array[i]) - return true; - - return false; -} - -static bool si476x_core_element_is_in_range(u16 element, - const struct si476x_property_range range[], - size_t size) -{ - int i; - - for (i = 0; i < size; i++) - if (element <= range[i].high && element >= range[i].low) - return true; - - return false; -} - -static bool si476x_core_is_valid_property_a10(struct si476x_core *core, - u16 property) -{ - static const u16 valid_properties[] = { - 0x0000, - 0x0500, 0x0501, - 0x0600, - 0x0709, 0x070C, 0x070D, 0x70E, 0x710, - 0x0718, - 0x1207, 0x1208, - 0x2007, - 0x2300, - }; - - static const struct si476x_property_range valid_ranges[] = { - { 0x0200, 0x0203 }, - { 0x0300, 0x0303 }, - { 0x0400, 0x0404 }, - { 0x0700, 0x0707 }, - { 0x1100, 0x1102 }, - { 0x1200, 0x1204 }, - { 0x1300, 0x1306 }, - { 0x2000, 0x2005 }, - { 0x2100, 0x2104 }, - { 0x2106, 0x2106 }, - { 0x2200, 0x220E }, - { 0x3100, 0x3104 }, - { 0x3207, 0x320F }, - { 0x3300, 0x3304 }, - { 0x3500, 0x3517 }, - { 0x3600, 0x3617 }, - { 0x3700, 0x3717 }, - { 0x4000, 0x4003 }, - }; - - return si476x_core_element_is_in_range(property, valid_ranges, - ARRAY_SIZE(valid_ranges)) || - si476x_core_element_is_in_array(property, valid_properties, - ARRAY_SIZE(valid_properties)); -} - -static bool si476x_core_is_valid_property_a20(struct si476x_core *core, - u16 property) -{ - static const u16 valid_properties[] = { - 0x071B, - 0x1006, - 0x2210, - 0x3401, - }; - - static const struct si476x_property_range valid_ranges[] = { - { 0x2215, 0x2219 }, - }; - - return si476x_core_is_valid_property_a10(core, property) || - si476x_core_element_is_in_range(property, valid_ranges, - ARRAY_SIZE(valid_ranges)) || - si476x_core_element_is_in_array(property, valid_properties, - ARRAY_SIZE(valid_properties)); -} - -static bool si476x_core_is_valid_property_a30(struct si476x_core *core, - u16 property) -{ - static const u16 valid_properties[] = { - 0x071C, 0x071D, - 0x1007, 0x1008, - 0x220F, 0x2214, - 0x2301, - 0x3105, 0x3106, - 0x3402, - }; - - static const struct si476x_property_range valid_ranges[] = { - { 0x0405, 0x0411 }, - { 0x2008, 0x200B }, - { 0x2220, 0x2223 }, - { 0x3100, 0x3106 }, - }; - - return si476x_core_is_valid_property_a20(core, property) || - si476x_core_element_is_in_range(property, valid_ranges, - ARRAY_SIZE(valid_ranges)) || - si476x_core_element_is_in_array(property, valid_properties, - ARRAY_SIZE(valid_properties)); -} - -typedef bool (*valid_property_pred_t) (struct si476x_core *, u16); - -static bool si476x_core_is_valid_property(struct si476x_core *core, - u16 property) -{ - static const valid_property_pred_t is_valid_property[] = { - [SI476X_REVISION_A10] = si476x_core_is_valid_property_a10, - [SI476X_REVISION_A20] = si476x_core_is_valid_property_a20, - [SI476X_REVISION_A30] = si476x_core_is_valid_property_a30, - }; - - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - return is_valid_property[core->revision](core, property); -} - - -static bool si476x_core_is_readonly_property(struct si476x_core *core, - u16 property) -{ - BUG_ON(core->revision > SI476X_REVISION_A30 || - core->revision == -1); - - switch (core->revision) { - case SI476X_REVISION_A10: - return (property == 0x3200); - case SI476X_REVISION_A20: - return (property == 0x1006 || - property == 0x2210 || - property == 0x3200); - case SI476X_REVISION_A30: - return false; - } - - return false; -} - -static bool si476x_core_regmap_readable_register(struct device *dev, - unsigned int reg) -{ - struct i2c_client *client = to_i2c_client(dev); - struct si476x_core *core = i2c_get_clientdata(client); - - return si476x_core_is_valid_property(core, (u16) reg); - -} - -static bool si476x_core_regmap_writable_register(struct device *dev, - unsigned int reg) -{ - struct i2c_client *client = to_i2c_client(dev); - struct si476x_core *core = i2c_get_clientdata(client); - - return si476x_core_is_valid_property(core, (u16) reg) && - !si476x_core_is_readonly_property(core, (u16) reg); -} - - -static int si476x_core_regmap_write(void *context, unsigned int reg, - unsigned int val) -{ - return si476x_core_cmd_set_property(context, reg, val); -} - -static int si476x_core_regmap_read(void *context, unsigned int reg, - unsigned *val) -{ - struct si476x_core *core = context; - int err; - - err = si476x_core_cmd_get_property(core, reg); - if (err < 0) - return err; - - *val = err; - - return 0; -} - - -static const struct regmap_config si476x_regmap_config = { - .reg_bits = 16, - .val_bits = 16, - - .max_register = 0x4003, - - .writeable_reg = si476x_core_regmap_writable_register, - .readable_reg = si476x_core_regmap_readable_register, - - .reg_read = si476x_core_regmap_read, - .reg_write = si476x_core_regmap_write, - - .cache_type = REGCACHE_RBTREE, -}; - -struct regmap *devm_regmap_init_si476x(struct si476x_core *core) -{ - return devm_regmap_init(&core->client->dev, NULL, - core, &si476x_regmap_config); -} -EXPORT_SYMBOL_GPL(devm_regmap_init_si476x); -- cgit v0.10.2 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 diff --git a/drivers/media/dvb-frontends/lg2160.h b/drivers/media/dvb-frontends/lg2160.h index a5f0368..194a07a 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 v0.10.2 From cdcfe40a5fee6a3300632b9a6e7f9de596f0b450 Mon Sep 17 00:00:00 2001 From: Ismael Luceno Date: Fri, 12 Apr 2013 18:28:33 -0300 Subject: [media] solo6x10: Update the encoder mode on VIDIOC_S_FMT Signed-off-by: Ismael Luceno Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c index 6c7d20f..90a0645 100644 --- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c @@ -872,6 +872,7 @@ static int solo_enc_set_fmt_cap(struct file *file, void *priv, if (pix->priv) solo_enc->type = SOLO_ENC_TYPE_EXT; */ + solo_update_mode(solo_enc); return 0; } -- cgit v0.10.2 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 diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index c9d3182..2d3507e 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 e3f6181..1b00615 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 v0.10.2 From 8c93c40080bda655295ae3673dfb26dee34d9d49 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 17 Apr 2013 03:20:30 -0300 Subject: [media] go7007: dubious one-bit signed bitfields Because they're signed, "is_video" and "is_audio" can be 0 and -1 instead of 0 and 1 as intended. It doesn't cause a bug, but it makes Sparse complain: drivers/staging/media/go7007/go7007-priv.h:94:31: error: dubious one-bit signed bitfield drivers/staging/media/go7007/go7007-priv.h:95:31: error: dubious one-bit signed bitfield Signed-off-by: Dan Carpenter Acked-by: Hans Verkuil Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/staging/media/go7007/go7007-priv.h index 8bde187..6e16af7 100644 --- a/drivers/staging/media/go7007/go7007-priv.h +++ b/drivers/staging/media/go7007/go7007-priv.h @@ -91,8 +91,8 @@ struct go7007_board_info { int num_i2c_devs; struct go_i2c { const char *type; - int is_video:1; - int is_audio:1; + unsigned int is_video:1; + unsigned int is_audio:1; int addr; u32 flags; } i2c_devs[5]; -- cgit v0.10.2 From 16af690fb071594ee7e261728bab470f3424d314 Mon Sep 17 00:00:00 2001 From: Ismael Luceno Date: Thu, 18 Apr 2013 10:56:35 -0300 Subject: [media] solo6x10: Fix pixelformat accepted/reported by the encoder The 6010 produces MPEG-4 part 2, while 6110 produces H.264. Signed-off-by: Ismael Luceno Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c index 90a0645..98e2902 100644 --- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c @@ -519,10 +519,15 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc, vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_DETECTED; } - if (solo_enc->fmt == V4L2_PIX_FMT_MPEG4) + switch (solo_enc->fmt) { + case V4L2_PIX_FMT_MPEG4: + case V4L2_PIX_FMT_H264: ret = solo_fill_mpeg(solo_enc, vb, vh); - else + break; + default: /* V4L2_PIX_FMT_MJPEG */ ret = solo_fill_jpeg(solo_enc, vb, vh); + break; + } if (!ret) { vb->v4l2_buf.sequence = solo_enc->sequence++; @@ -780,10 +785,21 @@ static int solo_enc_get_input(struct file *file, void *priv, static int solo_enc_enum_fmt_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { + struct solo_enc_dev *solo_enc = video_drvdata(file); + int dev_type = solo_enc->solo_dev->type; + switch (f->index) { case 0: - f->pixelformat = V4L2_PIX_FMT_MPEG4; - strcpy(f->description, "MPEG-4 AVC"); + switch (dev_type) { + case SOLO_DEV_6010: + f->pixelformat = V4L2_PIX_FMT_MPEG4; + strcpy(f->description, "MPEG-4 part 2"); + break; + case SOLO_DEV_6110: + f->pixelformat = V4L2_PIX_FMT_H264; + strcpy(f->description, "H.264"); + break; + } break; case 1: f->pixelformat = V4L2_PIX_FMT_MJPEG; @@ -798,6 +814,13 @@ static int solo_enc_enum_fmt_cap(struct file *file, void *priv, return 0; } +static inline int solo_valid_pixfmt(u32 pixfmt, int dev_type) +{ + return (pixfmt == V4L2_PIX_FMT_H264 && dev_type == SOLO_DEV_6110) + || (pixfmt == V4L2_PIX_FMT_MPEG4 && dev_type == SOLO_DEV_6010) + || pixfmt == V4L2_PIX_FMT_MJPEG ? 0 : -EINVAL; +} + static int solo_enc_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { @@ -805,8 +828,7 @@ static int solo_enc_try_fmt_cap(struct file *file, void *priv, struct solo_dev *solo_dev = solo_enc->solo_dev; struct v4l2_pix_format *pix = &f->fmt.pix; - if (pix->pixelformat != V4L2_PIX_FMT_MPEG4 && - pix->pixelformat != V4L2_PIX_FMT_MJPEG) + if (solo_valid_pixfmt(pix->pixelformat, solo_dev->type)) return -EINVAL; if (pix->width < solo_dev->video_hsize || @@ -919,8 +941,7 @@ static int solo_enum_framesizes(struct file *file, void *priv, struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_dev *solo_dev = solo_enc->solo_dev; - if (fsize->pixel_format != V4L2_PIX_FMT_MPEG4 && - fsize->pixel_format != V4L2_PIX_FMT_MJPEG) + if (solo_valid_pixfmt(fsize->pixel_format, solo_dev->type)) return -EINVAL; switch (fsize->index) { @@ -947,8 +968,7 @@ static int solo_enum_frameintervals(struct file *file, void *priv, struct solo_enc_dev *solo_enc = video_drvdata(file); struct solo_dev *solo_dev = solo_enc->solo_dev; - if (fintv->pixel_format != V4L2_PIX_FMT_MPEG4 && - fintv->pixel_format != V4L2_PIX_FMT_MJPEG) + if (solo_valid_pixfmt(fintv->pixel_format, solo_dev->type)) return -EINVAL; if (fintv->index) return -EINVAL; @@ -1225,7 +1245,8 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev, mutex_init(&solo_enc->lock); spin_lock_init(&solo_enc->av_lock); INIT_LIST_HEAD(&solo_enc->vidq_active); - solo_enc->fmt = V4L2_PIX_FMT_MPEG4; + solo_enc->fmt = (solo_dev->type == SOLO_DEV_6010) ? + V4L2_PIX_FMT_MPEG4 : V4L2_PIX_FMT_H264; solo_enc->type = SOLO_ENC_TYPE_STD; solo_enc->qp = SOLO_DEFAULT_QP; -- cgit v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index cc63f19..d2ed678 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 1f3bcb5..1d719cc 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 9e7a2b1..b8c11e5 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 5f48488..b538e05 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 1179842..5a4175e 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index 3e1eefa..effb87f 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 cf5e779..d08cdff 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index d9fe60b..f9916b8 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 5a4175e..d0916c8 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 v0.10.2 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 diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index 399e104..335a8f4 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 d0916c8..d8077f1 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index d8077f1..f081360 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 v0.10.2 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 diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 99b80b6..1957c0d 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 v0.10.2 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 diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index b8f9f85..624fd33 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 v0.10.2 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 diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 624fd33..3af7bb6 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 v0.10.2 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 diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 3af7bb6..72e3fa6 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index f25807d..a8eaad0 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h index d2fe162..953b074 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 71fed51..47da5e0 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 v0.10.2 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 diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index b353c50..ce8fcf2 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 v0.10.2 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 diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index ce8fcf2..cb52438 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/exynos4-is/fimc-is-i2c.c index 1ec6b3c..c397777 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 02b2719..6b3ea54 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 72c516a..558c528 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 3b9a664..d63947f 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 661d0d1..7ecf4e7 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.c b/drivers/media/platform/exynos4-is/fimc-is-sensor.c index 6b3ea54..035fa14 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-is-sensor.c b/drivers/media/platform/exynos4-is/fimc-is-sensor.c index 035fa14..6647421 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 50b8e4d..6036d49 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 3c81c88..c4049d4 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 1dbd554..a371ee5 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 7ecf4e7..14bb7bc 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index a371ee5..15ef8f2 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index c4049d4..ca72b02 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index ca72b02..5e89077 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c index 5e89077..47c6363 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index e810b1a..a5853fa 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 558c528..528f413 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 a8eaad0..379a5e9 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 953b074..539a3f7 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 8449c07..275a9f8 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c index 8636bcd..a2eda9d 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 275a9f8..bde1f47 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 14d663d..553d87e 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c index 3b02375..15d2396 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 v0.10.2 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 diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index a5853fa..01f9ae0 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 v0.10.2 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 diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index 20827ba..5612329 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 v0.10.2 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 diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index 386c0a7..40a73f7 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 v0.10.2 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 diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 6c4db9b..7585646 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 v0.10.2 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 diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index 4b9e0a2..f7440e5 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 v0.10.2 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 diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index 7487d72..4cc7f65d 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 v0.10.2 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 diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c index 3a43ba0..67f572c 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 f473aeb..f0ed825 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index d2ed678..83bfbe4 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 v0.10.2 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 diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 58c1744..7d833ee 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 ae35d25..fd56f25 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 59522b2..16ae3dc 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index 2e76274..d6daad1 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 v0.10.2 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 diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index d6daad1..90cfa35 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 v0.10.2 From 4ed7e7bae6a4edc90bfa82b55716e4000b584436 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 20 Apr 2013 12:07:16 -0300 Subject: [media] videodev2.h: Remove the unused old V4L1 buffer types Those aren't used anywhere for a long time. Drop it. Signed-off-by: Mauro Carvalho Chehab diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 97fb392..f40b41c 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -72,27 +72,6 @@ #define VIDEO_MAX_FRAME 32 #define VIDEO_MAX_PLANES 8 -#ifndef __KERNEL__ - -/* These defines are V4L1 specific and should not be used with the V4L2 API! - They will be removed from this header in the future. */ - -#define VID_TYPE_CAPTURE 1 /* Can capture */ -#define VID_TYPE_TUNER 2 /* Can tune */ -#define VID_TYPE_TELETEXT 4 /* Does teletext */ -#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ -#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ -#define VID_TYPE_CLIPPING 32 /* Can clip */ -#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ -#define VID_TYPE_SCALES 128 /* Scalable */ -#define VID_TYPE_MONOCHROME 256 /* Monochrome only */ -#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ -#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ -#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ -#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ -#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ -#endif - /* * M I S C E L L A N E O U S */ -- cgit v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 905a106..ba033fd 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index ba033fd..36ddbf1 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 36ddbf1..e6e7a06 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 1d719cc..d065a72 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index d065a72..77dac46 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 77dac46..57863d3 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 57863d3..a54182d 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 v0.10.2 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 diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index f9916b8..3ee22ff 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 v0.10.2 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 diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index e6e7a06..4835021 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 4c0823b..48af354 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index b194138..3ba856a 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 3ba856a..d270819 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 v0.10.2 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 diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 81361c2..6e91e84 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 v0.10.2 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 diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 9e7ce8b..f981d50 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 v0.10.2 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 diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 1f1f56f..b22f8fe 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 v0.10.2 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 diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index 07b700a..a87a0e1 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 39f095c..c8f3dcc 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 4e29c9d..51ce2c0 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 v0.10.2